Merge "Pass interaction type to FalsingManager.isFalse"
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
index cbced0a..f2f8854 100644
--- a/cmds/idmap2/tests/ResultTests.cpp
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -260,7 +260,8 @@
struct NoCopyContainer {
uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
- DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
+ NoCopyContainer(const NoCopyContainer&) = delete;
+ NoCopyContainer& operator=(const NoCopyContainer&) = delete;
};
Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 7f43640..fa135b1 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -83,6 +83,8 @@
private final AppPredictionSessionId mSessionId;
private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
+ private final IBinder mToken = new Binder();
+
/**
* Creates a new Prediction client.
* <p>
@@ -98,7 +100,7 @@
mSessionId = new AppPredictionSessionId(
context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
try {
- mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+ mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create predictor", e);
e.rethrowAsRuntimeException();
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
index 587e3fd..863fc6f9 100644
--- a/core/java/android/app/prediction/IPredictionManager.aidl
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -29,7 +29,7 @@
interface IPredictionManager {
void createPredictionSession(in AppPredictionContext context,
- in AppPredictionSessionId sessionId);
+ in AppPredictionSessionId sessionId, in IBinder token);
void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
index af77fe0..6d0fe72 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
@@ -20,5 +20,5 @@
/** {@hide} */
oneway interface ITimeZoneConfigurationListener {
- void onChange(in TimeZoneConfiguration configuration);
+ void onChange();
}
\ No newline at end of file
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
index 6e93af6..4f7e1f6 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -32,17 +32,15 @@
* this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
* for more complete documentation.
*
- *
* {@hide}
*/
interface ITimeZoneDetectorService {
TimeZoneCapabilities getCapabilities();
-
- TimeZoneConfiguration getConfiguration();
- boolean updateConfiguration(in TimeZoneConfiguration configuration);
void addConfigurationListener(ITimeZoneConfigurationListener listener);
void removeConfigurationListener(ITimeZoneConfigurationListener listener);
+ boolean updateConfiguration(in TimeZoneConfiguration configuration);
+
boolean suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion);
void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion);
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
index cc0af3f..09fffe9 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
+++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
@@ -16,9 +16,12 @@
package android.app.timezonedetector;
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.UserIdInt;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,9 +41,9 @@
*
* <p>Actions have associated methods, see the documentation for each action for details.
*
- * <p>For configuration capabilities, the associated current configuration value can be retrieved
- * using {@link TimeZoneDetector#getConfiguration()} and may be changed using
- * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)}.
+ * <p>For configuration settings capabilities, the associated settings value can be found via
+ * {@link #getConfiguration()} and may be changed using {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow).
*
* <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
*
@@ -60,7 +63,8 @@
public static final int CAPABILITY_NOT_SUPPORTED = 10;
/**
- * Indicates that a capability is supported on this device, but not allowed for the user.
+ * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
+ * if the capability relates to the ability to modify settings the user is not able to.
* This could be because of the user's type (e.g. maybe it applies to the primary user only) or
* device policy. Depending on the capability, this could mean the associated UI
* should be hidden, or displayed but disabled.
@@ -68,9 +72,11 @@
public static final int CAPABILITY_NOT_ALLOWED = 20;
/**
- * Indicates that a capability is possessed but not applicable, e.g. if it is configuration,
- * the current configuration or device state renders it irrelevant. The associated UI may be
- * hidden, disabled, or left visible (but ineffective) depending on requirements.
+ * Indicates that a capability is possessed but not currently applicable, e.g. if the
+ * capability relates to the ability to modify settings, the user has the ability to modify
+ * it, but it is currently rendered irrelevant by other settings or other device state (flags,
+ * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
+ * ineffective) depending on requirements.
*/
public static final int CAPABILITY_NOT_APPLICABLE = 30;
@@ -89,13 +95,13 @@
};
- private final @UserIdInt int mUserId;
+ @NonNull private final TimeZoneConfiguration mConfiguration;
private final @CapabilityState int mConfigureAutoDetectionEnabled;
private final @CapabilityState int mConfigureGeoDetectionEnabled;
private final @CapabilityState int mSuggestManualTimeZone;
private TimeZoneCapabilities(@NonNull Builder builder) {
- this.mUserId = builder.mUserId;
+ this.mConfiguration = Objects.requireNonNull(builder.mConfiguration);
this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
@@ -103,7 +109,8 @@
@NonNull
private static TimeZoneCapabilities createFromParcel(Parcel in) {
- return new TimeZoneCapabilities.Builder(in.readInt())
+ return new TimeZoneCapabilities.Builder()
+ .setConfiguration(in.readParcelable(null))
.setConfigureAutoDetectionEnabled(in.readInt())
.setConfigureGeoDetectionEnabled(in.readInt())
.setSuggestManualTimeZone(in.readInt())
@@ -112,21 +119,24 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mUserId);
+ dest.writeParcelable(mConfiguration, flags);
dest.writeInt(mConfigureAutoDetectionEnabled);
dest.writeInt(mConfigureGeoDetectionEnabled);
dest.writeInt(mSuggestManualTimeZone);
}
- /** Returns the user ID the capabilities are for. */
- public @UserIdInt int getUserId() {
- return mUserId;
+ /**
+ * Returns the user's time zone behavior configuration.
+ */
+ public @NonNull TimeZoneConfiguration getConfiguration() {
+ return mConfiguration;
}
/**
- * Returns the user's capability state for controlling whether automatic time zone detection is
- * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
- * TimeZoneConfiguration#isAutoDetectionEnabled()}.
+ * Returns the capability state associated with the user's ability to modify the automatic time
+ * zone detection setting. The setting can be updated via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+ * #getConfiguration()}.
*/
@CapabilityState
public int getConfigureAutoDetectionEnabled() {
@@ -134,9 +144,10 @@
}
/**
- * Returns the user's capability state for controlling whether geolocation can be used to detect
- * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
- * TimeZoneConfiguration#isGeoDetectionEnabled()}.
+ * Returns the capability state associated with the user's ability to modify the geolocation
+ * detection setting. The setting can be updated via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+ * #getConfiguration()}.
*/
@CapabilityState
public int getConfigureGeoDetectionEnabled() {
@@ -144,8 +155,8 @@
}
/**
- * Returns the user's capability state for manually setting the time zone on a device via
- * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
+ * Returns the capability state associated with the user's ability to manually set the time zone
+ * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
*
* <p>The suggestion will be ignored in all cases unless the value is {@link
* #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
@@ -155,6 +166,38 @@
return mSuggestManualTimeZone;
}
+ /**
+ * Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of
+ * {@code requestedChanges}, if the current capabilities allow. The new configuration is
+ * returned and the capabilities are left unchanged. If the capabilities do not permit one or
+ * more of the changes then {@code null} is returned.
+ */
+ @Nullable
+ public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) {
+ if (requestedChanges.getUserId() != mConfiguration.getUserId()) {
+ throw new IllegalArgumentException("User does not match:"
+ + " this=" + mConfiguration + ", other=" + requestedChanges);
+ }
+
+ TimeZoneConfiguration.Builder newConfigBuilder =
+ new TimeZoneConfiguration.Builder(mConfiguration);
+ if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) {
+ if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
+ }
+
+ if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) {
+ if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
+ }
+
+ return newConfigBuilder.build();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -169,7 +212,7 @@
return false;
}
TimeZoneCapabilities that = (TimeZoneCapabilities) o;
- return mUserId == that.mUserId
+ return Objects.equals(mConfiguration, that.mConfiguration)
&& mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
&& mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
&& mSuggestManualTimeZone == that.mSuggestManualTimeZone;
@@ -177,7 +220,7 @@
@Override
public int hashCode() {
- return Objects.hash(mUserId,
+ return Objects.hash(mConfiguration,
mConfigureAutoDetectionEnabled,
mConfigureGeoDetectionEnabled,
mSuggestManualTimeZone);
@@ -186,7 +229,7 @@
@Override
public String toString() {
return "TimeZoneDetectorCapabilities{"
- + "mUserId=" + mUserId
+ + "mConfiguration=" + mConfiguration
+ ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
+ ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
+ ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
@@ -196,16 +239,18 @@
/** @hide */
public static class Builder {
- private final @UserIdInt int mUserId;
+ private TimeZoneConfiguration mConfiguration;
private @CapabilityState int mConfigureAutoDetectionEnabled;
private @CapabilityState int mConfigureGeoDetectionEnabled;
private @CapabilityState int mSuggestManualTimeZone;
- /**
- * Creates a new Builder with no properties set.
- */
- public Builder(@UserIdInt int userId) {
- mUserId = userId;
+ /** Sets the user-visible configuration settings. */
+ public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) {
+ if (!configuration.isComplete()) {
+ throw new IllegalArgumentException(configuration + " is not complete");
+ }
+ this.mConfiguration = configuration;
+ return this;
}
/** Sets the state for the automatic time zone detection enabled config. */
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
index 6f84ee2..95db0a2 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
+++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.StringDef;
+import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,21 +28,20 @@
import java.util.Objects;
/**
- * Configuration that controls the behavior of the time zone detector associated with a specific
- * user.
+ * User visible settings that control the behavior of the time zone detector / manual time zone
+ * entry.
*
- * <p>Configuration consists of a set of known properties. When reading configuration via
- * {@link TimeZoneDetector#getConfiguration()} values for all known properties will be provided. In
- * some cases, such as when the configuration relies on optional hardware, the values may be
- * meaningless / defaulted to safe values.
+ * <p>When reading the configuration, values for all settings will be provided. In some cases, such
+ * as when the device behavior relies on optional hardware / OEM configuration, or the value of
+ * several settings, the device behavior may not be directly affected by the setting value.
*
- * <p>Configuration properties can be left absent when updating configuration via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those values will not be
- * changed. Not all configuration properties can be modified by all users. See {@link
- * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities}.
+ * <p>Settings can be left absent when updating configuration via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be
+ * changed. Not all configuration settings can be modified by all users: see {@link
+ * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details.
*
- * <p>See {@link #isComplete()} to tell if all known properties are present, and {@link
- * #hasProperty(String)} with {@code PROPERTY_} constants for testing individual properties.
+ * <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence
+ * of individual settings.
*
* @hide
*/
@@ -59,80 +59,82 @@
};
/** All configuration properties */
- @StringDef(PROPERTY_AUTO_DETECTION_ENABLED)
+ @StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED })
@Retention(RetentionPolicy.SOURCE)
- @interface Property {}
+ @interface Setting {}
/** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */
- @Property
- public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+ @Setting
+ public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
/** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
- @Property
- public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
+ @Setting
+ public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
- private final Bundle mBundle;
+ private final @UserIdInt int mUserId;
+ @NonNull private final Bundle mBundle;
private TimeZoneConfiguration(Builder builder) {
- this.mBundle = builder.mBundle;
+ this.mUserId = builder.mUserId;
+ this.mBundle = Objects.requireNonNull(builder.mBundle);
}
private static TimeZoneConfiguration createFromParcel(Parcel in) {
- return new TimeZoneConfiguration.Builder()
+ return new TimeZoneConfiguration.Builder(in.readInt())
.setPropertyBundleInternal(in.readBundle())
.build();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mUserId);
dest.writeBundle(mBundle);
}
- /** Returns {@code true} if all known properties are set. */
- public boolean isComplete() {
- return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
- && hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
}
- /** Returns true if the specified property is set. */
- public boolean hasProperty(@Property String property) {
- return mBundle.containsKey(property);
+ /** Returns {@code true} if all known settings are present. */
+ public boolean isComplete() {
+ return hasSetting(SETTING_AUTO_DETECTION_ENABLED)
+ && hasSetting(SETTING_GEO_DETECTION_ENABLED);
+ }
+
+ /** Returns true if the specified setting is set. */
+ public boolean hasSetting(@Setting String setting) {
+ return mBundle.containsKey(setting);
}
/**
- * Returns the value of the {@link #PROPERTY_AUTO_DETECTION_ENABLED} property. This
+ * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This
* controls whether a device will attempt to determine the time zone automatically using
- * contextual information.
+ * contextual information if the device supports auto detection.
*
- * @throws IllegalStateException if the field has not been set
+ * <p>This setting is global and can be updated by some users.
+ *
+ * @throws IllegalStateException if the setting has not been set
*/
public boolean isAutoDetectionEnabled() {
- if (!mBundle.containsKey(PROPERTY_AUTO_DETECTION_ENABLED)) {
- throw new IllegalStateException(PROPERTY_AUTO_DETECTION_ENABLED + " is not set");
- }
- return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED);
+ enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
+ return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
}
/**
- * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This
- * controls whether a device can use location to determine time zone. Only used when
- * {@link #isAutoDetectionEnabled()} is true.
+ * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This
+ * controls whether a device can use geolocation to determine time zone. Only used when
+ * {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their
+ * location to be used.
*
- * @throws IllegalStateException if the field has not been set
+ * <p>This setting is user-scoped and can be updated by some users.
+ * See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}.
+ *
+ * @throws IllegalStateException if the setting has not been set
*/
public boolean isGeoDetectionEnabled() {
- if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) {
- throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set");
- }
- return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED);
- }
-
- /**
- * Convenience method to merge this with another. The argument configuration properties have
- * precedence.
- */
- public TimeZoneConfiguration with(TimeZoneConfiguration other) {
- return new Builder(this).mergeProperties(other).build();
+ enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED);
+ return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED);
}
@Override
@@ -149,43 +151,61 @@
return false;
}
TimeZoneConfiguration that = (TimeZoneConfiguration) o;
- return mBundle.kindofEquals(that.mBundle);
+ return mUserId == that.mUserId
+ && mBundle.kindofEquals(that.mBundle);
}
@Override
public int hashCode() {
- return Objects.hash(mBundle);
+ return Objects.hash(mUserId, mBundle);
}
@Override
public String toString() {
return "TimeZoneDetectorConfiguration{"
+ + "mUserId=" + mUserId
+ "mBundle=" + mBundle
+ '}';
}
+ private void enforceSettingPresent(@Setting String setting) {
+ if (!mBundle.containsKey(setting)) {
+ throw new IllegalStateException(setting + " is not set");
+ }
+ }
+
/** @hide */
public static class Builder {
- private Bundle mBundle = new Bundle();
+ private final @UserIdInt int mUserId;
+ private final Bundle mBundle = new Bundle();
/**
- * Creates a new Builder with no properties set.
+ * Creates a new Builder for a userId with no settings held.
*/
- public Builder() {}
+ public Builder(@UserIdInt int userId) {
+ mUserId = userId;
+ }
/**
- * Creates a new Builder by copying properties from an existing instance.
+ * Creates a new Builder by copying the user ID and settings from an existing instance.
*/
public Builder(TimeZoneConfiguration toCopy) {
+ this.mUserId = toCopy.mUserId;
mergeProperties(toCopy);
}
/**
- * Merges {@code other} properties into this instances, replacing existing values in this
- * where the properties appear in both.
+ * Merges {@code other} settings into this instances, replacing existing values in this
+ * where the settings appear in both.
*/
public Builder mergeProperties(TimeZoneConfiguration other) {
+ if (mUserId != other.mUserId) {
+ throw new IllegalArgumentException(
+ "Cannot merge configurations for different user IDs."
+ + " this.mUserId=" + this.mUserId
+ + ", other.mUserId=" + other.mUserId);
+ }
this.mBundle.putAll(other.mBundle);
return this;
}
@@ -195,15 +215,19 @@
return this;
}
- /** Sets the desired state of the automatic time zone detection property. */
+ /**
+ * Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting.
+ */
public Builder setAutoDetectionEnabled(boolean enabled) {
- this.mBundle.putBoolean(PROPERTY_AUTO_DETECTION_ENABLED, enabled);
+ this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
return this;
}
- /** Sets the desired state of the geolocation time zone detection enabled property. */
+ /**
+ * Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting.
+ */
public Builder setGeoDetectionEnabled(boolean enabled) {
- this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled);
+ this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled);
return this;
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 7885613..2b1cbf2 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -37,37 +37,29 @@
TimeZoneCapabilities getCapabilities();
/**
- * Returns the current user's complete time zone configuration. See {@link
- * TimeZoneConfiguration}.
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @NonNull
- TimeZoneConfiguration getConfiguration();
-
- /**
* Modifies the time zone detection configuration.
*
- * <p>Configuration properties vary in scope: some may be device-wide, others may be specific to
- * the current user.
+ * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
+ * specific to the current user.
*
- * <p>The ability to modify configuration properties can be subject to restrictions. For
+ * <p>The ability to modify configuration settings can be subject to restrictions. For
* example, they may be determined by device hardware, general policy (i.e. only the primary
- * user can set them), or by a managed device policy. See {@link #getCapabilities()} to obtain
+ * user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain
* information at runtime about the user's capabilities.
*
- * <p>Attempts to set configuration with capabilities that are {@link
+ * <p>Attempts to modify configuration settings with capabilities that are {@link
* TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
* TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
- * will be returned. Setting configuration with capabilities that are {@link
+ * will be returned. Modifying configuration settings with capabilities that are {@link
* TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
* TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
* TimeZoneCapabilities} for further details.
*
- * <p>If the configuration is not "complete", then only the specified properties will be
- * updated (where the user's capabilities allow) and other settings will be left unchanged. See
- * {@link TimeZoneConfiguration#isComplete()}.
+ * <p>If the supplied configuration only has some values set, then only the specified settings
+ * will be updated (where the user's capabilities allow) and other settings will be left
+ * unchanged.
*
- * @return {@code true} if all the configuration properties specified have been set to the
+ * @return {@code true} if all the configuration settings specified have been set to the
* new values, {@code false} if none have
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -76,14 +68,20 @@
/**
* An interface that can be used to listen for changes to the time zone detector configuration.
*/
+ @FunctionalInterface
interface TimeZoneConfigurationListener {
- /** Called when the configuration changes. There are no guarantees about the thread used. */
- void onChange(@NonNull TimeZoneConfiguration configuration);
+ /**
+ * Called when something about the time zone configuration on the device has changed.
+ * This could be because the current user has changed, one of the device's relevant settings
+ * has changed, or something that could affect a user's capabilities has changed.
+ * There are no guarantees about the thread used.
+ */
+ void onChange();
}
/**
- * Registers a listener that will be informed when the configuration changes. The complete
- * configuration is passed to the listener, not just the properties that have changed.
+ * Registers a listener that will be informed when something about the time zone configuration
+ * changes.
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 0770aff..4c69732 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -57,19 +57,6 @@
}
@Override
- @NonNull
- public TimeZoneConfiguration getConfiguration() {
- if (DEBUG) {
- Log.d(TAG, "getConfiguration called");
- }
- try {
- return mITimeZoneDetectorService.getConfiguration();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
if (DEBUG) {
Log.d(TAG, "updateConfiguration called: " + configuration);
@@ -94,8 +81,8 @@
ITimeZoneConfigurationListener iListener =
new ITimeZoneConfigurationListener.Stub() {
@Override
- public void onChange(@NonNull TimeZoneConfiguration configuration) {
- notifyConfigurationListeners(configuration);
+ public void onChange() {
+ notifyConfigurationListeners();
}
};
mConfigurationReceiver = iListener;
@@ -116,14 +103,14 @@
}
}
- private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) {
+ private void notifyConfigurationListeners() {
final ArraySet<TimeZoneConfigurationListener> configurationListeners;
synchronized (this) {
configurationListeners = new ArraySet<>(mConfigurationListeners);
}
int size = configurationListeners.size();
for (int i = 0; i < size; i++) {
- configurationListeners.valueAt(i).onChange(configuration);
+ configurationListeners.valueAt(i).onChange();
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c302def..03cf0cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6404,6 +6404,17 @@
public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY;
/**
+ * The current location time zone detection enabled state for the user.
+ *
+ * See {@link
+ * android.app.timezonedetector.TimeZoneDetector#getCapabilities} for access. See {@link
+ * android.app.timezonedetector.TimeZoneDetector#updateConfiguration} to update.
+ * @hide
+ */
+ public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED =
+ "location_time_zone_detection_enabled";
+
+ /**
* The accuracy in meters used for coarsening location for clients with only the coarse
* location permission.
*
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 73d148c..0834b2d 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -36,7 +36,18 @@
Consts.TAG_WM),
WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
- WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+ WM_DEBUG_CONFIGURATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_SWITCH(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_CONTAINERS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_IMMERSIVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 23af70a..cbcbe7f 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -613,7 +613,7 @@
}
// Do not change sched policy cgroup after boot complete.
- rc = androidSetThreadPriority(pid, pri, !boot_completed);
+ rc = androidSetThreadPriorityAndPolicy(pid, pri, !boot_completed);
if (rc != 0) {
if (rc == INVALID_OPERATION) {
signalExceptionForPriorityError(env, errno, pid);
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
index 72391f4..db127c6 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import org.junit.Test;
@@ -31,11 +32,22 @@
@Test
public void testEquals() {
- TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration1)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration1)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -45,6 +57,20 @@
assertEquals(one, two);
}
+ builder2.setConfiguration(configuration2);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfiguration(configuration2);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
{
TimeZoneCapabilities one = builder1.build();
@@ -90,7 +116,12 @@
@Test
public void testParcelable() {
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -105,4 +136,51 @@
builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
assertRoundTripParcelable(builder.build());
}
+
+ @Test
+ public void testApplyUpdate_permitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+ .setConfiguration(oldConfiguration)
+ .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+ .build();
+ assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertEquals(expected, capabilities.applyUpdate(configChange));
+ }
+
+ @Test
+ public void testApplyUpdate_notPermitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+ .setConfiguration(oldConfiguration)
+ .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
+ .build();
+ assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ assertNull(capabilities.applyUpdate(configChange));
+ }
}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
index 00dc73e..faf908d 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
@@ -27,11 +27,14 @@
public class TimeZoneConfigurationTest {
+ private static final int ARBITRARY_USER_ID = 9876;
+
@Test
public void testBuilder_copyConstructor() {
- TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true);
+ TimeZoneConfiguration.Builder builder1 =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true);
TimeZoneConfiguration configuration1 = builder1.build();
TimeZoneConfiguration configuration2 =
@@ -41,28 +44,28 @@
}
@Test
- public void testIsComplete() {
- TimeZoneConfiguration.Builder builder =
- new TimeZoneConfiguration.Builder();
- assertFalse(builder.build().isComplete());
+ public void testIntrospectionMethods() {
+ TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build();
+ assertFalse(empty.isComplete());
+ assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
- builder.setAutoDetectionEnabled(true);
- assertFalse(builder.build().isComplete());
-
- builder.setGeoDetectionEnabled(true);
- assertTrue(builder.build().isComplete());
+ TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ assertTrue(completeConfig.isComplete());
+ assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
}
@Test
public void testBuilder_mergeProperties() {
- TimeZoneConfiguration configuration1 =
- new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .build();
+ TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .build();
{
TimeZoneConfiguration mergedEmptyAnd1 =
- new TimeZoneConfiguration.Builder()
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.mergeProperties(configuration1)
.build();
assertEquals(configuration1, mergedEmptyAnd1);
@@ -70,7 +73,7 @@
{
TimeZoneConfiguration configuration2 =
- new TimeZoneConfiguration.Builder()
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.setAutoDetectionEnabled(false)
.build();
@@ -87,14 +90,22 @@
@Test
public void testEquals() {
TimeZoneConfiguration.Builder builder1 =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
{
TimeZoneConfiguration one = builder1.build();
assertEquals(one, one);
}
+ {
+ TimeZoneConfiguration.Builder differentUserBuilder =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1);
+ TimeZoneConfiguration one = builder1.build();
+ TimeZoneConfiguration two = differentUserBuilder.build();
+ assertNotEquals(one, two);
+ }
+
TimeZoneConfiguration.Builder builder2 =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
{
TimeZoneConfiguration one = builder1.build();
TimeZoneConfiguration two = builder2.build();
@@ -148,7 +159,7 @@
@Test
public void testParcelable() {
TimeZoneConfiguration.Builder builder =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
assertRoundTripParcelable(builder.build());
builder.setAutoDetectionEnabled(true);
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 73296987..03f7be7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -13,6 +13,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-2121056984": {
+ "message": "%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-2109936758": {
"message": "removeAppToken make exiting: %s",
"level": "VERBOSE",
@@ -43,6 +49,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2029985709": {
+ "message": "setFocusedTask: taskId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-2024464438": {
"message": "app-onAnimationFinished(): mOuter=%s",
"level": "DEBUG",
@@ -139,6 +151,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-1868048288": {
+ "message": "Updating to new configuration after starting activity.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
"-1862269827": {
"message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -163,6 +181,18 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-1810446914": {
+ "message": "Trying to update display configuration for system\/invalid process.",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-1791031393": {
+ "message": "Ensuring correct configuration: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1782453012": {
"message": "Checking theme of starting window: 0x%x",
"level": "VERBOSE",
@@ -211,6 +241,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1699018375": {
+ "message": "Adding activity %s to task %s callers: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1698815688": {
"message": "Resetting app token %s of replacing window marks.",
"level": "DEBUG",
@@ -229,12 +265,30 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1638958146": {
+ "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+ },
"-1632122349": {
"message": "Changing surface while display frozen: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1630752478": {
+ "message": "removeLockedTask: removed %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
+ "-1598452494": {
+ "message": "activityDestroyedLocked: r=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_CONTAINERS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1596995693": {
"message": "startAnimation",
"level": "DEBUG",
@@ -307,6 +361,18 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-1495062622": {
+ "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_SWITCH",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-1492881555": {
+ "message": "Starting activity when config will change = %b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
"-1471946192": {
"message": "Marking app token %s with replacing child windows.",
"level": "DEBUG",
@@ -379,6 +445,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-1305755880": {
+ "message": "Initial config: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1292329638": {
"message": "Added starting %s: startingWindow=%s startingView=%s",
"level": "VERBOSE",
@@ -445,6 +517,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "-1155279885": {
+ "message": "Frontmost changed immersion: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_IMMERSIVE",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1144293044": {
"message": "SURFACE SET FREEZE LAYER: %s",
"level": "INFO",
@@ -475,6 +553,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-1115019498": {
+ "message": "Configuration & display unchanged in %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1113134997": {
"message": "Attempted to add application window with unknown token %s. Aborting.",
"level": "WARN",
@@ -559,12 +643,24 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-929676529": {
+ "message": "Configuration changes for %s, allChanges=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-928291778": {
"message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "-927199900": {
+ "message": "Updating global configuration to: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-916108501": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -619,12 +715,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-846078709": {
+ "message": "Configuration doesn't matter in finishing %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-809771899": {
"message": "findFocusedWindow: Reached focused app=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-804217032": {
+ "message": "Skipping config check (will change): %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-793346159": {
"message": "New transit into wallpaper: %s",
"level": "VERBOSE",
@@ -673,6 +781,18 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-743431900": {
+ "message": "Configuration no differences in %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-716565534": {
+ "message": "moveActivityStackToFront: unfocusable activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-714291355": {
"message": "Losing delayed focus: %s",
"level": "INFO",
@@ -739,6 +859,12 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-593535526": {
+ "message": "Binding proc %s with config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/am\/ActivityManagerService.java"
+ },
"-583031528": {
"message": "%s",
"level": "INFO",
@@ -757,6 +883,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-548282316": {
+ "message": "setLockTaskMode: Locking to %s Callers=%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-547111355": {
"message": "hideIme Control target: %s ",
"level": "DEBUG",
@@ -781,6 +913,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-503656156": {
+ "message": "Update process config of %s to new config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-496681057": {
"message": "Attempted to get remove mode of a display that does not exist: %d",
"level": "WARN",
@@ -799,6 +937,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "-449118559": {
+ "message": "Trying to update display configuration for invalid process, pid=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-445944810": {
"message": "finish(%b): mCanceled=%b",
"level": "DEBUG",
@@ -835,6 +979,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
},
+ "-401282500": {
+ "message": "destroyIfPossible: r=%s destroy returned removed=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_CONTAINERS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-395922585": {
"message": "InsetsSource setWin %s",
"level": "DEBUG",
@@ -907,18 +1057,42 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-317194205": {
+ "message": "clearLockedTasks: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-303497363": {
"message": "reparent: moving activity=%s to task=%d at %d",
"level": "INFO",
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-272719931": {
+ "message": "startLockTaskModeLocked: %s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-260960989": {
+ "message": "Removing and adding activity %s to stack at top callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-251259736": {
"message": "No longer freezing: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-235225312": {
+ "message": "Skipping config check for initializing activity: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-198463978": {
"message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
"level": "VERBOSE",
@@ -943,6 +1117,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-168799453": {
+ "message": "Allowing features %d:0x%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-167822951": {
"message": "Attempted to add starting window to token with already existing starting window",
"level": "WARN",
@@ -979,6 +1159,12 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-90559682": {
+ "message": "Config is skipping already pausing %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-87705714": {
"message": "findFocusedWindow: focusedApp=null using new focus @ %s",
"level": "VERBOSE",
@@ -1303,6 +1489,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "355940361": {
+ "message": "Config is destroying non-running %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"371641947": {
"message": "Window Manager Crash %s",
"level": "WTF",
@@ -1315,6 +1507,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "374506950": {
+ "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SWITCH",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"374972436": {
"message": "performEnableScreen: Waiting for anim complete",
"level": "INFO",
@@ -1411,6 +1609,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "556758086": {
+ "message": "Applying new update lock state '%s' for %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_IMMERSIVE",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"557227556": {
"message": "onAnimationFinished(): Notify animation finished:",
"level": "DEBUG",
@@ -1531,12 +1735,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "676824470": {
- "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.",
- "level": "ERROR",
- "group": "TEST_GROUP",
- "at": "com\/android\/server\/wm\/ProtoLogGroup.java"
- },
"685047360": {
"message": "Resizing window %s",
"level": "VERBOSE",
@@ -1561,6 +1759,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "715749922": {
+ "message": "Allowlisting %d:%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "736692676": {
+ "message": "Config is relaunching %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"745391677": {
"message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
"level": "INFO",
@@ -1615,6 +1825,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "869266572": {
+ "message": "Removing activity %s from stack, reason= %s callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"873914452": {
"message": "goodToGo()",
"level": "DEBUG",
@@ -1645,12 +1861,30 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "950074526": {
+ "message": "setLockTaskMode: Can't lock due to auth",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"954470154": {
"message": "FORCED DISPLAY SCALING DISABLED",
"level": "INFO",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "956374481": {
+ "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
+ "969323241": {
+ "message": "Sending new config to %s, config: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"972354148": {
"message": "\tcontainer=%s",
"level": "DEBUG",
@@ -1663,12 +1897,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1040675582": {
+ "message": "Can't report activity configuration update - client not running, activityRecord=%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1046922686": {
"message": "requestScrollCapture: caught exception dispatching callback: %s",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1049367566": {
+ "message": "Sending to proc %s new config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/WindowProcessController.java"
+ },
"1051545910": {
"message": "Exit animation finished in %s: remove=%b",
"level": "VERBOSE",
@@ -1681,6 +1927,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
},
+ "1088929964": {
+ "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1089714158": {
"message": " FREEZE %s: DESTROY",
"level": "INFO",
@@ -1789,6 +2041,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1337596507": {
+ "message": "Sending to proc %s new compat %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/CompatModePackages.java"
+ },
"1346895820": {
"message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
"level": "VERBOSE",
@@ -1801,6 +2059,12 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "1360551978": {
+ "message": "Trying to update display configuration for non-existing displayId=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"1364498663": {
"message": "notifyAppResumed: wasStopped=%b %s",
"level": "VERBOSE",
@@ -1819,6 +2083,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
+ "1401295262": {
+ "message": "Mode default, asking user",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1401700824": {
"message": "Window drawn win=%s",
"level": "DEBUG",
@@ -1927,6 +2197,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1522489371": {
+ "message": "moveActivityStackToFront: activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1525976603": {
"message": "cancelAnimation(): reason=%s",
"level": "DEBUG",
@@ -1951,6 +2227,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1576607724": {
+ "message": "Report configuration: %s %s %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"1577579529": {
"message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
"level": "ERROR",
@@ -1981,6 +2263,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1635062046": {
+ "message": "Skipping config check invisible: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1635462459": {
"message": "onMovedByResize: Moving %s",
"level": "DEBUG",
@@ -2023,6 +2311,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1679569477": {
+ "message": "Configuration doesn't matter not running %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1720229827": {
"message": "Creating animation bounds layer",
"level": "INFO",
@@ -2077,12 +2371,30 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1789603530": {
+ "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1822843721": {
"message": "Aborted starting %s: startingData=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1824105730": {
+ "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "1829094918": {
+ "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1831008694": {
"message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
"level": "DEBUG",
@@ -2161,6 +2473,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "1975793405": {
+ "message": "setFocusedStack: stackId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"1984470582": {
"message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
"level": "DEBUG",
@@ -2173,6 +2491,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowAnimator.java"
},
+ "1995093920": {
+ "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"2016061474": {
"message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
"level": "VERBOSE",
@@ -2191,6 +2515,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "2022322588": {
+ "message": "Adding activity %s to stack to task %s callers: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"2022422429": {
"message": "createAnimationAdapter(): container=%s",
"level": "DEBUG",
@@ -2269,6 +2599,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "2134999275": {
+ "message": "moveActivityStackToFront: already on top, activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"2137411379": {
"message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -2277,9 +2613,6 @@
}
},
"groups": {
- "TEST_GROUP": {
- "tag": "WindowManagetProtoLogTest"
- },
"WM_DEBUG_ADD_REMOVE": {
"tag": "WindowManager"
},
@@ -2292,6 +2625,12 @@
"WM_DEBUG_BOOT": {
"tag": "WindowManager"
},
+ "WM_DEBUG_CONFIGURATION": {
+ "tag": "WindowManager"
+ },
+ "WM_DEBUG_CONTAINERS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_DRAW": {
"tag": "WindowManager"
},
@@ -2304,9 +2643,15 @@
"WM_DEBUG_IME": {
"tag": "WindowManager"
},
+ "WM_DEBUG_IMMERSIVE": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_KEEP_SCREEN_ON": {
"tag": "WindowManager"
},
+ "WM_DEBUG_LOCKTASK": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_ORIENTATION": {
"tag": "WindowManager"
},
@@ -2325,6 +2670,9 @@
"WM_DEBUG_STARTING_WINDOW": {
"tag": "WindowManager"
},
+ "WM_DEBUG_SWITCH": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index 3b22fdb..38e1a48 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -299,10 +299,10 @@
// The glass pane is used to view touch events before passed to the notification list.
// This allows us to initialize gesture listeners and detect when to close the notifications
glassPane.setOnTouchListener((v, event) -> {
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (isClosingAction(event)) {
mNotificationListAtEndAtTimeOfTouch = false;
}
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (isOpeningAction(event)) {
mFirstTouchDownOnGlassPane = event.getRawX();
mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd;
// Reset the tracker when there is a touch down on the glass pane.
@@ -355,8 +355,7 @@
if (rect != null) {
clippedHeight = rect.bottom;
}
- if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
- && mIsSwipingVerticallyToClose) {
+ if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) {
if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) {
animatePanel(DEFAULT_FLING_VELOCITY, false);
} else if (clippedHeight != getLayout().getHeight() && isTracking) {
@@ -369,7 +368,7 @@
// Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after
// the event has been passed to the closeGestureDetector above, such that the
// closeGestureDetector sees the up event before the state has changed.
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (isClosingAction(event)) {
mNotificationListAtEndAtTimeOfTouch = false;
}
return handled || isTracking;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 45808a8..bde31f1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -191,6 +191,38 @@
}
}
+ /** Checks if a {@link MotionEvent} is an action to open the panel.
+ * @param e {@link MotionEvent} to check.
+ * @return true only if opening action.
+ */
+ protected boolean isOpeningAction(MotionEvent e) {
+ if (mAnimateDirection == POSITIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+ }
+
+ if (mAnimateDirection == NEGATIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_UP;
+ }
+
+ return false;
+ }
+
+ /** Checks if a {@link MotionEvent} is an action to close the panel.
+ * @param e {@link MotionEvent} to check.
+ * @return true only if closing action.
+ */
+ protected boolean isClosingAction(MotionEvent e) {
+ if (mAnimateDirection == POSITIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_UP;
+ }
+
+ if (mAnimateDirection == NEGATIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+ }
+
+ return false;
+ }
+
/* ***************************************************************************************** *
* Panel Animation
* ***************************************************************************************** */
@@ -243,8 +275,7 @@
* Depending on certain conditions, determines whether to fully expand or collapse the panel.
*/
protected void maybeCompleteAnimation(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_UP
- && isPanelVisible()) {
+ if (isClosingAction(event) && isPanelVisible()) {
if (mSettleClosePercentage < mPercentageFromEndingEdge) {
animatePanel(DEFAULT_FLING_VELOCITY, false);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index e38dce0..8364b48 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -262,11 +262,11 @@
onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
} else if (isLongPress) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
} else if (isWakeLockScreen) {
if (wakeEvent) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
}
} else {
proximityCheckThenCall((result) -> {
@@ -536,7 +536,7 @@
if (PULSE_ACTION.equals(intent.getAction())) {
if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
}
if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
mMachine.requestState(DozeMachine.State.FINISH);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index 214088c..7037403 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -36,8 +36,8 @@
* Activity to show the PIP menu to control PIP.
*/
public class PipMenuActivity extends Activity implements PipManager.Listener {
- private static final boolean DEBUG = false;
private static final String TAG = "PipMenuActivity";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index b587dd3..d127172 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -594,15 +594,23 @@
if (pointerIndex < 0) {
return;
}
- final float deltaX =
- mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
- - rawEvent.getX(pointerIndex);
- final float deltaY =
- mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
- - rawEvent.getY(pointerIndex);
- final double moveDelta = Math.hypot(deltaX, deltaY);
- if (moveDelta < mTouchSlop) {
- return;
+ // Require both fingers to have moved a certain amount before starting a drag.
+ for (int index = 0; index < event.getPointerCount(); ++index) {
+ int id = event.getPointerId(index);
+ if (!mReceivedPointerTracker.isReceivedPointerDown(id)) {
+ // Something is wrong with the event stream.
+ Slog.e(LOG_TAG, "Invalid pointer id: " + id);
+ }
+ final float deltaX =
+ mReceivedPointerTracker.getReceivedPointerDownX(id)
+ - rawEvent.getX(index);
+ final float deltaY =
+ mReceivedPointerTracker.getReceivedPointerDownY(id)
+ - rawEvent.getY(index);
+ final double moveDelta = Math.hypot(deltaX, deltaY);
+ if (moveDelta < mTouchSlop) {
+ return;
+ }
}
}
// More than one pointer so the user is not touch exploring
@@ -612,12 +620,20 @@
if (isDraggingGesture(event)) {
// Two pointers moving in the same direction within
// a given distance perform a drag.
- mState.startDragging();
computeDraggingPointerIdIfNeeded(event);
pointerIdBits = 1 << mDraggingPointerId;
event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
- mDispatcher.sendMotionEvent(
- event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ MotionEvent downEvent = computeDownEventForDrag(event);
+ if (downEvent != null) {
+ mDispatcher.sendMotionEvent(
+ downEvent, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ mDispatcher.sendMotionEvent(
+ event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags);
+ } else {
+ mDispatcher.sendMotionEvent(
+ event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ }
+ mState.startDragging();
} else {
// Two pointers moving arbitrary are delegated to the view hierarchy.
mState.startDelegating();
@@ -1004,6 +1020,49 @@
return distance;
}
+ /**
+ * Creates a down event using the down coordinates of the dragging pointer and other information
+ * from the supplied event. The supplied event's down time is adjusted to reflect the time when
+ * the dragging pointer initially went down.
+ */
+ private MotionEvent computeDownEventForDrag(MotionEvent event) {
+ // Creating a down event only makes sense if we haven't started touch exploring yet.
+ if (mState.isTouchExploring()
+ || mDraggingPointerId == INVALID_POINTER_ID
+ || event == null) {
+ return null;
+ }
+ final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId);
+ final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId);
+ final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId);
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
+ coords[0] = new MotionEvent.PointerCoords();
+ coords[0].x = x;
+ coords[0].y = y;
+ MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1];
+ properties[0] = new MotionEvent.PointerProperties();
+ properties[0].id = mDraggingPointerId;
+ properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ MotionEvent downEvent =
+ MotionEvent.obtain(
+ time,
+ time,
+ ACTION_DOWN,
+ 1,
+ properties,
+ coords,
+ event.getMetaState(),
+ event.getButtonState(),
+ event.getXPrecision(),
+ event.getYPrecision(),
+ event.getDeviceId(),
+ event.getEdgeFlags(),
+ event.getSource(),
+ event.getFlags());
+ event.setDownTime(time);
+ return downEvent;
+ }
+
public TouchState getState() {
return mState;
}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index 1c4db12..59ba82e 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
+import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.util.Slog;
@@ -108,9 +109,9 @@
@Override
public void createPredictionSession(@NonNull AppPredictionContext context,
- @NonNull AppPredictionSessionId sessionId) {
- runForUserLocked("createPredictionSession", sessionId,
- (service) -> service.onCreatePredictionSessionLocked(context, sessionId));
+ @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+ runForUserLocked("createPredictionSession", sessionId, (service) ->
+ service.onCreatePredictionSessionLocked(context, sessionId, token));
}
@Override
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 7ee607c..735f420 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
+import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.provider.DeviceConfig;
@@ -44,8 +45,6 @@
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.people.PeopleServiceInternal;
-import java.util.function.Consumer;
-
/**
* Per-user instance of {@link AppPredictionManagerService}.
*/
@@ -112,17 +111,24 @@
*/
@GuardedBy("mLock")
public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
- @NonNull AppPredictionSessionId sessionId) {
- if (!mSessionInfos.containsKey(sessionId)) {
- mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
- DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
- PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
- this::removeAppPredictionSessionInfo));
- }
- final boolean serviceExists = resolveService(sessionId, s ->
- s.onCreatePredictionSession(context, sessionId), true);
- if (!serviceExists) {
- mSessionInfos.remove(sessionId);
+ @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+ final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+ PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false);
+ final boolean serviceExists = resolveService(sessionId, false,
+ usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
+ if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
+ final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
+ sessionId, context, usesPeopleService, token, () -> {
+ synchronized (mLock) {
+ onDestroyPredictionSessionLocked(sessionId);
+ }
+ });
+ if (sessionInfo.linkToDeath()) {
+ mSessionInfos.put(sessionId, sessionInfo);
+ } else {
+ // destroy the session if calling process is already dead
+ onDestroyPredictionSessionLocked(sessionId);
+ }
}
}
@@ -132,7 +138,10 @@
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.notifyAppTargetEvent(sessionId, event));
}
/**
@@ -141,8 +150,10 @@
@GuardedBy("mLock")
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
- resolveService(sessionId, s ->
- s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
}
/**
@@ -151,7 +162,10 @@
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+ s -> s.sortAppTargets(sessionId, targets, callback));
}
/**
@@ -160,10 +174,12 @@
@GuardedBy("mLock")
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.registerPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
+ if (sessionInfo == null) return;
+ final boolean serviceExists = resolveService(sessionId, false,
+ sessionInfo.mUsesPeopleService,
+ s -> s.registerPredictionUpdates(sessionId, callback));
+ if (serviceExists) {
sessionInfo.addCallbackLocked(callback);
}
}
@@ -174,10 +190,12 @@
@GuardedBy("mLock")
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.unregisterPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
+ if (sessionInfo == null) return;
+ final boolean serviceExists = resolveService(sessionId, false,
+ sessionInfo.mUsesPeopleService,
+ s -> s.unregisterPredictionUpdates(sessionId, callback));
+ if (serviceExists) {
sessionInfo.removeCallbackLocked(callback);
}
}
@@ -187,7 +205,10 @@
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+ s -> s.requestPredictionUpdate(sessionId));
}
/**
@@ -195,12 +216,14 @@
*/
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.onDestroyPredictionSession(sessionId), false);
- final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
- sessionInfo.destroy();
+ if (isDebug()) {
+ Slog.d(TAG, "onDestroyPredictionSessionLocked(): sessionId=" + sessionId);
}
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.remove(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.onDestroyPredictionSession(sessionId));
+ sessionInfo.destroy();
}
@Override
@@ -291,27 +314,18 @@
}
for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) {
- sessionInfo.resurrectSessionLocked(this);
- }
- }
-
- private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) {
- if (isDebug()) {
- Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId);
- }
- synchronized (mLock) {
- mSessionInfos.remove(sessionId);
+ sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken);
}
}
@GuardedBy("mLock")
@Nullable
- protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
- @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
- boolean sendImmediately) {
- final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo == null) return false;
- if (sessionInfo.mUsesPeopleService) {
+ protected boolean resolveService(
+ @NonNull final AppPredictionSessionId sessionId,
+ boolean sendImmediately,
+ boolean usesPeopleService,
+ @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+ if (usesPeopleService) {
final IPredictionService service =
LocalServices.getService(PeopleServiceInternal.class);
if (service != null) {
@@ -368,7 +382,9 @@
private final AppPredictionContext mPredictionContext;
private final boolean mUsesPeopleService;
@NonNull
- private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
+ final IBinder mToken;
+ @NonNull
+ final IBinder.DeathRecipient mDeathRecipient;
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
new RemoteCallbackList<IPredictionCallback>() {
@@ -388,14 +404,16 @@
@NonNull final AppPredictionSessionId id,
@NonNull final AppPredictionContext predictionContext,
final boolean usesPeopleService,
- @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+ @NonNull final IBinder token,
+ @NonNull final IBinder.DeathRecipient deathRecipient) {
if (DEBUG) {
Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
}
mSessionId = id;
mPredictionContext = predictionContext;
mUsesPeopleService = usesPeopleService;
- mRemoveSessionInfoAction = removeSessionInfoAction;
+ mToken = token;
+ mDeathRecipient = deathRecipient;
}
void addCallbackLocked(IPredictionCallback callback) {
@@ -414,23 +432,38 @@
mCallbacks.unregister(callback);
}
+ boolean linkToDeath() {
+ try {
+ mToken.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Caller is dead before session can be started, sessionId: "
+ + mSessionId);
+ }
+ return false;
+ }
+ return true;
+ }
+
void destroy() {
if (DEBUG) {
Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
+ " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
}
+ if (mToken != null) {
+ mToken.unlinkToDeath(mDeathRecipient, 0);
+ }
mCallbacks.kill();
- mRemoveSessionInfoAction.accept(mSessionId);
}
- void resurrectSessionLocked(AppPredictionPerUserService service) {
+ void resurrectSessionLocked(AppPredictionPerUserService service, IBinder token) {
int callbackCount = mCallbacks.getRegisteredCallbackCount();
if (DEBUG) {
Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
+ ") for session Id=" + mSessionId + " and "
+ callbackCount + " callbacks.");
}
- service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
+ service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId, token);
mCallbacks.broadcast(
callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e1e3d0..2d803437 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -83,6 +83,7 @@
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -117,7 +118,6 @@
import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -319,6 +319,7 @@
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
@@ -4946,9 +4947,8 @@
notifyPackageUse(instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
- + processName + " with config "
- + app.getWindowProcessController().getConfiguration());
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s",
+ processName, app.getWindowProcessController().getConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackage(appInfo);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 3f949ba..653323d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -25,7 +25,7 @@
* A helper class to build {@link HdmiCecMessage} from various cec commands.
*/
public class HdmiCecMessageBuilder {
- private static final int OSD_NAME_MAX_LENGTH = 13;
+ private static final int OSD_NAME_MAX_LENGTH = 14;
private HdmiCecMessageBuilder() {}
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 05aa315..06105bf 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -314,6 +314,14 @@
}
@Override
+ public final <Listener> void onOperationFailure(ListenerOperation<Listener> operation,
+ Exception e) {
+ synchronized (mLock) {
+ super.onOperationFailure(operation, e);
+ }
+ }
+
+ @Override
public final LocationRequest getRequest() {
return mProviderLocationRequest;
}
diff --git a/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
new file mode 100644
index 0000000..1500cfa
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import android.annotation.UserIdInt;
+import android.os.Binder;
+import android.os.UserHandle;
+
+/**
+ * An interface to wrap various difficult-to-intercept calls that services make to access / manage
+ * caller identity, e.g. {@link Binder#clearCallingIdentity()}.
+ */
+public interface CallerIdentityInjector {
+
+ /** A singleton for the real implementation of {@link CallerIdentityInjector}. */
+ CallerIdentityInjector REAL = new Real();
+
+ /** A {@link UserHandle#getCallingUserId()} call. */
+ @UserIdInt int getCallingUserId();
+
+ /** A {@link Binder#clearCallingIdentity()} call. */
+ long clearCallingIdentity();
+
+ /** A {@link Binder#restoreCallingIdentity(long)} ()} call. */
+ void restoreCallingIdentity(long token);
+
+ /** The real implementation of {@link CallerIdentityInjector}. */
+ class Real implements CallerIdentityInjector {
+
+ protected Real() {
+ }
+
+ @Override
+ public int getCallingUserId() {
+ return UserHandle.getCallingUserId();
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
new file mode 100644
index 0000000..4c7b1f3
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+/**
+ * A listener used to receive notification that time zone configuration has changed.
+ */
+@FunctionalInterface
+public interface ConfigurationChangeListener {
+ /** Called when the current user or a configuration value has changed. */
+ void onChange();
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
new file mode 100644
index 0000000..aee3d8d
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.timezonedetector.TimeZoneCapabilities;
+import android.app.timezonedetector.TimeZoneConfiguration;
+
+import java.util.Objects;
+
+/**
+ * Holds all configuration values that affect time zone behavior and some associated logic, e.g.
+ * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
+ * #createCapabilities()}.
+ */
+public final class ConfigurationInternal {
+
+ private final @UserIdInt int mUserId;
+ private final boolean mUserConfigAllowed;
+ private final boolean mAutoDetectionSupported;
+ private final boolean mAutoDetectionEnabled;
+ private final boolean mLocationEnabled;
+ private final boolean mGeoDetectionEnabled;
+
+ private ConfigurationInternal(Builder builder) {
+ mUserId = builder.mUserId;
+ mUserConfigAllowed = builder.mUserConfigAllowed;
+ mAutoDetectionSupported = builder.mAutoDetectionSupported;
+ mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+ mLocationEnabled = builder.mLocationEnabled;
+ mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
+ }
+
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /** Returns true if the user allowed to modify time zone configuration. */
+ public boolean isUserConfigAllowed() {
+ return mUserConfigAllowed;
+ }
+
+ /** Returns true if the device supports some form of auto time zone detection. */
+ public boolean isAutoDetectionSupported() {
+ return mAutoDetectionSupported;
+ }
+
+ /** Returns the value of the auto time zone detection enabled setting. */
+ public boolean getAutoDetectionEnabledSetting() {
+ return mAutoDetectionEnabled;
+ }
+
+ /**
+ * Returns true if auto time zone detection behavior is actually enabled, which can be distinct
+ * from the raw setting value. */
+ public boolean getAutoDetectionEnabledBehavior() {
+ return mAutoDetectionSupported && mAutoDetectionEnabled;
+ }
+
+ /** Returns true if user's location can be used generally. */
+ public boolean isLocationEnabled() {
+ return mLocationEnabled;
+ }
+
+ /** Returns the value of the geolocation time zone detection enabled setting. */
+ public boolean getGeoDetectionEnabledSetting() {
+ return mGeoDetectionEnabled;
+ }
+
+ /**
+ * Returns true if geolocation time zone detection behavior is actually enabled, which can be
+ * distinct from the raw setting value.
+ */
+ public boolean getGeoDetectionEnabledBehavior() {
+ if (getAutoDetectionEnabledBehavior()) {
+ return mLocationEnabled && mGeoDetectionEnabled;
+ }
+ return false;
+ }
+
+ /** Creates a {@link TimeZoneCapabilities} object using the configuration values. */
+ public TimeZoneCapabilities createCapabilities() {
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+ .setConfiguration(asConfiguration());
+
+ boolean allowConfigDateTime = isUserConfigAllowed();
+
+ // Automatic time zone detection is only supported on devices if there is a telephony
+ // network available or geolocation time zone detection is possible.
+ boolean deviceHasTimeZoneDetection = isAutoDetectionSupported();
+
+ final int configureAutoDetectionEnabledCapability;
+ if (!deviceHasTimeZoneDetection) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+ } else if (!allowConfigDateTime) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+ } else {
+ configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability);
+
+ final int configureGeolocationDetectionEnabledCapability;
+ if (!deviceHasTimeZoneDetection) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+ } else if (!allowConfigDateTime) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+ } else if (!isLocationEnabled()) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
+ } else {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability);
+
+ // The ability to make manual time zone suggestions can also be restricted by policy. With
+ // the current logic above, this could lead to a situation where a device hardware does not
+ // support auto detection, the device has been forced into "auto" mode by an admin and the
+ // user is unable to disable auto detection.
+ final int suggestManualTimeZoneCapability;
+ if (!allowConfigDateTime) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
+ } else if (getAutoDetectionEnabledBehavior()) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
+ } else {
+ suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability);
+
+ return builder.build();
+ }
+
+ /** Returns a {@link TimeZoneConfiguration} from the configuration values. */
+ public TimeZoneConfiguration asConfiguration() {
+ return new TimeZoneConfiguration.Builder(mUserId)
+ .setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
+ .setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
+ .build();
+ }
+
+ /**
+ * Merges the configuration values from this with any properties set in {@code
+ * newConfiguration}. The new configuration has precedence. Used to apply user updates to
+ * internal configuration.
+ */
+ public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
+ Builder builder = new Builder(this);
+ if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) {
+ builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
+ }
+ if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) {
+ builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ConfigurationInternal that = (ConfigurationInternal) o;
+ return mUserId == that.mUserId
+ && mUserConfigAllowed == that.mUserConfigAllowed
+ && mAutoDetectionSupported == that.mAutoDetectionSupported
+ && mAutoDetectionEnabled == that.mAutoDetectionEnabled
+ && mLocationEnabled == that.mLocationEnabled
+ && mGeoDetectionEnabled == that.mGeoDetectionEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported,
+ mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled);
+ }
+
+ @Override
+ public String toString() {
+ return "TimeZoneDetectorConfiguration{"
+ + "mUserId=" + mUserId
+ + "mUserConfigAllowed=" + mUserConfigAllowed
+ + "mAutoDetectionSupported=" + mAutoDetectionSupported
+ + "mAutoDetectionEnabled=" + mAutoDetectionEnabled
+ + "mLocationEnabled=" + mLocationEnabled
+ + "mGeoDetectionEnabled=" + mGeoDetectionEnabled
+ + '}';
+ }
+
+ /**
+ * A Builder for {@link ConfigurationInternal}.
+ */
+ public static class Builder {
+
+ private final @UserIdInt int mUserId;
+ private boolean mUserConfigAllowed;
+ private boolean mAutoDetectionSupported;
+ private boolean mAutoDetectionEnabled;
+ private boolean mLocationEnabled;
+ private boolean mGeoDetectionEnabled;
+
+ /**
+ * Creates a new Builder with only the userId set.
+ */
+ public Builder(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Creates a new Builder by copying values from an existing instance.
+ */
+ public Builder(ConfigurationInternal toCopy) {
+ this.mUserId = toCopy.mUserId;
+ this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
+ this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
+ this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled;
+ this.mLocationEnabled = toCopy.mLocationEnabled;
+ this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled;
+ }
+
+ /**
+ * Sets whether the user is allowed to configure time zone settings on this device.
+ */
+ public Builder setUserConfigAllowed(boolean configAllowed) {
+ mUserConfigAllowed = configAllowed;
+ return this;
+ }
+
+ /**
+ * Sets whether automatic time zone detection is supported on this device.
+ */
+ public Builder setAutoDetectionSupported(boolean supported) {
+ mAutoDetectionSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the value of the automatic time zone detection enabled setting for this device.
+ */
+ public Builder setAutoDetectionEnabled(boolean enabled) {
+ mAutoDetectionEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Sets the value of the location mode setting for this user.
+ */
+ public Builder setLocationEnabled(boolean enabled) {
+ mLocationEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Sets the value of the geolocation time zone detection setting for this user.
+ */
+ public Builder setGeoDetectionEnabled(boolean enabled) {
+ mGeoDetectionEnabled = enabled;
+ return this;
+ }
+
+ /** Returns a new {@link ConfigurationInternal}. */
+ @NonNull
+ public ConfigurationInternal build() {
+ return new ConfigurationInternal(this);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 0ca36e0..d640323 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -16,24 +16,30 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.location.LocationManager;
import android.net.ConnectivityManager;
+import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
import java.util.Objects;
@@ -42,103 +48,87 @@
*/
public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategyImpl.Callback {
+ private static final String LOG_TAG = "TimeZoneDetectorCallbackImpl";
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
- private final Context mContext;
- private final ContentResolver mCr;
- private final UserManager mUserManager;
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ContentResolver mCr;
+ @NonNull private final UserManager mUserManager;
+ @NonNull private final boolean mGeoDetectionFeatureEnabled;
+ @NonNull private final LocationManager mLocationManager;
+ // @NonNull after setConfigChangeListener() is called.
+ private ConfigurationChangeListener mConfigChangeListener;
- TimeZoneDetectorCallbackImpl(Context context) {
- mContext = context;
+ TimeZoneDetectorCallbackImpl(@NonNull Context context, @NonNull Handler handler,
+ boolean geoDetectionFeatureEnabled) {
+ mContext = Objects.requireNonNull(context);
+ mHandler = Objects.requireNonNull(handler);
mCr = context.getContentResolver();
mUserManager = context.getSystemService(UserManager.class);
+ mLocationManager = context.getSystemService(LocationManager.class);
+ mGeoDetectionFeatureEnabled = geoDetectionFeatureEnabled;
+
+ // Wire up the change listener. All invocations are performed on the mHandler thread.
+
+ // Listen for the user changing / the user's location mode changing.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USER_SWITCHED);
+ filter.addAction(LocationManager.MODE_CHANGED_ACTION);
+ mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleConfigChangeOnHandlerThread();
+ }
+ }, filter, null, mHandler);
+
+ // Add async callbacks for global settings being changed.
+ ContentResolver contentResolver = mContext.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
+ new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ handleConfigChangeOnHandlerThread();
+ }
+ });
+
+ // Add async callbacks for user scoped location settings being changed.
+ contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
+ true,
+ new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ handleConfigChangeOnHandlerThread();
+ }
+ }, UserHandle.USER_ALL);
+ }
+
+ private void handleConfigChangeOnHandlerThread() {
+ if (mConfigChangeListener == null) {
+ Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
+ }
+ mConfigChangeListener.onChange();
}
@Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- UserHandle userHandle = UserHandle.of(userId);
- boolean disallowConfigDateTime =
- mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
-
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userId);
-
- // Automatic time zone detection is only supported (currently) on devices if there is a
- // telephony network available.
- if (!deviceHasTelephonyNetwork()) {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
- } else if (disallowConfigDateTime) {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- } else {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED);
- }
-
- // TODO(b/149014708) Replace this with real logic when the settings storage is fully
- // implemented.
- builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
-
- // The ability to make manual time zone suggestions can also be restricted by policy. With
- // the current logic above, this could lead to a situation where a device hardware does not
- // support auto detection, the device has been forced into "auto" mode by an admin and the
- // user is unable to disable auto detection.
- if (disallowConfigDateTime) {
- builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
- } else if (isAutoDetectionEnabled()) {
- builder.setSuggestManualTimeZone(CAPABILITY_NOT_APPLICABLE);
- } else {
- builder.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- }
- return builder.build();
+ public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
}
@Override
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return new TimeZoneConfiguration.Builder()
+ public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ return new ConfigurationInternal.Builder(userId)
+ .setUserConfigAllowed(isUserConfigAllowed(userId))
+ .setAutoDetectionSupported(isAutoDetectionSupported())
.setAutoDetectionEnabled(isAutoDetectionEnabled())
- .setGeoDetectionEnabled(isGeoDetectionEnabled())
+ .setLocationEnabled(isLocationEnabled(userId))
+ .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
.build();
}
@Override
- public void setConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
- Objects.requireNonNull(configuration);
- if (!configuration.isComplete()) {
- throw new IllegalArgumentException("configuration=" + configuration + " not complete");
- }
-
- // Avoid writing auto detection config for devices that do not support auto time zone
- // detection: if we wrote it down then we'd set the default explicitly. That might influence
- // what happens on later releases that do support auto detection on the same hardware.
- if (isAutoDetectionSupported()) {
- final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0;
- Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue);
-
- final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled();
- // TODO(b/149014708) Write this down to user-scoped settings once implemented.
- }
- }
-
- @Override
- public boolean isAutoDetectionEnabled() {
- // To ensure that TimeZoneConfiguration is "complete" for simplicity, devices that do not
- // support auto detection have safe, hard coded configuration values that make it look like
- // auto detection is turned off. It is therefore important that false is returned from this
- // method for devices that do not support auto time zone detection. Such devices will not
- // have a UI to turn the auto detection on/off. Returning true could prevent the user
- // entering information manually. On devices that do support auto time detection the default
- // is to turn auto detection on.
- if (isAutoDetectionSupported()) {
- return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
- }
- return false;
- }
-
- @Override
- public boolean isGeoDetectionEnabled() {
- // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's
- // location toggle will act as an override for this setting, i.e. so that the setting will
- // return false if the location toggle is disabled.
- return false;
+ public @UserIdInt int getCurrentUserId() {
+ return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
}
@Override
@@ -165,8 +155,55 @@
alarmManager.setTimeZone(zoneId);
}
+ @Override
+ public void storeConfiguration(TimeZoneConfiguration configuration) {
+ Objects.requireNonNull(configuration);
+
+ // Avoid writing the auto detection enabled setting for devices that do not support auto
+ // time zone detection: if we wrote it down then we'd set the value explicitly, which would
+ // prevent detecting "default" later. That might influence what happens on later releases
+ // that support new types of auto detection on the same hardware.
+ if (isAutoDetectionSupported()) {
+ final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+ setAutoDetectionEnabled(autoDetectionEnabled);
+
+ final int userId = configuration.getUserId();
+ final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
+ setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ }
+ }
+
+ private boolean isUserConfigAllowed(@UserIdInt int userId) {
+ UserHandle userHandle = UserHandle.of(userId);
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+ }
+
private boolean isAutoDetectionSupported() {
- return deviceHasTelephonyNetwork();
+ return deviceHasTelephonyNetwork() || mGeoDetectionFeatureEnabled;
+ }
+
+ private boolean isAutoDetectionEnabled() {
+ return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ }
+
+ private void setAutoDetectionEnabled(boolean enabled) {
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0);
+ }
+
+ private boolean isLocationEnabled(@UserIdInt int userId) {
+ return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId));
+ }
+
+ private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
+ final boolean locationEnabled = isLocationEnabled(userId);
+ return Settings.Secure.getIntForUser(mCr,
+ Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+ locationEnabled ? 1 : 0 /* defaultValue */, userId) != 0;
+ }
+
+ private void setGeoDetectionEnabled(@UserIdInt int userId, boolean enabled) {
+ Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+ enabled ? 1 : 0, userId);
}
private boolean deviceHasTelephonyNetwork() {
@@ -174,4 +211,4 @@
return mContext.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index fb7a73d..2d50390 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,6 +27,12 @@
*/
public interface TimeZoneDetectorInternal extends Dumpable.Container {
+ /** Adds a listener that will be invoked when time zone detection configuration is changed. */
+ void addConfigurationListener(ConfigurationChangeListener listener);
+
+ /** Returns the {@link ConfigurationInternal} for the current user. */
+ ConfigurationInternal getCurrentUserConfigurationInternal();
+
/**
* 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
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 15412a0..f0ce827 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -20,8 +20,8 @@
import android.content.Context;
import android.os.Handler;
-import com.android.internal.annotations.VisibleForTesting;
-
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -34,18 +34,26 @@
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
@NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+ @NonNull private final List<ConfigurationChangeListener> mConfigurationListeners =
+ new ArrayList<>();
- static TimeZoneDetectorInternalImpl create(@NonNull Context context, @NonNull Handler handler,
- @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
- return new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
- }
-
- @VisibleForTesting
public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
+
+ // Wire up a change listener so that any downstream listeners can be notified when
+ // the configuration changes for any reason.
+ mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
+ }
+
+ private void handleConfigurationChanged() {
+ synchronized (mConfigurationListeners) {
+ for (ConfigurationChangeListener listener : mConfigurationListeners) {
+ listener.onChange();
+ }
+ }
}
@Override
@@ -54,6 +62,19 @@
}
@Override
+ public void addConfigurationListener(ConfigurationChangeListener listener) {
+ synchronized (mConfigurationListeners) {
+ mConfigurationListeners.add(Objects.requireNonNull(listener));
+ }
+ }
+
+ @Override
+ @NonNull
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal();
+ }
+
+ @Override
public void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
Objects.requireNonNull(timeZoneSuggestion);
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index d81f949..7501d9f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -24,32 +24,24 @@
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
-import com.android.server.timezonedetector.TimeZoneDetectorStrategy.StrategyListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.Objects;
/**
@@ -65,6 +57,9 @@
private static final String TAG = "TimeZoneDetectorService";
+ /** A compile time switch for enabling / disabling geolocation-based time zone detection. */
+ private static final boolean GEOLOCATION_TIME_ZONE_DETECTION_ENABLED = false;
+
/**
* Handles the service lifecycle for {@link TimeZoneDetectorService} and
* {@link TimeZoneDetectorInternalImpl}.
@@ -80,18 +75,20 @@
// Obtain / create the shared dependencies.
Context context = getContext();
Handler handler = FgThread.getHandler();
+
TimeZoneDetectorStrategy timeZoneDetectorStrategy =
- TimeZoneDetectorStrategyImpl.create(context);
+ TimeZoneDetectorStrategyImpl.create(
+ context, handler, GEOLOCATION_TIME_ZONE_DETECTION_ENABLED);
// Create and publish the local service for use by internal callers.
TimeZoneDetectorInternal internal =
- TimeZoneDetectorInternalImpl.create(context, handler, timeZoneDetectorStrategy);
+ new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
publishLocalService(TimeZoneDetectorInternal.class, internal);
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
- TimeZoneDetectorService service =
- TimeZoneDetectorService.create(context, handler, timeZoneDetectorStrategy);
+ TimeZoneDetectorService service = TimeZoneDetectorService.create(
+ context, handler, timeZoneDetectorStrategy);
publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
}
}
@@ -103,52 +100,38 @@
private final Handler mHandler;
@NonNull
+ private final CallerIdentityInjector mCallerIdentityInjector;
+
+ @NonNull
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
- /**
- * This sparse array acts as a map from userId to listeners running as that userId. User scoped
- * as time zone detection configuration is partially user-specific, so different users can
- * get different configuration.
- */
@GuardedBy("mConfigurationListeners")
@NonNull
- private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners =
- new SparseArray<>();
+ private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners =
+ new ArrayList<>();
private static TimeZoneDetectorService create(
@NonNull Context context, @NonNull Handler handler,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
- TimeZoneDetectorService service =
- new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy);
-
- ContentResolver contentResolver = context.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
- new ContentObserver(handler) {
- public void onChange(boolean selfChange) {
- service.handleAutoTimeZoneConfigChanged();
- }
- });
- // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config.
- // This should also include listening to the current user and the current user's location
- // toggle since the config is user-scoped and the location toggle overrides the geolocation
- // time zone enabled setting.
+ CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
+ TimeZoneDetectorService service = new TimeZoneDetectorService(
+ context, handler, callerIdentityInjector, timeZoneDetectorStrategy);
return service;
}
@VisibleForTesting
public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull CallerIdentityInjector callerIdentityInjector,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
+ mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
- mTimeZoneDetectorStrategy.setStrategyListener(new StrategyListener() {
- @Override
- public void onConfigurationChanged() {
- handleConfigurationChanged();
- }
- });
+
+ // Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when
+ // the configuration changes for any reason.
+ mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
}
@Override
@@ -156,26 +139,12 @@
public TimeZoneCapabilities getCapabilities() {
enforceManageTimeZoneDetectorConfigurationPermission();
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int userId = mCallerIdentityInjector.getCallingUserId();
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.getCapabilities(userId);
+ return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities();
} finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- @NonNull
- public TimeZoneConfiguration getConfiguration() {
- enforceManageTimeZoneDetectorConfigurationPermission();
-
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
- try {
- return mTimeZoneDetectorStrategy.getConfiguration(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -184,12 +153,16 @@
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(configuration);
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int callingUserId = mCallerIdentityInjector.getCallingUserId();
+ if (callingUserId != configuration.getUserId()) {
+ return false;
+ }
+
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
+ return mTimeZoneDetectorStrategy.updateConfiguration(configuration);
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -197,25 +170,17 @@
public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(listener);
- int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
- ArrayList<ITimeZoneConfigurationListener> listeners =
- mConfigurationListeners.get(userId);
- if (listeners != null && listeners.contains(listener)) {
+ if (mConfigurationListeners.contains(listener)) {
return;
}
try {
- if (listeners == null) {
- listeners = new ArrayList<>(1);
- mConfigurationListeners.put(userId, listeners);
- }
-
// Ensure the reference to the listener will be removed if the client process dies.
listener.asBinder().linkToDeath(this, 0 /* flags */);
// Only add the listener if we can linkToDeath().
- listeners.add(listener);
+ mConfigurationListeners.add(listener);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
}
@@ -226,19 +191,16 @@
public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(listener);
- int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
boolean removedListener = false;
- ArrayList<ITimeZoneConfigurationListener> userListeners =
- mConfigurationListeners.get(userId);
- if (userListeners.remove(listener)) {
+ if (mConfigurationListeners.remove(listener)) {
// Stop listening for the client process to die.
listener.asBinder().unlinkToDeath(this, 0 /* flags */);
removedListener = true;
}
if (!removedListener) {
- Slog.w(TAG, "Client asked to remove listenener=" + listener
+ Slog.w(TAG, "Client asked to remove listener=" + listener
+ ", but no listeners were removed."
+ " mConfigurationListeners=" + mConfigurationListeners);
}
@@ -259,19 +221,14 @@
public void binderDied(IBinder who) {
synchronized (mConfigurationListeners) {
boolean removedListener = false;
- final int userCount = mConfigurationListeners.size();
- for (int i = 0; i < userCount; i++) {
- ArrayList<ITimeZoneConfigurationListener> userListeners =
- mConfigurationListeners.valueAt(i);
- Iterator<ITimeZoneConfigurationListener> userListenerIterator =
- userListeners.iterator();
- while (userListenerIterator.hasNext()) {
- ITimeZoneConfigurationListener userListener = userListenerIterator.next();
- if (userListener.asBinder().equals(who)) {
- userListenerIterator.remove();
- removedListener = true;
- break;
- }
+ final int listenerCount = mConfigurationListeners.size();
+ for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
+ ITimeZoneConfigurationListener listener =
+ mConfigurationListeners.get(listenerIndex);
+ if (listener.asBinder().equals(who)) {
+ mConfigurationListeners.remove(listenerIndex);
+ removedListener = true;
+ break;
}
}
if (!removedListener) {
@@ -283,42 +240,25 @@
}
void handleConfigurationChanged() {
- // Note: we could trigger an async time zone detection operation here via a call to
- // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying
- // setting value changing so it is currently unnecessary. If we get to a point where all
- // configuration changes are guaranteed to happen in response to an updateConfiguration()
- // call, then we can remove that path and call it here instead.
-
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
synchronized (mConfigurationListeners) {
- final int userCount = mConfigurationListeners.size();
- for (int userIndex = 0; userIndex < userCount; userIndex++) {
- int userId = mConfigurationListeners.keyAt(userIndex);
- TimeZoneConfiguration configuration =
- mTimeZoneDetectorStrategy.getConfiguration(userId);
-
- ArrayList<ITimeZoneConfigurationListener> listeners =
- mConfigurationListeners.valueAt(userIndex);
- final int listenerCount = listeners.size();
- for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
- ITimeZoneConfigurationListener listener = listeners.get(listenerIndex);
- try {
- listener.onChange(configuration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to notify listener=" + listener
- + " for userId=" + userId
- + " of updated configuration=" + configuration, e);
- }
+ final int listenerCount = mConfigurationListeners.size();
+ for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+ ITimeZoneConfigurationListener listener =
+ mConfigurationListeners.get(listenerIndex);
+ try {
+ listener.onChange();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to notify listener=" + listener, e);
}
}
}
}
/** Provided for command-line access. This is not exposed as a binder API. */
- void suggestGeolocationTimeZone(
- @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
+ void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
enforceSuggestGeolocationTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
@@ -331,12 +271,12 @@
enforceSuggestManualTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int userId = mCallerIdentityInjector.getCallingUserId();
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -358,12 +298,6 @@
ipw.flush();
}
- /** Internal method for handling the auto time zone configuration being changed. */
- @VisibleForTesting
- public void handleAutoTimeZoneConfigChanged() {
- mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneConfigChanged);
- }
-
private void enforceManageTimeZoneDetectorConfigurationPermission() {
// TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission.
mContext.enforceCallingPermission(
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index c5b7e39..f944c56 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -19,51 +19,84 @@
import android.annotation.UserIdInt;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
/**
- * The interface for the class that implements the time detection algorithm used by the
- * {@link TimeZoneDetectorService}.
+ * The interface for the class that is responsible for setting the time zone on a device, used by
+ * {@link TimeZoneDetectorService} and {@link TimeZoneDetectorInternal}.
*
- * <p>The strategy uses suggestions to decide whether to modify the device's time zone setting
- * and what to set it to.
+ * <p>The strategy receives suggestions, which it may use to modify the device's time zone setting.
+ * Suggestions are acted on or ignored as needed, depending on previously received suggestions and
+ * the current user's configuration (see {@link ConfigurationInternal}).
*
- * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example
- * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently
- * with other operations so implementations must still handle thread safety.
+ * <p>Devices can have zero, one or two automatic time zone detection algorithm available at any
+ * point in time.
+ *
+ * <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm
+ * availability and use depends on several factors:
+ * <ul>
+ * <li>Telephony is only available on devices with a telephony stack.
+ * <li>Geolocation is also optional and configured at image creation time. When enabled on a
+ * device, its availability depends on the current user's settings, so switching between users can
+ * change the automatic algorithm used by the device.</li>
+ * </ul>
+ *
+ * <p>If there are no automatic time zone detections algorithms available then the user can usually
+ * change the device time zone manually. Under most circumstances the current user can turn
+ * automatic time zone detection on or off, or choose the algorithm via settings.
+ *
+ * <p>Telephony detection is independent of the current user. The device keeps track of the most
+ * recent telephony suggestion from each slotIndex. When telephony detection is in use, the highest
+ * scoring suggestion is used to set the device time zone based on a scoring algorithm. If several
+ * slotIndexes provide the same score then the slotIndex with the lowest numeric value "wins". If
+ * the situation changes and it is no longer possible to be confident about the time zone,
+ * slotIndexes must have an empty suggestion submitted in order to "withdraw" their previous
+ * suggestion otherwise it will remain in use.
+ *
+ * <p>Geolocation detection is dependent on the current user and their settings. The device retains
+ * at most one geolocation suggestion. Generally, use of a device's location is dependent on the
+ * user's "location toggle", but even when that is enabled the user may choose to enable / disable
+ * the use of geolocation for device time zone detection. If the current user changes to one that
+ * does not have geolocation detection enabled, or the user turns off geolocation detection, then
+ * the strategy discards the latest geolocation suggestion. Devices that lose a location fix must
+ * have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it
+ * will remain in use.
+ *
+ * <p>Threading:
+ *
+ * <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
+ * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug
+ * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread
+ * concurrently with other operations.
*
* @hide
*/
public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
- /** A listener for strategy events. */
- interface StrategyListener {
- /**
- * Invoked when configuration has been changed.
- */
- void onConfigurationChanged();
- }
+ /**
+ * Sets a listener that will be triggered whenever time zone detection configuration is
+ * changed.
+ */
+ void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
- /** Sets the listener that enables the strategy to communicate with the surrounding service. */
- void setStrategyListener(@NonNull StrategyListener listener);
-
- /** Returns the user's time zone capabilities. */
+ /** Returns the user's time zone configuration. */
@NonNull
- TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
+ ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
/**
- * Returns the configuration that controls time zone detector behavior.
+ * Returns the configuration that controls time zone detector behavior for the current user.
*/
@NonNull
- TimeZoneConfiguration getConfiguration(@UserIdInt int userId);
+ ConfigurationInternal getCurrentUserConfigurationInternal();
/**
- * Updates the configuration settings that control time zone detector behavior.
+ * Updates the configuration properties that control a device's time zone behavior.
+ *
+ * <p>This method returns {@code true} if the configuration was changed,
+ * {@code false} otherwise.
*/
- boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
+ boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
/**
* Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
@@ -85,9 +118,4 @@
* suggestion.
*/
void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
-
- /**
- * Called when there has been a change to the automatic time zone detection configuration.
- */
- void handleAutoTimeZoneConfigChanged();
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index d1369a2..8a42b18 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -20,10 +20,7 @@
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,6 +30,7 @@
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
+import android.os.Handler;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Slog;
@@ -45,15 +43,7 @@
import java.util.Objects;
/**
- * An implementation of {@link TimeZoneDetectorStrategy} that handle telephony and manual
- * suggestions. Suggestions are acted on or ignored as needed, dependent on the current "auto time
- * zone detection" setting.
- *
- * <p>For automatic detection, it keeps track of the most recent telephony suggestion from each
- * slotIndex and it uses the best suggestion based on a scoring algorithm. If several slotIndexes
- * provide the same score then the slotIndex with the lowest numeric value "wins". If the situation
- * changes and it is no longer possible to be confident about the time zone, slotIndexes must have
- * an empty suggestion submitted in order to "withdraw" their previous suggestion.
+ * The real implementation of {@link TimeZoneDetectorStrategy}.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -61,48 +51,27 @@
/**
* Used by {@link TimeZoneDetectorStrategyImpl} to interact with device configuration / settings
- * / system properties. It can be faked for testing different scenarios.
+ * / system properties. It can be faked for testing.
*
* <p>Note: Because the settings / system properties-derived values can currently be modified
- * independently and from different threads (and processes!), their use are prone to race
- * conditions. That will be true until the responsibility for setting their values is moved to
- * {@link TimeZoneDetectorStrategyImpl} (which is thread safe).
+ * independently and from different threads (and processes!), their use is prone to race
+ * conditions.
*/
@VisibleForTesting
public interface Callback {
/**
- * Returns the capabilities for the user.
+ * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
+ * changes that could affect time zone detection. This is invoked during system server
+ * setup.
*/
- @NonNull
- TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
+ void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
- /**
- * Returns the configuration for the user.
- * @param userId
- */
- @NonNull
- TimeZoneConfiguration getConfiguration(int userId);
+ /** Returns the current user at the instant it is called. */
+ @UserIdInt int getCurrentUserId();
- /**
- * Sets the configuration for the user. This method handles storage only, the configuration
- * must have been validated by the caller and be complete.
- *
- * @throws IllegalArgumentException if {@link TimeZoneConfiguration#isComplete()}
- * returns {@code false}
- */
- void setConfiguration(@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
-
- /**
- * Returns true if automatic time zone detection is currently enabled.
- */
- boolean isAutoDetectionEnabled();
-
- /**
- * Returns whether geolocation can be used for time zone detection when {@link
- * #isAutoDetectionEnabled()} returns {@code true}.
- */
- boolean isGeoDetectionEnabled();
+ /** Returns the {@link ConfigurationInternal} for the specified user. */
+ ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
/**
* Returns true if the device has had an explicit time zone set.
@@ -118,6 +87,13 @@
* Sets the device's time zone.
*/
void setDeviceTimeZone(@NonNull String zoneId);
+
+ /**
+ * Stores the configuration properties contained in {@code newConfiguration}.
+ * All checks about user capabilities must be done by the caller and
+ * {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
+ */
+ void storeConfiguration(TimeZoneConfiguration newConfiguration);
}
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -189,9 +165,9 @@
@NonNull
private final Callback mCallback;
- /** Non-null after {@link #setStrategyListener(StrategyListener)} is called. */
- @Nullable
- private StrategyListener mListener;
+ @GuardedBy("this")
+ @NonNull
+ private List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
/**
* A log that records the decisions / decision metadata that affected the device's time zone.
@@ -211,7 +187,8 @@
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
/**
- * The latest geolocation suggestion received.
+ * The latest geolocation suggestion received. If the user disabled geolocation time zone
+ * detection then the latest suggestion is cleared.
*/
@GuardedBy("this")
private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
@@ -223,113 +200,120 @@
/**
* Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
*/
- public static TimeZoneDetectorStrategyImpl create(Context context) {
- Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context);
- return new TimeZoneDetectorStrategyImpl(timeZoneDetectionServiceHelper);
+ public static TimeZoneDetectorStrategyImpl create(
+ @NonNull Context context, @NonNull Handler handler,
+ boolean geolocationTimeZoneDetectionEnabled) {
+
+ TimeZoneDetectorCallbackImpl callback = new TimeZoneDetectorCallbackImpl(
+ context, handler, geolocationTimeZoneDetectionEnabled);
+ return new TimeZoneDetectorStrategyImpl(callback);
}
@VisibleForTesting
- public TimeZoneDetectorStrategyImpl(Callback callback) {
+ public TimeZoneDetectorStrategyImpl(@NonNull Callback callback) {
mCallback = Objects.requireNonNull(callback);
+ mCallback.setConfigChangeListener(this::handleConfigChanged);
}
/**
- * Sets a listener that allows the strategy to communicate with the surrounding service. This
- * must be called before the instance is used and must only be called once.
+ * Adds a listener that allows the strategy to communicate with the surrounding service /
+ * internal. This must be called before the instance is used.
*/
@Override
- public synchronized void setStrategyListener(@NonNull StrategyListener listener) {
- if (mListener != null) {
- throw new IllegalStateException("Strategy already has a listener");
- }
- mListener = Objects.requireNonNull(listener);
+ public synchronized void addConfigChangeListener(
+ @NonNull ConfigurationChangeListener listener) {
+ Objects.requireNonNull(listener);
+ mConfigChangeListeners.add(listener);
}
@Override
@NonNull
- public synchronized TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- return mCallback.getCapabilities(userId);
+ public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ return mCallback.getConfigurationInternal(userId);
}
@Override
@NonNull
- public synchronized TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return mCallback.getConfiguration(userId);
+ public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
+ int currentUserId = mCallback.getCurrentUserId();
+ return getConfigurationInternal(currentUserId);
}
@Override
public synchronized boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configurationChanges) {
- Objects.requireNonNull(configurationChanges);
+ @NonNull TimeZoneConfiguration requestedConfiguration) {
+ Objects.requireNonNull(requestedConfiguration);
- // Validate the requested configuration changes before applying any of them.
- TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
- boolean canManageTimeZoneDetection =
- capabilities.getConfigureAutoDetectionEnabled() >= CAPABILITY_NOT_APPLICABLE;
- if (!canManageTimeZoneDetection
- && containsAutoTimeDetectionProperties(configurationChanges)) {
+ int userId = requestedConfiguration.getUserId();
+ TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
+
+ // Create a new configuration builder, and copy across the mutable properties users are
+ // able to modify. Other properties are therefore ignored.
+ final TimeZoneConfiguration newConfiguration =
+ capabilities.applyUpdate(requestedConfiguration);
+ if (newConfiguration == null) {
+ // The changes could not be made due to
return false;
}
- // Create a complete configuration by merging the existing and new (possibly partial)
- // configuration.
- final TimeZoneConfiguration oldConfiguration = mCallback.getConfiguration(userId);
- final TimeZoneConfiguration newConfiguration =
- new TimeZoneConfiguration.Builder(oldConfiguration)
- .mergeProperties(configurationChanges)
- .build();
+ // Store the configuration / notify as needed. This will cause the mCallback to invoke
+ // handleConfigChanged() asynchronously.
+ mCallback.storeConfiguration(newConfiguration);
- // Set the configuration / notify as needed.
- boolean configurationChanged = !oldConfiguration.equals(newConfiguration);
- if (configurationChanged) {
- mCallback.setConfiguration(userId, newConfiguration);
-
- String logMsg = "Configuration changed:"
- + "oldConfiguration=" + oldConfiguration
- + ", configuration=" + configurationChanges
- + ", newConfiguration=" + newConfiguration;
- mTimeZoneChangesLog.log(logMsg);
- if (DBG) {
- Slog.d(LOG_TAG, logMsg);
- }
- mListener.onConfigurationChanged();
+ TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration();
+ String logMsg = "Configuration changed:"
+ + " oldConfiguration=" + oldConfiguration
+ + ", newConfiguration=" + newConfiguration;
+ mTimeZoneChangesLog.log(logMsg);
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
}
return true;
}
- private static boolean containsAutoTimeDetectionProperties(
- @NonNull TimeZoneConfiguration configuration) {
- return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
- || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
- }
-
@Override
public synchronized void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
if (DBG) {
- Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion);
+ Slog.d(LOG_TAG, "Geolocation suggestion received."
+ + " currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
}
-
Objects.requireNonNull(suggestion);
- mLatestGeoLocationSuggestion.set(suggestion);
- // Now perform auto time zone detection. The new suggestion may be used to modify the time
- // zone setting.
- if (mCallback.isGeoDetectionEnabled()) {
+ if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
+ // Only store a geolocation suggestion if geolocation detection is currently enabled.
+ mLatestGeoLocationSuggestion.set(suggestion);
+
+ // 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;
- doAutoTimeZoneDetection(reason);
+ doAutoTimeZoneDetection(currentUserConfig, reason);
}
}
@Override
public synchronized boolean suggestManualTimeZone(
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ if (userId != currentUserId) {
+ Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId
+ + " suggestion=" + suggestion);
+
+ // Only listen to changes from the current user.
+ return false;
+ }
+
Objects.requireNonNull(suggestion);
String timeZoneId = suggestion.getZoneId();
String cause = "Manual time suggestion received: suggestion=" + suggestion;
- TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
+ TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) {
Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
+ ", capabilities=" + capabilities
@@ -345,8 +329,12 @@
@Override
public synchronized void suggestTelephonyTimeZone(
@NonNull TelephonyTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
if (DBG) {
- Slog.d(LOG_TAG, "Telephony suggestion received. newSuggestion=" + suggestion);
+ Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -360,9 +348,9 @@
// Now perform auto time zone detection. The new suggestion may be used to modify the time
// zone setting.
- if (!mCallback.isGeoDetectionEnabled()) {
+ if (!currentUserConfig.getGeoDetectionEnabledBehavior()) {
String reason = "New telephony time zone suggested. suggestion=" + suggestion;
- doAutoTimeZoneDetection(reason);
+ doAutoTimeZoneDetection(currentUserConfig, reason);
}
}
@@ -392,15 +380,15 @@
* Performs automatic time zone detection.
*/
@GuardedBy("this")
- private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
- if (!mCallback.isAutoDetectionEnabled()) {
- // Avoid doing unnecessary work with this (race-prone) check.
+ private void doAutoTimeZoneDetection(
+ @NonNull ConfigurationInternal currentUserConfig, @NonNull String detectionReason) {
+ if (!currentUserConfig.getAutoDetectionEnabledBehavior()) {
+ // Avoid doing unnecessary work.
return;
}
- // Use the right suggestions based on the current configuration. This check is potentially
- // race-prone until this value is set via a call to TimeZoneDetectorStrategy.
- if (mCallback.isGeoDetectionEnabled()) {
+ // Use the right suggestions based on the current configuration.
+ if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
doGeolocationTimeZoneDetection(detectionReason);
} else {
doTelephonyTimeZoneDetection(detectionReason);
@@ -480,35 +468,18 @@
// Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
// zone ID.
- String newZoneId = bestTelephonySuggestion.suggestion.getZoneId();
- if (newZoneId == null) {
+ String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
+ if (zoneId == null) {
Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
+ " bestTelephonySuggestion=" + bestTelephonySuggestion
+ " detectionReason=" + detectionReason);
return;
}
- String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
String cause = "Found good suggestion."
+ ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
- setAutoDeviceTimeZoneIfRequired(zoneId, cause);
- }
-
- @GuardedBy("this")
- private void setAutoDeviceTimeZoneIfRequired(@NonNull String newZoneId, @NonNull String cause) {
- Objects.requireNonNull(newZoneId);
- Objects.requireNonNull(cause);
-
- if (!mCallback.isAutoDetectionEnabled()) {
- if (DBG) {
- Slog.d(LOG_TAG, "Auto time zone detection is not enabled."
- + ", newZoneId=" + newZoneId
- + ", cause=" + cause);
- }
- return;
- }
- setDeviceTimeZoneIfRequired(newZoneId, cause);
+ setDeviceTimeZoneIfRequired(zoneId, cause);
}
@GuardedBy("this")
@@ -582,13 +553,39 @@
return findBestTelephonySuggestion();
}
- @Override
- public synchronized void handleAutoTimeZoneConfigChanged() {
+ private synchronized void handleConfigChanged() {
if (DBG) {
- Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()");
+ Slog.d(LOG_TAG, "handleConfigChanged()");
}
- doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()");
+ clearGeolocationSuggestionIfNeeded();
+
+ for (ConfigurationChangeListener listener : mConfigChangeListeners) {
+ listener.onChange();
+ }
+ }
+
+ @GuardedBy("this")
+ private void clearGeolocationSuggestionIfNeeded() {
+ // This method is called whenever the user changes or the config for any user changes. We
+ // don't know what happened, so we capture the current user's config, check to see if we
+ // need to clear state associated with a previous user, and rerun detection.
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
+
+ GeolocationTimeZoneSuggestion latestGeoLocationSuggestion =
+ mLatestGeoLocationSuggestion.get();
+ if (latestGeoLocationSuggestion != null
+ && !currentUserConfig.getGeoDetectionEnabledBehavior()) {
+ // The current user's config has geodetection disabled, so clear the latest suggestion.
+ // This is done to ensure we only ever keep a geolocation suggestion if the user has
+ // said it is ok to do so.
+ mLatestGeoLocationSuggestion.set(null);
+ mTimeZoneChangesLog.log(
+ "clearGeolocationSuggestionIfNeeded: Cleared latest Geolocation suggestion.");
+ }
+
+ doAutoTimeZoneDetection(currentUserConfig, "clearGeolocationSuggestionIfNeeded()");
}
@Override
@@ -604,11 +601,14 @@
ipw.println("TimeZoneDetectorStrategy:");
ipw.increaseIndent(); // level 1
- ipw.println("mCallback.isAutoDetectionEnabled()=" + mCallback.isAutoDetectionEnabled());
+ int currentUserId = mCallback.getCurrentUserId();
+ ipw.println("mCallback.getCurrentUserId()=" + currentUserId);
+ ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId);
+ ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration);
+ ipw.println("[Capabilities=" + configuration.createCapabilities() + "]");
ipw.println("mCallback.isDeviceTimeZoneInitialized()="
+ mCallback.isDeviceTimeZoneInitialized());
ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
- ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled());
ipw.println("Time zone change log:");
ipw.increaseIndent(); // level 2
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 964de13..56261c4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -110,9 +110,13 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTAINERS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN;
@@ -145,9 +149,6 @@
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -1096,15 +1097,15 @@
private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
- "Can't report activity moved to display - client not running, activityRecord="
- + this + ", displayId=" + displayId);
+ ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
+ + "to display - client not running, activityRecord=%s, displayId=%d",
+ this, displayId);
return;
}
try {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Reporting activity moved to display" + ", activityRecord=" + this
- + ", displayId=" + displayId + ", config=" + config);
+ ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
+ + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
+ config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
MoveToDisplayItem.obtain(displayId, config));
@@ -1115,14 +1116,13 @@
private void scheduleConfigurationChanged(Configuration config) {
if (!attachedToProcess()) {
- if (DEBUG_CONFIGURATION) Slog.w(TAG,
- "Can't report activity configuration update - client not running"
- + ", activityRecord=" + this);
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "
+ + "update - client not running, activityRecord=%s", this);
return;
}
try {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
- + config);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
+ + "config: %s", this, config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
ActivityConfigurationChangeItem.obtain(config));
@@ -1949,10 +1949,8 @@
startingWindow = null;
startingDisplayed = false;
if (surface == null) {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
- "startingWindow was set but startingSurface==null, couldn't "
- + "remove");
-
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
+ + "startingSurface==null, couldn't remove");
return;
}
} else {
@@ -1962,9 +1960,10 @@
return;
}
+
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
- + " startingView=%s Callers=%s",
- this, startingWindow, startingSurface, Debug.getCallers(5));
+ + " startingView=%s Callers=%s", this, startingWindow, startingSurface,
+ Debug.getCallers(5));
// Use the same thread to remove the window as we used to add it, as otherwise we end up
@@ -2399,9 +2398,8 @@
*/
boolean moveFocusableActivityToTop(String reason) {
if (!isFocusable()) {
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: unfocusable "
+ + "activity=%s", this);
return false;
}
@@ -2414,15 +2412,11 @@
if (mRootWindowContainer.getTopResumedActivity() == this
&& getDisplayContent().mFocusedApp == this) {
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: already on top, "
+ + "activity=%s", this);
return !isState(RESUMED);
}
-
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: activity=%s", this);
stack.moveToFront(reason, task);
// Report top activity change to tracking services and WM
@@ -2798,10 +2792,8 @@
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
- if (DEBUG_CONTAINERS) {
- Slog.d(TAG_CONTAINERS, "destroyIfPossible: r=" + this + " destroy returned removed="
- + activityRemoved);
- }
+ ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned "
+ + "removed=%s", this, activityRemoved);
return activityRemoved;
}
@@ -2935,10 +2927,9 @@
finishActivityResults(Activity.RESULT_CANCELED,
null /* resultData */, null /* resultGrants */);
makeFinishingLocked();
- if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) {
- Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack, reason="
- + reason + ", callers=" + Debug.getCallers(5));
- }
+
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from stack, reason= %s "
+ + "callers=%s", this, reason, Debug.getCallers(5));
takeFromHistory();
removeTimeouts();
@@ -2978,7 +2969,7 @@
void destroyed(String reason) {
removeDestroyTimeout();
- if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this);
+ ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this);
if (!isState(DESTROYING, DESTROYED)) {
throw new IllegalStateException(
@@ -3179,12 +3170,9 @@
remove = false;
}
if (remove) {
- if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
- Slog.i(TAG_ADD_REMOVE, "Removing activity " + this
- + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded
- + " finishing=" + finishing + " state=" + mState
- + " callers=" + Debug.getCallers(5));
- }
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s hasSavedState=%b "
+ + "stateNotNeeded=%s finishing=%b state=%s callers=%s", this,
+ mHaveState, stateNotNeeded, finishing, mState, Debug.getCallers(5));
if (!finishing || (app != null && app.isRemoved())) {
Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
@@ -7007,27 +6995,27 @@
boolean ignoreVisibility) {
final Task stack = getRootTask();
if (stack.mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check (will change): " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ + "(will change): %s", this);
return true;
}
// We don't worry about activities that are finishing.
if (finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter in finishing " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter "
+ + "in finishing %s", this);
stopFreezingScreenLocked(false);
return true;
}
if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check invisible: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ + "invisible: %s", this);
return true;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Ensuring correct configuration: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct "
+ + "configuration: %s", this);
final int newDisplayId = getDisplayId();
final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
@@ -7043,8 +7031,8 @@
// the combine configurations are equal, but would otherwise differ in the override config
mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration & display unchanged in " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
+ + "unchanged in %s", this);
return true;
}
@@ -7064,14 +7052,14 @@
// No need to relaunch or schedule new config for activity that hasn't been launched
// yet. We do, however, return after applying the config to activity record, so that
// it will use it for launch transaction.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check for initializing activity: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for "
+ + "initializing activity: %s", this);
return true;
}
if (changes == 0 && !forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration no differences in " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s",
+ this);
// There are no significant differences, so we won't relaunch but should still deliver
// the new configuration to the client process.
if (displayChanged) {
@@ -7082,26 +7070,23 @@
return true;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration changes for " + this + ", allChanges="
- + Configuration.configurationDiffToString(changes));
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, "
+ + "allChanges=%s", this, Configuration.configurationDiffToString(changes));
// If the activity isn't currently running, just leave the new configuration and it will
// pick that up next time it starts.
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter not running " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this);
stopFreezingScreenLocked(false);
forceNewConfig = false;
return true;
}
// Figure out how to handle the changes between the configurations.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Checking to restart " + info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(info.getRealConfigChanged())
- + ", mLastReportedConfiguration=" + mLastReportedConfiguration);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
+ + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
+ Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
+ mLastReportedConfiguration);
if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
@@ -7118,20 +7103,20 @@
mRelaunchReason = RELAUNCH_REASON_NONE;
}
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is destroying non-running " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Config is destroying non-running %s", this);
destroyImmediately("config");
} else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is skipping already pausing " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Config is skipping already pausing %s", this);
deferRelaunchUntilPaused = true;
preserveWindowOnDeferredRelaunch = preserveWindow;
return true;
} else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
+ this);
if (DEBUG_STATES && !mVisibleRequested) {
Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
+ " called by " + Debug.getCallers(4));
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4c93b9e..be7a6ae 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -56,12 +56,12 @@
import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -116,6 +116,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.power.ShutdownCheckPoints;
@@ -669,10 +670,8 @@
if (stack != null) {
stack.mConfigWillChange = globalConfigWillChange;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
- + globalConfigWillChange);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
+ + "will change = %b", globalConfigWillChange);
final long origId = Binder.clearCallingIdentity();
@@ -695,10 +694,9 @@
if (stack != null) {
stack.mConfigWillChange = false;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION,
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
"Updating to new configuration after starting activity.");
- }
+
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index da0bfd6..3c562a6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -43,12 +43,6 @@
// Enable all debug log categories for activities.
private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
- static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
- public static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
- static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_FOCUS = false;
- static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
- static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2adaa52..6a8cbfb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -66,6 +66,10 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -92,10 +96,6 @@
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -242,6 +242,7 @@
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -813,7 +814,7 @@
// in-place.
updateConfigurationLocked(configuration, null, true);
final Configuration globalConfig = getGlobalConfiguration();
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Initial config: %s", globalConfig);
// Load resources only after the current configuration has been set.
final Resources res = mContext.getResources();
@@ -1960,7 +1961,7 @@
// update associated state if we're frontmost
if (r.isFocusedActivityOnDisplay()) {
- if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
+ ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r);
applyUpdateLockStateLocked(r);
}
}
@@ -1974,8 +1975,8 @@
final boolean nextState = r != null && r.immersive;
mH.post(() -> {
if (mUpdateLock.isHeld() != nextState) {
- if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
- "Applying new update lock state '" + nextState + "' for " + r);
+ ProtoLog.d(WM_DEBUG_IMMERSIVE, "Applying new update lock state '%s' for %s",
+ nextState, r);
if (nextState) {
mUpdateLock.acquire();
} else {
@@ -2176,7 +2177,7 @@
@Override
public void setFocusedStack(int stackId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
+ ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedStack: stackId=%d", stackId);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2198,7 +2199,7 @@
@Override
public void setFocusedTask(int taskId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
+ ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3013,7 +3014,7 @@
}
private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskModeLocked: %s", task);
if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
}
@@ -3075,8 +3076,7 @@
"updateLockTaskPackages()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
- + Arrays.toString(packages));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId, Arrays.toString(packages));
getLockTaskController().updateLockTaskPackages(userId, packages);
}
}
@@ -4001,9 +4001,9 @@
@Override
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
- + Arrays.toString(horizontalSizeConfiguration) + " "
- + Arrays.toString(verticalSizeConfigurations));
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s",
+ token, Arrays.toString(horizontalSizeConfiguration),
+ Arrays.toString(verticalSizeConfigurations));
synchronized (mGlobalLock) {
ActivityRecord record = ActivityRecord.isInStackLocked(token);
if (record == null) {
@@ -4497,8 +4497,8 @@
"updateLockTaskFeatures()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowing features " + userId + ":0x" +
- Integer.toHexString(flags));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowing features %d:0x%s",
+ userId, Integer.toHexString(flags));
getLockTaskController().updateLockTaskFeatures(userId, flags);
}
}
@@ -5183,8 +5183,8 @@
return 0;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
- "Updating global configuration to: " + values);
+ ProtoLog.i(WM_DEBUG_CONFIGURATION, "Updating global configuration "
+ + "to: %s", values);
writeConfigurationChanged(changes);
FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
values.colorMode,
@@ -5262,10 +5262,8 @@
for (int i = pidMap.size() - 1; i >= 0; i--) {
final int pid = pidMap.keyAt(i);
final WindowProcessController app = pidMap.get(pid);
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Update process config of "
- + app.mName + " to new config " + configCopy);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new "
+ + "config %s", app.mName, configCopy);
app.onConfigurationChanged(configCopy);
}
@@ -6563,10 +6561,8 @@
if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return;
if (pid == MY_PID || pid < 0) {
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG,
+ ProtoLog.w(WM_DEBUG_CONFIGURATION,
"Trying to update display configuration for system/invalid process.");
- }
return;
}
synchronized (mGlobalLock) {
@@ -6574,18 +6570,14 @@
mRootWindowContainer.getDisplayContent(displayId);
if (displayContent == null) {
// Call might come when display is not yet added or has been removed.
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Trying to update display configuration for non-existing "
- + "displayId=" + displayId);
- }
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+ + "configuration for non-existing displayId=%d", displayId);
return;
}
final WindowProcessController process = mProcessMap.getProcess(pid);
if (process == null) {
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Trying to update display configuration for invalid "
- + "process, pid=" + pid);
- }
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+ + "configuration for invalid process, pid=%d", pid);
return;
}
process.registerDisplayConfigurationListener(displayContent);
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 167afab..7e55f0a 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -37,6 +37,7 @@
import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -333,8 +334,8 @@
}
try {
if (app.hasThread()) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.mName + " new compat " + ci);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s "
+ + "new compat %s", app.mName, ci);
app.getThread().updatePackageCompatibilityInfo(packageName, ci);
}
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 8ef57f7..c8d7693 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -29,7 +29,7 @@
import static android.os.UserHandle.USER_CURRENT;
import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -65,6 +65,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
@@ -448,7 +449,7 @@
* unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
*/
void clearLockedTasks(String reason) {
- if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
+ ProtoLog.i(WM_DEBUG_LOCKTASK, "clearLockedTasks: %s", reason);
if (!mLockTaskModeTasks.isEmpty()) {
clearLockedTask(mLockTaskModeTasks.get(0));
}
@@ -490,10 +491,10 @@
if (!mLockTaskModeTasks.remove(task)) {
return;
}
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: removed " + task);
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: removed %s", task);
if (mLockTaskModeTasks.isEmpty()) {
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
- " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: task=%s last task, "
+ + "reverting locktask mode. Callers=%s", task, Debug.getCallers(3));
mHandler.post(() -> performStopLockTask(task.mUserId));
}
}
@@ -558,7 +559,7 @@
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
// startLockTask() called by app, but app is not part of lock task allowlist. Show
// app pinning request. We will come back here with isSystemCaller true.
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Mode default, asking user");
StatusBarManagerInternal statusBarManager = LocalServices.getService(
StatusBarManagerInternal.class);
if (statusBarManager != null) {
@@ -569,8 +570,7 @@
}
// System can only initiate screen pinning, not full lock task mode
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
- isSystemCaller ? "Locking pinned" : "Locking fully");
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
"startLockTask", true);
}
@@ -584,7 +584,7 @@
String reason, boolean andResume) {
// Should have already been checked, but do it again.
if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+ ProtoLog.w(WM_DEBUG_LOCKTASK,
"setLockTaskMode: Can't lock due to auth");
return;
}
@@ -602,8 +602,8 @@
task.mUserId,
lockTaskModeState));
}
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
- " Callers=" + Debug.getCallers(4));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Locking to %s Callers=%s",
+ task, Debug.getCallers(4));
if (!mLockTaskModeTasks.contains(task)) {
mLockTaskModeTasks.add(task);
@@ -672,8 +672,8 @@
}
// Terminate locked tasks that have recently lost allowlist authorization.
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
- lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s"
+ + " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
lockedTask.performClearTaskLocked();
taskChanged = true;
@@ -686,8 +686,8 @@
if (mLockTaskModeTasks.isEmpty() && task!= null
&& task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
// This task must have just been authorized.
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
- "onLockTaskPackagesUpdated: starting new locktask task=" + task);
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: starting new "
+ + "locktask task=%s", task);
setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
taskChanged = true;
}
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index cc5ed36..c3953b4 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -16,9 +16,8 @@
package com.android.server.wm;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.TAG_ADD_REMOVE;
import static com.android.server.wm.Task.TAG_TASKS;
import android.app.ActivityOptions;
@@ -27,6 +26,7 @@
import android.os.Debug;
import android.util.Slog;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -218,8 +218,8 @@
if (takeOptions) {
noOptions = takeOption(p, noOptions);
}
- if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing activity " + p + " from task="
- + mTask + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4));
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s "
+ + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Pushing next activity " + p + " out to target's task " + target);
p.reparent(targetTask, position, "resetTargetTaskIfNeeded");
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 6cf9432..7b5b0ad 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -99,9 +99,8 @@
// the task's profile
return;
}
- if (!mAllowed && !task.isActivityTypeHome()) {
- // Skip if the caller isn't allowed to fetch this task, except for the home
- // task which we always return.
+ if (!mAllowed) {
+ // Skip if the caller isn't allowed to fetch this task
return;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e77a535..19bf451 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -79,6 +79,7 @@
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
@@ -87,9 +88,7 @@
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -1651,8 +1650,8 @@
* Reorder the history stack so that the passed activity is brought to the front.
*/
final void moveActivityToFrontLocked(ActivityRecord newTop) {
- if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
- + newTop + " to stack at top callers=" + Debug.getCallers(4));
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to stack at top "
+ + "callers=%s", newTop, Debug.getCallers(4));
positionChildAtTop(newTop);
updateEffectiveIntent();
@@ -1951,8 +1950,8 @@
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
- + " mLockTaskAuth=" + lockTaskAuthToString());
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this,
+ lockTaskAuthToString());
}
@Override
@@ -6370,7 +6369,8 @@
// Here it is! Now, if this is not yet visible (occluded by another task) to the
// user, then just add it without starting; it will get started when the user
// navigates back to it.
- if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task,
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
+ + "callers: %s", r, task,
new RuntimeException("here").fillInStackTrace());
rTask.positionChildAtTop(r);
ActivityOptions.abort(options);
@@ -6392,8 +6392,8 @@
task = activityTask;
// Slot the activity into the history stack and proceed
- if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
- new RuntimeException("here").fillInStackTrace());
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to stack to task %s "
+ + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
task.positionChildAtTop(r);
// The transition animation and starting window are not needed if {@code allowMoveToFront}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bb9cf2e..c5ebace 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -22,9 +22,9 @@
import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -72,6 +72,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.wm.ActivityTaskManagerService.HotPath;
@@ -1348,9 +1349,8 @@
}
return;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
+ config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 763654d..dda81ff 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -187,7 +187,7 @@
moveEachPointers(mLastEvent, p(10, 10), p(10, 10));
send(mLastEvent);
goToStateClearFrom(STATE_DRAGGING_2FINGERS);
- assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
+ assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
}
@Test
@@ -288,7 +288,7 @@
assertState(STATE_DRAGGING);
goToStateClearFrom(STATE_DRAGGING_2FINGERS);
assertState(STATE_CLEAR);
- assertCapturedEvents(ACTION_DOWN, ACTION_UP);
+ assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
assertCapturedEventsNoHistory();
}
@@ -301,6 +301,7 @@
assertState(STATE_CLEAR);
assertCapturedEvents(
/* goto dragging state */ ACTION_DOWN,
+ ACTION_MOVE,
/* leave dragging state */ ACTION_UP,
ACTION_DOWN,
ACTION_POINTER_DOWN,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index 53c4d6f..f17173f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -62,6 +62,32 @@
assertThat(message).isEqualTo(buildMessage("5F:81:21:00"));
}
+ @Test
+ public void buildSetOsdName_short() {
+ String deviceName = "abc";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(buildMessage("40:47:61:62:63"));
+ }
+
+ @Test
+ public void buildSetOsdName_maximumLength() {
+ String deviceName = "abcdefghijklmn";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(
+ buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+ }
+
+ @Test
+ public void buildSetOsdName_tooLong() {
+ String deviceName = "abcdefghijklmnop";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(
+ buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+ }
+
/**
* Build a CEC message from a hex byte string with bytes separated by {@code :}.
*
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
new file mode 100644
index 0000000..d7ed96f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.timezonedetector.TimeZoneCapabilities;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and
+ * {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it.
+ */
+public class ConfigurationInternalTest {
+
+ private static final int ARBITRARY_USER_ID = 99999;
+
+ /**
+ * Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
+ * {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
+ */
+ @Test
+ public void test_unrestricted() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+
+ /** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
+ @Test
+ public void test_restricted() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+
+ /** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
+ @Test
+ public void test_autoDetectNotSupported() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(false)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index e5e9311..4ef2082 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -32,56 +33,64 @@
class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
- private StrategyListener mListener;
+ private ConfigurationChangeListener mConfigurationChangeListener;
// Fake state
- private TimeZoneCapabilities mCapabilities;
- private TimeZoneConfiguration mConfiguration;
+ private ConfigurationInternal mConfigurationInternal;
// Call tracking.
private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion;
private ManualTimeZoneSuggestion mLastManualSuggestion;
private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
- private boolean mHandleAutoTimeZoneConfigChangedCalled;
private boolean mDumpCalled;
private final List<Dumpable> mDumpables = new ArrayList<>();
@Override
- public void setStrategyListener(@NonNull StrategyListener listener) {
- mListener = listener;
+ public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ if (mConfigurationChangeListener != null) {
+ fail("Fake only supports one listener");
+ }
+ mConfigurationChangeListener = listener;
}
@Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- return mCapabilities;
+ public ConfigurationInternal getConfigurationInternal(int userId) {
+ if (mConfigurationInternal.getUserId() != userId) {
+ fail("Fake only supports one user");
+ }
+ return mConfigurationInternal;
}
@Override
- public boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
- assertNotNull(mConfiguration);
- assertNotNull(configuration);
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mConfigurationInternal;
+ }
- // Simulate the strategy's behavior: the new configuration will be the old configuration
- // merged with the new.
- TimeZoneConfiguration oldConfiguration = mConfiguration;
- TimeZoneConfiguration newConfiguration =
- new TimeZoneConfiguration.Builder(mConfiguration)
- .mergeProperties(configuration)
- .build();
+ @Override
+ public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) {
+ assertNotNull(mConfigurationInternal);
+ assertNotNull(requestedChanges);
- if (newConfiguration.equals(oldConfiguration)) {
+ // Simulate the real strategy's behavior: the new configuration will be updated to be the
+ // old configuration merged with the new if the user has the capability to up the settings.
+ // Then, if the configuration changed, the change listener is invoked.
+ TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities();
+ TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges);
+ if (newConfiguration == null) {
return false;
}
- mConfiguration = newConfiguration;
- mListener.onConfigurationChanged();
+
+ if (!newConfiguration.equals(capabilities.getConfiguration())) {
+ mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+
+ // Note: Unlike the real strategy, the listeners is invoked synchronously.
+ mConfigurationChangeListener.onChange();
+ }
return true;
}
- @Override
- @NonNull
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return mConfiguration;
+ public void simulateConfigurationChangeForTests() {
+ mConfigurationChangeListener.onChange();
}
@Override
@@ -103,11 +112,6 @@
}
@Override
- public void handleAutoTimeZoneConfigChanged() {
- mHandleAutoTimeZoneConfigChangedCalled = true;
- }
-
- @Override
public void addDumpable(Dumpable dumpable) {
mDumpables.add(dumpable);
}
@@ -117,19 +121,14 @@
mDumpCalled = true;
}
- void initializeConfiguration(TimeZoneConfiguration configuration) {
- mConfiguration = configuration;
- }
-
- void initializeCapabilities(TimeZoneCapabilities capabilities) {
- mCapabilities = capabilities;
+ void initializeConfiguration(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal = configurationInternal;
}
void resetCallTracking() {
mLastGeolocationSuggestion = null;
mLastManualSuggestion = null;
mLastTelephonySuggestion = null;
- mHandleAutoTimeZoneConfigChangedCalled = false;
mDumpCalled = false;
}
@@ -146,10 +145,6 @@
assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
- void verifyHandleAutoTimeZoneConfigChangedCalled() {
- assertTrue(mHandleAutoTimeZoneConfigChangedCalled);
- }
-
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
new file mode 100644
index 0000000..f45b3a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.UserIdInt;
+
+/** A fake {@link CallerIdentityInjector} used in tests. */
+public class TestCallerIdentityInjector implements CallerIdentityInjector {
+
+ private long mToken = 9999L;
+ private int mCallingUserId;
+ private Integer mCurrentCallingUserId;
+
+ public void initializeCallingUserId(@UserIdInt int userId) {
+ mCallingUserId = userId;
+ mCurrentCallingUserId = userId;
+ }
+
+ @Override
+ public int getCallingUserId() {
+ assertNotNull("callingUserId has been cleared", mCurrentCallingUserId);
+ return mCurrentCallingUserId;
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ mCurrentCallingUserId = null;
+ return mToken;
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {
+ assertEquals(token, mToken);
+ mCurrentCallingUserId = mCallingUserId;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index e9d57e5..918babc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -16,6 +16,7 @@
package com.android.server.timezonedetector;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -85,6 +86,18 @@
mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable);
}
+ @Test
+ public void testAddConfigurationListener() throws Exception {
+ boolean[] changeCalled = new boolean[2];
+ mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[0] = true);
+ mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[1] = true);
+
+ mFakeTimeZoneDetectorStrategy.simulateConfigurationChangeForTests();
+
+ assertTrue(changeCalled[0]);
+ assertTrue(changeCalled[1]);
+ }
+
private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 3a1ec4f..27b04b6 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -16,8 +16,6 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -36,7 +34,6 @@
import android.app.timezonedetector.ITimeZoneConfigurationListener;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -65,6 +62,7 @@
private TimeZoneDetectorService mTimeZoneDetectorService;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
+ private TestCallerIdentityInjector mTestCallerIdentityInjector;
@Before
@@ -76,10 +74,14 @@
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
+ mTestCallerIdentityInjector = new TestCallerIdentityInjector();
+ mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
+
mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mTimeZoneDetectorService = new TimeZoneDetectorService(
- mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
+ mMockContext, mTestHandler, mTestCallerIdentityInjector,
+ mFakeTimeZoneDetectorStrategy);
}
@After
@@ -107,40 +109,12 @@
public void testGetCapabilities() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeZoneCapabilities capabilities = createTimeZoneCapabilities();
- mFakeTimeZoneDetectorStrategy.initializeCapabilities(capabilities);
-
- assertEquals(capabilities, mTimeZoneDetectorService.getCapabilities());
-
- verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
- anyString());
- }
-
- @Test(expected = SecurityException.class)
- public void testGetConfiguration_withoutPermission() {
- doThrow(new SecurityException("Mock"))
- .when(mMockContext).enforceCallingPermission(anyString(), any());
-
- try {
- mTimeZoneDetectorService.getConfiguration();
- fail();
- } finally {
- verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
- anyString());
- }
- }
-
- @Test
- public void testGetConfiguration() {
- doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
-
- TimeZoneConfiguration configuration =
- createTimeZoneConfiguration(false /* autoDetectionEnabled */);
+ ConfigurationInternal configuration =
+ createConfigurationInternal(true /* autoDetectionEnabled*/);
mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
- assertEquals(configuration, mTimeZoneDetectorService.getConfiguration());
+ assertEquals(configuration.createCapabilities(),
+ mTimeZoneDetectorService.getCapabilities());
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
@@ -181,10 +155,9 @@
@Test
public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception {
- TimeZoneConfiguration autoDetectDisabledConfiguration =
- createTimeZoneConfiguration(false /* autoDetectionEnabled */);
-
- mFakeTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration);
+ ConfigurationInternal initialConfiguration =
+ createConfigurationInternal(false /* autoDetectionEnabled */);
+ mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
@@ -210,13 +183,12 @@
// Simulate the configuration being changed and verify the mockListener was notified.
TimeZoneConfiguration autoDetectEnabledConfiguration =
createTimeZoneConfiguration(true /* autoDetectionEnabled */);
-
mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
anyString());
- verify(mockListener).onChange(autoDetectEnabledConfiguration);
+ verify(mockListener).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
reset(mockListenerBinder, mockListener, mMockContext);
}
@@ -242,12 +214,14 @@
{
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+ TimeZoneConfiguration autoDetectDisabledConfiguration =
+ createTimeZoneConfiguration(false /* autoDetectionEnabled */);
mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
anyString());
- verify(mockListener, never()).onChange(any());
+ verify(mockListener, never()).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
reset(mockListenerBinder, mockListener, mMockContext);
}
@@ -379,33 +353,22 @@
mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
}
- @Test
- public void testHandleAutoTimeZoneConfigChanged() throws Exception {
- mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
- mTestHandler.assertTotalMessagesEnqueued(1);
- mTestHandler.waitForMessagesToBeProcessed();
- mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
-
- mFakeTimeZoneDetectorStrategy.resetCallTracking();
-
- mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
- mTestHandler.assertTotalMessagesEnqueued(2);
- mTestHandler.waitForMessagesToBeProcessed();
- mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
- }
-
- private static TimeZoneConfiguration createTimeZoneConfiguration(
- boolean autoDetectionEnabled) {
- return new TimeZoneConfiguration.Builder()
+ private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
+ return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.setAutoDetectionEnabled(autoDetectionEnabled)
.build();
}
- private static TimeZoneCapabilities createTimeZoneCapabilities() {
- return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+ private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
+ // Default geo detection settings from auto detection settings - they are not important to
+ // the tests.
+ final boolean geoDetectionEnabled = autoDetectionEnabled;
+ return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(autoDetectionEnabled)
+ .setLocationEnabled(geoDetectionEnabled)
+ .setGeoDetectionEnabled(geoDetectionEnabled)
.build();
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index a6caa42..2bee5e5 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -23,10 +23,6 @@
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH;
import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST;
@@ -37,9 +33,9 @@
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;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -47,7 +43,6 @@
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
@@ -61,7 +56,6 @@
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -94,192 +88,149 @@
TELEPHONY_SCORE_HIGHEST),
};
- private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
- new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .build();
-
- private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
.setAutoDetectionEnabled(false)
- .build();
-
- private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
- new TimeZoneConfiguration.Builder()
+ .setLocationEnabled(true)
.setGeoDetectionEnabled(false)
.build();
- private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
.setGeoDetectionEnabled(true)
.build();
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(false)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+
+ private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
+ createConfig(false /* autoDetection */, null);
+ private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
+ createConfig(true /* autoDetection */, null);
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
+ createConfig(null, true /* geoDetection */);
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
+ createConfig(null, false /* geoDetection */);
+
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
private FakeCallback mFakeCallback;
- private MockStrategyListener mMockStrategyListener;
+ private MockConfigChangeListener mMockConfigChangeListener;
+
@Before
public void setUp() {
mFakeCallback = new FakeCallback();
- mMockStrategyListener = new MockStrategyListener();
+ mMockConfigChangeListener = new MockConfigChangeListener();
mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(mFakeCallback);
- mFakeCallback.setStrategyForSettingsCallbacks(mTimeZoneDetectorStrategy);
- mTimeZoneDetectorStrategy.setStrategyListener(mMockStrategyListener);
+ mTimeZoneDetectorStrategy.addConfigChangeListener(mMockConfigChangeListener);
}
@Test
- public void testGetCapabilities() {
- new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID));
- }
-
- @Test
- public void testGetConfiguration() {
- new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID);
- assertTrue(expectedConfiguration.isComplete());
- assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID));
- }
-
- @Test
- public void testCapabilitiesTestInfra_unrestricted() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
- }
-
- @Test
- public void testCapabilitiesTestInfra_restricted() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- }
- }
-
- @Test
- public void testCapabilitiesTestInfra_autoDetectNotSupported() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
+ public void testGetCurrentUserConfiguration() {
+ new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
+ ConfigurationInternal expectedConfiguration =
+ mFakeCallback.getConfigurationInternal(USER_ID);
+ assertEquals(expectedConfiguration,
+ mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal());
}
@Test
public void testUpdateConfiguration_unrestricted() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Set the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// Nothing should have happened: it was initialized in this state.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
+ CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
}
@Test
public void testUpdateConfiguration_restricted() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
- // Update the configuration to enable geolocation time zone detection.
+ // Try to update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
+ CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -287,20 +238,16 @@
@Test
public void testUpdateConfiguration_autoDetectNotSupported() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -313,8 +260,7 @@
TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
createEmptySlotIndex2Suggestion();
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
@@ -359,9 +305,7 @@
TelephonyTestCase testCase2 = newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// A low quality suggestions will not be taken: The device time zone setting is left
// uninitialized.
@@ -426,8 +370,7 @@
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
// Start with the device in a known state.
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ script.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
TelephonyTimeZoneSuggestion suggestion =
@@ -447,8 +390,7 @@
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting on should cause the device setting to be set.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED,
- true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// When time zone detection is already enabled the suggestion (if it scores highly
// enough) should be set immediately.
@@ -465,8 +407,7 @@
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting should off should do nothing.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Assert internal service state.
@@ -480,8 +421,7 @@
@Test
public void testTelephonySuggestionsSingleSlotId() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
@@ -546,8 +486,7 @@
TELEPHONY_SCORE_NONE);
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
// Initialize the latest suggestions as empty so we don't need to worry about nulls
// below for the first loop.
@@ -632,9 +571,7 @@
*/
@Test
public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
TelephonyTestCase testCase = newTelephonyTestCase(
MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -652,40 +589,39 @@
// Toggling time zone detection should set the device time zone only if the current setting
// value is different from the most recent telephony suggestion.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Simulate a user turning auto detection off, a new suggestion being made while auto
// detection is off, and the user turning it on again.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
.verifyTimeZoneNotChanged();
// Latest suggestion should be used.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(newYorkSuggestion);
}
@Test
- public void testManualSuggestion_autoDetectionEnabled_autoTelephony() {
- checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */);
+ public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoTelephony() {
+ checkManualSuggestion_unrestricted_autoDetectionEnabled(false /* geoDetectionEnabled */);
}
@Test
- public void testManualSuggestion_autoDetectionEnabled_autoGeo() {
- checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */);
+ public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoGeo() {
+ checkManualSuggestion_unrestricted_autoDetectionEnabled(true /* geoDetectionEnabled */);
}
- private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) {
- TimeZoneConfiguration geoTzEnabledConfig =
- new TimeZoneConfiguration.Builder()
+ private void checkManualSuggestion_unrestricted_autoDetectionEnabled(
+ boolean geoDetectionEnabled) {
+ ConfigurationInternal geoTzEnabledConfig =
+ new ConfigurationInternal.Builder(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.setGeoDetectionEnabled(geoDetectionEnabled)
.build();
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig))
+ .initializeConfig(geoTzEnabledConfig)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -697,35 +633,19 @@
@Test
public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- // Auto time zone detection is enabled so the manual suggestion should be ignored.
+ // User is restricted so the manual suggestion should be ignored.
script.simulateManualTimeZoneSuggestion(
USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */)
- .verifyTimeZoneNotChanged();
- }
-
- @Test
- public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
- .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
-
- // Auto time zone detection is enabled so the manual suggestion should be ignored.
- ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
- script.simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion);
+ .verifyTimeZoneNotChanged();
}
@Test
public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is disabled so the manual suggestion should be used.
@@ -738,8 +658,7 @@
@Test
public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Restricted users do not have the capability.
@@ -750,10 +669,9 @@
}
@Test
- public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() {
+ public void testManualSuggestion_autoDetectNotSupported() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Unrestricted users have the capability.
@@ -765,9 +683,7 @@
@Test
public void testGeoSuggestion_uncertain() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion();
@@ -783,8 +699,7 @@
@Test
public void testGeoSuggestion_noZones() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list());
@@ -802,8 +717,7 @@
createGeoLocationSuggestion(list("Europe/London"));
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateGeolocationTimeZoneSuggestion(suggestion)
@@ -828,8 +742,7 @@
createGeoLocationSuggestion(list("Europe/Paris"));
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
@@ -856,72 +769,27 @@
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
- /**
- * Confirms that toggling the auto time zone detection enabled setting has the expected behavior
- * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is
- * enabled.
- */
@Test
- public void testTogglingAutoDetectionEnabled_autoGeo() {
- GeolocationTimeZoneSuggestion geolocationSuggestion =
+ public void testGeoSuggestion_togglingGeoDetectionClearsLastSuggestion() {
+ GeolocationTimeZoneSuggestion suggestion =
createGeoLocationSuggestion(list("Europe/London"));
- GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
- createUncertainGeoLocationSuggestion();
- ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion);
-
- // When time zone detection is not enabled, the time zone suggestion will not be set.
- script.verifyTimeZoneNotChanged();
-
- // Assert internal service state.
- assertEquals(geolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
-
- // Toggling the time zone setting on should cause the device setting to be set.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateGeolocationTimeZoneSuggestion(suggestion)
.verifyTimeZoneChangedAndReset("Europe/London");
- // Toggling the time zone setting should off should do nothing because the device is now
- // set to that time zone.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
+ // Assert internal service state.
+ assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
- // Now toggle auto time zone setting, and confirm it is opinionated.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion)
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset("Europe/London");
-
- // Now withdraw the geolocation suggestion, and assert the strategy is no longer
- // opinionated.
- /* expectedResult */
- script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion)
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
+ // Turn off geo detection and verify the latest suggestion is cleared.
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true)
+ .verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Assert internal service state.
- assertEquals(uncertainGeolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
/**
@@ -937,88 +805,48 @@
"Europe/Paris");
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Add suggestions. Nothing should happen as time zone detection is disabled.
script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
.verifyTimeZoneNotChanged();
+
+ // Geolocation suggestions are only stored when geolocation detection is enabled.
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
.verifyTimeZoneNotChanged();
- // Assert internal service state.
- assertEquals(geolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ // Telephony suggestions are always stored.
assertEquals(telephonySuggestion,
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion);
// Toggling the time zone detection enabled setting on should cause the device setting to be
// set from the telephony signal, as we've started with geolocation time zone detection
// disabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
- // Changing the detection to enable geo detection should cause the device tz setting to
- // change to the geo suggestion.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ // Changing the detection to enable geo detection won't cause the device tz setting to
+ // change because the geo suggestion is empty.
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged()
+ .simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
.verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
// Changing the detection to disable geo detection should cause the device tz setting to
// change to the telephony suggestion.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
- }
- /**
- * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time
- * zone is actually necessary. This test proves that the strategy doesn't assume it knows the
- * current setting.
- */
- @Test
- public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() {
- GeolocationTimeZoneSuggestion losAngelesSuggestion =
- createGeoLocationSuggestion(list("America/Los_Angeles"));
- GeolocationTimeZoneSuggestion newYorkSuggestion =
- createGeoLocationSuggestion(list("America/New_York"));
-
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
-
- // Initialization.
- script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
- .verifyTimeZoneChangedAndReset("America/Los_Angeles");
- // Suggest it again - it should not be set because it is already set.
- script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
- .verifyTimeZoneNotChanged();
-
- // Toggling time zone detection should set the device time zone only if the current setting
- // value is different from the most recent telephony suggestion.
- /* expectedResult */
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
-
- // Simulate a user turning auto detection off, a new suggestion being made while auto
- // detection is off, and the user turning it on again.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion)
- .verifyTimeZoneNotChanged();
- // Latest suggestion should be used.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset("America/New_York");
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
@Test
public void testAddDumpable() {
new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
AtomicBoolean dumpCalled = new AtomicBoolean(false);
@@ -1069,25 +897,26 @@
return suggestion;
}
+ private static TimeZoneConfiguration createConfig(
+ @Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
+ TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID);
+ if (autoDetection != null) {
+ builder.setAutoDetectionEnabled(autoDetection);
+ }
+ if (geoDetection != null) {
+ builder.setGeoDetectionEnabled(geoDetection);
+ }
+ return builder.build();
+ }
+
static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback {
- private TimeZoneCapabilities mCapabilities;
- private final TestState<UserConfiguration> mConfiguration = new TestState<>();
+ private final TestState<ConfigurationInternal> mConfigurationInternal = new TestState<>();
private final TestState<String> mTimeZoneId = new TestState<>();
- private TimeZoneDetectorStrategyImpl mStrategy;
+ private ConfigurationChangeListener mConfigChangeListener;
- void setStrategyForSettingsCallbacks(TimeZoneDetectorStrategyImpl strategy) {
- assertNotNull(strategy);
- mStrategy = strategy;
- }
-
- void initializeUser(@UserIdInt int userId, TimeZoneCapabilities capabilities,
- TimeZoneConfiguration configuration) {
- assertEquals(userId, capabilities.getUserId());
- mCapabilities = capabilities;
- assertTrue("Configuration must be complete when initializing, config=" + configuration,
- configuration.isComplete());
- mConfiguration.init(new UserConfiguration(userId, configuration));
+ void initializeConfig(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal.init(configurationInternal);
}
void initializeTimeZoneSetting(String zoneId) {
@@ -1095,43 +924,22 @@
}
@Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- assertEquals(userId, mCapabilities.getUserId());
- return mCapabilities;
+ public void setConfigChangeListener(ConfigurationChangeListener listener) {
+ mConfigChangeListener = listener;
}
@Override
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- UserConfiguration latest = mConfiguration.getLatest();
- assertEquals(userId, latest.userId);
- return latest.configuration;
- }
-
- @Override
- public void setConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfig) {
- assertNotNull(newConfig);
- assertTrue(newConfig.isComplete());
-
- UserConfiguration latestUserConfig = mConfiguration.getLatest();
- assertEquals(userId, latestUserConfig.userId);
- TimeZoneConfiguration oldConfig = latestUserConfig.configuration;
-
- mConfiguration.set(new UserConfiguration(userId, newConfig));
-
- if (!newConfig.equals(oldConfig)) {
- // Simulate what happens when the auto detection configuration is changed.
- mStrategy.handleAutoTimeZoneConfigChanged();
+ public ConfigurationInternal getConfigurationInternal(int userId) {
+ ConfigurationInternal configuration = mConfigurationInternal.getLatest();
+ if (userId != configuration.getUserId()) {
+ fail("FakeCallback does not support multiple users.");
}
+ return configuration;
}
@Override
- public boolean isAutoDetectionEnabled() {
- return mConfiguration.getLatest().configuration.isAutoDetectionEnabled();
- }
-
- @Override
- public boolean isGeoDetectionEnabled() {
- return mConfiguration.getLatest().configuration.isGeoDetectionEnabled();
+ public int getCurrentUserId() {
+ return mConfigurationInternal.getLatest().getUserId();
}
@Override
@@ -1149,9 +957,25 @@
mTimeZoneId.set(zoneId);
}
+ @Override
+ public void storeConfiguration(TimeZoneConfiguration newConfiguration) {
+ ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
+ if (newConfiguration.getUserId() != oldConfiguration.getUserId()) {
+ fail("FakeCallback does not support multiple users");
+ }
+
+ ConfigurationInternal mergedConfiguration = oldConfiguration.merge(newConfiguration);
+ if (!mergedConfiguration.equals(oldConfiguration)) {
+ mConfigurationInternal.set(mergedConfiguration);
+
+ // Note: Unlike the real callback impl, the listener is invoked synchronously.
+ mConfigChangeListener.onChange();
+ }
+ }
+
void assertKnownUser(int userId) {
- assertEquals(userId, mCapabilities.getUserId());
- assertEquals(userId, mConfiguration.getLatest().userId);
+ assertEquals("FakeCallback does not support multiple users",
+ mConfigurationInternal.getLatest().getUserId(), userId);
}
void assertTimeZoneNotChanged() {
@@ -1166,43 +990,7 @@
void commitAllChanges() {
mTimeZoneId.commitLatest();
- mConfiguration.commitLatest();
- }
- }
-
- private static final class UserConfiguration {
- public final @UserIdInt int userId;
- public final TimeZoneConfiguration configuration;
-
- UserConfiguration(int userId, TimeZoneConfiguration configuration) {
- this.userId = userId;
- this.configuration = configuration;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UserConfiguration that = (UserConfiguration) o;
- return userId == that.userId
- && Objects.equals(configuration, that.configuration);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(userId, configuration);
- }
-
- @Override
- public String toString() {
- return "UserConfiguration{"
- + "userId=" + userId
- + ", configuration=" + configuration
- + '}';
+ mConfigurationInternal.commitLatest();
}
}
@@ -1255,64 +1043,14 @@
}
}
- /** Simulated user test cases. */
- enum UserCase {
- /** A catch-all for users that can set auto time zone config. */
- UNRESTRICTED,
- /** A catch-all for users that can't set auto time zone config. */
- RESTRICTED,
- /**
- * Like {@link #UNRESTRICTED}, but auto tz detection is not
- * supported on the device.
- */
- AUTO_DETECT_NOT_SUPPORTED,
- }
-
- /**
- * Creates a {@link TimeZoneCapabilities} object for a user in the specific role with the
- * supplied configuration.
- */
- private static TimeZoneCapabilities createCapabilities(
- int userId, UserCase userCase, TimeZoneConfiguration configuration) {
- switch (userCase) {
- case UNRESTRICTED: {
- int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled()
- ? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED;
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(suggestManualTimeZoneCapability)
- .build();
- }
- case RESTRICTED: {
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
- .build();
- }
- case AUTO_DETECT_NOT_SUPPORTED: {
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
- .build();
- }
- default:
- throw new AssertionError(userCase + " not recognized");
- }
- }
-
/**
* A "fluent" class allows reuse of code in tests: initialization, simulation and verification
* logic.
*/
private class Script {
- Script initializeUser(
- @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) {
- TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration);
- mFakeCallback.initializeUser(userId, capabilities, configuration);
+ Script initializeConfig(ConfigurationInternal configuration) {
+ mFakeCallback.initializeConfig(configuration);
return this;
}
@@ -1326,10 +1064,9 @@
* the return value.
*/
Script simulateUpdateConfiguration(
- @UserIdInt int userId, TimeZoneConfiguration configuration,
- boolean expectedResult) {
+ TimeZoneConfiguration configuration, boolean expectedResult) {
assertEquals(expectedResult,
- mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
+ mTimeZoneDetectorStrategy.updateConfiguration(configuration));
return this;
}
@@ -1392,16 +1129,14 @@
/**
* Verifies that the configuration has been changed to the expected value.
*/
- Script verifyConfigurationChangedAndReset(
- @UserIdInt int userId, TimeZoneConfiguration expected) {
- mFakeCallback.mConfiguration.assertHasBeenSet();
- UserConfiguration expectedUserConfig = new UserConfiguration(userId, expected);
- assertEquals(expectedUserConfig, mFakeCallback.mConfiguration.getLatest());
+ Script verifyConfigurationChangedAndReset(ConfigurationInternal expected) {
+ mFakeCallback.mConfigurationInternal.assertHasBeenSet();
+ assertEquals(expected, mFakeCallback.mConfigurationInternal.getLatest());
mFakeCallback.commitAllChanges();
// Also confirm the listener triggered.
- mMockStrategyListener.verifyOnConfigurationChangedCalled();
- mMockStrategyListener.reset();
+ mMockConfigChangeListener.verifyOnChangeCalled();
+ mMockConfigChangeListener.reset();
return this;
}
@@ -1410,10 +1145,10 @@
* {@link TimeZoneConfiguration} have been changed.
*/
Script verifyConfigurationNotChanged() {
- mFakeCallback.mConfiguration.assertHasNotBeenSet();
+ mFakeCallback.mConfigurationInternal.assertHasNotBeenSet();
// Also confirm the listener did not trigger.
- mMockStrategyListener.verifyOnConfigurationChangedNotCalled();
+ mMockConfigChangeListener.verifyOnChangeNotCalled();
return this;
}
@@ -1448,24 +1183,24 @@
return new TelephonyTestCase(matchType, quality, expectedScore);
}
- private static class MockStrategyListener implements TimeZoneDetectorStrategy.StrategyListener {
- private boolean mOnConfigurationChangedCalled;
+ private static class MockConfigChangeListener implements ConfigurationChangeListener {
+ private boolean mOnChangeCalled;
@Override
- public void onConfigurationChanged() {
- mOnConfigurationChangedCalled = true;
+ public void onChange() {
+ mOnChangeCalled = true;
}
- void verifyOnConfigurationChangedCalled() {
- assertTrue(mOnConfigurationChangedCalled);
+ void verifyOnChangeCalled() {
+ assertTrue(mOnChangeCalled);
}
- void verifyOnConfigurationChangedNotCalled() {
- assertFalse(mOnConfigurationChangedCalled);
+ void verifyOnChangeNotCalled() {
+ assertFalse(mOnChangeCalled);
}
void reset() {
- mOnConfigurationChangedCalled = false;
+ mOnChangeCalled = false;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index bce1142..ca3f815 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -53,7 +53,6 @@
import androidx.test.filters.MediumTest;
import com.android.compatibility.common.util.SystemUtil;
-import com.android.internal.annotations.GuardedBy;
import org.junit.After;
import org.junit.Before;
@@ -76,14 +75,10 @@
private static final int WAIT_TIMEOUT_MS = 5000;
private static final Object sLock = new Object();
- @GuardedBy("sLock")
- private static boolean sTaskStackChangedCalled;
- private static boolean sActivityBResumed;
@Before
public void setUp() throws Exception {
mService = ActivityManager.getService();
- sTaskStackChangedCalled = false;
}
@After
@@ -94,47 +89,33 @@
@Test
@Presubmit
- @FlakyTest(bugId = 130388819)
public void testTaskStackChanged_afterFinish() throws Exception {
+ final TestActivity activity = startTestActivity(ActivityA.class);
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- Context context = getInstrumentation().getContext();
- context.startActivity(
- new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
- assertTrue(sActivityBResumed);
+ activity.finish();
+ waitForCallback(latch);
}
@Test
@Presubmit
public void testTaskStackChanged_resumeWhilePausing() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- final Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, ResumeWhilePausingActivity.class).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
-
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
+ startTestActivity(ResumeWhilePausingActivity.class);
+ waitForCallback(latch);
}
@Test
@@ -512,7 +493,7 @@
try {
final boolean result = latch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (!result) {
- throw new RuntimeException("Timed out waiting for task stack change notification");
+ throw new AssertionError("Timed out waiting for task stack change notification");
}
} catch (InterruptedException e) {
}
@@ -569,19 +550,6 @@
}
public static class ActivityA extends TestActivity {
-
- private boolean mActivityBLaunched = false;
-
- @Override
- protected void onPostResume() {
- super.onPostResume();
- if (mActivityBLaunched) {
- return;
- }
- mActivityBLaunched = true;
- finish();
- startActivity(new Intent(this, ActivityB.class));
- }
}
public static class ActivityB extends TestActivity {
@@ -589,10 +557,6 @@
@Override
protected void onPostResume() {
super.onPostResume();
- synchronized (sLock) {
- sTaskStackChangedCalled = false;
- }
- sActivityBResumed = true;
finish();
}
}