Merge "Removed old data stack"
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 40d1b4c..bd475e9 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -37,6 +37,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -993,69 +994,69 @@
"pre_idle_factor_short";
private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms";
- private static final long DEFAULT_FLEX_TIME_SHORT =
+ private long mDefaultFlexTimeShort =
!COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
- private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
+ private long mDefaultLightIdleAfterInactiveTimeout =
!COMPRESS_TIME ? 4 * 60 * 1000L : 30 * 1000L;
- private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
+ private long mDefaultLightIdleTimeout =
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
- private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
- private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
+ private float mDefaultLightIdleFactor = 2f;
+ private long mDefaultLightMaxIdleTimeout =
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
- private static final long DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
+ private long mDefaultLightIdleMaintenanceMinBudget =
!COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L;
- private static final long DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET =
+ private long mDefaultLightIdleMaintenanceMaxBudget =
!COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L;
- private static final long DEFAULT_MIN_LIGHT_MAINTENANCE_TIME =
+ private long mDefaultMinLightMaintenanceTime =
!COMPRESS_TIME ? 5 * 1000L : 1 * 1000L;
- private static final long DEFAULT_MIN_DEEP_MAINTENANCE_TIME =
+ private long mDefaultMinDeepMaintenanceTime =
!COMPRESS_TIME ? 30 * 1000L : 5 * 1000L;
- private static final long DEFAULT_INACTIVE_TIMEOUT =
+ private long mDefaultInactiveTimeout =
(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
private static final long DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY =
(15 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
- private static final long DEFAULT_SENSING_TIMEOUT =
+ private long mDefaultSensingTimeout =
!COMPRESS_TIME ? 4 * 60 * 1000L : 60 * 1000L;
- private static final long DEFAULT_LOCATING_TIMEOUT =
+ private long mDefaultLocatingTimeout =
!COMPRESS_TIME ? 30 * 1000L : 15 * 1000L;
- private static final float DEFAULT_LOCATION_ACCURACY = 20f;
- private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT =
+ private float mDefaultLocationAccuracy = 20f;
+ private long mDefaultMotionInactiveTimeout =
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
- private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX =
+ private long mDefaultMotionInactiveTimeoutFlex =
!COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
- private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT =
+ private long mDefaultIdleAfterInactiveTimeout =
(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY =
(15 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
- private static final long DEFAULT_IDLE_PENDING_TIMEOUT =
+ private long mDefaultIdlePendingTimeout =
!COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L;
- private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT =
+ private long mDefaultMaxIdlePendingTimeout =
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
- private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
- private static final long DEFAULT_QUICK_DOZE_DELAY_TIMEOUT =
+ private float mDefaultIdlePendingFactor = 2f;
+ private long mDefaultQuickDozeDelayTimeout =
!COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
- private static final long DEFAULT_IDLE_TIMEOUT =
+ private long mDefaultIdleTimeout =
!COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L;
- private static final long DEFAULT_MAX_IDLE_TIMEOUT =
+ private long mDefaultMaxIdleTimeout =
!COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L;
- private static final float DEFAULT_IDLE_FACTOR = 2f;
- private static final long DEFAULT_MIN_TIME_TO_ALARM =
+ private float mDefaultIdleFactor = 2f;
+ private long mDefaultMinTimeToAlarm =
!COMPRESS_TIME ? 30 * 60 * 1000L : 6 * 60 * 1000L;
- private static final long DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS = 5 * 60 * 1000L;
- private static final long DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS = 60 * 1000L;
- private static final long DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS = 20 * 1000L;
- private static final long DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS = 30 * 1000L;
- private static final boolean DEFAULT_WAIT_FOR_UNLOCK = true;
- private static final float DEFAULT_PRE_IDLE_FACTOR_LONG = 1.67f;
- private static final float DEFAULT_PRE_IDLE_FACTOR_SHORT = .33f;
- private static final boolean DEFAULT_USE_WINDOW_ALARMS = true;
+ private long mDefaultMaxTempAppAllowlistDurationMs = 5 * 60 * 1000L;
+ private long mDefaultMmsTempAppAllowlistDurationMs = 60 * 1000L;
+ private long mDefaultSmsTempAppAllowlistDurationMs = 20 * 1000L;
+ private long mDefaultNotificationAllowlistDurationMs = 30 * 1000L;
+ private boolean mDefaultWaitForUnlock = true;
+ private float mDefaultPreIdleFactorLong = 1.67f;
+ private float mDefaultPreIdleFactorShort = .33f;
+ private boolean mDefaultUseWindowAlarms = true;
/**
* A somewhat short alarm window size that we will tolerate for various alarm timings.
*
* @see #KEY_FLEX_TIME_SHORT
*/
- public long FLEX_TIME_SHORT = DEFAULT_FLEX_TIME_SHORT;
+ public long FLEX_TIME_SHORT = mDefaultFlexTimeShort;
/**
* This is the time, after becoming inactive, that we go in to the first
@@ -1063,28 +1064,28 @@
*
* @see #KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
*/
- public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+ public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
/**
* This is the initial time that we will run in light idle maintenance mode.
*
* @see #KEY_LIGHT_IDLE_TIMEOUT
*/
- public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
+ public long LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
/**
* Scaling factor to apply to the light idle mode time each time we complete a cycle.
*
* @see #KEY_LIGHT_IDLE_FACTOR
*/
- public float LIGHT_IDLE_FACTOR = DEFAULT_LIGHT_IDLE_FACTOR;
+ public float LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
/**
* This is the maximum time we will stay in light idle mode.
*
* @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
*/
- public long LIGHT_MAX_IDLE_TIMEOUT = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT;
+ public long LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
/**
* This is the minimum amount of time we want to make available for maintenance mode
@@ -1093,7 +1094,7 @@
*
* @see #KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
*/
- public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
/**
* This is the maximum amount of time we want to make available for maintenance mode
@@ -1104,7 +1105,7 @@
*
* @see #KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
*/
- public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
+ public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
/**
* This is the minimum amount of time that we will stay in maintenance mode after
@@ -1115,7 +1116,7 @@
*
* @see #KEY_MIN_LIGHT_MAINTENANCE_TIME
*/
- public long MIN_LIGHT_MAINTENANCE_TIME = DEFAULT_MIN_LIGHT_MAINTENANCE_TIME;
+ public long MIN_LIGHT_MAINTENANCE_TIME = mDefaultMinLightMaintenanceTime;
/**
* This is the minimum amount of time that we will stay in maintenance mode after
@@ -1125,7 +1126,7 @@
* mode immediately.
* @see #KEY_MIN_DEEP_MAINTENANCE_TIME
*/
- public long MIN_DEEP_MAINTENANCE_TIME = DEFAULT_MIN_DEEP_MAINTENANCE_TIME;
+ public long MIN_DEEP_MAINTENANCE_TIME = mDefaultMinDeepMaintenanceTime;
/**
* This is the time, after becoming inactive, at which we start looking at the
@@ -1134,7 +1135,7 @@
* the motion sensor whenever the screen is off.
* @see #KEY_INACTIVE_TIMEOUT
*/
- public long INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT;
+ public long INACTIVE_TIMEOUT = mDefaultInactiveTimeout;
/**
* If we don't receive a callback from AnyMotion in this amount of time +
@@ -1143,14 +1144,14 @@
* will be ignored.
* @see #KEY_SENSING_TIMEOUT
*/
- public long SENSING_TIMEOUT = DEFAULT_SENSING_TIMEOUT;
+ public long SENSING_TIMEOUT = mDefaultSensingTimeout;
/**
* This is how long we will wait to try to get a good location fix before going in to
* idle mode.
* @see #KEY_LOCATING_TIMEOUT
*/
- public long LOCATING_TIMEOUT = DEFAULT_LOCATING_TIMEOUT;
+ public long LOCATING_TIMEOUT = mDefaultLocatingTimeout;
/**
* The desired maximum accuracy (in meters) we consider the location to be good enough to go
@@ -1158,7 +1159,7 @@
* {@link #LOCATING_TIMEOUT} expires.
* @see #KEY_LOCATION_ACCURACY
*/
- public float LOCATION_ACCURACY = DEFAULT_LOCATION_ACCURACY;
+ public float LOCATION_ACCURACY = mDefaultLocationAccuracy;
/**
* This is the time, after seeing motion, that we wait after becoming inactive from
@@ -1166,14 +1167,14 @@
*
* @see #KEY_MOTION_INACTIVE_TIMEOUT
*/
- public long MOTION_INACTIVE_TIMEOUT = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+ public long MOTION_INACTIVE_TIMEOUT = mDefaultMotionInactiveTimeout;
/**
* This is the alarm window size we will tolerate for motion detection timings.
*
* @see #KEY_MOTION_INACTIVE_TIMEOUT_FLEX
*/
- public long MOTION_INACTIVE_TIMEOUT_FLEX = DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX;
+ public long MOTION_INACTIVE_TIMEOUT_FLEX = mDefaultMotionInactiveTimeoutFlex;
/**
* This is the time, after the inactive timeout elapses, that we will wait looking
@@ -1181,7 +1182,7 @@
*
* @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
*/
- public long IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
+ public long IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultIdleAfterInactiveTimeout;
/**
* This is the initial time, after being idle, that we will allow ourself to be back
@@ -1189,20 +1190,20 @@
* idle.
* @see #KEY_IDLE_PENDING_TIMEOUT
*/
- public long IDLE_PENDING_TIMEOUT = DEFAULT_IDLE_PENDING_TIMEOUT;
+ public long IDLE_PENDING_TIMEOUT = mDefaultIdlePendingTimeout;
/**
* Maximum pending idle timeout (time spent running) we will be allowed to use.
* @see #KEY_MAX_IDLE_PENDING_TIMEOUT
*/
- public long MAX_IDLE_PENDING_TIMEOUT = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
+ public long MAX_IDLE_PENDING_TIMEOUT = mDefaultMaxIdlePendingTimeout;
/**
* Scaling factor to apply to current pending idle timeout each time we cycle through
* that state.
* @see #KEY_IDLE_PENDING_FACTOR
*/
- public float IDLE_PENDING_FACTOR = DEFAULT_IDLE_PENDING_FACTOR;
+ public float IDLE_PENDING_FACTOR = mDefaultIdlePendingFactor;
/**
* This is amount of time we will wait from the point where we go into
@@ -1210,33 +1211,33 @@
* and other current activity to finish.
* @see #KEY_QUICK_DOZE_DELAY_TIMEOUT
*/
- public long QUICK_DOZE_DELAY_TIMEOUT = DEFAULT_QUICK_DOZE_DELAY_TIMEOUT;
+ public long QUICK_DOZE_DELAY_TIMEOUT = mDefaultQuickDozeDelayTimeout;
/**
* This is the initial time that we want to sit in the idle state before waking up
* again to return to pending idle and allowing normal work to run.
* @see #KEY_IDLE_TIMEOUT
*/
- public long IDLE_TIMEOUT = DEFAULT_IDLE_TIMEOUT;
+ public long IDLE_TIMEOUT = mDefaultIdleTimeout;
/**
* Maximum idle duration we will be allowed to use.
* @see #KEY_MAX_IDLE_TIMEOUT
*/
- public long MAX_IDLE_TIMEOUT = DEFAULT_MAX_IDLE_TIMEOUT;
+ public long MAX_IDLE_TIMEOUT = mDefaultMaxIdleTimeout;
/**
* Scaling factor to apply to current idle timeout each time we cycle through that state.
* @see #KEY_IDLE_FACTOR
*/
- public float IDLE_FACTOR = DEFAULT_IDLE_FACTOR;
+ public float IDLE_FACTOR = mDefaultIdleFactor;
/**
* This is the minimum time we will allow until the next upcoming alarm for us to
* actually go in to idle mode.
* @see #KEY_MIN_TIME_TO_ALARM
*/
- public long MIN_TIME_TO_ALARM = DEFAULT_MIN_TIME_TO_ALARM;
+ public long MIN_TIME_TO_ALARM = mDefaultMinTimeToAlarm;
/**
* Max amount of time to temporarily whitelist an app when it receives a high priority
@@ -1244,48 +1245,49 @@
*
* @see #KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS
*/
- public long MAX_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS;
+ public long MAX_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMaxTempAppAllowlistDurationMs;
/**
* Amount of time we would like to whitelist an app that is receiving an MMS.
* @see #KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS
*/
- public long MMS_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS;
+ public long MMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMmsTempAppAllowlistDurationMs;
/**
* Amount of time we would like to whitelist an app that is receiving an SMS.
* @see #KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS
*/
- public long SMS_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS;
+ public long SMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultSmsTempAppAllowlistDurationMs;
/**
* Amount of time we would like to whitelist an app that is handling a
* {@link android.app.PendingIntent} triggered by a {@link android.app.Notification}.
* @see #KEY_NOTIFICATION_ALLOWLIST_DURATION_MS
*/
- public long NOTIFICATION_ALLOWLIST_DURATION_MS = DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS;
+ public long NOTIFICATION_ALLOWLIST_DURATION_MS = mDefaultNotificationAllowlistDurationMs;
/**
* Pre idle time factor use to make idle delay longer
*/
- public float PRE_IDLE_FACTOR_LONG = DEFAULT_PRE_IDLE_FACTOR_LONG;
+ public float PRE_IDLE_FACTOR_LONG = mDefaultPreIdleFactorLong;
/**
* Pre idle time factor use to make idle delay shorter
*/
- public float PRE_IDLE_FACTOR_SHORT = DEFAULT_PRE_IDLE_FACTOR_SHORT;
+ public float PRE_IDLE_FACTOR_SHORT = mDefaultPreIdleFactorShort;
- public boolean WAIT_FOR_UNLOCK = DEFAULT_WAIT_FOR_UNLOCK;
+ public boolean WAIT_FOR_UNLOCK = mDefaultWaitForUnlock;
/**
* Whether to use window alarms. True to use window alarms (call AlarmManager.setWindow()).
* False to use the legacy inexact alarms (call AlarmManager.set()).
*/
- public boolean USE_WINDOW_ALARMS = DEFAULT_USE_WINDOW_ALARMS;
+ public boolean USE_WINDOW_ALARMS = mDefaultUseWindowAlarms;
private final boolean mSmallBatteryDevice;
public Constants() {
+ initDefault();
mSmallBatteryDevice = ActivityManager.isSmallBatteryDevice();
if (mSmallBatteryDevice) {
INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY;
@@ -1297,6 +1299,132 @@
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_DEVICE_IDLE));
}
+ private void initDefault() {
+ final Resources res = getContext().getResources();
+
+ mDefaultFlexTimeShort = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_flex_time_short_ms),
+ mDefaultFlexTimeShort);
+ mDefaultLightIdleAfterInactiveTimeout = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_light_after_inactive_to_ms),
+ mDefaultLightIdleAfterInactiveTimeout);
+ mDefaultLightIdleTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_light_idle_to_ms),
+ mDefaultLightIdleTimeout);
+ mDefaultLightIdleFactor = res.getFloat(
+ com.android.internal.R.integer.device_idle_light_idle_factor);
+ mDefaultLightMaxIdleTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_light_max_idle_to_ms),
+ mDefaultLightMaxIdleTimeout);
+ mDefaultLightIdleMaintenanceMinBudget = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_light_idle_maintenance_min_budget_ms
+ ), mDefaultLightIdleMaintenanceMinBudget);
+ mDefaultLightIdleMaintenanceMaxBudget = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_light_idle_maintenance_max_budget_ms
+ ), mDefaultLightIdleMaintenanceMaxBudget);
+ mDefaultMinLightMaintenanceTime = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_min_light_maintenance_time_ms),
+ mDefaultMinLightMaintenanceTime);
+ mDefaultMinDeepMaintenanceTime = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_min_deep_maintenance_time_ms),
+ mDefaultMinDeepMaintenanceTime);
+ mDefaultInactiveTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_inactive_to_ms),
+ mDefaultInactiveTimeout);
+ mDefaultSensingTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_sensing_to_ms),
+ mDefaultSensingTimeout);
+ mDefaultLocatingTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_locating_to_ms),
+ mDefaultLocatingTimeout);
+ mDefaultLocationAccuracy = res.getFloat(
+ com.android.internal.R.integer.device_idle_location_accuracy);
+ mDefaultMotionInactiveTimeout = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_motion_inactive_to_ms),
+ mDefaultMotionInactiveTimeout);
+ mDefaultMotionInactiveTimeoutFlex = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_motion_inactive_to_flex_ms),
+ mDefaultMotionInactiveTimeoutFlex);
+ mDefaultIdleAfterInactiveTimeout = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_idle_after_inactive_to_ms),
+ mDefaultIdleAfterInactiveTimeout);
+ mDefaultIdlePendingTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_idle_pending_to_ms),
+ mDefaultIdlePendingTimeout);
+ mDefaultMaxIdlePendingTimeout = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_max_idle_pending_to_ms),
+ mDefaultMaxIdlePendingTimeout);
+ mDefaultIdlePendingFactor = res.getFloat(
+ com.android.internal.R.integer.device_idle_idle_pending_factor);
+ mDefaultQuickDozeDelayTimeout = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_quick_doze_delay_to_ms),
+ mDefaultQuickDozeDelayTimeout);
+ mDefaultIdleTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_idle_to_ms),
+ mDefaultIdleTimeout);
+ mDefaultMaxIdleTimeout = getTimeout(
+ res.getInteger(com.android.internal.R.integer.device_idle_max_idle_to_ms),
+ mDefaultMaxIdleTimeout);
+ mDefaultIdleFactor = res.getFloat(
+ com.android.internal.R.integer.device_idle_idle_factor);
+ mDefaultMinTimeToAlarm = getTimeout(res.getInteger(
+ com.android.internal.R.integer.device_idle_min_time_to_alarm_ms),
+ mDefaultMinTimeToAlarm);
+ mDefaultMaxTempAppAllowlistDurationMs = res.getInteger(
+ com.android.internal.R.integer.device_idle_max_temp_app_allowlist_duration_ms);
+ mDefaultMmsTempAppAllowlistDurationMs = res.getInteger(
+ com.android.internal.R.integer.device_idle_mms_temp_app_allowlist_duration_ms);
+ mDefaultSmsTempAppAllowlistDurationMs = res.getInteger(
+ com.android.internal.R.integer.device_idle_sms_temp_app_allowlist_duration_ms);
+ mDefaultNotificationAllowlistDurationMs = res.getInteger(
+ com.android.internal.R.integer.device_idle_notification_allowlist_duration_ms);
+ mDefaultWaitForUnlock = res.getBoolean(
+ com.android.internal.R.bool.device_idle_wait_for_unlock);
+ mDefaultPreIdleFactorLong = res.getFloat(
+ com.android.internal.R.integer.device_idle_pre_idle_factor_long);
+ mDefaultPreIdleFactorShort = res.getFloat(
+ com.android.internal.R.integer.device_idle_pre_idle_factor_short);
+ mDefaultUseWindowAlarms = res.getBoolean(
+ com.android.internal.R.bool.device_idle_use_window_alarms);
+
+ FLEX_TIME_SHORT = mDefaultFlexTimeShort;
+ LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
+ LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
+ LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
+ LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
+ LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
+ LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
+ MIN_LIGHT_MAINTENANCE_TIME = mDefaultMinLightMaintenanceTime;
+ MIN_DEEP_MAINTENANCE_TIME = mDefaultMinDeepMaintenanceTime;
+ INACTIVE_TIMEOUT = mDefaultInactiveTimeout;
+ SENSING_TIMEOUT = mDefaultSensingTimeout;
+ LOCATING_TIMEOUT = mDefaultLocatingTimeout;
+ LOCATION_ACCURACY = mDefaultLocationAccuracy;
+ MOTION_INACTIVE_TIMEOUT = mDefaultMotionInactiveTimeout;
+ MOTION_INACTIVE_TIMEOUT_FLEX = mDefaultMotionInactiveTimeoutFlex;
+ IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultIdleAfterInactiveTimeout;
+ IDLE_PENDING_TIMEOUT = mDefaultIdlePendingTimeout;
+ MAX_IDLE_PENDING_TIMEOUT = mDefaultMaxIdlePendingTimeout;
+ IDLE_PENDING_FACTOR = mDefaultIdlePendingFactor;
+ QUICK_DOZE_DELAY_TIMEOUT = mDefaultQuickDozeDelayTimeout;
+ IDLE_TIMEOUT = mDefaultIdleTimeout;
+ MAX_IDLE_TIMEOUT = mDefaultMaxIdleTimeout;
+ IDLE_FACTOR = mDefaultIdleFactor;
+ MIN_TIME_TO_ALARM = mDefaultMinTimeToAlarm;
+ MAX_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMaxTempAppAllowlistDurationMs;
+ MMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMmsTempAppAllowlistDurationMs;
+ SMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultSmsTempAppAllowlistDurationMs;
+ NOTIFICATION_ALLOWLIST_DURATION_MS = mDefaultNotificationAllowlistDurationMs;
+ WAIT_FOR_UNLOCK = mDefaultWaitForUnlock;
+ PRE_IDLE_FACTOR_LONG = mDefaultPreIdleFactorLong;
+ PRE_IDLE_FACTOR_SHORT = mDefaultPreIdleFactorShort;
+ USE_WINDOW_ALARMS = mDefaultUseWindowAlarms;
+ }
+
+ private long getTimeout(long defTimeout, long compTimeout) {
+ return (!COMPRESS_TIME || defTimeout < compTimeout) ? defTimeout : compTimeout;
+ }
+
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
@@ -1308,147 +1436,147 @@
switch (name) {
case KEY_FLEX_TIME_SHORT:
FLEX_TIME_SHORT = properties.getLong(
- KEY_FLEX_TIME_SHORT, DEFAULT_FLEX_TIME_SHORT);
+ KEY_FLEX_TIME_SHORT, mDefaultFlexTimeShort);
break;
case KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT:
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
- DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+ mDefaultLightIdleAfterInactiveTimeout);
break;
case KEY_LIGHT_IDLE_TIMEOUT:
LIGHT_IDLE_TIMEOUT = properties.getLong(
- KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
+ KEY_LIGHT_IDLE_TIMEOUT, mDefaultLightIdleTimeout);
break;
case KEY_LIGHT_IDLE_FACTOR:
LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
- KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
+ KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));
break;
case KEY_LIGHT_MAX_IDLE_TIMEOUT:
LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
- KEY_LIGHT_MAX_IDLE_TIMEOUT, DEFAULT_LIGHT_MAX_IDLE_TIMEOUT);
+ KEY_LIGHT_MAX_IDLE_TIMEOUT, mDefaultLightMaxIdleTimeout);
break;
case KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET:
LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = properties.getLong(
KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
- DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+ mDefaultLightIdleMaintenanceMinBudget);
break;
case KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET:
LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = properties.getLong(
KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,
- DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET);
+ mDefaultLightIdleMaintenanceMaxBudget);
break;
case KEY_MIN_LIGHT_MAINTENANCE_TIME:
MIN_LIGHT_MAINTENANCE_TIME = properties.getLong(
KEY_MIN_LIGHT_MAINTENANCE_TIME,
- DEFAULT_MIN_LIGHT_MAINTENANCE_TIME);
+ mDefaultMinLightMaintenanceTime);
break;
case KEY_MIN_DEEP_MAINTENANCE_TIME:
MIN_DEEP_MAINTENANCE_TIME = properties.getLong(
KEY_MIN_DEEP_MAINTENANCE_TIME,
- DEFAULT_MIN_DEEP_MAINTENANCE_TIME);
+ mDefaultMinDeepMaintenanceTime);
break;
case KEY_INACTIVE_TIMEOUT:
final long defaultInactiveTimeout = mSmallBatteryDevice
? DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY
- : DEFAULT_INACTIVE_TIMEOUT;
+ : mDefaultInactiveTimeout;
INACTIVE_TIMEOUT = properties.getLong(
KEY_INACTIVE_TIMEOUT, defaultInactiveTimeout);
break;
case KEY_SENSING_TIMEOUT:
SENSING_TIMEOUT = properties.getLong(
- KEY_SENSING_TIMEOUT, DEFAULT_SENSING_TIMEOUT);
+ KEY_SENSING_TIMEOUT, mDefaultSensingTimeout);
break;
case KEY_LOCATING_TIMEOUT:
LOCATING_TIMEOUT = properties.getLong(
- KEY_LOCATING_TIMEOUT, DEFAULT_LOCATING_TIMEOUT);
+ KEY_LOCATING_TIMEOUT, mDefaultLocatingTimeout);
break;
case KEY_LOCATION_ACCURACY:
LOCATION_ACCURACY = properties.getFloat(
- KEY_LOCATION_ACCURACY, DEFAULT_LOCATION_ACCURACY);
+ KEY_LOCATION_ACCURACY, mDefaultLocationAccuracy);
break;
case KEY_MOTION_INACTIVE_TIMEOUT:
MOTION_INACTIVE_TIMEOUT = properties.getLong(
- KEY_MOTION_INACTIVE_TIMEOUT, DEFAULT_MOTION_INACTIVE_TIMEOUT);
+ KEY_MOTION_INACTIVE_TIMEOUT, mDefaultMotionInactiveTimeout);
break;
case KEY_MOTION_INACTIVE_TIMEOUT_FLEX:
MOTION_INACTIVE_TIMEOUT_FLEX = properties.getLong(
KEY_MOTION_INACTIVE_TIMEOUT_FLEX,
- DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX);
+ mDefaultMotionInactiveTimeoutFlex);
break;
case KEY_IDLE_AFTER_INACTIVE_TIMEOUT:
final long defaultIdleAfterInactiveTimeout = mSmallBatteryDevice
? DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY
- : DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
+ : mDefaultIdleAfterInactiveTimeout;
IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
defaultIdleAfterInactiveTimeout);
break;
case KEY_IDLE_PENDING_TIMEOUT:
IDLE_PENDING_TIMEOUT = properties.getLong(
- KEY_IDLE_PENDING_TIMEOUT, DEFAULT_IDLE_PENDING_TIMEOUT);
+ KEY_IDLE_PENDING_TIMEOUT, mDefaultIdlePendingTimeout);
break;
case KEY_MAX_IDLE_PENDING_TIMEOUT:
MAX_IDLE_PENDING_TIMEOUT = properties.getLong(
- KEY_MAX_IDLE_PENDING_TIMEOUT, DEFAULT_MAX_IDLE_PENDING_TIMEOUT);
+ KEY_MAX_IDLE_PENDING_TIMEOUT, mDefaultMaxIdlePendingTimeout);
break;
case KEY_IDLE_PENDING_FACTOR:
IDLE_PENDING_FACTOR = properties.getFloat(
- KEY_IDLE_PENDING_FACTOR, DEFAULT_IDLE_PENDING_FACTOR);
+ KEY_IDLE_PENDING_FACTOR, mDefaultIdlePendingFactor);
break;
case KEY_QUICK_DOZE_DELAY_TIMEOUT:
QUICK_DOZE_DELAY_TIMEOUT = properties.getLong(
- KEY_QUICK_DOZE_DELAY_TIMEOUT, DEFAULT_QUICK_DOZE_DELAY_TIMEOUT);
+ KEY_QUICK_DOZE_DELAY_TIMEOUT, mDefaultQuickDozeDelayTimeout);
break;
case KEY_IDLE_TIMEOUT:
IDLE_TIMEOUT = properties.getLong(
- KEY_IDLE_TIMEOUT, DEFAULT_IDLE_TIMEOUT);
+ KEY_IDLE_TIMEOUT, mDefaultIdleTimeout);
break;
case KEY_MAX_IDLE_TIMEOUT:
MAX_IDLE_TIMEOUT = properties.getLong(
- KEY_MAX_IDLE_TIMEOUT, DEFAULT_MAX_IDLE_TIMEOUT);
+ KEY_MAX_IDLE_TIMEOUT, mDefaultMaxIdleTimeout);
break;
case KEY_IDLE_FACTOR:
- IDLE_FACTOR = properties.getFloat(KEY_IDLE_FACTOR, DEFAULT_IDLE_FACTOR);
+ IDLE_FACTOR = properties.getFloat(KEY_IDLE_FACTOR, mDefaultIdleFactor);
break;
case KEY_MIN_TIME_TO_ALARM:
MIN_TIME_TO_ALARM = properties.getLong(
- KEY_MIN_TIME_TO_ALARM, DEFAULT_MIN_TIME_TO_ALARM);
+ KEY_MIN_TIME_TO_ALARM, mDefaultMinTimeToAlarm);
break;
case KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS:
MAX_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS,
- DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS);
+ mDefaultMaxTempAppAllowlistDurationMs);
break;
case KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS:
MMS_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS,
- DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS);
+ mDefaultMmsTempAppAllowlistDurationMs);
break;
case KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS:
SMS_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS,
- DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS);
+ mDefaultSmsTempAppAllowlistDurationMs);
break;
case KEY_NOTIFICATION_ALLOWLIST_DURATION_MS:
NOTIFICATION_ALLOWLIST_DURATION_MS = properties.getLong(
KEY_NOTIFICATION_ALLOWLIST_DURATION_MS,
- DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS);
+ mDefaultNotificationAllowlistDurationMs);
break;
case KEY_WAIT_FOR_UNLOCK:
WAIT_FOR_UNLOCK = properties.getBoolean(
- KEY_WAIT_FOR_UNLOCK, DEFAULT_WAIT_FOR_UNLOCK);
+ KEY_WAIT_FOR_UNLOCK, mDefaultWaitForUnlock);
break;
case KEY_PRE_IDLE_FACTOR_LONG:
PRE_IDLE_FACTOR_LONG = properties.getFloat(
- KEY_PRE_IDLE_FACTOR_LONG, DEFAULT_PRE_IDLE_FACTOR_LONG);
+ KEY_PRE_IDLE_FACTOR_LONG, mDefaultPreIdleFactorLong);
break;
case KEY_PRE_IDLE_FACTOR_SHORT:
PRE_IDLE_FACTOR_SHORT = properties.getFloat(
- KEY_PRE_IDLE_FACTOR_SHORT, DEFAULT_PRE_IDLE_FACTOR_SHORT);
+ KEY_PRE_IDLE_FACTOR_SHORT, mDefaultPreIdleFactorShort);
break;
case KEY_USE_WINDOW_ALARMS:
USE_WINDOW_ALARMS = properties.getBoolean(
- KEY_USE_WINDOW_ALARMS, DEFAULT_USE_WINDOW_ALARMS);
+ KEY_USE_WINDOW_ALARMS, mDefaultUseWindowAlarms);
break;
default:
Slog.e(TAG, "Unknown configuration key: " + name);
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d25ad7..f554e71 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -52951,7 +52951,7 @@
package android.view.inputmethod {
public class BaseInputConnection implements android.view.inputmethod.InputConnection {
- ctor public BaseInputConnection(android.view.View, boolean);
+ ctor public BaseInputConnection(@NonNull android.view.View, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
method @CallSuper public void closeConnection();
@@ -52963,24 +52963,24 @@
method public boolean deleteSurroundingTextInCodePoints(int, int);
method public boolean endBatchEdit();
method public boolean finishComposingText();
- method public static int getComposingSpanEnd(android.text.Spannable);
- method public static int getComposingSpanStart(android.text.Spannable);
+ method public static int getComposingSpanEnd(@NonNull android.text.Spannable);
+ method public static int getComposingSpanStart(@NonNull android.text.Spannable);
method public int getCursorCapsMode(int);
- method public android.text.Editable getEditable();
- method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
- method public android.os.Handler getHandler();
- method public CharSequence getSelectedText(int);
+ method @Nullable public android.text.Editable getEditable();
+ method @Nullable public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method @Nullable public android.os.Handler getHandler();
+ method @Nullable public CharSequence getSelectedText(int);
method @Nullable public CharSequence getTextAfterCursor(@IntRange(from=0) int, int);
method @Nullable public CharSequence getTextBeforeCursor(@IntRange(from=0) int, int);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(String, android.os.Bundle);
- method public static final void removeComposingSpans(android.text.Spannable);
+ method public static final void removeComposingSpans(@NonNull android.text.Spannable);
method public boolean reportFullscreenMode(boolean);
method public boolean requestCursorUpdates(int);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
- method public static void setComposingSpans(android.text.Spannable);
+ method public static void setComposingSpans(@NonNull android.text.Spannable);
method public boolean setComposingText(CharSequence, int);
method public boolean setSelection(int, int);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f09244a..619e9fd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1318,6 +1318,7 @@
method @NonNull public java.time.Instant getStartTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR;
+ field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3
field public static final int EVENT_COUGH = 1; // 0x1
field public static final int EVENT_SNORE = 2; // 0x2
field public static final int EVENT_UNKNOWN = 0; // 0x0
@@ -10347,6 +10348,7 @@
field public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
field public static final String NAMESPACE_AUTOFILL = "autofill";
+ field public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore";
field public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
field public static final String NAMESPACE_BIOMETRICS = "biometrics";
field public static final String NAMESPACE_BLOBSTORE = "blobstore";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index deb5aca..f780e6f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2709,7 +2709,7 @@
public class SparseArrayMap<K, V> {
ctor public SparseArrayMap();
- method public void add(int, @NonNull K, @Nullable V);
+ method public V add(int, @NonNull K, @Nullable V);
method public void clear();
method public boolean contains(int, @NonNull K);
method public void delete(int);
diff --git a/core/java/android/app/AppOpInfo.java b/core/java/android/app/AppOpInfo.java
index 979c910..5268ec4 100644
--- a/core/java/android/app/AppOpInfo.java
+++ b/core/java/android/app/AppOpInfo.java
@@ -26,6 +26,7 @@
* Information about a particular app op.
*/
class AppOpInfo {
+
/**
* A unique constant identifying this app op.
*/
@@ -91,6 +92,11 @@
*/
public final boolean restrictRead;
+ /**
+ * Whether to collect noteOp instances, and send them to callbacks.
+ */
+ public final boolean forceCollectNotes;
+
AppOpInfo(int code,
int switchCode,
@NonNull String name,
@@ -100,7 +106,8 @@
AppOpsManager.RestrictionBypass allowSystemRestrictionBypass,
int defaultMode,
boolean disableReset,
- boolean restrictRead) {
+ boolean restrictRead,
+ boolean forceCollectNotes) {
if (code < OP_NONE) throw new IllegalArgumentException();
if (switchCode < OP_NONE) throw new IllegalArgumentException();
Objects.requireNonNull(name);
@@ -115,6 +122,7 @@
this.defaultMode = defaultMode;
this.disableReset = disableReset;
this.restrictRead = restrictRead;
+ this.forceCollectNotes = forceCollectNotes;
}
static class Builder {
@@ -128,6 +136,7 @@
private int mDefaultMode = AppOpsManager.MODE_DEFAULT;
private boolean mDisableReset = false;
private boolean mRestrictRead = false;
+ private boolean mForceCollectNotes = false;
Builder(int code, @NonNull String name, @NonNull String simpleName) {
if (code < OP_NONE) throw new IllegalArgumentException();
@@ -190,9 +199,15 @@
return this;
}
+ public Builder setForceCollectNotes(boolean value) {
+ this.mForceCollectNotes = value;
+ return this;
+ }
+
public AppOpInfo build() {
return new AppOpInfo(mCode, mSwitchCode, mName, mSimpleName, mPermission, mRestriction,
- mAllowSystemRestrictionBypass, mDefaultMode, mDisableReset, mRestrictRead);
+ mAllowSystemRestrictionBypass, mDefaultMode, mDisableReset, mRestrictRead,
+ mForceCollectNotes);
}
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bc59d60..2a0553e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1831,6 +1831,9 @@
})
private @interface ShouldCollectNoteOp {}
+ /** Whether noting for an appop should be collected */
+ private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
+
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
// Contacts
@@ -2281,10 +2284,19 @@
"ACCESS_RESTRICTED_SETTINGS").setDefaultMode(AppOpsManager.MODE_ALLOWED)
.setDisableReset(true).setRestrictRead(true).build(),
new AppOpInfo.Builder(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- "RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
+ "RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .setForceCollectNotes(true).build()
};
/**
+ * @hide
+ */
+ public static boolean shouldForceCollectNoteForOp(int op) {
+ Preconditions.checkArgumentInRange(op, 0, _NUM_OP - 1, "opCode");
+ return sAppOpInfos[op].forceCollectNotes;
+ }
+
+ /**
* Mapping from an app op name to the app op code.
*/
private static HashMap<String, Integer> sOpStrToOp = new HashMap<>();
@@ -2313,9 +2325,6 @@
private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
new ThreadLocal<>();
- /** Whether noting for an appop should be collected */
- private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
-
static {
if (sAppOpInfos.length != _NUM_OP) {
throw new IllegalStateException("mAppOpInfos length " + sAppOpInfos.length
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index bd999fc..9c8d010 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -522,9 +522,6 @@
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd);
- /** Enables server-side binder tracing for the calling uid. */
- void enableBinderTracing();
-
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void suppressResizeConfigChanges(boolean suppress);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java
index af48fde..865e1fb 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEvent.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java
@@ -63,8 +63,6 @@
* The integer indicating a double-tap event was detected.
* For detecting this event type, there's no specific consent activity to request access, but
* the consent is implied through the double tap toggle in the Settings app.
- *
- * @hide
*/
public static final int EVENT_BACK_DOUBLE_TAP = 3;
diff --git a/core/java/android/ddm/DdmHandleViewDebug.java b/core/java/android/ddm/DdmHandleViewDebug.java
index 6b0f78f..0f66fcb 100644
--- a/core/java/android/ddm/DdmHandleViewDebug.java
+++ b/core/java/android/ddm/DdmHandleViewDebug.java
@@ -16,12 +16,16 @@
package android.ddm;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.util.Log;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
@@ -34,6 +38,7 @@
import java.lang.reflect.Method;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
/**
* Handle various requests related to profiling / debugging of the view system.
@@ -123,14 +128,15 @@
}
if (type == CHUNK_VURT) {
- if (op == VURT_DUMP_HIERARCHY)
+ if (op == VURT_DUMP_HIERARCHY) {
return dumpHierarchy(rootView, in);
- else if (op == VURT_CAPTURE_LAYERS)
+ } else if (op == VURT_CAPTURE_LAYERS) {
return captureLayers(rootView);
- else if (op == VURT_DUMP_THEME)
+ } else if (op == VURT_DUMP_THEME) {
return dumpTheme(rootView);
- else
+ } else {
return createFailChunk(ERR_INVALID_OP, "Unknown view root operation: " + op);
+ }
}
final View targetView = getTargetView(rootView, in);
@@ -207,9 +213,9 @@
/**
* Returns the view hierarchy and/or view properties starting at the provided view.
* Based on the input options, the return data may include:
- * - just the view hierarchy
- * - view hierarchy & the properties for each of the views
- * - just the view properties for a specific view.
+ * - just the view hierarchy
+ * - view hierarchy & the properties for each of the views
+ * - just the view properties for a specific view.
* TODO: Currently this only returns views starting at the root, need to fix so that
* it can return properties of any view.
*/
@@ -220,7 +226,7 @@
long start = System.currentTimeMillis();
- ByteArrayOutputStream b = new ByteArrayOutputStream(2*1024*1024);
+ ByteArrayOutputStream b = new ByteArrayOutputStream(2 * 1024 * 1024);
try {
if (v2) {
ViewDebug.dumpv2(rootView, b);
@@ -304,17 +310,47 @@
* Invokes provided method on the view.
* The method name and its arguments are passed in as inputs via the byte buffer.
* The buffer contains:<ol>
- * <li> len(method name) </li>
- * <li> method name </li>
- * <li> # of args </li>
- * <li> arguments: Each argument comprises of a type specifier followed by the actual argument.
- * The type specifier is a single character as used in JNI:
- * (Z - boolean, B - byte, C - char, S - short, I - int, J - long,
- * F - float, D - double). <p>
- * The type specifier is followed by the actual value of argument.
- * Booleans are encoded via bytes with 0 indicating false.</li>
+ * <li> len(method name) </li>
+ * <li> method name (encoded as UTF-16 2-byte characters) </li>
+ * <li> # of args </li>
+ * <li> arguments: Each argument comprises of a type specifier followed by the actual argument.
+ * The type specifier is one character modelled after JNI signatures:
+ * <ul>
+ * <li>[ - array<br>
+ * This is followed by a second character according to this spec, indicating the
+ * array type, then the array length as an Int, followed by a repeated encoding
+ * of the actual data.
+ * WARNING: Only <b>byte[]</b> is supported currently.
+ * </li>
+ * <li>Z - boolean<br>
+ * Booleans are encoded via bytes with 0 indicating false</li>
+ * <li>B - byte</li>
+ * <li>C - char</li>
+ * <li>S - short</li>
+ * <li>I - int</li>
+ * <li>J - long</li>
+ * <li>F - float</li>
+ * <li>D - double</li>
+ * <li>V - void<br>
+ * NOT followed by a value. Only used for return types</li>
+ * <li>R - String (not a real JNI type, but added for convenience)<br>
+ * Strings are encoded as an unsigned short of the number of <b>bytes</b>,
+ * followed by the actual UTF-8 encoded bytes.
+ * WARNING: This is the same encoding as produced by
+ * ViewHierarchyEncoder#writeString. However, note that this encoding is
+ * different to what DdmHandle#getString() expects, which is used in other places
+ * in this class.
+ * WARNING: Since the length is the number of UTF-8 encoded bytes, Strings can
+ * contain up to 64k ASCII characters, yet depending on the actual data, the true
+ * maximum might be as little as 21844 unicode characters.
+ * <b>null</b> String objects are encoded as an empty string
+ * </li>
+ * </ul>
+ * </li>
* </ol>
* Methods that take no arguments need only specify the method name.
+ *
+ * The return value is encoded the same way as a single parameter (type + value)
*/
private Chunk invokeViewMethod(final View rootView, final View targetView, ByteBuffer in) {
int l = in.getInt();
@@ -327,54 +363,17 @@
args = new Object[0];
} else {
int nArgs = in.getInt();
-
argTypes = new Class<?>[nArgs];
args = new Object[nArgs];
- for (int i = 0; i < nArgs; i++) {
- char c = in.getChar();
- switch (c) {
- case 'Z':
- argTypes[i] = boolean.class;
- args[i] = in.get() == 0 ? false : true;
- break;
- case 'B':
- argTypes[i] = byte.class;
- args[i] = in.get();
- break;
- case 'C':
- argTypes[i] = char.class;
- args[i] = in.getChar();
- break;
- case 'S':
- argTypes[i] = short.class;
- args[i] = in.getShort();
- break;
- case 'I':
- argTypes[i] = int.class;
- args[i] = in.getInt();
- break;
- case 'J':
- argTypes[i] = long.class;
- args[i] = in.getLong();
- break;
- case 'F':
- argTypes[i] = float.class;
- args[i] = in.getFloat();
- break;
- case 'D':
- argTypes[i] = double.class;
- args[i] = in.getDouble();
- break;
- default:
- Log.e(TAG, "arg " + i + ", unrecognized type: " + c);
- return createFailChunk(ERR_INVALID_PARAM,
- "Unsupported parameter type (" + c + ") to invoke view method.");
- }
+ try {
+ deserializeMethodParameters(args, argTypes, in);
+ } catch (ViewMethodInvocationSerializationException e) {
+ return createFailChunk(ERR_INVALID_PARAM, e.getMessage());
}
}
- Method method = null;
+ Method method;
try {
method = targetView.getClass().getMethod(methodName, argTypes);
} catch (NoSuchMethodException e) {
@@ -384,7 +383,10 @@
}
try {
- ViewDebug.invokeViewMethod(targetView, method, args);
+ Object result = ViewDebug.invokeViewMethod(targetView, method, args);
+ Class<?> returnType = method.getReturnType();
+ byte[] returnValue = serializeReturnValue(returnType, returnType.cast(result));
+ return new Chunk(CHUNK_VUOP, returnValue, 0, returnValue.length);
} catch (Exception e) {
Log.e(TAG, "Exception while invoking method: " + e.getCause().getMessage());
String msg = e.getCause().getMessage();
@@ -393,8 +395,6 @@
}
return createFailChunk(ERR_EXCEPTION, msg);
}
-
- return null;
}
private Chunk setLayoutParameter(final View rootView, final View targetView, ByteBuffer in) {
@@ -406,7 +406,7 @@
} catch (Exception e) {
Log.e(TAG, "Exception setting layout parameter: " + e);
return createFailChunk(ERR_EXCEPTION, "Error accessing field "
- + param + ":" + e.getMessage());
+ + param + ":" + e.getMessage());
}
return null;
@@ -431,4 +431,175 @@
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VUOP, data, 0, data.length);
}
+
+ /**
+ * Deserializes parameters according to the VUOP_INVOKE_VIEW_METHOD protocol the {@code in}
+ * buffer.
+ *
+ * The length of {@code args} determines how many arguments are read. The {@code argTypes} must
+ * be the same length, and will be set to the argument types of the data read.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static void deserializeMethodParameters(
+ Object[] args, Class<?>[] argTypes, ByteBuffer in) throws
+ ViewMethodInvocationSerializationException {
+ checkArgument(args.length == argTypes.length);
+
+ for (int i = 0; i < args.length; i++) {
+ char typeSignature = in.getChar();
+ boolean isArray = typeSignature == SIG_ARRAY;
+ if (isArray) {
+ char arrayType = in.getChar();
+ if (arrayType != SIG_BYTE) {
+ // This implementation only supports byte-arrays for now.
+ throw new ViewMethodInvocationSerializationException(
+ "Unsupported array parameter type (" + typeSignature
+ + ") to invoke view method @argument " + i);
+ }
+
+ int arrayLength = in.getInt();
+ if (arrayLength > in.remaining()) {
+ // The sender did not actually sent the specified amount of bytes. This
+ // avoids a malformed packet to trigger an out-of-memory error.
+ throw new BufferUnderflowException();
+ }
+
+ byte[] byteArray = new byte[arrayLength];
+ in.get(byteArray);
+
+ argTypes[i] = byte[].class;
+ args[i] = byteArray;
+ } else {
+ switch (typeSignature) {
+ case SIG_BOOLEAN:
+ argTypes[i] = boolean.class;
+ args[i] = in.get() != 0;
+ break;
+ case SIG_BYTE:
+ argTypes[i] = byte.class;
+ args[i] = in.get();
+ break;
+ case SIG_CHAR:
+ argTypes[i] = char.class;
+ args[i] = in.getChar();
+ break;
+ case SIG_SHORT:
+ argTypes[i] = short.class;
+ args[i] = in.getShort();
+ break;
+ case SIG_INT:
+ argTypes[i] = int.class;
+ args[i] = in.getInt();
+ break;
+ case SIG_LONG:
+ argTypes[i] = long.class;
+ args[i] = in.getLong();
+ break;
+ case SIG_FLOAT:
+ argTypes[i] = float.class;
+ args[i] = in.getFloat();
+ break;
+ case SIG_DOUBLE:
+ argTypes[i] = double.class;
+ args[i] = in.getDouble();
+ break;
+ case SIG_STRING: {
+ argTypes[i] = String.class;
+ int stringUtf8ByteCount = Short.toUnsignedInt(in.getShort());
+ byte[] rawStringBuffer = new byte[stringUtf8ByteCount];
+ in.get(rawStringBuffer);
+ args[i] = new String(rawStringBuffer, StandardCharsets.UTF_8);
+ break;
+ }
+ default:
+ Log.e(TAG, "arg " + i + ", unrecognized type: " + typeSignature);
+ throw new ViewMethodInvocationSerializationException(
+ "Unsupported parameter type (" + typeSignature
+ + ") to invoke view method.");
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Serializes {@code value} to the wire protocol of VUOP_INVOKE_VIEW_METHOD.
+ * @hide
+ */
+ @VisibleForTesting
+ public static byte[] serializeReturnValue(Class<?> type, Object value)
+ throws ViewMethodInvocationSerializationException, IOException {
+ ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(1024);
+ DataOutputStream dos = new DataOutputStream(byteOutStream);
+
+ if (type.isArray()) {
+ if (!type.equals(byte[].class)) {
+ // Only byte arrays are supported currently.
+ throw new ViewMethodInvocationSerializationException(
+ "Unsupported array return type (" + type + ")");
+ }
+ byte[] byteArray = (byte[]) value;
+ dos.writeChar(SIG_ARRAY);
+ dos.writeChar(SIG_BYTE);
+ dos.writeInt(byteArray.length);
+ dos.write(byteArray);
+ } else if (boolean.class.equals(type)) {
+ dos.writeChar(SIG_BOOLEAN);
+ dos.write((boolean) value ? 1 : 0);
+ } else if (byte.class.equals(type)) {
+ dos.writeChar(SIG_BYTE);
+ dos.writeByte((byte) value);
+ } else if (char.class.equals(type)) {
+ dos.writeChar(SIG_CHAR);
+ dos.writeChar((char) value);
+ } else if (short.class.equals(type)) {
+ dos.writeChar(SIG_SHORT);
+ dos.writeShort((short) value);
+ } else if (int.class.equals(type)) {
+ dos.writeChar(SIG_INT);
+ dos.writeInt((int) value);
+ } else if (long.class.equals(type)) {
+ dos.writeChar(SIG_LONG);
+ dos.writeLong((long) value);
+ } else if (double.class.equals(type)) {
+ dos.writeChar(SIG_DOUBLE);
+ dos.writeDouble((double) value);
+ } else if (float.class.equals(type)) {
+ dos.writeChar(SIG_FLOAT);
+ dos.writeFloat((float) value);
+ } else if (String.class.equals(type)) {
+ dos.writeChar(SIG_STRING);
+ dos.writeUTF(value != null ? (String) value : "");
+ } else {
+ dos.writeChar(SIG_VOID);
+ }
+
+ return byteOutStream.toByteArray();
+ }
+
+ // Prefixes for simple primitives. These match the JNI definitions.
+ private static final char SIG_ARRAY = '[';
+ private static final char SIG_BOOLEAN = 'Z';
+ private static final char SIG_BYTE = 'B';
+ private static final char SIG_SHORT = 'S';
+ private static final char SIG_CHAR = 'C';
+ private static final char SIG_INT = 'I';
+ private static final char SIG_LONG = 'J';
+ private static final char SIG_FLOAT = 'F';
+ private static final char SIG_DOUBLE = 'D';
+ private static final char SIG_VOID = 'V';
+ // Prefixes for some commonly used objects
+ private static final char SIG_STRING = 'R';
+
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public static class ViewMethodInvocationSerializationException extends Exception {
+ ViewMethodInvocationSerializationException(String message) {
+ super(message);
+ }
+ }
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 4f26ad2..d2e5f9e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -22,7 +22,6 @@
import android.app.AppOpsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ExceptionUtils;
-import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
@@ -144,9 +143,6 @@
*/
private static volatile boolean sStackTrackingEnabled = false;
- private static final Object sTracingUidsWriteLock = new Object();
- private static volatile IntArray sTracingUidsImmutable = new IntArray();
-
/**
* Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to
* {@link TransactionTracker}.
@@ -167,17 +163,6 @@
}
/**
- * @hide
- */
- public static void enableTracingForUid(int uid) {
- synchronized (sTracingUidsWriteLock) {
- final IntArray copy = sTracingUidsImmutable.clone();
- copy.add(uid);
- sTracingUidsImmutable = copy;
- }
- }
-
- /**
* Check if binder transaction stack tracking is enabled.
*
* @hide
@@ -187,13 +172,6 @@
}
/**
- * @hide
- */
- public static boolean isTracingEnabled(int callingUid) {
- return sTracingUidsImmutable.indexOf(callingUid) != -1;
- }
-
- /**
* Get the binder transaction tracker for this process.
*
* @hide
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index d125cbb..fe46c9e 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -783,6 +783,14 @@
@TestApi
public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
+ /**
+ * Namespace for backup and restore service related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/util/SparseArrayMap.java b/core/java/android/util/SparseArrayMap.java
index e5bb9f45..1a2c4df 100644
--- a/core/java/android/util/SparseArrayMap.java
+++ b/core/java/android/util/SparseArrayMap.java
@@ -34,14 +34,20 @@
public class SparseArrayMap<K, V> {
private final SparseArray<ArrayMap<K, V>> mData = new SparseArray<>();
- /** Add an entry associating obj with the int-K pair. */
- public void add(int key, @NonNull K mapKey, @Nullable V obj) {
+ /**
+ * Add an entry associating obj with the int-K pair.
+ *
+ * @return the previous value associated with key, or null if there was no mapping for key.
+ * (A null return can also indicate that the map previously associated null with key, if the
+ * implementation supports null values.)
+ */
+ public V add(int key, @NonNull K mapKey, @Nullable V obj) {
ArrayMap<K, V> data = mData.get(key);
if (data == null) {
data = new ArrayMap<>();
mData.put(key, data);
}
- data.put(mapKey, obj);
+ return data.put(mapKey, obj);
}
/** Remove all entries from the map. */
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 624937f..8d75072 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -20,6 +20,7 @@
import android.annotation.CallSuper;
import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -61,8 +62,15 @@
static final Object COMPOSING = new ComposingText();
/** @hide */
- protected final InputMethodManager mIMM;
- final View mTargetView;
+ @NonNull protected final InputMethodManager mIMM;
+
+ /**
+ * Target view for the input connection.
+ *
+ * <p>This could be null for a fallback input connection.
+ */
+ @Nullable final View mTargetView;
+
final boolean mFallbackMode;
private Object[] mDefaultComposingSpans;
@@ -70,20 +78,25 @@
Editable mEditable;
KeyCharacterMap mKeyCharacterMap;
- BaseInputConnection(InputMethodManager mgr, boolean fullEditor) {
+ BaseInputConnection(@NonNull InputMethodManager mgr, boolean fullEditor) {
mIMM = mgr;
mTargetView = null;
mFallbackMode = !fullEditor;
}
- public BaseInputConnection(View targetView, boolean fullEditor) {
+ public BaseInputConnection(@NonNull View targetView, boolean fullEditor) {
mIMM = (InputMethodManager)targetView.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
mTargetView = targetView;
mFallbackMode = !fullEditor;
}
- public static final void removeComposingSpans(Spannable text) {
+ /**
+ * Removes the composing spans from the given text if any.
+ *
+ * @param text the spannable text to remove composing spans
+ */
+ public static final void removeComposingSpans(@NonNull Spannable text) {
text.removeSpan(COMPOSING);
Object[] sps = text.getSpans(0, text.length(), Object.class);
if (sps != null) {
@@ -96,12 +109,17 @@
}
}
- public static void setComposingSpans(Spannable text) {
+ /**
+ * Removes the composing spans from the given text if any.
+ *
+ * @param text the spannable text to remove composing spans
+ */
+ public static void setComposingSpans(@NonNull Spannable text) {
setComposingSpans(text, 0, text.length());
}
/** @hide */
- public static void setComposingSpans(Spannable text, int start, int end) {
+ public static void setComposingSpans(@NonNull Spannable text, int start, int end) {
final Object[] sps = text.getSpans(start, end, Object.class);
if (sps != null) {
for (int i=sps.length-1; i>=0; i--) {
@@ -114,7 +132,10 @@
final int fl = text.getSpanFlags(o);
if ((fl & (Spanned.SPAN_COMPOSING | Spanned.SPAN_POINT_MARK_MASK))
!= (Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
- text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
+ text.setSpan(
+ o,
+ text.getSpanStart(o),
+ text.getSpanEnd(o),
(fl & ~Spanned.SPAN_POINT_MARK_MASK)
| Spanned.SPAN_COMPOSING
| Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -126,20 +147,24 @@
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
}
- public static int getComposingSpanStart(Spannable text) {
+ /** Return the beginning of the range of composing text, or -1 if there's no composing text. */
+ public static int getComposingSpanStart(@NonNull Spannable text) {
return text.getSpanStart(COMPOSING);
}
- public static int getComposingSpanEnd(Spannable text) {
+ /** Return the end of the range of composing text, or -1 if there's no composing text. */
+ public static int getComposingSpanEnd(@NonNull Spannable text) {
return text.getSpanEnd(COMPOSING);
}
/**
- * Return the target of edit operations. The default implementation
- * returns its own fake editable that is just used for composing text;
- * subclasses that are real text editors should override this and
- * supply their own.
+ * Return the target of edit operations. The default implementation returns its own fake
+ * editable that is just used for composing text; subclasses that are real text editors should
+ * override this and supply their own.
+ *
+ * <p>Subclasses could override this method to turn null.
*/
+ @Nullable
public Editable getEditable() {
if (mEditable == null) {
mEditable = Editable.Factory.getInstance().newEditable("");
@@ -148,16 +173,14 @@
return mEditable;
}
- /**
- * Default implementation does nothing.
- */
+ /** Default implementation does nothing. */
+ @Override
public boolean beginBatchEdit() {
return false;
}
- /**
- * Default implementation does nothing.
- */
+ /** Default implementation does nothing. */
+ @Override
public boolean endBatchEdit() {
return false;
}
@@ -165,29 +188,29 @@
/**
* Called after only the composing region is modified (so it isn't called if the text also
* changes).
- * <p>
- * Default implementation does nothing.
+ *
+ * <p>Default implementation does nothing.
*
* @hide
*/
- public void endComposingRegionEditInternal() {
- }
+ public void endComposingRegionEditInternal() {}
/**
- * Default implementation calls {@link #finishComposingText()} and
- * {@code setImeConsumesInput(false)}.
+ * Default implementation calls {@link #finishComposingText()} and {@code
+ * setImeConsumesInput(false)}.
*/
@CallSuper
+ @Override
public void closeConnection() {
finishComposingText();
setImeConsumesInput(false);
}
/**
- * Default implementation uses
- * {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
+ * Default implementation uses {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
* MetaKeyKeyListener.clearMetaKeyState(long, int)} to clear the state.
*/
+ @Override
public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
if (content == null) return false;
@@ -195,25 +218,24 @@
return true;
}
- /**
- * Default implementation does nothing and returns false.
- */
+ /** Default implementation does nothing and returns false. */
+ @Override
public boolean commitCompletion(CompletionInfo text) {
return false;
}
- /**
- * Default implementation does nothing and returns false.
- */
+ /** Default implementation does nothing and returns false. */
+ @Override
public boolean commitCorrection(CorrectionInfo correctionInfo) {
return false;
}
/**
- * Default implementation replaces any existing composing text with
- * the given text. In addition, only if fallback mode, a key event is
- * sent for the new text and the current editable buffer cleared.
+ * Default implementation replaces any existing composing text with the given text. In addition,
+ * only if fallback mode, a key event is sent for the new text and the current editable buffer
+ * cleared.
*/
+ @Override
public boolean commitText(CharSequence text, int newCursorPosition) {
if (DEBUG) Log.v(TAG, "commitText " + text);
replaceText(text, newCursorPosition, false);
@@ -226,21 +248,19 @@
* editable text.
*
* @param beforeLength The number of characters before the cursor to be deleted, in code unit.
- * If this is greater than the number of existing characters between the beginning of the
- * text and the cursor, then this method does not fail but deletes all the characters in
- * that range.
- * @param afterLength The number of characters after the cursor to be deleted, in code unit.
- * If this is greater than the number of existing characters between the cursor and
- * the end of the text, then this method does not fail but deletes all the characters in
- * that range.
- *
- * @return {@code true} when selected text is deleted, {@code false} when either the
- * selection is invalid or not yet attached (i.e. selection start or end is -1),
- * or the editable text is {@code null}.
+ * If this is greater than the number of existing characters between the beginning of the
+ * text and the cursor, then this method does not fail but deletes all the characters in
+ * that range.
+ * @param afterLength The number of characters after the cursor to be deleted, in code unit. If
+ * this is greater than the number of existing characters between the cursor and the end of
+ * the text, then this method does not fail but deletes all the characters in that range.
+ * @return {@code true} when selected text is deleted, {@code false} when either the selection
+ * is invalid or not yet attached (i.e. selection start or end is -1), or the editable text
+ * is {@code null}.
*/
+ @Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
- if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
- + " / " + afterLength);
+ if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength);
final Editable content = getEditable();
if (content == null) return false;
@@ -389,7 +409,7 @@
continue;
}
if (java.lang.Character.isLowSurrogate(c)) {
- return INVALID_INDEX; // A invalid surrogate pair is found.
+ return INVALID_INDEX; // A invalid surrogate pair is found.
}
waitingLowSurrogate = true;
++currentIndex;
@@ -399,18 +419,18 @@
/**
* The default implementation performs the deletion around the current selection position of the
* editable text.
+ *
* @param beforeLength The number of characters before the cursor to be deleted, in code points.
- * If this is greater than the number of existing characters between the beginning of the
- * text and the cursor, then this method does not fail but deletes all the characters in
- * that range.
+ * If this is greater than the number of existing characters between the beginning of the
+ * text and the cursor, then this method does not fail but deletes all the characters in
+ * that range.
* @param afterLength The number of characters after the cursor to be deleted, in code points.
- * If this is greater than the number of existing characters between the cursor and
- * the end of the text, then this method does not fail but deletes all the characters in
- * that range.
+ * If this is greater than the number of existing characters between the cursor and the end
+ * of the text, then this method does not fail but deletes all the characters in that range.
*/
+ @Override
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
- if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
- + " / " + afterLength);
+ if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength);
final Editable content = getEditable();
if (content == null) return false;
@@ -466,10 +486,11 @@
}
/**
- * The default implementation removes the composing state from the
- * current editable text. In addition, only if fallback mode, a key event is
- * sent for the new text and the current editable buffer cleared.
+ * The default implementation removes the composing state from the current editable text. In
+ * addition, only if fallback mode, a key event is sent for the new text and the current
+ * editable buffer cleared.
*/
+ @Override
public boolean finishComposingText() {
if (DEBUG) Log.v(TAG, "finishComposingText");
final Editable content = getEditable();
@@ -485,10 +506,11 @@
}
/**
- * The default implementation uses TextUtils.getCapsMode to get the
- * cursor caps mode for the current selection position in the editable
- * text, unless in fallback mode in which case 0 is always returned.
+ * The default implementation uses TextUtils.getCapsMode to get the cursor caps mode for the
+ * current selection position in the editable text, unless in fallback mode in which case 0 is
+ * always returned.
*/
+ @Override
public int getCursorCapsMode(int reqModes) {
if (mFallbackMode) return 0;
@@ -507,17 +529,18 @@
return TextUtils.getCapsMode(content, a, reqModes);
}
- /**
- * The default implementation always returns null.
- */
+ /** The default implementation always returns null. */
+ @Override
+ @Nullable
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
return null;
}
/**
- * The default implementation returns the given amount of text from the
- * current cursor position in the buffer.
+ * The default implementation returns the given amount of text from the current cursor position
+ * in the buffer.
*/
+ @Override
@Nullable
public CharSequence getTextBeforeCursor(@IntRange(from = 0) int length, int flags) {
Preconditions.checkArgumentNonnegative(length);
@@ -549,9 +572,10 @@
}
/**
- * The default implementation returns the text currently selected, or null if none is
- * selected.
+ * The default implementation returns the text currently selected, or null if none is selected.
*/
+ @Override
+ @Nullable
public CharSequence getSelectedText(int flags) {
final Editable content = getEditable();
if (content == null) return null;
@@ -574,9 +598,10 @@
}
/**
- * The default implementation returns the given amount of text from the
- * current cursor position in the buffer.
+ * The default implementation returns the given amount of text from the current cursor position
+ * in the buffer.
*/
+ @Override
@Nullable
public CharSequence getTextAfterCursor(@IntRange(from = 0) int length, int flags) {
Preconditions.checkArgumentNonnegative(length);
@@ -602,7 +627,6 @@
length = content.length() - b;
}
-
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
return content.subSequence(b, b + length);
}
@@ -613,9 +637,10 @@
* The default implementation returns the given amount of text around the current cursor
* position in the buffer.
*/
+ @Override
@Nullable
public SurroundingText getSurroundingText(
- @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags) {
+ @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags) {
Preconditions.checkArgumentNonnegative(beforeLength);
Preconditions.checkArgumentNonnegative(afterLength);
@@ -659,60 +684,75 @@
surroundingText, selStart - startPos, selEnd - startPos, startPos);
}
- /**
- * The default implementation turns this into the enter key.
- */
+ /** The default implementation turns this into the enter key. */
+ @Override
public boolean performEditorAction(int actionCode) {
long eventTime = SystemClock.uptimeMillis();
- sendKeyEvent(new KeyEvent(eventTime, eventTime,
- KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
- | KeyEvent.FLAG_EDITOR_ACTION));
- sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
- KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
- | KeyEvent.FLAG_EDITOR_ACTION));
+ sendKeyEvent(
+ new KeyEvent(
+ eventTime,
+ eventTime,
+ KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_ENTER,
+ 0,
+ 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD,
+ 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD
+ | KeyEvent.FLAG_KEEP_TOUCH_MODE
+ | KeyEvent.FLAG_EDITOR_ACTION));
+ sendKeyEvent(
+ new KeyEvent(
+ SystemClock.uptimeMillis(),
+ eventTime,
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_ENTER,
+ 0,
+ 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD,
+ 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD
+ | KeyEvent.FLAG_KEEP_TOUCH_MODE
+ | KeyEvent.FLAG_EDITOR_ACTION));
return true;
}
- /**
- * The default implementation does nothing.
- */
+ /** The default implementation does nothing. */
+ @Override
public boolean performContextMenuAction(int id) {
return false;
}
- /**
- * The default implementation does nothing.
- */
+ /** The default implementation does nothing. */
+ @Override
public boolean performPrivateCommand(String action, Bundle data) {
return false;
}
- /**
- * The default implementation does nothing.
- */
+ /** The default implementation does nothing. */
+ @Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
return false;
}
+ @Override
+ @Nullable
public Handler getHandler() {
return null;
}
/**
- * The default implementation places the given text into the editable,
- * replacing any existing composing text. The new text is marked as
- * in a composing state with the composing style.
+ * The default implementation places the given text into the editable, replacing any existing
+ * composing text. The new text is marked as in a composing state with the composing style.
*/
+ @Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
if (DEBUG) Log.v(TAG, "setComposingText " + text);
replaceText(text, newCursorPosition, true);
return true;
}
+ @Override
public boolean setComposingRegion(int start, int end) {
final Editable content = getEditable();
if (content != null) {
@@ -735,7 +775,10 @@
ensureDefaultComposingSpans();
if (mDefaultComposingSpans != null) {
for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
- content.setSpan(mDefaultComposingSpans[i], a, b,
+ content.setSpan(
+ mDefaultComposingSpans[i],
+ a,
+ b,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
}
}
@@ -751,10 +794,8 @@
return true;
}
- /**
- * The default implementation changes the selection position in the
- * current editable text.
- */
+ /** The default implementation changes the selection position in the current editable text. */
+ @Override
public boolean setSelection(int start, int end) {
if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end);
final Editable content = getEditable();
@@ -779,17 +820,17 @@
}
/**
- * Provides standard implementation for sending a key event to the window
- * attached to the input connection's view.
+ * Provides standard implementation for sending a key event to the window attached to the input
+ * connection's view.
*/
+ @Override
public boolean sendKeyEvent(KeyEvent event) {
mIMM.dispatchKeyEventFromInputMethod(mTargetView, event);
return false;
}
- /**
- * Updates InputMethodManager with the current fullscreen mode.
- */
+ /** Updates InputMethodManager with the current fullscreen mode. */
+ @Override
public boolean reportFullscreenMode(boolean enabled) {
return true;
}
@@ -934,8 +975,7 @@
newCursorPosition += a;
}
if (newCursorPosition < 0) newCursorPosition = 0;
- if (newCursorPosition > content.length())
- newCursorPosition = content.length();
+ if (newCursorPosition > content.length()) newCursorPosition = content.length();
Selection.setSelection(content, newCursorPosition);
content.replace(a, b, text);
@@ -950,11 +990,16 @@
}
/**
- * Default implementation which invokes {@link View#performReceiveContent} on the target
- * view if the view {@link View#getReceiveContentMimeTypes allows} content insertion;
- * otherwise returns false without any side effects.
+ * Default implementation which invokes {@link View#performReceiveContent} on the target view if
+ * the view {@link View#getReceiveContentMimeTypes allows} content insertion; otherwise returns
+ * false without any side effects.
*/
+ @Override
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ if (mTargetView == null) {
+ return false;
+ }
+
ClipDescription description = inputContentInfo.getDescription();
if (mTargetView.getReceiveContentMimeTypes() == null) {
if (DEBUG) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index f24c666..746f88c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2179,7 +2179,7 @@
break;
}
- nAudioMix->mCriteria.add(nCriterion);
+ nAudioMix->mCriteria.push_back(nCriterion);
env->DeleteLocalRef(jCriterion);
}
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
new file mode 100644
index 0000000..8ed58f3
--- /dev/null
+++ b/core/res/res/values/config_device_idle.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. Do not translate.
+
+ NOTE: The naming convention is "config_camelCaseValue". Some legacy
+ entries do not follow the convention, but all new entries should. -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Default for DeviceIdleController.Constants.FLEX_TIME_SHORT -->
+ <integer name="device_idle_flex_time_short_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT -->
+ <integer name="device_idle_light_after_inactive_to_ms">180000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_TIMEOUT -->
+ <integer name="device_idle_light_idle_to_ms">300000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->
+ <item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_MAX_IDLE_TIMEOUT -->
+ <integer name="device_idle_light_max_idle_to_ms">900000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET -->
+ <integer name="device_idle_light_idle_maintenance_min_budget_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET -->
+ <integer name="device_idle_light_idle_maintenance_max_budget_ms">300000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MIN_LIGHT_MAINTENANCE_TIME -->
+ <integer name="device_idle_min_light_maintenance_time_ms">5000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MIN_DEEP_MAINTENANCE_TIME -->
+ <integer name="device_idle_min_deep_maintenance_time_ms">30000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.INACTIVE_TIMEOUT -->
+ <integer name="device_idle_inactive_to_ms">1800000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.SENSING_TIMEOUT -->
+ <integer name="device_idle_sensing_to_ms">240000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LOCATING_TIMEOUT -->
+ <integer name="device_idle_locating_to_ms">30000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LOCATION_ACCURACY -->
+ <item name="device_idle_location_accuracy" format="float" type="integer">20.0</item>
+
+ <!-- Default for DeviceIdleController.Constants.MOTION_INACTIVE_TIMEOUT -->
+ <integer name="device_idle_motion_inactive_to_ms">600000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MOTION_INACTIVE_TIMEOUT_FLEX -->
+ <integer name="device_idle_motion_inactive_to_flex_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.IDLE_AFTER_INACTIVE_TIMEOUT -->
+ <integer name="device_idle_idle_after_inactive_to_ms">1800000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.IDLE_PENDING_TIMEOUT -->
+ <integer name="device_idle_idle_pending_to_ms">300000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MAX_IDLE_PENDING_TIMEOUT -->
+ <integer name="device_idle_max_idle_pending_to_ms">600000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.IDLE_PENDING_FACTOR -->
+ <item name="device_idle_idle_pending_factor" format="float" type="integer">2.0</item>
+
+ <!-- Default for DeviceIdleController.Constants.QUICK_DOZE_DELAY_TIMEOUT -->
+ <integer name="device_idle_quick_doze_delay_to_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.IDLE_TIMEOUT -->
+ <integer name="device_idle_idle_to_ms">3600000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MAX_IDLE_TIMEOUT -->
+ <integer name="device_idle_max_idle_to_ms">21600000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.IDLE_FACTOR -->
+ <item name="device_idle_idle_factor" format="float" type="integer">2.0</item>
+
+ <!-- Default for DeviceIdleController.Constants.MIN_TIME_TO_ALARM -->
+ <integer name="device_idle_min_time_to_alarm_ms">3600000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MAX_TEMP_APP_ALLOWLIST_DURATION_MS -->
+ <integer name="device_idle_max_temp_app_allowlist_duration_ms">300000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.MMS_TEMP_APP_ALLOWLIST_DURATION_MS -->
+ <integer name="device_idle_mms_temp_app_allowlist_duration_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.SMS_TEMP_APP_ALLOWLIST_DURATION_MS -->
+ <integer name="device_idle_sms_temp_app_allowlist_duration_ms">20000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.NOTIFICATION_ALLOWLIST_DURATION_MS -->
+ <integer name="device_idle_notification_allowlist_duration_ms">30000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.WAIT_FOR_UNLOCK -->
+ <bool name="device_idle_wait_for_unlock">true</bool>
+
+ <!-- Default for DeviceIdleController.Constants.PRE_IDLE_FACTOR_LONG -->
+ <item name="device_idle_pre_idle_factor_long" format="float" type="integer">1.67</item>
+
+ <!-- Default for DeviceIdleController.Constants.PRE_IDLE_FACTOR_SHORT -->
+ <item name="device_idle_pre_idle_factor_short" format="float" type="integer">0.33</item>
+
+ <!-- Default for DeviceIdleController.Constants.USE_WINDOW_ALARMS -->
+ <bool name="device_idle_use_window_alarms">true</bool>
+</resources>
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a535c50..7e8423a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4414,6 +4414,40 @@
<java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
+ <!-- To config device idle -->
+ <java-symbol type="integer" name="device_idle_flex_time_short_ms" />
+ <java-symbol type="integer" name="device_idle_light_after_inactive_to_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_to_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_factor" />
+ <java-symbol type="integer" name="device_idle_light_max_idle_to_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_maintenance_max_budget_ms" />
+ <java-symbol type="integer" name="device_idle_min_light_maintenance_time_ms" />
+ <java-symbol type="integer" name="device_idle_min_deep_maintenance_time_ms" />
+ <java-symbol type="integer" name="device_idle_inactive_to_ms" />
+ <java-symbol type="integer" name="device_idle_sensing_to_ms" />
+ <java-symbol type="integer" name="device_idle_locating_to_ms" />
+ <java-symbol type="integer" name="device_idle_location_accuracy" />
+ <java-symbol type="integer" name="device_idle_motion_inactive_to_ms" />
+ <java-symbol type="integer" name="device_idle_motion_inactive_to_flex_ms" />
+ <java-symbol type="integer" name="device_idle_idle_after_inactive_to_ms" />
+ <java-symbol type="integer" name="device_idle_idle_pending_to_ms" />
+ <java-symbol type="integer" name="device_idle_max_idle_pending_to_ms" />
+ <java-symbol type="integer" name="device_idle_idle_pending_factor" />
+ <java-symbol type="integer" name="device_idle_quick_doze_delay_to_ms" />
+ <java-symbol type="integer" name="device_idle_idle_to_ms" />
+ <java-symbol type="integer" name="device_idle_max_idle_to_ms" />
+ <java-symbol type="integer" name="device_idle_idle_factor" />
+ <java-symbol type="integer" name="device_idle_min_time_to_alarm_ms" />
+ <java-symbol type="integer" name="device_idle_max_temp_app_allowlist_duration_ms" />
+ <java-symbol type="integer" name="device_idle_mms_temp_app_allowlist_duration_ms" />
+ <java-symbol type="integer" name="device_idle_sms_temp_app_allowlist_duration_ms" />
+ <java-symbol type="integer" name="device_idle_notification_allowlist_duration_ms" />
+ <java-symbol type="bool" name="device_idle_wait_for_unlock" />
+ <java-symbol type="integer" name="device_idle_pre_idle_factor_long" />
+ <java-symbol type="integer" name="device_idle_pre_idle_factor_short" />
+ <java-symbol type="bool" name="device_idle_use_window_alarms" />
+
<!-- Binder heavy hitter watcher configs -->
<java-symbol type="bool" name="config_defaultBinderHeavyHitterWatcherEnabled" />
<java-symbol type="integer" name="config_defaultBinderHeavyHitterWatcherBatchSize" />
diff --git a/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java b/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java
new file mode 100644
index 0000000..7248983
--- /dev/null
+++ b/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ddm;
+
+import static android.ddm.DdmHandleViewDebug.deserializeMethodParameters;
+import static android.ddm.DdmHandleViewDebug.serializeReturnValue;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.ddm.DdmHandleViewDebug.ViewMethodInvocationSerializationException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class DdmHandleViewDebugTest {
+ // true
+ private static final byte[] SERIALIZED_BOOLEAN_TRUE = {0x00, 0x5A, 1};
+
+ @Test
+ public void serializeReturnValue_booleanTrue() throws Exception {
+ assertArrayEquals(SERIALIZED_BOOLEAN_TRUE, serializeReturnValue(boolean.class, true));
+ }
+
+ @Test
+ public void deserializeMethodParameters_booleanTrue() throws Exception {
+ expectDeserializedArgument(boolean.class, true, SERIALIZED_BOOLEAN_TRUE);
+ }
+
+ // false
+ private static final byte[] SERIALIZED_BOOLEAN_FALSE = {0x00, 0x5A, 0};
+
+ @Test
+ public void serializeReturnValue_booleanFalse() throws Exception {
+ assertArrayEquals(SERIALIZED_BOOLEAN_FALSE, serializeReturnValue(boolean.class, false));
+ }
+
+ @Test
+ public void deserializeMethodParameters_booleanFalse() throws Exception {
+ expectDeserializedArgument(boolean.class, false, SERIALIZED_BOOLEAN_FALSE);
+ }
+
+ // (byte) 42
+ private static final byte[] SERIALIZED_BYTE = {0x00, 0x42, 42};
+
+ @Test
+ public void serializeReturnValue_byte() throws Exception {
+ assertArrayEquals(SERIALIZED_BYTE, serializeReturnValue(byte.class, (byte) 42));
+ }
+
+ @Test
+ public void deserializeMethodParameters_byte() throws Exception {
+ expectDeserializedArgument(byte.class, (byte) 42, SERIALIZED_BYTE);
+ }
+
+ // '\u1122'
+ private static final byte[] SERIALIZED_CHAR = {0x00, 0x43, 0x11, 0x22};
+
+ @Test
+ public void serializeReturnValue_char() throws Exception {
+ assertArrayEquals(SERIALIZED_CHAR, serializeReturnValue(char.class, '\u1122'));
+ }
+
+ @Test
+ public void deserializeMethodParameters_char() throws Exception {
+ expectDeserializedArgument(char.class, '\u1122', SERIALIZED_CHAR);
+ }
+
+ // (short) 0x1011
+ private static final byte[] SERIALIZED_SHORT = {0x00, 0x53, 0x10, 0x11};
+
+ @Test
+ public void serializeReturnValue_short() throws Exception {
+ assertArrayEquals(SERIALIZED_SHORT,
+ serializeReturnValue(short.class, (short) 0x1011));
+ }
+
+ @Test
+ public void deserializeMethodParameters_short() throws Exception {
+ expectDeserializedArgument(short.class, (short) 0x1011, SERIALIZED_SHORT);
+ }
+
+ // 0x11223344
+ private static final byte[] SERIALIZED_INT = {0x00, 0x49, 0x11, 0x22, 0x33, 0x44};
+
+ @Test
+ public void serializeReturnValue_int() throws Exception {
+ assertArrayEquals(SERIALIZED_INT,
+ serializeReturnValue(int.class, 0x11223344));
+ }
+
+ @Test
+ public void deserializeMethodParameters_int() throws Exception {
+ expectDeserializedArgument(int.class, 0x11223344, SERIALIZED_INT);
+ }
+
+ // 0x0011223344556677L
+ private static final byte[] SERIALIZED_LONG =
+ {0x00, 0x4a, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+ @Test
+ public void serializeReturnValue_long() throws Exception {
+ assertArrayEquals(SERIALIZED_LONG,
+ serializeReturnValue(long.class, 0x0011223344556677L));
+ }
+
+ @Test
+ public void deserializeMethodParameters_long() throws Exception {
+ expectDeserializedArgument(long.class, 0x0011223344556677L, SERIALIZED_LONG);
+ }
+
+ // 3.141d
+ private static final byte[] SERIALIZED_DOUBLE =
+ {0x00, 0x44, (byte) 0x40, (byte) 0x09, (byte) 0x20, (byte) 0xc4, (byte) 0x9b,
+ (byte) 0xa5, (byte) 0xe3, (byte) 0x54};
+
+ @Test
+ public void serializeReturnValue_double() throws Exception {
+ assertArrayEquals(
+ SERIALIZED_DOUBLE,
+ serializeReturnValue(double.class, 3.141d));
+ }
+
+ @Test
+ public void deserializeMethodParameters_double() throws Exception {
+ expectDeserializedArgument(double.class, 3.141d, SERIALIZED_DOUBLE);
+ }
+
+ // 3.141f
+ private static final byte[] SERIALIZED_FLOAT =
+ {0x00, 0x46, (byte) 0x40, (byte) 0x49, (byte) 0x06, (byte) 0x25};
+
+ @Test
+ public void serializeReturnValue_float() throws Exception {
+ assertArrayEquals(SERIALIZED_FLOAT,
+ serializeReturnValue(float.class, 3.141f));
+ }
+
+ @Test
+ public void deserializeMethodParameters_float() throws Exception {
+ expectDeserializedArgument(float.class, 3.141f, SERIALIZED_FLOAT);
+ }
+
+ // "foo"
+ private static final byte[] SERIALIZED_ASCII_STRING = {0x00, 0x52, 0, 3, 0x66, 0x6f, 0x6f};
+
+ @Test
+ public void serializeReturnValue_asciiString() throws Exception {
+ assertArrayEquals(SERIALIZED_ASCII_STRING,
+ serializeReturnValue(String.class, "foo"));
+ }
+
+ @Test
+ public void deserializeMethodParameters_asciiString() throws Exception {
+ expectDeserializedArgument(String.class, "foo", SERIALIZED_ASCII_STRING);
+ }
+
+ // "\u1122"
+ private static final byte[] SERIALIZED_NON_ASCII_STRING =
+ {0x00, 0x52, 0, 3, (byte) 0xe1, (byte) 0x84, (byte) 0xa2};
+
+ @Test
+ public void serializeReturnValue_nonAsciiString_encodesAsUtf8() throws Exception {
+ assertArrayEquals(SERIALIZED_NON_ASCII_STRING,
+ serializeReturnValue(String.class, "\u1122"));
+ }
+
+ @Test
+ public void deserializeMethodParameters_decodesFromUtf8() throws Exception {
+ expectDeserializedArgument(String.class, "\u1122", SERIALIZED_NON_ASCII_STRING);
+ }
+
+ // ""
+ private static final byte[] SERIALIZED_EMPTY_STRING = {0x00, 0x52, 0, 0};
+
+ @Test
+ public void serializeReturnValue_emptyString() throws Exception {
+ assertArrayEquals(SERIALIZED_EMPTY_STRING, serializeReturnValue(String.class, ""));
+ }
+
+ @Test
+ public void deserializeMethodParameters_emptyString() throws Exception {
+ expectDeserializedArgument(String.class, "", SERIALIZED_EMPTY_STRING);
+ }
+
+ @Test
+ public void serializeReturnValue_nullString_encodesAsEmptyString() throws Exception {
+ assertArrayEquals(new byte[]{0x00, 0x52, 0, 0}, serializeReturnValue(String.class, null));
+ }
+
+ // Illegal - string length exceeding actual bytes
+ private static final byte[] SERIALIZED_INVALID_STRING =
+ {0x00, 0x52, 0, 3, 0x66};
+
+ @Test
+ public void deserializeMethodParameters_stringPayloadMissing_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(BufferUnderflowException.class,
+ () -> deserializeMethodParameters(args, argTypes,
+ ByteBuffer.wrap(SERIALIZED_INVALID_STRING)));
+ }
+
+ @Test
+ public void serializeAndDeserialize_handlesStringsUpTo64k() throws Exception {
+ char[] chars = new char[65535];
+ Arrays.fill(chars, 'a');
+ String original = new String(chars);
+ byte[] serialized = serializeReturnValue(String.class, original);
+
+ // 2 bytes for the R signature char, 2 bytes char string byte count, 2^16-1 bytes ASCII
+ // payload
+ assertEquals(2 + 2 + 65535, serialized.length);
+
+ // length is unsigned short
+ assertArrayEquals(new byte[]{0x00, 0x52, (byte) 0xff, (byte) 0xff},
+ Arrays.copyOfRange(serialized, 0, 4));
+
+ // length of string must be interpreted as unsigned short, returning original content
+ expectDeserializedArgument(String.class, original, serialized);
+ }
+
+ private static final byte[] SERIALIZED_VOID = {0x00, 0x56};
+
+ @Test
+ public void serializeReturnValue_void() throws Exception {
+ assertArrayEquals(SERIALIZED_VOID, serializeReturnValue(void.class, null));
+ }
+
+ @Test
+ public void deserializeMethodParameters_void_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(ViewMethodInvocationSerializationException.class,
+ () -> deserializeMethodParameters(args, argTypes,
+ ByteBuffer.wrap(SERIALIZED_VOID)));
+ }
+
+ // new byte[]{}
+ private static final byte[] SERIALIZED_EMPTY_BYTE_ARRAY = {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 0};
+
+ @Test
+ public void serializeReturnValue_emptyByteArray() throws Exception {
+ assertArrayEquals(SERIALIZED_EMPTY_BYTE_ARRAY,
+ serializeReturnValue(byte[].class, new byte[]{}));
+ }
+
+ @Test
+ public void deserializeMethodParameters_emptyByteArray() throws Exception {
+ expectDeserializedArgument(byte[].class, new byte[]{}, SERIALIZED_EMPTY_BYTE_ARRAY);
+ }
+
+ // new byte[]{0, 42}
+ private static final byte[] SERIALIZED_SIMPLE_BYTE_ARRAY =
+ {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 2, 0, 42};
+
+ @Test
+ public void serializeReturnValue_byteArray() throws Exception {
+ assertArrayEquals(SERIALIZED_SIMPLE_BYTE_ARRAY,
+ serializeReturnValue(byte[].class, new byte[]{0, 42}));
+ }
+
+ @Test
+ public void deserializeMethodParameters_byteArray() throws Exception {
+ expectDeserializedArgument(byte[].class, new byte[]{0, 42}, SERIALIZED_SIMPLE_BYTE_ARRAY);
+ }
+
+ @Test
+ public void serializeReturnValue_largeByteArray_encodesSizeCorrectly() throws Exception {
+ byte[] result = serializeReturnValue(byte[].class, new byte[0x012233]);
+ // 2 bytes for the each [Z signature char, 4 bytes int array length, 0x012233 bytes payload
+ assertEquals(2 + 2 + 4 + 74291, result.length);
+
+ assertArrayEquals(new byte[]{0x00, 0x5b, 0x00, 0x42, 0x00, 0x01, 0x22, 0x33},
+ Arrays.copyOfRange(result, 0, 8));
+ }
+
+ // Illegal - declared size exceeds remaining buffer length
+ private static final byte[] SERIALIZED_INVALID_BYTE_ARRAY =
+ {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 3, 0, 42};
+
+ @Test
+ public void deserializeMethodParameters_sizeExceedsBuffer_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(BufferUnderflowException.class,
+ () -> deserializeMethodParameters(args, argTypes,
+ ByteBuffer.wrap(SERIALIZED_INVALID_BYTE_ARRAY)));
+ }
+
+ // new int[]{}
+ private static final byte[] SERIALIZED_EMPTY_INT_ARRAY = {0x00, 0x5b, 0x00, 0x49, 0, 0, 0, 0};
+
+ @Test
+ public void serializeReturnValue_nonByteArrayType_throws() throws Exception {
+ assertThrows(ViewMethodInvocationSerializationException.class,
+ () -> serializeReturnValue(int[].class, 42));
+ }
+
+ @Test
+ public void deserializeMethodParameters_nonByteArrayType_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(ViewMethodInvocationSerializationException.class,
+ () -> deserializeMethodParameters(args, argTypes,
+ ByteBuffer.wrap(SERIALIZED_EMPTY_INT_ARRAY)));
+ }
+
+ // new byte[]{0, 42}
+ private static final byte[] SERIALIZED_MULTIPLE_PARAMETERS =
+ {0x00, 0x42, 42, 0x00, 0x5A, 1};
+
+ @Test
+ public void deserializeMethodParameters_multipleParameters() throws Exception {
+ expectDeserializedArguments(new Class[]{byte.class, boolean.class},
+ new Object[]{(byte) 42, true}, SERIALIZED_MULTIPLE_PARAMETERS);
+ }
+
+ // Illegal - type 'X'
+ private static final byte[] SERIALIZED_INVALID_UNKNOWN_TYPE = {0x00, 0x58};
+
+ @Test
+ public void deserializeMethodParameters_unknownType_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(ViewMethodInvocationSerializationException.class,
+ () -> deserializeMethodParameters(args, argTypes,
+ ByteBuffer.wrap(SERIALIZED_INVALID_UNKNOWN_TYPE)));
+ }
+
+ @Test
+ public void deserializeMethodParameters_noArgumentsEmptyPacket_isNoop() throws Exception {
+ Object[] args = new Object[0];
+ Class<?>[] argTypes = new Class<?>[0];
+ deserializeMethodParameters(args, argTypes, ByteBuffer.wrap(new byte[0]));
+ }
+
+ @Test
+ public void deserializeMethodParameters_withArgumentsEmptyPacket_throws() throws Exception {
+ Object[] args = new Object[1];
+ Class<?>[] argTypes = new Class<?>[1];
+ assertThrows(BufferUnderflowException.class,
+ () -> deserializeMethodParameters(args, argTypes, ByteBuffer.wrap(new byte[0])));
+ }
+
+ private static void expectDeserializedArgument(Class<?> expectedType, Object expectedValue,
+ byte[] argumentBuffer) throws Exception {
+ expectDeserializedArguments(new Class[]{expectedType}, new Object[]{expectedValue},
+ argumentBuffer);
+ }
+
+ private static void expectDeserializedArguments(Class<?>[] expectedTypes,
+ Object[] expectedValues, byte[] argumentBuffer) throws Exception {
+ final int argCount = expectedTypes.length;
+ assertEquals("test helper not used correctly", argCount, expectedValues.length);
+ Object[] actualArgs = new Object[argCount];
+ Class<?>[] actualArgTypes = new Class<?>[argCount];
+
+ ByteBuffer buffer = ByteBuffer.wrap(argumentBuffer);
+ deserializeMethodParameters(actualArgs, actualArgTypes, buffer);
+
+ for (int i = 0; i < argCount; i++) {
+ String context = "argument " + i;
+ assertEquals(context, expectedTypes[i], actualArgTypes[i]);
+ if (byte[].class.equals(expectedTypes[i])) {
+ assertArrayEquals((byte[]) expectedValues[i], (byte[]) actualArgs[i]);
+ } else {
+ assertEquals(expectedValues[i], actualArgs[i]);
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java b/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java
new file mode 100644
index 0000000..2bb5abe
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.inputmethod;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.SuggestionSpan;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BaseInputConnectionTest {
+ private static final int[] CURSOR_CAPS_MODES =
+ new int[] {
+ InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
+ InputType.TYPE_TEXT_FLAG_CAP_WORDS,
+ InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
+ };
+
+ private BaseInputConnection mBaseInputConnection;
+ private Editable mEditable;
+ private View mMockView;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockView = new View(InstrumentationRegistry.getInstrumentation().getContext());
+ mBaseInputConnection = new BaseInputConnection(mMockView, /*fullEditor=*/ true);
+ mEditable = mBaseInputConnection.getEditable();
+ verifyContent("", 0, 0, -1, -1);
+ }
+
+ @Test
+ public void testCommitText_toEditorWithoutSelectionAndComposing() {
+ // before commit: "|"
+ // after commit: "text1|"
+ assertThat(mBaseInputConnection.commitText("text1", 1)).isTrue();
+ verifyContent("text1", 5, 5, -1, -1);
+
+ // before commit: "text1|"
+ // after commit: "text1text2|"
+ assertThat(mBaseInputConnection.commitText("text2", "text1".length())).isTrue();
+ verifyContent("text1text2", 10, 10, -1, -1);
+
+ // before commit: "text1text2|"
+ // after commit: "text1text2text3|"
+ assertThat(mBaseInputConnection.commitText("text3", 100)).isTrue();
+ verifyContent("text1text2text3", 15, 15, -1, -1);
+
+ // before commit: "text1text2text3|"
+ // after commit: "text1text2text3text4|"
+ // BUG(b/21476564): this behavior is inconsistent with API description.
+ assertThat(mBaseInputConnection.commitText("text4", 0)).isTrue();
+ verifyContent("text1text2text3text4", 20, 20, -1, -1);
+
+ // before commit: "text1text2text3text4|"
+ // after commit: "text1text2text3text|4text5"
+ assertThat(mBaseInputConnection.commitText("text5", -1)).isTrue();
+ verifyContent("text1text2text3text4text5", 19, 19, -1, -1);
+
+ // before commit: "text1text2text3text|4text5"
+ // after commit: "text1text2text3te|xttext64text5"
+ assertThat(mBaseInputConnection.commitText("text6", -2)).isTrue();
+ verifyContent("text1text2text3texttext64text5", 17, 17, -1, -1);
+
+ // before commit: "text1text2text3te|xttext64text5"
+ // after commit: "|text1text2text3tetext7xttext64text5"
+ assertThat(mBaseInputConnection.commitText("text7", -100)).isTrue();
+ verifyContent("text1text2text3tetext7xttext64text5", 0, 0, -1, -1);
+ }
+
+ @Test
+ public void testCommitText_toEditorWithSelection() {
+ // before commit: "123|456|789"
+ // before commit: "123text|789"
+ prepareContent("123456789", 3, 6, -1, -1);
+ assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+ verifyContent("123text789", 7, 7, -1, -1);
+
+ // before commit: "|123|"
+ // before commit: "|text"
+ prepareContent("123", 0, 3, -1, -1);
+ assertThat(mBaseInputConnection.commitText("text", 0)).isTrue();
+ verifyContent("text", 0, 0, -1, -1);
+ }
+
+ @Test
+ public void testCommitText_toEditorWithComposing() {
+ // before commit: "123456|789"
+ // ---
+ // before commit: "123text|789"
+ prepareContent("123456789", 6, 6, 3, 6);
+ assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+ verifyContent("123text789", 7, 7, -1, -1);
+
+ // before commit: "123456789|"
+ // ---
+ // before commit: "123text|789"
+ prepareContent("123456789", 6, 6, 3, 6);
+ assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+ verifyContent("123text789", 7, 7, -1, -1);
+
+ // before commit: "|123456789|"
+ // ---
+ // before commit: "123text|789"
+ prepareContent("123456789", 0, 9, 3, 6);
+ assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+ verifyContent("123text789", 7, 7, -1, -1);
+ }
+
+ @Test
+ public void deleteSurroundingText_fromEditorWithoutSelectionAndComposing() {
+ // before delete: "123456789|"
+ // after delete: "123456|"
+ prepareContent("123456789", 9, 9, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(3, 0)).isTrue();
+ verifyContent("123456", 6, 6, -1, -1);
+
+ // before delete: "123456|"
+ // after delete: "|"
+ assertThat(mBaseInputConnection.deleteSurroundingText(100, 0)).isTrue();
+ verifyContent("", 0, 0, -1, -1);
+
+ // before commit: "|123456789"
+ // after delete: "|456789"
+ prepareContent("123456789", 0, 0, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(0, 3)).isTrue();
+ verifyContent("456789", 0, 0, -1, -1);
+
+ // before delete: "|123456789"
+ // after delete: "|"
+ assertThat(mBaseInputConnection.deleteSurroundingText(0, 100)).isTrue();
+ verifyContent("", 0, 0, -1, -1);
+
+ // before delete: "123|456789"
+ // after delete: "1|789"
+ prepareContent("123456789", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(2, 3)).isTrue();
+ verifyContent("1789", 1, 1, -1, -1);
+ }
+
+ @Test
+ public void deleteSurroundingText_fromEditorSelectionOrComposing() {
+ // before delete: "123|456|789"
+ // before delete: "12|456|9"
+ prepareContent("123456789", 3, 6, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(1, 2)).isTrue();
+ verifyContent("124569", 2, 5, -1, -1);
+
+ // before delete: "12|456|9"
+ // before delete: "|456|"
+ assertThat(mBaseInputConnection.deleteSurroundingText(100, 100)).isTrue();
+ verifyContent("456", 0, 3, -1, -1);
+
+ // before commit: "123456|789"
+ // ---
+ // before commit: "1[456]|89"
+ prepareContent("123456789", 6, 6, 3, 6);
+ assertThat(mBaseInputConnection.deleteSurroundingText(2, 1)).isTrue();
+ verifyContent("145689", 4, 4, 1, 4);
+
+ // before commit: "1234|56789"
+ // - --
+ // before commit: "124|56|89"
+ // - --
+ prepareContent("123456789", 4, 4, 3, 6);
+ assertThat(mBaseInputConnection.deleteSurroundingText(1, 1)).isTrue();
+ verifyContent("1245689", 3, 3, 2, 5);
+ }
+
+ @Test
+ public void deleteSurroundingText_negativeLength_willBeIgnored() {
+ // before delete: "123|45678"
+ // after delete: "123|45678"
+ prepareContent("123456789", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(-1, -1)).isTrue();
+ verifyContent("123456789", 3, 3, -1, -1);
+
+ // before delete: "123|45678"
+ // after delete: "123|5678"
+ assertThat(mBaseInputConnection.deleteSurroundingText(-1, 1)).isTrue();
+ verifyContent("12356789", 3, 3, -1, -1);
+
+ // before delete: "123|45678"
+ // after delete: "12|45678"
+ prepareContent("123456789", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.deleteSurroundingText(1, -1)).isTrue();
+ verifyContent("12456789", 2, 2, -1, -1);
+ }
+
+ @Test
+ public void testFinishComposingText() {
+ // before finish composing: "123456|789"
+ // ---
+ // before finish composing: "123456|789"
+ prepareContent("123456789", 6, 6, 3, 6);
+ assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+ verifyContent("123456789", 6, 6, -1, -1);
+
+ // before finish composing: "123456789|"
+ // ---
+ // before finish composing: "123456789|"
+ prepareContent("123456789", 9, 9, 3, 6);
+ assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+ verifyContent("123456789", 9, 9, -1, -1);
+
+ // before finish composing: "|123456789|"
+ // ---
+ // before finish composing: "|123456789|"
+ prepareContent("123456789", 0, 9, 3, 6);
+ assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+ verifyContent("123456789", 0, 9, -1, -1);
+
+ // before finish composing: "1234|5|6789|"
+ // ---- - ----
+ // before finish composing: "1234|5|6789"
+ prepareContent("123456789", 4, 5, 0, 9);
+ assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+ verifyContent("123456789", 4, 5, -1, -1);
+ }
+
+ @Test
+ public void testGetCursorCapsMode() {
+ // "|"
+ prepareContent("", 0, 0, -1, -1);
+ verifyCursorCapsModeWithMode("", 0);
+
+ // Hello|
+ prepareContent("Hello", 5, 5, -1, -1);
+ verifyCursorCapsModeWithMode("Hello", 5);
+
+ // Hello. |
+ prepareContent("Hello. ", 7, 7, -1, -1);
+ verifyCursorCapsModeWithMode("Hello. ", 7);
+
+ // Hello. |Hi|
+ prepareContent("Hello. Hi", 7, 9, -1, -1);
+ verifyCursorCapsModeWithMode("Hello. Hi", 7);
+
+ // Hello. |
+ // -----
+ prepareContent("Hello. ", 7, 7, 0, 5);
+ verifyCursorCapsModeWithMode("Hello. ", 7);
+ }
+
+ private void verifyCursorCapsModeWithMode(CharSequence text, int off) {
+ for (int reqMode : CURSOR_CAPS_MODES) {
+ assertThat(mBaseInputConnection.getCursorCapsMode(reqMode))
+ .isEqualTo(TextUtils.getCapsMode(text, off, reqMode));
+ }
+ }
+
+ @Test
+ public void testSetComposingText_toEditorWithoutSelectionAndComposing() {
+ // before set composing text: "|"
+ // after set composing text: "abc|"
+ // ---
+ assertThat(mBaseInputConnection.setComposingText("abc", 1)).isTrue();
+ verifyContent("abc", 3, 3, 0, 3);
+
+ // before set composing text: "abc|"
+ // after set composing text: "abcdef|"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("def", 100)).isTrue();
+ verifyContent("abcdef", 6, 6, 3, 6);
+
+ // before set composing text: "abc|"
+ // after set composing text: "abcdef|"
+ // ---
+ // BUG(b/21476564): this behavior is inconsistent with API description.
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("def", 0)).isTrue();
+ verifyContent("abcdef", 6, 6, 3, 6);
+
+ // before set composing text: "abc|"
+ // after set composing text: "ab|cdef"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("def", -1)).isTrue();
+ verifyContent("abcdef", 2, 2, 3, 6);
+
+ // before set composing text: "abc|"
+ // after set composing text: "|abcdef"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("def", -100)).isTrue();
+ verifyContent("abcdef", 0, 0, 3, 6);
+ }
+
+ @Test
+ public void testSetComposingText_toEditorWithComposing() {
+ // before set composing text: "abc|"
+ // ---
+ // after set composing text: "def|"
+ // ---
+ prepareContent("abc", 3, 3, 0, 3);
+ assertThat(mBaseInputConnection.setComposingText("def", 1)).isTrue();
+ verifyContent("def", 3, 3, 0, 3);
+
+ // before set composing text: "abc|"
+ // ---
+ // after set composing text: "hijkl|"
+ // -----
+ assertThat(mBaseInputConnection.setComposingText("hijkl", 1)).isTrue();
+ verifyContent("hijkl", 5, 5, 0, 5);
+
+ // before set composing text: "hijkl|"
+ // -----
+ // after set composing text: "|mn"
+ // --
+ assertThat(mBaseInputConnection.setComposingText("mn", 0)).isTrue();
+ verifyContent("mn", 0, 0, 0, 2);
+
+ // before set composing text: "|mn"
+ // --
+ // after set composing text: "|opq"
+ // ---
+ assertThat(mBaseInputConnection.setComposingText("opq", -1)).isTrue();
+ verifyContent("opq", 0, 0, 0, 3);
+ }
+
+ @Test
+ public void testSetComposingText_toEditorWithSelection() {
+ // before set composing text: "|abc|"
+ // after set composing text: "defgh|"
+ // -----
+ prepareContent("abc", 0, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("defgh", 1)).isTrue();
+ verifyContent("defgh", 5, 5, 0, 5);
+
+ // before set composing text: "a|bcdef|g"
+ // after set composing text: "a|123g"
+ // ---
+ prepareContent("abcdefg", 1, 6, -1, -1);
+ assertThat(mBaseInputConnection.setComposingText("123", 0)).isTrue();
+ verifyContent("a123g", 1, 1, 1, 4);
+
+ // before set composing text: "a|bcdef|g"
+ // ---
+ // after set composing text: "ab123456|fg"
+ // ------
+ prepareContent("abcdefg", 1, 6, 2, 5);
+ assertThat(mBaseInputConnection.setComposingText("123456", 1)).isTrue();
+ verifyContent("ab123456fg", 8, 8, 2, 8);
+
+ // before set composing text: "a|bc"
+ // ----
+ // after set composing text: "|12345"
+ // -----
+ prepareContent("abc", 1, 1, 0, 3);
+ assertThat(mBaseInputConnection.setComposingText("12345", -1)).isTrue();
+ verifyContent("12345", 0, 0, 0, 5);
+ }
+
+ @Test
+ public void testSetComposingRegion_toEditorWithoutSelectionAndComposing() {
+ // before set composing region: "|"
+ // after set composing region: "|"
+ assertThat(mBaseInputConnection.setComposingRegion(1, 1)).isTrue();
+ verifyContent("", 0, 0, -1, -1);
+
+ // before set composing region: "abc|"
+ // after set composing region: "abc|"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(0, 3)).isTrue();
+ verifyContent("abc", 3, 3, 0, 3);
+
+ // before set composing region: "abc|"
+ // after set composing region: "abc|"
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(1, 1)).isTrue();
+ verifyContent("abc", 3, 3, -1, -1);
+
+ // before set composing region: "abc|"
+ // after set composing region: "abc|"
+ // -
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(1, 2)).isTrue();
+ verifyContent("abc", 3, 3, 1, 2);
+
+ // before set composing region: "abc|"
+ // after set composing region: "abc|"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(3, 0)).isTrue();
+ verifyContent("abc", 3, 3, 0, 3);
+
+ // before set composing region: "abc|"
+ // after set composing region: "abc|"
+ // ---
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(-100, 100)).isTrue();
+ verifyContent("abc", 3, 3, 0, 3);
+ }
+
+ @Test
+ public void testSetComposingRegion_toEditorWithSelection() {
+ // before set composing region: "|abc|"
+ // after set composing region: "|abc|"
+ // ---
+ prepareContent("abc", 0, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(0, 3)).isTrue();
+ verifyContent("abc", 0, 3, 0, 3);
+
+ // before set composing region: "ab|cd|ef"
+ // after set composing region: "ab|cd|ef"
+ // - -- -
+ prepareContent("abcdef", 2, 4, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(1, 5)).isTrue();
+ verifyContent("abcdef", 2, 4, 1, 5);
+ }
+
+ @Test
+ public void testSetComposingRegion_toEditorWithComposing() {
+ // before set composing region: "abc|"
+ // ---
+ // after set composing region: "abc|"
+ // -
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setComposingRegion(1, 2)).isTrue();
+ verifyContent("abc", 3, 3, 1, 2);
+
+ // before set composing region: "ab|cd|ef"
+ // --
+ // after set composing region: "ab|cd|ef"
+ // - -- -
+ prepareContent("abcdef", 2, 4, 2, 4);
+ assertThat(mBaseInputConnection.setComposingRegion(1, 5)).isTrue();
+ verifyContent("abcdef", 2, 4, 1, 5);
+ }
+
+ @Test
+ public void testSetSelection_toEditorWithoutComposing() {
+ // before set selection: "|"
+ // after set selection: "|"
+ assertThat(mBaseInputConnection.setSelection(0, 0)).isTrue();
+ assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+ assertThat(mBaseInputConnection.setSelection(-1, -1)).isTrue();
+
+ // before set selection: "abc|"
+ // after set selection: "a|b|c"
+ prepareContent("abc", 3, 3, -1, -1);
+ assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+ verifyContent("abc", 1, 1, -1, -1);
+
+ // before set selection: "abcdef|"
+ // after set selection: "ab|cd|ef"
+ prepareContent("abcdef", 6, 6, -1, -1);
+ assertThat(mBaseInputConnection.setSelection(4, 2)).isTrue();
+ verifyContent("abcdef", 4, 2, -1, -1);
+
+ // before set selection: "|abc"
+ // after set selection: "|abc"
+ prepareContent("abc", 0, 0, -1, -1);
+ assertThat(mBaseInputConnection.setSelection(0, 100)).isTrue();
+ verifyContent("abc", 0, 0, -1, -1);
+
+ // before set selection: "|abc"
+ // after set selection: "ab|c"
+ prepareContent("abc", 0, 0, -1, -1);
+ assertThat(mBaseInputConnection.setSelection(2, 2)).isTrue();
+ verifyContent("abc", 2, 2, -1, -1);
+
+ // before set selection: "|abc"
+ // after set selection: "|abc"
+ prepareContent("abc", 0, 0, -1, -1);
+ assertThat(mBaseInputConnection.setSelection(-1, 2)).isTrue();
+ verifyContent("abc", 0, 0, -1, -1);
+ }
+
+ @Test
+ public void testSetSelection_toEditorWithComposing() {
+ // before set selection: "abc|"
+ // ---
+ // after set selection: "a|bc"
+ // - --
+ prepareContent("abc", 3, 3, 0, 3);
+ assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+ verifyContent("abc", 1, 1, 0, 3);
+
+ // before set selection: "abcdef|"
+ // ---
+ // after set selection: "|abcdef|"
+ // ---
+ prepareContent("abcdef", 6, 6, 2, 5);
+ assertThat(mBaseInputConnection.setSelection(0, 6)).isTrue();
+ verifyContent("abcdef", 0, 6, 2, 5);
+ }
+
+ @Test
+ public void testGetText_noStyle() {
+ // "123|456|789"
+ prepareContent("123456789", 3, 6, -1, -1);
+
+ verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(1, 0), "3");
+ verifyContentEquals(mBaseInputConnection.getTextAfterCursor(1, 0), "7");
+ verifyContentEquals(mBaseInputConnection.getSelectedText(0), "456");
+ // This falls back to default implementation in {@code InputConnection}, which always return
+ // -1 for offset.
+ assertThat(
+ mBaseInputConnection
+ .getSurroundingText(1, 1, 0)
+ .isEqualTo(new SurroundingText("34567", 1, 4, -1)))
+ .isTrue();
+
+ verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(100, 0), "123");
+ verifyContentEquals(mBaseInputConnection.getTextAfterCursor(100, 0), "789");
+ assertThat(
+ mBaseInputConnection
+ .getSurroundingText(100, 100, 0)
+ .isEqualTo(new SurroundingText("123456789", 3, 6, -1)))
+ .isTrue();
+
+ verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(0, 0), "");
+ verifyContentEquals(mBaseInputConnection.getTextAfterCursor(0, 0), "");
+ assertThat(
+ mBaseInputConnection
+ .getSurroundingText(0, 0, 0)
+ .isEqualTo(new SurroundingText("456", 0, 3, -1)))
+ .isTrue();
+
+ int cursorCapsMode =
+ TextUtils.getCapsMode(
+ "123456789",
+ 3,
+ TextUtils.CAP_MODE_CHARACTERS
+ | TextUtils.CAP_MODE_WORDS
+ | TextUtils.CAP_MODE_SENTENCES);
+ TextSnapshot expectedTextSnapshot =
+ new TextSnapshot(
+ new SurroundingText("123456789", 3, 6, -1), -1, -1, cursorCapsMode);
+ verifyTextSnapshotContentEquals(mBaseInputConnection.takeSnapshot(), expectedTextSnapshot);
+ }
+
+ @Test
+ public void testGetText_withStyle() {
+ // "123|456|789"
+ SpannableStringBuilder text = new SpannableStringBuilder("123456789");
+ SuggestionSpan suggestionSpanA =
+ new SuggestionSpan(Locale.US, new String[] {"a"}, SuggestionSpan.FLAG_EASY_CORRECT);
+ SuggestionSpan suggestionSpanB =
+ new SuggestionSpan(Locale.US, new String[] {"b"}, SuggestionSpan.FLAG_EASY_CORRECT);
+ SuggestionSpan suggestionSpanC =
+ new SuggestionSpan(Locale.US, new String[] {"c"}, SuggestionSpan.FLAG_EASY_CORRECT);
+ text.setSpan(suggestionSpanA, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(suggestionSpanB, 3, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(suggestionSpanC, 6, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ prepareContent(text, 3, 6, -1, -1);
+
+ verifySpannableString(
+ mBaseInputConnection.getTextBeforeCursor(1, InputConnection.GET_TEXT_WITH_STYLES),
+ "3",
+ 1,
+ new int[][] {new int[] {0, 1}},
+ new Object[] {suggestionSpanA});
+ verifySpannableString(
+ mBaseInputConnection.getTextAfterCursor(1, InputConnection.GET_TEXT_WITH_STYLES),
+ "7",
+ 1,
+ new int[][] {new int[] {0, 1}},
+ new Object[] {suggestionSpanC});
+ verifySpannableString(
+ mBaseInputConnection.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES),
+ "456",
+ 1,
+ new int[][] {new int[] {0, 3}},
+ new Object[] {suggestionSpanB});
+ CharSequence surroundTextString =
+ TextUtils.concat(
+ text.subSequence(0, 3), text.subSequence(3, 6), text.subSequence(6, 9));
+ assertThat(
+ mBaseInputConnection
+ .getSurroundingText(100, 100, InputConnection.GET_TEXT_WITH_STYLES)
+ .isEqualTo(new SurroundingText(surroundTextString, 3, 6, -1)))
+ .isTrue();
+
+ int cursorCapsMode =
+ TextUtils.getCapsMode(
+ "123456789",
+ 3,
+ TextUtils.CAP_MODE_CHARACTERS
+ | TextUtils.CAP_MODE_WORDS
+ | TextUtils.CAP_MODE_SENTENCES);
+ TextSnapshot expectedTextSnapshot =
+ new TextSnapshot(
+ new SurroundingText(surroundTextString, 3, 6, -1), -1, -1, cursorCapsMode);
+ verifyTextSnapshotContentEquals(mBaseInputConnection.takeSnapshot(), expectedTextSnapshot);
+ }
+
+ private void prepareContent(
+ CharSequence text,
+ int selectionStart,
+ int selectionEnd,
+ int composingSpanStart,
+ int composingSpanEnd) {
+ mEditable.clear();
+ mEditable.append(text);
+ Selection.setSelection(mEditable, selectionStart, selectionEnd);
+ if (isValidComposingSpan(text.length(), composingSpanStart, composingSpanEnd)) {
+ BaseInputConnection.setComposingSpans(mEditable, composingSpanStart, composingSpanEnd);
+ }
+ verifyContent(text, selectionStart, selectionEnd, composingSpanStart, composingSpanEnd);
+ }
+
+ private boolean isValidComposingSpan(
+ int textLength, int composingSpanStart, int composingSpanEnd) {
+ return composingSpanStart >= 0
+ && composingSpanStart <= textLength
+ && composingSpanEnd >= 0
+ && composingSpanEnd <= textLength;
+ }
+
+ private void verifyContent(
+ CharSequence text,
+ int selectionStart,
+ int selectionEnd,
+ int composingSpanStart,
+ int composingSpanEnd) {
+ assertThat(mEditable).isNotNull();
+ verifyContentEquals(mEditable, text.toString());
+ assertThat(Selection.getSelectionStart(mEditable)).isEqualTo(selectionStart);
+ assertThat(Selection.getSelectionEnd(mEditable)).isEqualTo(selectionEnd);
+ assertThat(BaseInputConnection.getComposingSpanStart(mEditable))
+ .isEqualTo(composingSpanStart);
+ assertThat(BaseInputConnection.getComposingSpanEnd(mEditable)).isEqualTo(composingSpanEnd);
+ }
+
+ private void verifySpannableString(
+ CharSequence text,
+ String expectedString,
+ int expectedSpanSize,
+ int[][] expectedSpanRanges,
+ Object[] expectedSpans) {
+ verifyContentEquals(text, expectedString);
+ SpannableStringBuilder spannableString = new SpannableStringBuilder(text);
+ Object[] spanList = spannableString.getSpans(0, text.length(), Object.class);
+ assertThat(spanList).isNotNull();
+ assertThat(spanList).hasLength(expectedSpanSize);
+ for (int i = 0; i < expectedSpanSize; i++) {
+ assertThat(spannableString.getSpanStart(spanList[i]))
+ .isEqualTo(expectedSpanRanges[i][0]);
+ assertThat(spannableString.getSpanEnd(spanList[i])).isEqualTo(expectedSpanRanges[i][1]);
+ }
+ for (int i = 0; i < expectedSpanSize; i++) {
+ assertThat(spanList[i]).isEqualTo(expectedSpans[i]);
+ }
+ }
+
+ private void verifyContentEquals(CharSequence text, String expectedText) {
+ assertThat(text.toString().contentEquals(expectedText)).isTrue();
+ }
+
+ private void verifyTextSnapshotContentEquals(TextSnapshot t1, TextSnapshot t2) {
+ assertThat(t1.getCompositionStart()).isEqualTo(t2.getCompositionStart());
+ assertThat(t1.getCompositionEnd()).isEqualTo(t2.getCompositionEnd());
+ assertThat(t1.getCursorCapsMode()).isEqualTo(t2.getCursorCapsMode());
+ assertThat(t1.getSurroundingText().isEqualTo(t2.getSurroundingText())).isTrue();
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java b/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
index 50ce335..047f330 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
@@ -16,18 +16,21 @@
package android.view.inputmethod;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertFalse;
+import static com.google.common.truth.Truth.assertThat;
import android.os.Parcel;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.SuggestionSpan;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Locale;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SurroundingTextTest {
@@ -35,22 +38,22 @@
@Test
public void testSurroundingTextBasicCreation() {
SurroundingText surroundingText1 = new SurroundingText("test", 0, 0, 0);
- assertThat(surroundingText1.getText(), is("test"));
- assertThat(surroundingText1.getSelectionStart(), is(0));
- assertThat(surroundingText1.getSelectionEnd(), is(0));
- assertThat(surroundingText1.getOffset(), is(0));
+ assertThat(surroundingText1.getText().toString()).isEqualTo("test");
+ assertThat(surroundingText1.getSelectionStart()).isEqualTo(0);
+ assertThat(surroundingText1.getSelectionEnd()).isEqualTo(0);
+ assertThat(surroundingText1.getOffset()).isEqualTo(0);
SurroundingText surroundingText2 = new SurroundingText("", -1, -1, -1);
- assertThat(surroundingText2.getText(), is(""));
- assertThat(surroundingText2.getSelectionStart(), is(-1));
- assertThat(surroundingText2.getSelectionEnd(), is(-1));
- assertThat(surroundingText2.getOffset(), is(-1));
+ assertThat(surroundingText2.getText().toString()).isEmpty();
+ assertThat(surroundingText2.getSelectionStart()).isEqualTo(-1);
+ assertThat(surroundingText2.getSelectionEnd()).isEqualTo(-1);
+ assertThat(surroundingText2.getOffset()).isEqualTo(-1);
SurroundingText surroundingText3 = new SurroundingText("hello", 0, 5, 0);
- assertThat(surroundingText3.getText(), is("hello"));
- assertThat(surroundingText3.getSelectionStart(), is(0));
- assertThat(surroundingText3.getSelectionEnd(), is(5));
- assertThat(surroundingText3.getOffset(), is(0));
+ assertThat(surroundingText3.getText().toString()).isEqualTo("hello");
+ assertThat(surroundingText3.getSelectionStart()).isEqualTo(0);
+ assertThat(surroundingText3.getSelectionEnd()).isEqualTo(5);
+ assertThat(surroundingText3.getOffset()).isEqualTo(0);
}
@Test
@@ -62,20 +65,73 @@
parcel.setDataPosition(0);
SurroundingText surroundingTextFromParcel =
SurroundingText.CREATOR.createFromParcel(parcel);
- assertThat(surroundingText.getText(), is("text"));
- assertThat(surroundingText.getSelectionStart(), is(0));
- assertThat(surroundingText.getSelectionEnd(), is(1));
- assertThat(surroundingText.getOffset(), is(2));
- assertThat(surroundingTextFromParcel.getText(), is("text"));
- assertThat(surroundingTextFromParcel.getSelectionStart(), is(0));
- assertThat(surroundingTextFromParcel.getSelectionEnd(), is(1));
- assertThat(surroundingTextFromParcel.getOffset(), is(2));
+ assertThat(surroundingText.getText().toString()).isEqualTo("text");
+ assertThat(surroundingText.getSelectionStart()).isEqualTo(0);
+ assertThat(surroundingText.getSelectionEnd()).isEqualTo(1);
+ assertThat(surroundingText.getOffset()).isEqualTo(2);
+ assertThat(surroundingTextFromParcel.getText().toString()).isEqualTo("text");
+ assertThat(surroundingTextFromParcel.getSelectionStart()).isEqualTo(0);
+ assertThat(surroundingTextFromParcel.getSelectionEnd()).isEqualTo(1);
+ assertThat(surroundingTextFromParcel.getOffset()).isEqualTo(2);
}
@Test
- public void testIsEqualComparesText() {
- final SurroundingText text1 = new SurroundingText("hello", 0, 1, 0);
- final SurroundingText text2 = new SurroundingText("there", 0, 1, 0);
- assertFalse(text1.isEqualTo(text2));
+ public void testIsEqualComparesText_isNotEqualTo() {
+ final SurroundingText text = new SurroundingText("hello", 0, 1, 0);
+
+ verifySurroundingTextNotEquals(text, new SurroundingText("there", 0, 1, 0));
+ verifySurroundingTextNotEquals(text, new SurroundingText("hello", 0, 1, -1));
+ verifySurroundingTextNotEquals(text, new SurroundingText("hello", 0, 0, 0));
+ verifySurroundingTextNotEquals(text, new SurroundingText("hello", 1, 1, 0));
+
+ SpannableString spannableString = new SpannableString("hello");
+ spannableString.setSpan(
+ new SuggestionSpan(
+ Locale.US, new String[] {"Hello"}, SuggestionSpan.FLAG_EASY_CORRECT),
+ 0,
+ 5,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ verifySurroundingTextNotEquals(text, new SurroundingText(spannableString, 1, 1, 0));
+ }
+
+ private void verifySurroundingTextNotEquals(SurroundingText text1, SurroundingText text2) {
+ assertThat(text1.isEqualTo(text2)).isFalse();
+ assertThat(text1).isNotEqualTo(text2);
+ assertThat(text1.equals(text2)).isFalse();
+ assertThat(text1.hashCode()).isNotEqualTo(text2.hashCode());
+ assertThat(text1 == text2).isFalse();
+ }
+
+ @Test
+ public void testIsEqualComparesText_isEqualTo() {
+ final SurroundingText text = new SurroundingText("hello", 0, 1, 0);
+
+ verifySurroundingTextEquals(
+ text,
+ new SurroundingText("hello", 0, 1, 0),
+ /*equals=*/ false,
+ /*isSameInstance=*/ false);
+ verifySurroundingTextEquals(text, text, /*equals=*/ true, /*isSameInstance=*/ true);
+ }
+
+ private void verifySurroundingTextEquals(
+ SurroundingText text1, SurroundingText text2, boolean equals, boolean isSameInstance) {
+ assertThat(text1.isEqualTo(text2)).isTrue();
+ if (equals) {
+ assertThat(text1).isEqualTo(text2);
+ assertThat(text1.equals(text2)).isTrue();
+ assertThat(text1.hashCode()).isEqualTo(text2.hashCode());
+ } else {
+ assertThat(text1).isNotEqualTo(text2);
+ assertThat(text1.equals(text2)).isFalse();
+ assertThat(text1.hashCode()).isNotEqualTo(text2.hashCode());
+ }
+ if (isSameInstance) {
+ assertThat(text1 == text2).isTrue();
+ assertThat(text1).isSameInstanceAs(text2);
+ } else {
+ assertThat(text1 == text2).isFalse();
+ assertThat(text1).isNotSameInstanceAs(text2);
+ }
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 6af3d2b..126f835 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -139,6 +139,16 @@
}
}
+ @Override
+ public void setSplitAttributesCalculator(@NonNull SplitAttributesCalculator calculator) {
+ // TODO: Implement this method
+ }
+
+ @Override
+ public void clearSplitAttributesCalculator() {
+ // TODO: Implement this method
+ }
+
@NonNull
List<EmbeddingRule> getSplitRules() {
return mSplitRules;
@@ -1516,13 +1526,20 @@
.toActivityStack();
final ActivityStack secondaryContainer = container.getSecondaryContainer()
.toActivityStack();
+ final SplitAttributes.SplitType splitType = shouldShowSideBySide(container)
+ ? new SplitAttributes.SplitType.RatioSplitType(
+ container.getSplitRule().getSplitRatio())
+ : new SplitAttributes.SplitType.ExpandContainersSplitType();
final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
// Splits that are not showing side-by-side are reported as having 0 split
// ratio, since by definition in the API the primary container occupies no
// width of the split when covered by the secondary.
- shouldShowSideBySide(container)
- ? container.getSplitRule().getSplitRatio()
- : 0.0f);
+ // TODO(b/241042437): use v2 APIs for splitAttributes
+ new SplitAttributes.Builder()
+ .setSplitType(splitType)
+ .setLayoutDirection(container.getSplitRule().getLayoutDirection())
+ .build()
+ );
splitStates.add(splitState);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index cdee9e3..af5d8c5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -16,7 +16,6 @@
package androidx.window.extensions.embedding;
-import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
@@ -41,30 +40,44 @@
*/
private static final int LAYER_NO_OVERRIDE = -1;
+ @NonNull
final Animation mAnimation;
+ @NonNull
final RemoteAnimationTarget mTarget;
+ @NonNull
final SurfaceControl mLeash;
+ /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
+ @NonNull
+ private final Rect mWholeAnimationBounds = new Rect();
+ @NonNull
final Transformation mTransformation = new Transformation();
+ @NonNull
final float[] mMatrix = new float[9];
+ @NonNull
final float[] mVecs = new float[4];
+ @NonNull
final Rect mRect = new Rect();
private boolean mIsFirstFrame = true;
private int mOverrideLayer = LAYER_NO_OVERRIDE;
TaskFragmentAnimationAdapter(@NonNull Animation animation,
@NonNull RemoteAnimationTarget target) {
- this(animation, target, target.leash);
+ this(animation, target, target.leash, target.screenSpaceBounds);
}
/**
* @param leash the surface to animate.
+ * @param wholeAnimationBounds area in absolute coordinate that the animation surface shouldn't
+ * go beyond.
*/
TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash) {
+ @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
+ @NonNull Rect wholeAnimationBounds) {
mAnimation = animation;
mTarget = target;
mLeash = leash;
+ mWholeAnimationBounds.set(wholeAnimationBounds);
}
/**
@@ -94,23 +107,32 @@
/** To be overridden by subclasses to adjust the animation surface change. */
void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Update the surface position and alpha.
mTransformation.getMatrix().postTranslate(
mTarget.localBounds.left, mTarget.localBounds.top);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
- // Get current animation position.
+
+ // Get current surface bounds in absolute coordinate.
+ // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
final int positionX = Math.round(mMatrix[MTRANS_X]);
final int positionY = Math.round(mMatrix[MTRANS_Y]);
- // The exiting surface starts at position: mTarget.localBounds and moves with
- // positionX varying. Offset our crop region by the amount we have slided so crop
- // regions stays exactly on the original container in split.
- final int cropOffsetX = mTarget.localBounds.left - positionX;
- final int cropOffsetY = mTarget.localBounds.top - positionY;
- final Rect cropRect = new Rect();
- cropRect.set(mTarget.localBounds);
- // Because window crop uses absolute position.
- cropRect.offsetTo(0, 0);
- cropRect.offset(cropOffsetX, cropOffsetY);
+ final Rect cropRect = new Rect(mTarget.screenSpaceBounds);
+ final Rect localBounds = mTarget.localBounds;
+ cropRect.offset(positionX - localBounds.left, positionY - localBounds.top);
+
+ // Store the current offset of the surface top left from (0,0) in absolute coordinate.
+ final int offsetX = cropRect.left;
+ final int offsetY = cropRect.top;
+
+ // Intersect to make sure the animation happens within the whole animation bounds.
+ if (!cropRect.intersect(mWholeAnimationBounds)) {
+ // Hide the surface when it is outside of the animation area.
+ t.setAlpha(mLeash, 0);
+ }
+
+ // cropRect is in absolute coordinate, so we need to translate it to surface top left.
+ cropRect.offset(-offsetX, -offsetY);
t.setCrop(mLeash, cropRect);
}
@@ -124,52 +146,6 @@
}
/**
- * Should be used when the {@link RemoteAnimationTarget} is in split with others, and want to
- * animate together as one. This adapter will offset the animation leash to make the animate of
- * two windows look like a single window.
- */
- static class SplitAdapter extends TaskFragmentAnimationAdapter {
- private final boolean mIsLeftHalf;
- private final int mWholeAnimationWidth;
-
- /**
- * @param isLeftHalf whether this is the left half of the animation.
- * @param wholeAnimationWidth the whole animation windows width.
- */
- SplitAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target,
- boolean isLeftHalf, int wholeAnimationWidth) {
- super(animation, target);
- mIsLeftHalf = isLeftHalf;
- mWholeAnimationWidth = wholeAnimationWidth;
- if (wholeAnimationWidth == 0) {
- throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
- }
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- float posX = mTarget.localBounds.left;
- final float posY = mTarget.localBounds.top;
- // This window is half of the whole animation window. Offset left/right to make it
- // look as one with the other half.
- mTransformation.getMatrix().getValues(mMatrix);
- final int targetWidth = mTarget.localBounds.width();
- final float scaleX = mMatrix[MSCALE_X];
- final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
- final float curOffset = targetWidth * (1 - scaleX) / 2;
- final float offsetDiff = totalOffset - curOffset;
- if (mIsLeftHalf) {
- posX += offsetDiff;
- } else {
- posX -= offsetDiff;
- }
- mTransformation.getMatrix().postTranslate(posX, posY);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
- }
- }
-
- /**
* Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
* size change.
*/
@@ -177,7 +153,7 @@
SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
// Start leash is the snapshot of the starting surface.
- super(animation, target, target.startLeash);
+ super(animation, target, target.startLeash, target.screenSpaceBounds);
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 8af2d9c..8c416e8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -213,10 +213,10 @@
for (RemoteAnimationTarget target : targets) {
if (target.mode != MODE_CLOSING) {
openingTargets.add(target);
- openingWholeScreenBounds.union(target.localBounds);
+ openingWholeScreenBounds.union(target.screenSpaceBounds);
} else {
closingTargets.add(target);
- closingWholeScreenBounds.union(target.localBounds);
+ closingWholeScreenBounds.union(target.screenSpaceBounds);
}
}
@@ -249,20 +249,8 @@
@NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
@NonNull Rect wholeAnimationBounds) {
final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
- final Rect targetBounds = target.localBounds;
- if (targetBounds.left == wholeAnimationBounds.left
- && targetBounds.right != wholeAnimationBounds.right) {
- // This is the left split of the whole animation window.
- return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
- true /* isLeftHalf */, wholeAnimationBounds.width());
- } else if (targetBounds.left != wholeAnimationBounds.left
- && targetBounds.right == wholeAnimationBounds.right) {
- // This is the right split of the whole animation window.
- return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
- false /* isLeftHalf */, wholeAnimationBounds.width());
- }
- // Open/close window that fills the whole animation.
- return new TaskFragmentAnimationAdapter(animation, target);
+ return new TaskFragmentAnimationAdapter(animation, target, target.leash,
+ wholeAnimationBounds);
}
@NonNull
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 97d42391b..ef5ea56 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -195,7 +195,10 @@
? com.android.internal.R.anim.task_fragment_open_enter
: com.android.internal.R.anim.task_fragment_open_exit);
}
- animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are opening at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are launching together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
wholeAnimationBounds.width(), wholeAnimationBounds.height());
animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
return animation;
@@ -215,7 +218,10 @@
? com.android.internal.R.anim.task_fragment_close_enter
: com.android.internal.R.anim.task_fragment_close_exit);
}
- animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are closing at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are finishing together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
wholeAnimationBounds.width(), wholeAnimationBounds.height());
animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
return animation;
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index e9a1721..2c766d8 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index cc4db93..591e347 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.activityembedding;
-import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
@@ -42,31 +41,45 @@
*/
private static final int LAYER_NO_OVERRIDE = -1;
+ @NonNull
final Animation mAnimation;
+ @NonNull
final TransitionInfo.Change mChange;
+ @NonNull
final SurfaceControl mLeash;
+ /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
+ @NonNull
+ private final Rect mWholeAnimationBounds = new Rect();
+ @NonNull
final Transformation mTransformation = new Transformation();
+ @NonNull
final float[] mMatrix = new float[9];
+ @NonNull
final float[] mVecs = new float[4];
+ @NonNull
final Rect mRect = new Rect();
private boolean mIsFirstFrame = true;
private int mOverrideLayer = LAYER_NO_OVERRIDE;
ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
@NonNull TransitionInfo.Change change) {
- this(animation, change, change.getLeash());
+ this(animation, change, change.getLeash(), change.getEndAbsBounds());
}
/**
* @param leash the surface to animate, which is not necessary the same as
- * {@link TransitionInfo.Change#getLeash()}, it can be a screenshot for example.
+ * {@link TransitionInfo.Change#getLeash()}, it can be a screenshot for example.
+ * @param wholeAnimationBounds area in absolute coordinate that the animation surface shouldn't
+ * go beyond.
*/
ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
- @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash) {
+ @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash,
+ @NonNull Rect wholeAnimationBounds) {
mAnimation = animation;
mChange = change;
mLeash = leash;
+ mWholeAnimationBounds.set(wholeAnimationBounds);
}
/**
@@ -96,23 +109,31 @@
/** To be overridden by subclasses to adjust the animation surface change. */
void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Update the surface position and alpha.
final Point offset = mChange.getEndRelOffset();
mTransformation.getMatrix().postTranslate(offset.x, offset.y);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
- // Get current animation position.
+
+ // Get current surface bounds in absolute coordinate.
+ // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
final int positionX = Math.round(mMatrix[MTRANS_X]);
final int positionY = Math.round(mMatrix[MTRANS_Y]);
- // The exiting surface starts at position: Change#getEndRelOffset() and moves with
- // positionX varying. Offset our crop region by the amount we have slided so crop
- // regions stays exactly on the original container in split.
- final int cropOffsetX = offset.x - positionX;
- final int cropOffsetY = offset.y - positionY;
- final Rect cropRect = new Rect();
- cropRect.set(mChange.getEndAbsBounds());
- // Because window crop uses absolute position.
- cropRect.offsetTo(0, 0);
- cropRect.offset(cropOffsetX, cropOffsetY);
+ final Rect cropRect = new Rect(mChange.getEndAbsBounds());
+ cropRect.offset(positionX - offset.x, positionY - offset.y);
+
+ // Store the current offset of the surface top left from (0,0) in absolute coordinate.
+ final int offsetX = cropRect.left;
+ final int offsetY = cropRect.top;
+
+ // Intersect to make sure the animation happens within the whole animation bounds.
+ if (!cropRect.intersect(mWholeAnimationBounds)) {
+ // Hide the surface when it is outside of the animation area.
+ t.setAlpha(mLeash, 0);
+ }
+
+ // cropRect is in absolute coordinate, so we need to translate it to surface top left.
+ cropRect.offset(-offsetX, -offsetY);
t.setCrop(mLeash, cropRect);
}
@@ -127,53 +148,6 @@
}
/**
- * Should be used when the {@link TransitionInfo.Change} is in split with others, and wants to
- * animate together as one. This adapter will offset the animation leash to make the animate of
- * two windows look like a single window.
- */
- static class SplitAdapter extends ActivityEmbeddingAnimationAdapter {
- private final boolean mIsLeftHalf;
- private final int mWholeAnimationWidth;
-
- /**
- * @param isLeftHalf whether this is the left half of the animation.
- * @param wholeAnimationWidth the whole animation windows width.
- */
- SplitAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
- boolean isLeftHalf, int wholeAnimationWidth) {
- super(animation, change);
- mIsLeftHalf = isLeftHalf;
- mWholeAnimationWidth = wholeAnimationWidth;
- if (wholeAnimationWidth == 0) {
- throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
- }
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- final Point offset = mChange.getEndRelOffset();
- float posX = offset.x;
- final float posY = offset.y;
- // This window is half of the whole animation window. Offset left/right to make it
- // look as one with the other half.
- mTransformation.getMatrix().getValues(mMatrix);
- final int changeWidth = mChange.getEndAbsBounds().width();
- final float scaleX = mMatrix[MSCALE_X];
- final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
- final float curOffset = changeWidth * (1 - scaleX) / 2;
- final float offsetDiff = totalOffset - curOffset;
- if (mIsLeftHalf) {
- posX += offsetDiff;
- } else {
- posX -= offsetDiff;
- }
- mTransformation.getMatrix().postTranslate(posX, posY);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
- }
- }
-
- /**
* Should be used for the animation of the snapshot of a {@link TransitionInfo.Change} that has
* size change.
*/
@@ -181,7 +155,7 @@
SnapshotAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
@NonNull SurfaceControl snapshotLeash) {
- super(animation, change, snapshotLeash);
+ super(animation, change, snapshotLeash, change.getEndAbsBounds());
}
@Override
@@ -196,7 +170,9 @@
void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
super.onAnimationEnd(t);
// Remove the screenshot leash after animation is finished.
- t.remove(mLeash);
+ if (mLeash.isValid()) {
+ t.remove(mLeash);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 7e0795d..d88cc00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -22,9 +22,9 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.util.ArraySet;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.animation.Animation;
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.function.BiFunction;
/** To run the ActivityEmbedding animations. */
@@ -169,15 +170,12 @@
final Rect openingWholeScreenBounds = new Rect();
final Rect closingWholeScreenBounds = new Rect();
for (TransitionInfo.Change change : info.getChanges()) {
- final Rect bounds = new Rect(change.getEndAbsBounds());
- final Point offset = change.getEndRelOffset();
- bounds.offsetTo(offset.x, offset.y);
if (Transitions.isOpeningType(change.getMode())) {
openingChanges.add(change);
- openingWholeScreenBounds.union(bounds);
+ openingWholeScreenBounds.union(change.getEndAbsBounds());
} else {
closingChanges.add(change);
- closingWholeScreenBounds.union(bounds);
+ closingWholeScreenBounds.union(change.getEndAbsBounds());
}
}
@@ -210,60 +208,73 @@
@NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
@NonNull Rect wholeAnimationBounds) {
final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
- final Rect bounds = new Rect(change.getEndAbsBounds());
- final Point offset = change.getEndRelOffset();
- bounds.offsetTo(offset.x, offset.y);
- if (bounds.left == wholeAnimationBounds.left
- && bounds.right != wholeAnimationBounds.right) {
- // This is the left split of the whole animation window.
- return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
- true /* isLeftHalf */, wholeAnimationBounds.width());
- } else if (bounds.left != wholeAnimationBounds.left
- && bounds.right == wholeAnimationBounds.right) {
- // This is the right split of the whole animation window.
- return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
- false /* isLeftHalf */, wholeAnimationBounds.width());
- }
- // Open/close window that fills the whole animation.
- return new ActivityEmbeddingAnimationAdapter(animation, change);
+ return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
+ wholeAnimationBounds);
}
@NonNull
private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters(
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
+ final Set<TransitionInfo.Change> handledChanges = new ArraySet<>();
+
+ // For the first iteration, we prepare the animation for the change type windows. This is
+ // needed because there may be window that is reparented while resizing. In such case, we
+ // will do the following:
+ // 1. Capture a screenshot from the Activity surface.
+ // 2. Attach the screenshot surface to the top of TaskFragment (Activity's parent) surface.
+ // 3. Animate the TaskFragment using Activity Change info (start/end bounds).
+ // This is because the TaskFragment surface/change won't contain the Activity's before its
+ // reparent.
for (TransitionInfo.Change change : info.getChanges()) {
- if (change.getMode() == TRANSIT_CHANGE
- && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
- // This is the window with bounds change.
- final WindowContainerToken parentToken = change.getParent();
- final Rect parentBounds;
- if (parentToken != null) {
- TransitionInfo.Change parentChange = info.getChange(parentToken);
- parentBounds = parentChange != null
- ? parentChange.getEndAbsBounds()
- : change.getEndAbsBounds();
- } else {
- parentBounds = change.getEndAbsBounds();
- }
- final Animation[] animations =
- mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds);
- // Adapter for the starting screenshot leash.
- final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction);
- if (screenshotLeash != null) {
- // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
- adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
- animations[0], change, screenshotLeash));
- } else {
- Log.e(TAG, "Failed to take screenshot for change=" + change);
- }
- // Adapter for the ending bounds changed leash.
- adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
- animations[1], change));
+ if (change.getMode() != TRANSIT_CHANGE
+ || change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
continue;
}
- // These are the other windows that don't have bounds change in the same transition.
+ // This is the window with bounds change.
+ handledChanges.add(change);
+ final WindowContainerToken parentToken = change.getParent();
+ TransitionInfo.Change boundsAnimationChange = change;
+ if (parentToken != null) {
+ // When the parent window is also included in the transition as an opening window,
+ // we would like to animate the parent window instead.
+ final TransitionInfo.Change parentChange = info.getChange(parentToken);
+ if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) {
+ // We won't create a separate animation for the parent, but to animate the
+ // parent for the child resizing.
+ handledChanges.add(parentChange);
+ boundsAnimationChange = parentChange;
+ }
+ }
+
+ final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
+ boundsAnimationChange.getEndAbsBounds());
+
+ // Create a screenshot based on change, but attach it to the top of the
+ // boundsAnimationChange.
+ final SurfaceControl screenshotLeash = getOrCreateScreenshot(change,
+ boundsAnimationChange, startTransaction);
+ if (screenshotLeash != null) {
+ // Adapter for the starting screenshot leash.
+ // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
+ adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
+ animations[0], change, screenshotLeash));
+ } else {
+ Log.e(TAG, "Failed to take screenshot for change=" + change);
+ }
+ // Adapter for the ending bounds changed leash.
+ adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
+ animations[1], boundsAnimationChange));
+ }
+
+ // Handle the other windows that don't have bounds change in the same transition.
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (handledChanges.contains(change)) {
+ // Skip windows that we have already handled in the previous iteration.
+ continue;
+ }
+
final Animation animation;
if (!TransitionInfo.isIndependent(change, info)) {
// No-op if it will be covered by the changing parent window.
@@ -278,13 +289,27 @@
return adapters;
}
- /** Takes a screenshot of the given {@link TransitionInfo.Change} surface. */
+ /**
+ * Takes a screenshot of the given {@code screenshotChange} surface if WM Core hasn't taken one.
+ * The screenshot leash should be attached to the {@code animationChange} surface which we will
+ * animate later.
+ */
@Nullable
- private SurfaceControl createScreenshot(@NonNull TransitionInfo.Change change,
- @NonNull SurfaceControl.Transaction startTransaction) {
- final Rect cropBounds = new Rect(change.getStartAbsBounds());
+ private SurfaceControl getOrCreateScreenshot(@NonNull TransitionInfo.Change screenshotChange,
+ @NonNull TransitionInfo.Change animationChange,
+ @NonNull SurfaceControl.Transaction t) {
+ final SurfaceControl screenshotLeash = screenshotChange.getSnapshot();
+ if (screenshotLeash != null) {
+ // If WM Core has already taken a screenshot, make sure it is reparented to the
+ // animation leash.
+ t.reparent(screenshotLeash, animationChange.getLeash());
+ return screenshotLeash;
+ }
+
+ // If WM Core hasn't taken a screenshot, take a screenshot now.
+ final Rect cropBounds = new Rect(screenshotChange.getStartAbsBounds());
cropBounds.offsetTo(0, 0);
- return ScreenshotUtils.takeScreenshot(startTransaction, change.getLeash(), cropBounds,
- Integer.MAX_VALUE);
+ return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
+ animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 6f06f28..ad0dddf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -185,8 +185,10 @@
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
? R.anim.task_fragment_open_enter
: R.anim.task_fragment_open_exit);
- final Rect bounds = change.getEndAbsBounds();
- animation.initialize(bounds.width(), bounds.height(),
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are opening at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are launching together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
wholeAnimationBounds.width(), wholeAnimationBounds.height());
animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
return animation;
@@ -203,8 +205,10 @@
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
? R.anim.task_fragment_close_enter
: R.anim.task_fragment_close_exit);
- final Rect bounds = change.getEndAbsBounds();
- animation.initialize(bounds.width(), bounds.height(),
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are closing at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are finishing together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
wholeAnimationBounds.width(), wholeAnimationBounds.height());
animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
return animation;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
index c4bd73b..2a1bf0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
@@ -28,7 +28,7 @@
public class ScreenshotUtils {
/**
- * Take a screenshot of the specified SurfaceControl.
+ * Takes a screenshot of the specified SurfaceControl.
*
* @param sc the SurfaceControl to take a screenshot of
* @param crop the crop to use when capturing the screenshot
@@ -49,11 +49,14 @@
SurfaceControl mScreenshot = null;
SurfaceControl.Transaction mTransaction;
SurfaceControl mSurfaceControl;
+ SurfaceControl mParentSurfaceControl;
int mLayer;
- BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) {
+ BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc,
+ int layer) {
mTransaction = t;
mSurfaceControl = sc;
+ mParentSurfaceControl = parentSc;
mLayer = layer;
}
@@ -72,7 +75,7 @@
mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer());
mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
- mTransaction.reparent(mScreenshot, mSurfaceControl);
+ mTransaction.reparent(mScreenshot, mParentSurfaceControl);
mTransaction.setLayer(mScreenshot, mLayer);
mTransaction.show(mScreenshot);
mTransaction.apply();
@@ -80,7 +83,7 @@
}
/**
- * Take a screenshot of the specified SurfaceControl.
+ * Takes a screenshot of the specified SurfaceControl.
*
* @param t the transaction used to set changes on the resulting screenshot.
* @param sc the SurfaceControl to take a screenshot of
@@ -91,7 +94,23 @@
*/
public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
Rect crop, int layer) {
- BufferConsumer consumer = new BufferConsumer(t, sc, layer);
+ return takeScreenshot(t, sc, sc /* parentSc */, crop, layer);
+ }
+
+ /**
+ * Takes a screenshot of the specified SurfaceControl.
+ *
+ * @param t the transaction used to set changes on the resulting screenshot.
+ * @param sc the SurfaceControl to take a screenshot of
+ * @param parentSc the SurfaceControl to attach the screenshot to.
+ * @param crop the crop to use when capturing the screenshot
+ * @param layer the layer to place the screenshot
+ *
+ * @return A SurfaceControl where the screenshot will be attached, or null if failed.
+ */
+ public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
+ SurfaceControl parentSc, Rect crop, int layer) {
+ BufferConsumer consumer = new BufferConsumer(t, sc, parentSc, layer);
captureLayer(sc, crop, consumer);
return consumer.mScreenshot;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 3714fe7..ecdafa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -21,6 +21,7 @@
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
+import com.android.internal.logging.InstanceId;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.window.RemoteTransition;
@@ -67,34 +68,35 @@
* Starts a shortcut in a stage.
*/
oneway void startShortcut(String packageName, String shortcutId, int position,
- in Bundle options, in UserHandle user) = 8;
+ in Bundle options, in UserHandle user, in InstanceId instanceId) = 8;
/**
* Starts an activity in a stage.
*/
oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int position,
- in Bundle options) = 9;
+ in Bundle options, in InstanceId instanceId) = 9;
/**
* Starts tasks simultaneously in one transition.
*/
oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
in Bundle sideOptions, int sidePosition, float splitRatio,
- in RemoteTransition remoteTransition) = 10;
+ in RemoteTransition remoteTransition, in InstanceId instanceId) = 10;
/**
* Version of startTasks using legacy transition system.
*/
oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
int sideTaskId, in Bundle sideOptions, int sidePosition,
- float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+ float splitRatio, in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 11;
/**
* Starts a pair of intent and task using legacy transition system.
*/
oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions,
- int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter) = 12;
+ int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter,
+ in InstanceId instanceId) = 12;
/**
* Blocking call that notifies and gets additional split-screen targets when entering
@@ -115,5 +117,5 @@
*/
oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId,
in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio,
- in RemoteAnimationAdapter adapter) = 15;
+ in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 15;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 9206afb..025e559 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -387,6 +387,17 @@
}
}
+ /**
+ * See {@link #startShortcut(String, String, int, Bundle, UserHandle)}
+ * @param instanceId to be used by {@link SplitscreenEventLogger}
+ */
+ public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
+ @Nullable Bundle options, UserHandle user, @NonNull InstanceId instanceId) {
+ mStageCoordinator.getLogger().enterRequested(instanceId);
+ startShortcut(packageName, shortcutId, position, options, user);
+ }
+
+ @Override
public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
@Nullable Bundle options, UserHandle user) {
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -415,7 +426,6 @@
0 /* duration */, 0 /* statusBarTransitionDelay */);
ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
activityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
-
try {
LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
@@ -425,6 +435,17 @@
}
}
+ /**
+ * See {@link #startIntent(PendingIntent, Intent, int, Bundle)}
+ * @param instanceId to be used by {@link SplitscreenEventLogger}
+ */
+ public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+ @SplitPosition int position, @Nullable Bundle options, @NonNull InstanceId instanceId) {
+ mStageCoordinator.getLogger().enterRequested(instanceId);
+ startIntent(intent, fillInIntent, position, options);
+ }
+
+ @Override
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options) {
if (fillInIntent == null) {
@@ -446,7 +467,6 @@
mStageCoordinator.startIntentLegacy(intent, fillInIntent, position, options);
return;
}
-
mStageCoordinator.startIntent(intent, fillInIntent, position, options);
}
@@ -772,60 +792,64 @@
@Override
public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- float splitRatio, RemoteAnimationAdapter adapter) {
+ float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController, "startTasks",
(controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
- splitRatio, adapter));
+ splitRatio, adapter, instanceId));
}
@Override
public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions,
- int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController,
"startIntentAndTaskWithLegacyTransition", (controller) ->
controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
pendingIntent, fillInIntent, taskId, mainOptions, sideOptions,
- sidePosition, splitRatio, adapter));
+ sidePosition, splitRatio, adapter, instanceId));
}
@Override
public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
- @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController,
"startShortcutAndTaskWithLegacyTransition", (controller) ->
controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
shortcutInfo, taskId, mainOptions, sideOptions, sidePosition,
- splitRatio, adapter));
+ splitRatio, adapter, instanceId));
}
@Override
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition, float splitRatio,
- @Nullable RemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController, "startTasks",
(controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
- sideTaskId, sideOptions, sidePosition, splitRatio, remoteTransition));
+ sideTaskId, sideOptions, sidePosition, splitRatio, remoteTransition,
+ instanceId));
}
@Override
public void startShortcut(String packageName, String shortcutId, int position,
- @Nullable Bundle options, UserHandle user) {
+ @Nullable Bundle options, UserHandle user, InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController, "startShortcut",
(controller) -> {
- controller.startShortcut(packageName, shortcutId, position, options, user);
+ controller.startShortcut(packageName, shortcutId, position, options, user,
+ instanceId);
});
}
@Override
public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
- @Nullable Bundle options) {
+ @Nullable Bundle options, InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController, "startIntent",
(controller) -> {
- controller.startIntent(intent, fillInIntent, position, options);
+ controller.startIntent(intent, fillInIntent, position, options, instanceId);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index 3e7a100..626ccb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -16,7 +16,7 @@
package com.android.wm.shell.splitscreen;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
@@ -59,7 +59,7 @@
// Drag info
private @SplitPosition int mDragEnterPosition;
- private InstanceId mDragEnterSessionId;
+ private InstanceId mEnterSessionId;
// For deduping async events
private int mLastMainStagePosition = -1;
@@ -82,9 +82,17 @@
/**
* May be called before logEnter() to indicate that the session was started from a drag.
*/
- public void enterRequestedByDrag(@SplitPosition int position, InstanceId dragSessionId) {
+ public void enterRequestedByDrag(@SplitPosition int position, InstanceId enterSessionId) {
mDragEnterPosition = position;
- mDragEnterSessionId = dragSessionId;
+ enterRequested(enterSessionId);
+ }
+
+ /**
+ * May be called before logEnter() to indicate that the session was started from launcher.
+ * This specifically is for all the scenarios where split started without a drag interaction
+ */
+ public void enterRequested(InstanceId enterSessionId) {
+ mEnterSessionId = enterSessionId;
}
/**
@@ -97,7 +105,7 @@
mLoggerSessionId = mIdSequence.newInstanceId();
int enterReason = mDragEnterPosition != SPLIT_POSITION_UNDEFINED
? getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape)
- : SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+ : SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
mainStageUid);
updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
@@ -112,7 +120,7 @@
mLastMainStageUid,
mLastSideStagePosition,
mLastSideStageUid,
- mDragEnterSessionId != null ? mDragEnterSessionId.getId() : 0,
+ mEnterSessionId != null ? mEnterSessionId.getId() : 0,
mLoggerSessionId.getId());
}
@@ -176,7 +184,7 @@
// Reset states
mLoggerSessionId = null;
mDragEnterPosition = SPLIT_POSITION_UNDEFINED;
- mDragEnterSessionId = null;
+ mEnterSessionId = null;
mLastMainStagePosition = -1;
mLastMainStageUid = -1;
mLastSideStagePosition = -1;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8ed16ce..946dfde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -69,6 +69,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.IActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
@@ -87,6 +88,7 @@
import android.util.Slog;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -405,6 +407,10 @@
return result;
}
+ SplitscreenEventLogger getLogger() {
+ return mLogger;
+ }
+
/** Launches an activity into split. */
void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
@Nullable Bundle options) {
@@ -497,7 +503,7 @@
/** Starts 2 tasks in one transition. */
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
@Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
- @Nullable RemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mainOptions = mainOptions != null ? mainOptions : new Bundle();
sideOptions = sideOptions != null ? sideOptions : new Bundle();
@@ -526,46 +532,57 @@
mSplitTransitions.startEnterTransition(
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null);
+ setEnterInstanceId(instanceId);
}
/** Starts 2 tasks in one legacy transition. */
void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- float splitRatio, RemoteAnimationAdapter adapter) {
+ float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (sideOptions == null) sideOptions = new Bundle();
addActivityOptions(sideOptions, mSideStage);
wct.startTask(sideTaskId, sideOptions);
- startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter);
+ startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter,
+ instanceId);
}
/** Start an intent and a task ordered by {@code intentFirst}. */
void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
- @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (sideOptions == null) sideOptions = new Bundle();
addActivityOptions(sideOptions, mSideStage);
wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
- startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
+ startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+ instanceId);
}
void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
- @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (sideOptions == null) sideOptions = new Bundle();
addActivityOptions(sideOptions, mSideStage);
wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions);
- startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
+ startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+ instanceId);
}
- private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId,
+ /**
+ * @param instanceId if {@code null}, will not log. Otherwise it will be used in
+ * {@link SplitscreenEventLogger#logEnter(float, int, int, int, int, boolean)}
+ */
+ private void startWithLegacyTransition(WindowContainerTransaction wct, int mainTaskId,
@Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
- RemoteAnimationAdapter adapter) {
+ RemoteAnimationAdapter adapter, InstanceId instanceId) {
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
mSplitLayout.setDivideRatio(splitRatio);
@@ -574,59 +591,56 @@
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = true;
- LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+ prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
+
+ IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@Override
- public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
- IRemoteAnimationFinishedCallback finishedCallback,
- SurfaceControl.Transaction t) {
- if (apps == null || apps.length == 0) {
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- setDividerVisibility(true, t);
- t.apply();
- onRemoteAnimationFinished(apps);
- try {
- adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- return;
- }
-
- // Wrap the divider bar into non-apps target to animate together.
- nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
- getDividerBarLegacyTarget());
-
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- setDividerVisibility(true, t);
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) {
- t.show(apps[i].leash);
- // Reset the surface position of the opening app to prevent double-offset.
- t.setPosition(apps[i].leash, 0, 0);
- }
- }
- t.apply();
-
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ final IRemoteAnimationFinishedCallback finishedCallback) {
IRemoteAnimationFinishedCallback wrapCallback =
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
- onRemoteAnimationFinished(apps);
+ onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct);
finishedCallback.onAnimationFinished();
}
};
Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
try {
- adapter.getRunner().onAnimationStart(
- transit, apps, wallpapers, nonApps, wrapCallback);
+ adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
+ ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+ getDividerBarLegacyTarget()), wrapCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ }
+
+ @Override
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct);
+ try {
+ adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
} catch (RemoteException e) {
Slog.e(TAG, "Error starting remote animation", e);
}
}
};
+ RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
+ wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
- final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mainOptions == null) {
+ mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
+ } else {
+ ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
+ mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+ mainOptions = mainActivityOptions.toBundle();
+ }
+
setSideStagePosition(sidePosition, wct);
if (!mMainStage.isActive()) {
mMainStage.activate(wct, false /* reparent */);
@@ -634,34 +648,40 @@
if (mainOptions == null) mainOptions = new Bundle();
addActivityOptions(mainOptions, mMainStage);
- wct.startTask(mainTaskId, mainOptions);
- wct.merge(sideWct, true);
-
updateWindowBounds(mSplitLayout, wct);
+ wct.startTask(mainTaskId, mainOptions);
wct.reorder(mRootTaskInfo.token, true);
wct.setForceTranslucent(mRootTaskInfo.token, false);
- mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ setDividerVisibility(true, t);
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ });
+
+ setEnterInstanceId(instanceId);
}
- private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
+ private void setEnterInstanceId(InstanceId instanceId) {
+ if (instanceId != null) {
+ mLogger.enterRequested(instanceId);
+ }
+ }
+
+ private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
+ WindowContainerTransaction evictWct) {
mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
- if (apps == null || apps.length == 0) return;
-
- // If any stage has no child after finished animation, that side of the split will display
- // nothing. This might happen if starting the same app on the both sides while not
- // supporting multi-instance. Exit the split screen and expand that app to full screen.
- if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
- mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
- ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
- return;
+ // If any stage has no child after animation finished, it means that split will display
+ // nothing, such status will happen if task and intent is same app but not support
+ // multi-instance, we should exit split and expand that app as full screen.
+ if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
+ mMainExecutor.execute(() ->
+ exitSplitScreen(mMainStage.getChildCount() == 0
+ ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ } else {
+ mSyncQueue.queue(evictWct);
}
-
- final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
- mSyncQueue.queue(evictWct);
}
/**
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 60c812a..819358b 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -677,21 +677,39 @@
@Override
public String toString() {
- return "AudioPlaybackConfiguration piid:" + mPlayerIId
- + " deviceId:" + mDeviceId
- + " type:" + toLogFriendlyPlayerType(mPlayerType)
- + " u/pid:" + mClientUid + "/" + mClientPid
- + " state:" + toLogFriendlyPlayerState(mPlayerState)
- + " attr:" + mPlayerAttr
- + " sessionId:" + mSessionId
- + " mutedState:"
- + " muteFromMasterMute=" + ((mMutedState & PLAYER_MUTE_MASTER) != 0)
- + " muteFromStreamVolume=" + ((mMutedState & PLAYER_MUTE_STREAM_VOLUME) != 0)
- + " muteFromStreamMuted=" + ((mMutedState & PLAYER_MUTE_STREAM_MUTED) != 0)
- + " muteFromPlaybackRestricted=" + ((mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED)
- != 0)
- + " muteFromClientVolume=" + ((mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0)
- + " muteFromVolumeShaper=" + ((mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0);
+ StringBuilder apcToString = new StringBuilder();
+ apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
+ " deviceId:").append(mDeviceId).append(" type:").append(
+ toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(mClientUid).append(
+ "/").append(mClientPid).append(" state:").append(
+ toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(mPlayerAttr).append(
+ " sessionId:").append(mSessionId).append(" mutedState:");
+ if (mMutedState == PLAYER_MUTE_INVALID) {
+ apcToString.append("invalid ");
+ } else if (mMutedState == 0) {
+ apcToString.append("none ");
+ } else {
+ if ((mMutedState & PLAYER_MUTE_MASTER) != 0) {
+ apcToString.append("master ");
+ }
+ if ((mMutedState & PLAYER_MUTE_STREAM_VOLUME) != 0) {
+ apcToString.append("streamVolume ");
+ }
+ if ((mMutedState & PLAYER_MUTE_STREAM_MUTED) != 0) {
+ apcToString.append("streamMute ");
+ }
+ if ((mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
+ apcToString.append("playbackRestricted ");
+ }
+ if ((mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
+ apcToString.append("clientVolume ");
+ }
+ if ((mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
+ apcToString.append("volumeShaper ");
+ }
+ }
+
+ return apcToString.toString();
}
//=====================================================================
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
index cbdac61..3152e65 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -16,20 +16,6 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothAdapter.STATE_CONNECTED;
-import static android.bluetooth.BluetoothAdapter.STATE_CONNECTING;
-import static android.bluetooth.BluetoothAdapter.STATE_DISCONNECTED;
-import static android.bluetooth.BluetoothAdapter.STATE_DISCONNECTING;
-import static android.bluetooth.BluetoothAdapter.STATE_OFF;
-import static android.bluetooth.BluetoothAdapter.STATE_ON;
-import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF;
-import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* BluetoothCallback provides a callback interface for the settings
@@ -47,7 +33,7 @@
* {@link android.bluetooth.BluetoothAdapter#STATE_ON},
* {@link android.bluetooth.BluetoothAdapter#STATE_TURNING_OFF}.
*/
- default void onBluetoothStateChanged(@AdapterState int bluetoothState) {}
+ default void onBluetoothStateChanged(int bluetoothState) {}
/**
* It will be called when the local Bluetooth adapter has started
@@ -103,9 +89,7 @@
* {@link android.bluetooth.BluetoothAdapter#STATE_CONNECTED},
* {@link android.bluetooth.BluetoothAdapter#STATE_DISCONNECTING}.
*/
- default void onConnectionStateChanged(
- @Nullable CachedBluetoothDevice cachedDevice,
- @ConnectionState int state) {}
+ default void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {}
/**
* It will be called when device been set as active for {@code bluetoothProfile}
@@ -140,10 +124,8 @@
* {@link android.bluetooth.BluetoothProfile#STATE_DISCONNECTING}.
* @param bluetoothProfile the BluetoothProfile id.
*/
- default void onProfileConnectionStateChanged(
- CachedBluetoothDevice cachedDevice,
- @ConnectionState int state,
- int bluetoothProfile) {
+ default void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
}
/**
@@ -158,22 +140,4 @@
*/
default void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "STATE_" }, value = {
- STATE_DISCONNECTED,
- STATE_CONNECTING,
- STATE_CONNECTED,
- STATE_DISCONNECTING,
- })
- @interface ConnectionState {}
-
- @IntDef(prefix = { "STATE_" }, value = {
- STATE_OFF,
- STATE_TURNING_ON,
- STATE_ON,
- STATE_TURNING_OFF,
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface AdapterState {}
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 08b1bdc..e76047e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -520,7 +520,7 @@
<dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
<dimen name="qs_tile_margin_top_bottom">4dp</dimen>
<dimen name="qs_brightness_margin_top">8dp</dimen>
- <dimen name="qs_brightness_margin_bottom">24dp</dimen>
+ <dimen name="qs_brightness_margin_bottom">16dp</dimen>
<dimen name="qqs_layout_margin_top">16dp</dimen>
<dimen name="qqs_layout_padding_bottom">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 919b71b..f82e7db 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -55,6 +55,8 @@
val bouncerIsOrWillShow: Boolean,
val faceAuthenticated: Boolean,
val faceDisabled: Boolean,
+ val faceLockedOut: Boolean,
+ val fpLockedOut: Boolean,
val goingToSleep: Boolean,
val keyguardAwakeExcludingBouncerShowing: Boolean,
val keyguardGoingAway: Boolean,
@@ -65,7 +67,7 @@
val scanningAllowedByStrongAuth: Boolean,
val secureCameraLaunched: Boolean,
val switchingUser: Boolean,
- val udfpsBouncerShowing: Boolean
+ val udfpsBouncerShowing: Boolean,
) : KeyguardListenModel()
/**
* Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock].
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1463840..5ccab54 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2612,6 +2612,7 @@
final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
final boolean onlyFaceEnrolled = isOnlyFaceEnrolled();
+ final boolean fpOrFaceIsLockedOut = isFaceLockedOut() || fpLockedout;
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -2628,7 +2629,7 @@
&& strongAuthAllowsScanning && mIsPrimaryUser
&& (!mSecureCameraLaunched || mOccludingAppRequestingFace)
&& !faceAuthenticated
- && !fpLockedout;
+ && !fpOrFaceIsLockedOut;
// Aggregate relevant fields for debug logging.
maybeLogListenerModelData(
@@ -2643,6 +2644,8 @@
mBouncerIsOrWillBeShowing,
faceAuthenticated,
faceDisabledForUser,
+ isFaceLockedOut(),
+ fpLockedout,
mGoingToSleep,
awakeKeyguardExcludingBouncerShowing,
mKeyguardGoingAway,
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 9138b23..9cfd399 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.Application;
import android.app.Notification;
@@ -29,7 +28,6 @@
import android.os.Bundle;
import android.os.Looper;
import android.os.Process;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -130,13 +128,6 @@
ThreadedRenderer.EGL_CONTEXT_PRIORITY_HIGH_IMG);
}
- // Enable binder tracing on system server for calls originating from SysUI
- try {
- ActivityManager.getService().enableBinderTracing();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to enable binder tracing", e);
- }
-
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
deleted file mode 100644
index b5da7b6..0000000
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bluetooth
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.dagger.BluetoothLog
-import javax.inject.Inject
-
-/** Helper class for logging bluetooth events. */
-@SysUISingleton
-class BluetoothLogger @Inject constructor(@BluetoothLog private val logBuffer: LogBuffer) {
- fun logActiveDeviceChanged(address: String, profileId: Int) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = address
- int1 = profileId
- },
- { "ActiveDeviceChanged. address=$str1 profileId=$int1" }
- )
-
- fun logDeviceConnectionStateChanged(address: String?, state: String) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = address
- str2 = state
- },
- { "DeviceConnectionStateChanged. address=$str1 state=$str2" }
- )
-
- fun logAclConnectionStateChanged(address: String, state: String) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = address
- str2 = state
- },
- { "AclConnectionStateChanged. address=$str1 state=$str2" }
- )
-
- fun logProfileConnectionStateChanged(address: String, state: String, profileId: Int) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = address
- str2 = state
- int1 = profileId
- },
- { "ProfileConnectionStateChanged. address=$str1 state=$str2 profileId=$int1" }
- )
-
- fun logStateChange(state: String) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = state },
- { "BluetoothStateChanged. state=$str1" }
- )
-
- fun logBondStateChange(address: String, state: Int) =
- logBuffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = address
- int1 = state
- },
- { "DeviceBondStateChanged. address=$str1 state=$int1" }
- )
-
- fun logDeviceAdded(address: String) =
- logBuffer.log(TAG, LogLevel.DEBUG, { str1 = address }, { "DeviceAdded. address=$str1" })
-
- fun logDeviceDeleted(address: String) =
- logBuffer.log(TAG, LogLevel.DEBUG, { str1 = address }, { "DeviceDeleted. address=$str1" })
-
- fun logDeviceAttributesChanged() =
- logBuffer.log(TAG, LogLevel.DEBUG, {}, { "DeviceAttributesChanged." })
-}
-
-private const val TAG = "BluetoothLog"
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 659f286..a3dc779 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -601,7 +601,7 @@
private final class BluetoothCallbackHandler implements BluetoothCallback {
@Override
- public void onBluetoothStateChanged(@BluetoothCallback.AdapterState int bluetoothState) {
+ public void onBluetoothStateChanged(int bluetoothState) {
mHandler.obtainMessage(MSG_ON_BLUETOOTH_STATE_CHANGED,
bluetoothState, 0).sendToTarget();
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BluetoothLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/BluetoothLog.kt
deleted file mode 100644
index 4887b6a..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/BluetoothLog.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log.dagger
-
-import javax.inject.Qualifier
-
-/** A [com.android.systemui.log.LogBuffer] for bluetooth. */
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class BluetoothLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
index b551125..323ee21 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
@@ -1,9 +1,4 @@
package com.android.systemui.log.dagger
-import javax.inject.Qualifier
-
/** A [com.android.systemui.log.LogBuffer] for KeyguardUpdateMonitor. */
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardUpdateMonitorLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index eeba6b3..c2a8764 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -305,14 +305,4 @@
public static LogBuffer provideKeyguardUpdateMonitorLogBuffer(LogBufferFactory factory) {
return factory.create("KeyguardUpdateMonitorLog", 200);
}
-
- /**
- * Provides a {@link LogBuffer} for bluetooth-related logs.
- */
- @Provides
- @SysUISingleton
- @BluetoothLog
- public static LogBuffer providerBluetoothLogBuffer(LogBufferFactory factory) {
- return factory.create("BluetoothLog", 50);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 920f463..e1289a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -99,7 +99,7 @@
// slider, as well as animating the alpha of the QS tile layout (as we are tracking QQS tiles)
@Nullable
private TouchAnimator mFirstPageAnimator;
- // TranslationX animator for QQS/QS tiles
+ // TranslationX animator for QQS/QS tiles. Only used on the first page!
private TouchAnimator mTranslationXAnimator;
// TranslationY animator for QS tiles (and their components) in the first page
private TouchAnimator mTranslationYAnimator;
@@ -107,13 +107,14 @@
private TouchAnimator mQQSTranslationYAnimator;
// Animates alpha of permanent views (QS tile layout, QQS tiles) when not in first page
private TouchAnimator mNonfirstPageAlphaAnimator;
- // TranslatesY the QS Tile layout using QS.getHeightDiff()
- private TouchAnimator mQSTileLayoutTranslatorAnimator;
// This animates fading of media player
private TouchAnimator mAllPagesDelayedAnimator;
- // Animator for brightness slider(s)
+ // Brightness slider translation driver, uses mQSExpansionPathInterpolator.yInterpolator
@Nullable
- private TouchAnimator mBrightnessAnimator;
+ private TouchAnimator mBrightnessTranslationAnimator;
+ // Brightness slider opacity driver. Uses linear interpolator.
+ @Nullable
+ private TouchAnimator mBrightnessOpacityAnimator;
// Animator for Footer actions in QQS
private TouchAnimator mQQSFooterActionsAnimator;
// Height animator for QQS tiles (height changing from QQS size to QS size)
@@ -137,7 +138,6 @@
private final QSTileHost mHost;
private final Executor mExecutor;
private boolean mShowCollapsedOnKeyguard;
- private boolean mTranslateWhileExpanding;
private int mQQSTop;
private int[] mTmpLoc1 = new int[2];
@@ -298,13 +298,6 @@
QSTileLayout tileLayout = mQsPanelController.getTileLayout();
mAllViews.add((View) tileLayout);
- int heightDiff = mQs.getHeightDiff();
- if (!mTranslateWhileExpanding) {
- heightDiff *= SHORT_PARALLAX_AMOUNT;
- }
- mQSTileLayoutTranslatorAnimator = new Builder()
- .addFloat(tileLayout, "translationY", heightDiff, 0)
- .build();
mLastQQSTileHeight = 0;
@@ -407,12 +400,7 @@
mAnimatedQsViews.add(tileView);
mAllViews.add(quickTileView);
mAllViews.add(quickTileView.getSecondaryLabel());
- } else if (isIconInAnimatedRow(count)) {
-
- firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
-
- mAllViews.add(tileIcon);
- } else {
+ } else if (!isIconInAnimatedRow(count)) {
// Pretend there's a corresponding QQS tile (for the position) that we are
// expanding from.
SideLabelTileLayout qqsLayout =
@@ -442,7 +430,7 @@
}
}
- animateBrightnessSlider(firstPageBuilder);
+ animateBrightnessSlider();
mFirstPageAnimator = firstPageBuilder
// Fade in the tiles/labels as we reach the final position.
@@ -568,7 +556,9 @@
return new Pair<>(animator, builder.build());
}
- private void animateBrightnessSlider(Builder firstPageBuilder) {
+ private void animateBrightnessSlider() {
+ mBrightnessTranslationAnimator = null;
+ mBrightnessOpacityAnimator = null;
View qsBrightness = mQsPanelController.getBrightnessView();
View qqsBrightness = mQuickQSPanelController.getBrightnessView();
if (qqsBrightness != null && qqsBrightness.getVisibility() == View.VISIBLE) {
@@ -576,25 +566,45 @@
mAnimatedQsViews.add(qsBrightness);
mAllViews.add(qqsBrightness);
int translationY = getRelativeTranslationY(qsBrightness, qqsBrightness);
- mBrightnessAnimator = new Builder()
+ mBrightnessTranslationAnimator = new Builder()
// we need to animate qs brightness even if animation will not be visible,
// as we might start from sliderScaleY set to 0.3 if device was in collapsed QS
// portrait orientation before
.addFloat(qsBrightness, "sliderScaleY", 0.3f, 1)
.addFloat(qqsBrightness, "translationY", 0, translationY)
+ .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator())
.build();
} else if (qsBrightness != null) {
- firstPageBuilder.addFloat(qsBrightness, "translationY",
- qsBrightness.getMeasuredHeight() * 0.5f, 0);
- mBrightnessAnimator = new Builder()
+ // The brightness slider's visible bottom edge must maintain a constant margin from the
+ // QS tiles during transition. Thus the slider must (1) perform the same vertical
+ // translation as the tiles, and (2) compensate for the slider scaling.
+
+ // For (1), compute the distance via the vertical distance between QQS and QS tile
+ // layout top.
+ View quickSettingsRootView = mQs.getView();
+ View qsTileLayout = (View) mQsPanelController.getTileLayout();
+ View qqsTileLayout = (View) mQuickQSPanelController.getTileLayout();
+ getRelativePosition(mTmpLoc1, qsTileLayout, quickSettingsRootView);
+ getRelativePosition(mTmpLoc2, qqsTileLayout, quickSettingsRootView);
+ int tileMovement = mTmpLoc2[1] - mTmpLoc1[1];
+
+ // For (2), the slider scales to the vertical center, so compensate with half the
+ // height at full collapse.
+ float scaleCompensation = qsBrightness.getMeasuredHeight() * 0.5f;
+ mBrightnessTranslationAnimator = new Builder()
+ .addFloat(qsBrightness, "translationY", scaleCompensation + tileMovement, 0)
+ .addFloat(qsBrightness, "sliderScaleY", 0, 1)
+ .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator())
+ .build();
+
+ // While the slider's position and unfurl is animated throughouth the motion, the
+ // fade in happens independently.
+ mBrightnessOpacityAnimator = new Builder()
.addFloat(qsBrightness, "alpha", 0, 1)
- .addFloat(qsBrightness, "sliderScaleY", 0.3f, 1)
- .setInterpolator(Interpolators.ALPHA_IN)
- .setStartDelay(0.3f)
+ .setStartDelay(0.2f)
+ .setEndDelay(1 - 0.5f)
.build();
mAllViews.add(qsBrightness);
- } else {
- mBrightnessAnimator = null;
}
}
@@ -676,11 +686,13 @@
if (mQQSTileHeightAnimator != null) {
mQQSTileHeightAnimator.setPosition(position);
}
- mQSTileLayoutTranslatorAnimator.setPosition(position);
mQQSTranslationYAnimator.setPosition(position);
mAllPagesDelayedAnimator.setPosition(position);
- if (mBrightnessAnimator != null) {
- mBrightnessAnimator.setPosition(position);
+ if (mBrightnessOpacityAnimator != null) {
+ mBrightnessOpacityAnimator.setPosition(position);
+ }
+ if (mBrightnessTranslationAnimator != null) {
+ mBrightnessTranslationAnimator.setPosition(position);
}
if (mQQSFooterActionsAnimator != null) {
mQQSFooterActionsAnimator.setPosition(position);
@@ -774,13 +786,6 @@
setCurrentPosition();
};
- /**
- * True whe QS will be pulled from the top, false when it will be clipped.
- */
- public void setTranslateWhileExpanding(boolean shouldTranslate) {
- mTranslateWhileExpanding = shouldTranslate;
- }
-
private static class HeightExpansionAnimator {
private final List<View> mViews = new ArrayList<>();
private final ValueAnimator mAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 072c32f..3820500 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -573,7 +573,6 @@
@Override
public void setInSplitShade(boolean inSplitShade) {
mInSplitShade = inSplitShade;
- mQSAnimator.setTranslateWhileExpanding(inSplitShade);
updateShowCollapsedOnKeyguard();
updateQsState();
}
@@ -669,7 +668,11 @@
mQSPanelController.setRevealExpansion(expansion);
mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
- mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
+
+ float qsScrollViewTranslation =
+ onKeyguard && !mShowCollapsedOnKeyguard ? panelTranslationY : 0;
+ mQSPanelScrollView.setTranslationY(qsScrollViewTranslation);
+
if (fullyCollapsed) {
mQSPanelScrollView.setScrollY(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 0b2d443..4576a64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -23,7 +23,6 @@
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
import android.os.Handler;
@@ -654,10 +653,7 @@
final boolean fingerprintLockout = biometricSourceType == BiometricSourceType.FINGERPRINT
&& (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
|| msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT);
- final boolean faceLockout = biometricSourceType == BiometricSourceType.FACE
- && (msgId == FaceManager.FACE_ERROR_LOCKOUT
- || msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT);
- if (fingerprintLockout || faceLockout) {
+ if (fingerprintLockout) {
startWakeAndUnlock(MODE_SHOW_BOUNCER);
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index c7ea3c6..e7fa6d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -27,6 +27,7 @@
import android.os.Message;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import androidx.annotation.NonNull;
@@ -36,7 +37,6 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.systemui.bluetooth.BluetoothLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -57,9 +57,9 @@
public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
CachedBluetoothDevice.Callback, LocalBluetoothProfileManager.ServiceListener {
private static final String TAG = "BluetoothController";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final DumpManager mDumpManager;
- private final BluetoothLogger mLogger;
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
@@ -70,7 +70,6 @@
private final List<CachedBluetoothDevice> mConnectedDevices = new ArrayList<>();
private boolean mEnabled;
- @ConnectionState
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private boolean mAudioProfileOnly;
private boolean mIsActive;
@@ -84,12 +83,10 @@
public BluetoothControllerImpl(
Context context,
DumpManager dumpManager,
- BluetoothLogger logger,
@Background Looper bgLooper,
@Main Looper mainLooper,
@Nullable LocalBluetoothManager localBluetoothManager) {
mDumpManager = dumpManager;
- mLogger = logger;
mLocalBluetoothManager = localBluetoothManager;
mBgHandler = new Handler(bgLooper);
mHandler = new H(mainLooper);
@@ -119,7 +116,7 @@
return;
}
pw.print(" mEnabled="); pw.println(mEnabled);
- pw.print(" mConnectionState="); pw.println(connectionStateToString(mConnectionState));
+ pw.print(" mConnectionState="); pw.println(stateToString(mConnectionState));
pw.print(" mAudioProfileOnly="); pw.println(mAudioProfileOnly);
pw.print(" mIsActive="); pw.println(mIsActive);
pw.print(" mConnectedDevices="); pw.println(getConnectedDevices());
@@ -130,7 +127,7 @@
}
}
- private static String connectionStateToString(@ConnectionState int state) {
+ private static String stateToString(int state) {
switch (state) {
case BluetoothAdapter.STATE_CONNECTED:
return "CONNECTED";
@@ -323,8 +320,8 @@
}
@Override
- public void onBluetoothStateChanged(@AdapterState int bluetoothState) {
- mLogger.logStateChange(BluetoothAdapter.nameForState(bluetoothState));
+ public void onBluetoothStateChanged(int bluetoothState) {
+ if (DEBUG) Log.d(TAG, "BluetoothStateChanged=" + stateToString(bluetoothState));
mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
|| bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
mState = bluetoothState;
@@ -334,7 +331,7 @@
@Override
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
- mLogger.logDeviceAdded(cachedDevice.getAddress());
+ if (DEBUG) Log.d(TAG, "DeviceAdded=" + cachedDevice.getAddress());
cachedDevice.registerCallback(this);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
@@ -342,7 +339,7 @@
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
- mLogger.logDeviceDeleted(cachedDevice.getAddress());
+ if (DEBUG) Log.d(TAG, "DeviceDeleted=" + cachedDevice.getAddress());
mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
@@ -350,7 +347,7 @@
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
- mLogger.logBondStateChange(cachedDevice.getAddress(), bondState);
+ if (DEBUG) Log.d(TAG, "DeviceBondStateChanged=" + cachedDevice.getAddress());
mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
@@ -358,29 +355,29 @@
@Override
public void onDeviceAttributesChanged() {
- mLogger.logDeviceAttributesChanged();
+ if (DEBUG) Log.d(TAG, "DeviceAttributesChanged");
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@Override
- public void onConnectionStateChanged(
- @Nullable CachedBluetoothDevice cachedDevice,
- @ConnectionState int state) {
- String address = cachedDevice == null ? null : cachedDevice.getAddress();
- mLogger.logDeviceConnectionStateChanged(address, connectionStateToString(state));
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ if (DEBUG) {
+ Log.d(TAG, "ConnectionStateChanged=" + cachedDevice.getAddress() + " "
+ + stateToString(state));
+ }
mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
@Override
- public void onProfileConnectionStateChanged(
- CachedBluetoothDevice cachedDevice,
- @ConnectionState int state,
- int bluetoothProfile) {
- mLogger.logProfileConnectionStateChanged(
- cachedDevice.getAddress(), connectionStateToString(state), bluetoothProfile);
+ public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
+ if (DEBUG) {
+ Log.d(TAG, "ProfileConnectionStateChanged=" + cachedDevice.getAddress() + " "
+ + stateToString(state) + " profileId=" + bluetoothProfile);
+ }
mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -388,15 +385,20 @@
@Override
public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
- mLogger.logActiveDeviceChanged(activeDevice.getAddress(), bluetoothProfile);
+ if (DEBUG) {
+ Log.d(TAG, "ActiveDeviceChanged=" + activeDevice.getAddress()
+ + " profileId=" + bluetoothProfile);
+ }
updateActive();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
@Override
public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
- mLogger.logAclConnectionStateChanged(
- cachedDevice.getAddress(), connectionStateToString(state));
+ if (DEBUG) {
+ Log.d(TAG, "ACLConnectionStateChanged=" + cachedDevice.getAddress() + " "
+ + stateToString(state));
+ }
mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
index 0bf038d..2714cf4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -90,6 +90,8 @@
onlyFaceEnrolled = false,
faceAuthenticated = false,
faceDisabled = false,
+ faceLockedOut = false,
+ fpLockedOut = false,
goingToSleep = false,
keyguardAwakeExcludingBouncerShowing = false,
keyguardGoingAway = false,
@@ -99,5 +101,5 @@
scanningAllowedByStrongAuth = false,
secureCameraLaunched = false,
switchingUser = false,
- udfpsBouncerShowing = false
+ udfpsBouncerShowing = false,
)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 093e592..508f81d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -20,6 +20,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -751,8 +752,7 @@
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback
- .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+ faceAuthLockedOut();
verify(mLockPatternUtils, never()).requireStrongAuth(anyInt(), anyInt());
}
@@ -764,7 +764,7 @@
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
- .onAuthenticationError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
+ .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
verify(mLockPatternUtils).requireStrongAuth(anyInt(), anyInt());
}
@@ -775,10 +775,9 @@
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback
- .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+ faceAuthLockedOut();
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
- .onAuthenticationError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
+ .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
verify(mLockPatternUtils).requireStrongAuth(anyInt(), anyInt());
}
@@ -1217,7 +1216,7 @@
public void testShouldListenForFace_whenFpIsLockedOut_returnsFalse() throws RemoteException {
// Face auth should run when the following is true.
keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
+ occludingAppRequestsFaceAuth();
currentUserIsPrimary();
strongAuthNotRequired();
biometricsEnabledForCurrentUser();
@@ -1225,6 +1224,7 @@
biometricsNotDisabledThroughDevicePolicyManager();
userNotCurrentlySwitching();
mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
// Fingerprint is locked out.
fingerprintErrorLockedOut();
@@ -1500,6 +1500,27 @@
}
@Test
+ public void testShouldListenForFace_whenFaceIsLockedOut_returnsFalse()
+ throws RemoteException {
+ // Preconditions for face auth to run
+ keyguardNotGoingAway();
+ currentUserIsPrimary();
+ currentUserDoesNotHaveTrust();
+ biometricsNotDisabledThroughDevicePolicyManager();
+ biometricsEnabledForCurrentUser();
+ userNotCurrentlySwitching();
+ mKeyguardUpdateMonitor.setUdfpsBouncerShowing(true);
+ mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+
+ // Face is locked out.
+ faceAuthLockedOut();
+ mTestableLooper.processAllMessages();
+
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
+ }
+
+ @Test
public void testBouncerVisibility_whenBothFingerprintAndFaceIsEnrolled_stopsFaceAuth()
throws RemoteException {
// Both fingerprint and face are enrolled by default
@@ -1587,6 +1608,11 @@
verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
}
+ private void faceAuthLockedOut() {
+ mKeyguardUpdateMonitor.mFaceAuthenticationCallback
+ .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+ }
+
private void faceAuthEnabled() {
// this ensures KeyguardUpdateMonitor updates the cached mIsFaceEnrolled flag using the
// face manager mock wire-up in setup()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index cf5e878..3dd36d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -41,7 +41,6 @@
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bluetooth.BluetoothLogger;
import com.android.systemui.dump.DumpManager;
import org.junit.Before;
@@ -82,7 +81,6 @@
mBluetoothControllerImpl = new BluetoothControllerImpl(mContext,
mMockDumpManager,
- mock(BluetoothLogger.class),
mTestableLooper.getLooper(),
mTestableLooper.getLooper(),
mMockBluetoothManager);
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 0bba3c9..9f27f72 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -150,8 +150,9 @@
// Create a PendingIntent
final long token = Binder.clearCallingIdentity();
try {
- return PendingIntent.getActivity(mContext, /*requestCode */ associationId, intent,
- FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
+ return PendingIntent.getActivityAsUser(mContext, /*requestCode */ associationId, intent,
+ FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, /* options= */ null,
+ UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e52d21..842498d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16396,11 +16396,6 @@
}
}
- @Override
- public void enableBinderTracing() {
- Binder.enableTracingForUid(Binder.getCallingUid());
- }
-
@VisibleForTesting
public final class LocalService extends ActivityManagerInternal
implements ActivityManagerLocal {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 62ae9b8..8b11c39 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -267,10 +267,6 @@
OP_CAMERA,
};
- private static final int[] WATCHABLE_NON_PERMISSION_OPS = {
- OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- };
-
private static final int MAX_UNFORWARDED_OPS = 10;
private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
@@ -4252,7 +4248,7 @@
public boolean shouldCollectNotes(int opCode) {
Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
- if (ArrayUtils.contains(WATCHABLE_NON_PERMISSION_OPS, opCode)) {
+ if (AppOpsManager.shouldForceCollectNoteForOp(opCode)) {
return true;
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 454894e..e5d40d9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -1150,18 +1150,29 @@
}
return builder.toString();
case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED:
- builder.append(" muteFromMasterMute:").append(
- (mEventValue & PLAYER_MUTE_MASTER) != 0);
- builder.append(" muteFromStreamVolume:").append(
- (mEventValue & PLAYER_MUTE_STREAM_VOLUME) != 0);
- builder.append(" muteFromStreamMute:").append(
- (mEventValue & PLAYER_MUTE_STREAM_MUTED) != 0);
- builder.append(" muteFromPlaybackRestricted:").append(
- (mEventValue & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0);
- builder.append(" muteFromClientVolume:").append(
- (mEventValue & PLAYER_MUTE_CLIENT_VOLUME) != 0);
- builder.append(" muteFromVolumeShaper:").append(
- (mEventValue & PLAYER_MUTE_VOLUME_SHAPER) != 0);
+ builder.append(" source:");
+ if (mEventValue <= 0) {
+ builder.append("none ");
+ } else {
+ if ((mEventValue & PLAYER_MUTE_MASTER) != 0) {
+ builder.append("masterMute ");
+ }
+ if ((mEventValue & PLAYER_MUTE_STREAM_VOLUME) != 0) {
+ builder.append("streamVolume ");
+ }
+ if ((mEventValue & PLAYER_MUTE_STREAM_MUTED) != 0) {
+ builder.append("streamMute ");
+ }
+ if ((mEventValue & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
+ builder.append("playbackRestricted ");
+ }
+ if ((mEventValue & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
+ builder.append("clientVolume ");
+ }
+ if ((mEventValue & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
+ builder.append("volumeShaper ");
+ }
+ }
return builder.toString();
default:
return builder.toString();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 431be88..676dc19 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -99,6 +99,7 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -2784,26 +2785,18 @@
// When restricted to test networks, select any network with TRANSPORT_TEST. Since the
// creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
// this is considered safe.
- final NetworkRequest req;
if (mProfile.isRestrictedToTestNetworks()) {
- req = new NetworkRequest.Builder()
+ final NetworkRequest req = new NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
.addCapability(NET_CAPABILITY_NOT_VPN)
.build();
+ mConnectivityManager.requestNetwork(req, mNetworkCallback);
} else {
- // Basically, the request here is referring to the default request which is defined
- // in ConnectivityService. Ideally, ConnectivityManager should provide an new API
- // which can provide the status of physical network even though there is a virtual
- // network. b/147280869 is used for tracking the new API.
- // TODO: Use the new API to register default physical network.
- req = new NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
+ mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback,
+ new Handler(mLooper));
}
-
- mConnectivityManager.requestNetwork(req, mNetworkCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 6145a91c..b3aee22 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -131,6 +131,8 @@
// Configuration object for determining thresholds to change brightness dynamically
private final HysteresisLevels mAmbientBrightnessThresholds;
private final HysteresisLevels mScreenBrightnessThresholds;
+ private final HysteresisLevels mAmbientBrightnessThresholdsIdle;
+ private final HysteresisLevels mScreenBrightnessThresholdsIdle;
private boolean mLoggingEnabled;
@@ -242,7 +244,9 @@
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context,
+ HysteresisLevels screenBrightnessThresholds,
+ HysteresisLevels ambientBrightnessThresholdsIdle,
+ HysteresisLevels screenBrightnessThresholdsIdle, Context context,
HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong) {
@@ -251,7 +255,8 @@
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
- ambientBrightnessThresholds, screenBrightnessThresholds, context,
+ ambientBrightnessThresholds, screenBrightnessThresholds,
+ ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, context,
hbmController, brightnessThrottler, idleModeBrightnessMapper,
ambientLightHorizonShort, ambientLightHorizonLong
);
@@ -265,7 +270,9 @@
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context,
+ HysteresisLevels screenBrightnessThresholds,
+ HysteresisLevels ambientBrightnessThresholdsIdle,
+ HysteresisLevels screenBrightnessThresholdsIdle, Context context,
HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong) {
@@ -289,7 +296,9 @@
mAmbientLightHorizonShort = ambientLightHorizonShort;
mWeightingIntercept = ambientLightHorizonLong;
mAmbientBrightnessThresholds = ambientBrightnessThresholds;
+ mAmbientBrightnessThresholdsIdle = ambientBrightnessThresholdsIdle;
mScreenBrightnessThresholds = screenBrightnessThresholds;
+ mScreenBrightnessThresholdsIdle = screenBrightnessThresholdsIdle;
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
mHandler = new AutomaticBrightnessHandler(looper);
@@ -586,6 +595,8 @@
pw.println();
mAmbientBrightnessThresholds.dump(pw);
mScreenBrightnessThresholds.dump(pw);
+ mScreenBrightnessThresholdsIdle.dump(pw);
+ mScreenBrightnessThresholdsIdle.dump(pw);
}
private String configStateToString(int state) {
@@ -680,8 +691,17 @@
lux = 0;
}
mAmbientLux = lux;
- mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
- mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
+ if (isInIdleMode()) {
+ mAmbientBrighteningThreshold =
+ mAmbientBrightnessThresholdsIdle.getBrighteningThreshold(lux);
+ mAmbientDarkeningThreshold =
+ mAmbientBrightnessThresholdsIdle.getDarkeningThreshold(lux);
+ } else {
+ mAmbientBrighteningThreshold =
+ mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
+ mAmbientDarkeningThreshold =
+ mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
+ }
mHbmController.onAmbientLuxChange(mAmbientLux);
// If the short term model was invalidated and the change is drastic enough, reset it.
@@ -903,10 +923,20 @@
mPreThresholdBrightness = mScreenAutoBrightness;
}
mScreenAutoBrightness = newScreenAutoBrightness;
- mScreenBrighteningThreshold = clampScreenBrightness(
- mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
- mScreenDarkeningThreshold = clampScreenBrightness(
- mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
+ if (isInIdleMode()) {
+ mScreenBrighteningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholdsIdle.getBrighteningThreshold(
+ newScreenAutoBrightness));
+ mScreenDarkeningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholdsIdle.getDarkeningThreshold(
+ newScreenAutoBrightness));
+ } else {
+ mScreenBrighteningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholds.getBrighteningThreshold(
+ newScreenAutoBrightness));
+ mScreenDarkeningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
+ }
if (sendUpdate) {
mCallbacks.updateBrightness();
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 12b2f47..4165186 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -188,8 +188,8 @@
* <ambientLightHorizonLong>10001</ambientLightHorizonLong>
* <ambientLightHorizonShort>2001</ambientLightHorizonShort>
*
- * <displayBrightnessChangeThresholds>
- * <brighteningThresholds>
+ * <displayBrightnessChangeThresholds> // Thresholds for screen changes
+ * <brighteningThresholds> // Thresholds for active mode brightness changes.
* <minimum>0.001</minimum> // Minimum change needed in screen brightness to brighten.
* </brighteningThresholds>
* <darkeningThresholds>
@@ -197,8 +197,8 @@
* </darkeningThresholds>
* </displayBrightnessChangeThresholds>
*
- * <ambientBrightnessChangeThresholds>
- * <brighteningThresholds>
+ * <ambientBrightnessChangeThresholds> // Thresholds for lux changes
+ * <brighteningThresholds> // Thresholds for active mode brightness changes.
* <minimum>0.003</minimum> // Minimum change needed in ambient brightness to brighten.
* </brighteningThresholds>
* <darkeningThresholds>
@@ -206,6 +206,24 @@
* </darkeningThresholds>
* </ambientBrightnessChangeThresholds>
*
+ * <displayBrightnessChangeThresholdsIdle> // Thresholds for screen changes in idle mode
+ * <brighteningThresholds> // Thresholds for idle mode brightness changes.
+ * <minimum>0.001</minimum> // Minimum change needed in screen brightness to brighten.
+ * </brighteningThresholds>
+ * <darkeningThresholds>
+ * <minimum>0.002</minimum> // Minimum change needed in screen brightness to darken.
+ * </darkeningThresholds>
+ * </displayBrightnessChangeThresholdsIdle>
+ *
+ * <ambientBrightnessChangeThresholdsIdle> // Thresholds for lux changes in idle mode
+ * <brighteningThresholds> // Thresholds for idle mode brightness changes.
+ * <minimum>0.003</minimum> // Minimum change needed in ambient brightness to brighten.
+ * </brighteningThresholds>
+ * <darkeningThresholds>
+ * <minimum>0.004</minimum> // Minimum change needed in ambient brightness to darken.
+ * </darkeningThresholds>
+ * </ambientBrightnessChangeThresholdsIdle>
+ *
* </displayConfiguration>
* }
* </pre>
@@ -319,9 +337,13 @@
private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS;
private float mScreenBrighteningMinThreshold = 0.0f; // Retain behaviour as though there is
- private float mScreenDarkeningMinThreshold = 0.0f; // no minimum threshold for change in
- private float mAmbientLuxBrighteningMinThreshold = 0.0f; // screen brightness or ambient
- private float mAmbientLuxDarkeningMinThreshold = 0.0f; // brightness.
+ private float mScreenBrighteningMinThresholdIdle = 0.0f; // no minimum threshold for change in
+ private float mScreenDarkeningMinThreshold = 0.0f; // screen brightness or ambient
+ private float mScreenDarkeningMinThresholdIdle = 0.0f; // brightness.
+ private float mAmbientLuxBrighteningMinThreshold = 0.0f;
+ private float mAmbientLuxBrighteningMinThresholdIdle = 0.0f;
+ private float mAmbientLuxDarkeningMinThreshold = 0.0f;
+ private float mAmbientLuxDarkeningMinThresholdIdle = 0.0f;
private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline;
private Spline mBacklightToNitsSpline;
@@ -625,22 +647,76 @@
return mAmbientHorizonShort;
}
+ /**
+ * The minimum value for the screen brightness increase to actually occur.
+ * @return float value in brightness scale of 0 - 1.
+ */
public float getScreenBrighteningMinThreshold() {
return mScreenBrighteningMinThreshold;
}
+ /**
+ * The minimum value for the screen brightness decrease to actually occur.
+ * @return float value in brightness scale of 0 - 1.
+ */
public float getScreenDarkeningMinThreshold() {
return mScreenDarkeningMinThreshold;
}
+ /**
+ * The minimum value for the screen brightness increase to actually occur while in idle screen
+ * brightness mode.
+ * @return float value in brightness scale of 0 - 1.
+ */
+ public float getScreenBrighteningMinThresholdIdle() {
+ return mScreenBrighteningMinThresholdIdle;
+ }
+
+ /**
+ * The minimum value for the screen brightness decrease to actually occur while in idle screen
+ * brightness mode.
+ * @return float value in brightness scale of 0 - 1.
+ */
+ public float getScreenDarkeningMinThresholdIdle() {
+ return mScreenDarkeningMinThresholdIdle;
+ }
+
+ /**
+ * The minimum value for the ambient lux increase for a screen brightness change to actually
+ * occur.
+ * @return float value in brightness scale of 0 - 1.
+ */
public float getAmbientLuxBrighteningMinThreshold() {
return mAmbientLuxBrighteningMinThreshold;
}
+ /**
+ * The minimum value for the ambient lux decrease for a screen brightness change to actually
+ * occur.
+ * @return float value in brightness scale of 0 - 1.
+ */
public float getAmbientLuxDarkeningMinThreshold() {
return mAmbientLuxDarkeningMinThreshold;
}
+ /**
+ * The minimum value for the ambient lux increase for a screen brightness change to actually
+ * occur while in idle screen brightness mode.
+ * @return float value in brightness scale of 0 - 1.
+ */
+ public float getAmbientLuxBrighteningMinThresholdIdle() {
+ return mAmbientLuxBrighteningMinThresholdIdle;
+ }
+
+ /**
+ * The minimum value for the ambient lux decrease for a screen brightness change to actually
+ * occur while in idle screen brightness mode.
+ * @return float value in brightness scale of 0 - 1.
+ */
+ public float getAmbientLuxDarkeningMinThresholdIdle() {
+ return mAmbientLuxDarkeningMinThresholdIdle;
+ }
+
SensorData getAmbientLightSensor() {
return mAmbientLightSensor;
}
@@ -745,9 +821,14 @@
+ ", mAmbientHorizonLong=" + mAmbientHorizonLong
+ ", mAmbientHorizonShort=" + mAmbientHorizonShort
+ ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
+ + ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
+ ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
+ + ", mScreenBrighteningMinThresholdIdle=" + mScreenBrighteningMinThresholdIdle
+ ", mAmbientLuxDarkeningMinThreshold=" + mAmbientLuxDarkeningMinThreshold
+ + ", mAmbientLuxDarkeningMinThresholdIdle=" + mAmbientLuxDarkeningMinThresholdIdle
+ ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold
+ + ", mAmbientLuxBrighteningMinThresholdIdle="
+ + mAmbientLuxBrighteningMinThresholdIdle
+ ", mAmbientLightSensor=" + mAmbientLightSensor
+ ", mProximitySensor=" + mProximitySensor
+ ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
@@ -1376,24 +1457,34 @@
private void loadBrightnessChangeThresholds(DisplayConfiguration config) {
Thresholds displayBrightnessThresholds = config.getDisplayBrightnessChangeThresholds();
Thresholds ambientBrightnessThresholds = config.getAmbientBrightnessChangeThresholds();
+ Thresholds displayBrightnessThresholdsIdle =
+ config.getDisplayBrightnessChangeThresholdsIdle();
+ Thresholds ambientBrightnessThresholdsIdle =
+ config.getAmbientBrightnessChangeThresholdsIdle();
+ loadDisplayBrightnessThresholds(displayBrightnessThresholds);
+ loadAmbientBrightnessThresholds(ambientBrightnessThresholds);
+ loadIdleDisplayBrightnessThresholds(displayBrightnessThresholdsIdle);
+ loadIdleAmbientBrightnessThresholds(ambientBrightnessThresholdsIdle);
+ }
+
+ private void loadDisplayBrightnessThresholds(Thresholds displayBrightnessThresholds) {
if (displayBrightnessThresholds != null) {
BrightnessThresholds brighteningScreen =
displayBrightnessThresholds.getBrighteningThresholds();
BrightnessThresholds darkeningScreen =
displayBrightnessThresholds.getDarkeningThresholds();
- final BigDecimal screenBrighteningThreshold = brighteningScreen.getMinimum();
- final BigDecimal screenDarkeningThreshold = darkeningScreen.getMinimum();
-
- if (screenBrighteningThreshold != null) {
- mScreenBrighteningMinThreshold = screenBrighteningThreshold.floatValue();
+ if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
+ mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
}
- if (screenDarkeningThreshold != null) {
- mScreenDarkeningMinThreshold = screenDarkeningThreshold.floatValue();
+ if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
+ mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
}
}
+ }
+ private void loadAmbientBrightnessThresholds(Thresholds ambientBrightnessThresholds) {
if (ambientBrightnessThresholds != null) {
BrightnessThresholds brighteningAmbientLux =
ambientBrightnessThresholds.getBrighteningThresholds();
@@ -1412,6 +1503,44 @@
}
}
+ private void loadIdleDisplayBrightnessThresholds(Thresholds idleDisplayBrightnessThresholds) {
+ if (idleDisplayBrightnessThresholds != null) {
+ BrightnessThresholds brighteningScreenIdle =
+ idleDisplayBrightnessThresholds.getBrighteningThresholds();
+ BrightnessThresholds darkeningScreenIdle =
+ idleDisplayBrightnessThresholds.getDarkeningThresholds();
+
+ if (brighteningScreenIdle != null
+ && brighteningScreenIdle.getMinimum() != null) {
+ mScreenBrighteningMinThresholdIdle =
+ brighteningScreenIdle.getMinimum().floatValue();
+ }
+ if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
+ mScreenDarkeningMinThresholdIdle =
+ darkeningScreenIdle.getMinimum().floatValue();
+ }
+ }
+ }
+
+ private void loadIdleAmbientBrightnessThresholds(Thresholds idleAmbientBrightnessThresholds) {
+ if (idleAmbientBrightnessThresholds != null) {
+ BrightnessThresholds brighteningAmbientLuxIdle =
+ idleAmbientBrightnessThresholds.getBrighteningThresholds();
+ BrightnessThresholds darkeningAmbientLuxIdle =
+ idleAmbientBrightnessThresholds.getDarkeningThresholds();
+
+ if (brighteningAmbientLuxIdle != null
+ && brighteningAmbientLuxIdle.getMinimum() != null) {
+ mAmbientLuxBrighteningMinThresholdIdle =
+ brighteningAmbientLuxIdle.getMinimum().floatValue();
+ }
+ if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
+ mAmbientLuxDarkeningMinThresholdIdle =
+ darkeningAmbientLuxIdle.getMinimum().floatValue();
+ }
+ }
+ }
+
private boolean thermalStatusIsValid(ThermalStatus value) {
if (value == null) {
return false;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e53ac37..fd30d7e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -200,6 +200,8 @@
private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
+ private static final String PROP_USE_NEW_DISPLAY_POWER_CONTROLLER =
+ "persist.sys.use_new_display_power_controller";
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
// This value needs to be in sync with the threshold
// in RefreshRateConfigs::getFrameRateDivisor.
@@ -274,7 +276,7 @@
new CopyOnWriteArrayList<>();
/** All {@link DisplayPowerController}s indexed by {@link LogicalDisplay} ID. */
- private final SparseArray<DisplayPowerController> mDisplayPowerControllers =
+ private final SparseArray<DisplayPowerControllerInterface> mDisplayPowerControllers =
new SparseArray<>();
/** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
@@ -497,7 +499,6 @@
ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
mWideColorSpace = colorSpaces[1];
mAllowNonNativeRefreshRateOverride = mInjector.getAllowNonNativeRefreshRateOverride();
-
mSystemReady = false;
}
@@ -577,7 +578,7 @@
if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
return;
}
- final DisplayPowerController dpc = mDisplayPowerControllers.get(
+ final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
logicalDisplay.getDisplayIdLocked());
if (dpc == null) {
return;
@@ -1557,7 +1558,7 @@
scheduleTraversalLocked(false);
mPersistentDataStore.saveIfNeeded();
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDisplayChanged();
}
@@ -1575,7 +1576,8 @@
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
- final DisplayPowerController dpc = mDisplayPowerControllers.removeReturnOld(displayId);
+ final DisplayPowerControllerInterface dpc =
+ mDisplayPowerControllers.removeReturnOld(displayId);
if (dpc != null) {
dpc.stop();
}
@@ -1604,7 +1606,7 @@
mHandler.post(work);
}
final int displayId = display.getDisplayIdLocked();
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDisplayChanged();
}
@@ -1615,7 +1617,7 @@
private void handleLogicalDisplayDeviceStateTransitionLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
- final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDeviceStateTransition();
}
@@ -1852,14 +1854,14 @@
if (userId != mCurrentUserId) {
return;
}
- DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+ DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
if (dpc != null) {
dpc.setBrightnessConfiguration(c);
}
}
}
- private DisplayPowerController getDpcFromUniqueIdLocked(String uniqueId) {
+ private DisplayPowerControllerInterface getDpcFromUniqueIdLocked(String uniqueId) {
final DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayDevice);
if (logicalDisplay != null) {
@@ -1900,7 +1902,7 @@
final BrightnessConfiguration config =
getBrightnessConfigForDisplayWithPdsFallbackLocked(uniqueId, userSerial);
if (config != null) {
- final DisplayPowerController dpc = mDisplayPowerControllers.get(
+ final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
logicalDisplay.getDisplayIdLocked());
if (dpc != null) {
dpc.setBrightnessConfiguration(config);
@@ -2132,8 +2134,8 @@
void setAutoBrightnessLoggingEnabled(boolean enabled) {
synchronized (mSyncRoot) {
- final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
- Display.DEFAULT_DISPLAY);
+ final DisplayPowerControllerInterface displayPowerController =
+ mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
if (displayPowerController != null) {
displayPowerController.setAutoBrightnessLoggingEnabled(enabled);
}
@@ -2142,8 +2144,8 @@
void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
synchronized (mSyncRoot) {
- final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
- Display.DEFAULT_DISPLAY);
+ final DisplayPowerControllerInterface displayPowerController =
+ mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
if (displayPowerController != null) {
displayPowerController.setDisplayWhiteBalanceLoggingEnabled(enabled);
}
@@ -2170,8 +2172,8 @@
void setAmbientColorTemperatureOverride(float cct) {
synchronized (mSyncRoot) {
- final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
- Display.DEFAULT_DISPLAY);
+ final DisplayPowerControllerInterface displayPowerController =
+ mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
if (displayPowerController != null) {
displayPowerController.setAmbientColorTemperatureOverride(cct);
}
@@ -2180,8 +2182,8 @@
void setDockedAndIdleEnabled(boolean enabled, int displayId) {
synchronized (mSyncRoot) {
- final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
- displayId);
+ final DisplayPowerControllerInterface displayPowerController =
+ mDisplayPowerControllers.get(displayId);
if (displayPowerController != null) {
displayPowerController.setAutomaticScreenBrightnessMode(enabled);
}
@@ -2554,10 +2556,19 @@
final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore,
display, mSyncRoot);
- final DisplayPowerController displayPowerController = new DisplayPowerController(
- mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
- mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display));
+ final DisplayPowerController displayPowerController;
+
+ if (SystemProperties.getInt(PROP_USE_NEW_DISPLAY_POWER_CONTROLLER, 0) == 1) {
+ displayPowerController = new DisplayPowerController(
+ mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
+ mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
+ () -> handleBrightnessChange(display));
+ } else {
+ displayPowerController = new DisplayPowerController(
+ mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
+ mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
+ () -> handleBrightnessChange(display));
+ }
mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
@@ -3212,7 +3223,7 @@
uniqueId, userSerial);
if (config == null) {
// Get default configuration
- DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+ DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
if (dpc != null) {
config = dpc.getDefaultBrightnessConfiguration();
}
@@ -3263,7 +3274,7 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
return dpc.getBrightnessInfo();
}
@@ -3310,7 +3321,7 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.setBrightness(brightness);
}
@@ -3330,7 +3341,7 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
brightness = dpc.getScreenBrightnessSetting();
}
@@ -3534,7 +3545,7 @@
id).getPrimaryDisplayDeviceLocked();
final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
- final DisplayPowerController displayPowerController =
+ final DisplayPowerControllerInterface displayPowerController =
mDisplayPowerControllers.get(id);
ready &= displayPowerController.requestPowerState(request,
waitForNegativeProximity);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2476350..58a80e3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -104,7 +104,7 @@
* slower by changing the "animator duration scale" option in Development Settings.
*/
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks,
- DisplayWhiteBalanceController.Callbacks {
+ DisplayWhiteBalanceController.Callbacks, DisplayPowerControllerInterface {
private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked";
@@ -682,6 +682,7 @@
/**
* Returns true if the proximity sensor screen-off function is available.
*/
+ @Override
public boolean isProximitySensorAvailable() {
return mProximitySensor != null;
}
@@ -693,6 +694,7 @@
* @param includePackage if false will null out the package name in events
*/
@Nullable
+ @Override
public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(
@UserIdInt int userId, boolean includePackage) {
if (mBrightnessTracker == null) {
@@ -701,6 +703,7 @@
return mBrightnessTracker.getEvents(userId, includePackage);
}
+ @Override
public void onSwitchUser(@UserIdInt int newUserId) {
handleSettingsChange(true /* userSwitch */);
if (mBrightnessTracker != null) {
@@ -709,6 +712,7 @@
}
@Nullable
+ @Override
public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(
@UserIdInt int userId) {
if (mBrightnessTracker == null) {
@@ -720,6 +724,7 @@
/**
* Persist the brightness slider events and ambient brightness stats to disk.
*/
+ @Override
public void persistBrightnessTrackerState() {
if (mBrightnessTracker != null) {
mBrightnessTracker.persistBrightnessTrackerState();
@@ -781,6 +786,7 @@
}
}
+ @Override
public BrightnessConfiguration getDefaultBrightnessConfiguration() {
if (mAutomaticBrightnessController == null) {
return null;
@@ -794,6 +800,7 @@
* of each display need to be properly reflected in AutomaticBrightnessController.
*/
@GuardedBy("DisplayManagerService.mSyncRoot")
+ @Override
public void onDisplayChanged() {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
if (device == null) {
@@ -823,6 +830,7 @@
* This process involves turning off some displays so we need updatePowerState() to run and
* calculate the new state.
*/
+ @Override
public void onDeviceStateTransition() {
sendUpdatePowerState();
}
@@ -833,6 +841,7 @@
* This method should be called when the DisplayPowerController is no longer in use; i.e. when
* the {@link #mDisplayId display} has been removed.
*/
+ @Override
public void stop() {
synchronized (mLock) {
mStopped = true;
@@ -989,6 +998,25 @@
screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
screenDarkeningMinThreshold, screenBrighteningMinThreshold);
+ // Idle screen thresholds
+ float screenDarkeningMinThresholdIdle =
+ mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle();
+ float screenBrighteningMinThresholdIdle =
+ mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle();
+ HysteresisLevels screenBrightnessThresholdsIdle = new HysteresisLevels(
+ screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
+ screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle);
+
+ // Idle ambient thresholds
+ float ambientDarkeningMinThresholdIdle =
+ mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle();
+ float ambientBrighteningMinThresholdIdle =
+ mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle();
+ HysteresisLevels ambientBrightnessThresholdsIdle = new HysteresisLevels(
+ ambientBrighteningThresholds, ambientDarkeningThresholds,
+ ambientThresholdLevels, ambientDarkeningMinThresholdIdle,
+ ambientBrighteningMinThresholdIdle);
+
long brighteningLightDebounce = mDisplayDeviceConfig
.getAutoBrightnessBrighteningLightDebounce();
long darkeningLightDebounce = mDisplayDeviceConfig
@@ -1024,7 +1052,8 @@
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
- ambientBrightnessThresholds, screenBrightnessThresholds, mContext,
+ ambientBrightnessThresholds, screenBrightnessThresholds,
+ ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
mDisplayDeviceConfig.getAmbientHorizonShort(),
mDisplayDeviceConfig.getAmbientHorizonLong());
@@ -1063,6 +1092,7 @@
}
}
+ @Override
public void setAutomaticScreenBrightnessMode(boolean isIdle) {
if (mAutomaticBrightnessController != null) {
if (isIdle) {
@@ -1766,27 +1796,32 @@
* Ignores the proximity sensor until the sensor state changes, but only if the sensor is
* currently enabled and forcing the screen to be dark.
*/
+ @Override
public void ignoreProximitySensorUntilChanged() {
mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY);
}
+ @Override
public void setBrightnessConfiguration(BrightnessConfiguration c) {
Message msg = mHandler.obtainMessage(MSG_CONFIGURE_BRIGHTNESS, c);
msg.sendToTarget();
}
+ @Override
public void setTemporaryBrightness(float brightness) {
Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
Float.floatToIntBits(brightness), 0 /*unused*/);
msg.sendToTarget();
}
+ @Override
public void setTemporaryAutoBrightnessAdjustment(float adjustment) {
Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT,
Float.floatToIntBits(adjustment), 0 /*unused*/);
msg.sendToTarget();
}
+ @Override
public BrightnessInfo getBrightnessInfo() {
synchronized (mCachedBrightnessInfo) {
return new BrightnessInfo(
@@ -2347,7 +2382,8 @@
return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj);
}
- float getScreenBrightnessSetting() {
+ @Override
+ public float getScreenBrightnessSetting() {
float brightness = mBrightnessSetting.getBrightness();
if (Float.isNaN(brightness)) {
brightness = mScreenBrightnessDefault;
@@ -2362,7 +2398,8 @@
return clampScreenBrightnessForVr(brightnessFloat);
}
- void setBrightness(float brightnessValue) {
+ @Override
+ public void setBrightness(float brightnessValue) {
// Update the setting, which will eventually call back into DPC to have us actually update
// the display with the new value.
mBrightnessSetting.setBrightness(brightnessValue);
@@ -2511,6 +2548,7 @@
}
};
+ @Override
public void dump(final PrintWriter pw) {
synchronized (mLock) {
pw.println();
@@ -2919,7 +2957,8 @@
}
}
- void setAutoBrightnessLoggingEnabled(boolean enabled) {
+ @Override
+ public void setAutoBrightnessLoggingEnabled(boolean enabled) {
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.setLoggingEnabled(enabled);
}
@@ -2930,14 +2969,16 @@
sendUpdatePowerState();
}
- void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
+ @Override
+ public void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
if (mDisplayWhiteBalanceController != null) {
mDisplayWhiteBalanceController.setLoggingEnabled(enabled);
mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled);
}
}
- void setAmbientColorTemperatureOverride(float cct) {
+ @Override
+ public void setAmbientColorTemperatureOverride(float cct) {
if (mDisplayWhiteBalanceController != null) {
mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct);
// The ambient color temperature override is only applied when the ambient color
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
new file mode 100644
index 0000000..6677f35
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.content.pm.ParceledListSlice;
+import android.hardware.display.AmbientBrightnessDayStats;
+import android.hardware.display.BrightnessChangeEvent;
+import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
+
+import java.io.PrintWriter;
+
+/**
+ * An interface to manage the display's power state and brightness
+ */
+public interface DisplayPowerControllerInterface {
+
+ /**
+ * Notified when the display is changed. We use this to apply any changes that might be needed
+ * when displays get swapped on foldable devices.
+ */
+ void onDisplayChanged();
+
+ /**
+ * Unregisters all listeners and interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerController is no longer in use; i.e. when
+ * the display has been removed.
+ */
+ void stop();
+
+ /**
+ * Used to manage the displays preparing to transition from one device state to another.
+ */
+ void onDeviceStateTransition();
+
+ /**
+ * Used to update the display's BrightnessConfiguration
+ * @param config The new BrightnessConfiguration
+ */
+ void setBrightnessConfiguration(BrightnessConfiguration config);
+
+ /**
+ * Used to set the ambient color temperature of the Display
+ * @param ambientColorTemperature The target ambientColorTemperature
+ */
+ void setAmbientColorTemperatureOverride(float ambientColorTemperature);
+
+ /**
+ * Used to decide the associated AutomaticBrightnessController's BrightnessMode
+ * @param isIdle Flag which represents if the Idle BrightnessMode is to be set
+ */
+ void setAutomaticScreenBrightnessMode(boolean isIdle);
+
+ /**
+ * Used to enable/disable the logging of the WhileBalance associated entities
+ * @param enabled Flag which represents if the logging is the be enabled
+ */
+ void setDisplayWhiteBalanceLoggingEnabled(boolean enabled);
+
+ /**
+ * Used to dump the state.
+ * @param writer The PrintWriter used to dump the state.
+ */
+ void dump(PrintWriter writer);
+
+ /**
+ * Used to get the ambient brightness stats
+ */
+ ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId);
+
+ /**
+ * Get the default brightness configuration
+ */
+ BrightnessConfiguration getDefaultBrightnessConfiguration();
+
+ /**
+ * Set the screen brightness of the associated display
+ * @param brightness The value to which the brightness is to be set
+ */
+ void setBrightness(float brightness);
+
+ /**
+ * Checks if the proximity sensor is available
+ */
+ boolean isProximitySensorAvailable();
+
+ /**
+ * Persist the brightness slider events and ambient brightness stats to disk.
+ */
+ void persistBrightnessTrackerState();
+
+ /**
+ * Ignores the proximity sensor until the sensor state changes, but only if the sensor is
+ * currently enabled and forcing the screen to be dark.
+ */
+ void ignoreProximitySensorUntilChanged();
+
+ /**
+ * Requests a new power state.
+ *
+ * @param request The requested power state.
+ * @param waitForNegativeProximity If true, issues a request to wait for
+ * negative proximity before turning the screen back on,
+ * assuming the screen was turned off by the proximity sensor.
+ * @return True if display is ready, false if there are important changes that must
+ * be made asynchronously.
+ */
+ boolean requestPowerState(DisplayManagerInternal.DisplayPowerRequest request,
+ boolean waitForNegativeProximity);
+
+ /**
+ * Sets up the temporary autobrightness adjustment when the user is yet to settle down to a
+ * value.
+ */
+ void setTemporaryAutoBrightnessAdjustment(float adjustment);
+
+ /**
+ * Gets the screen brightness setting
+ */
+ float getScreenBrightnessSetting();
+
+ /**
+ * Sets up the temporary brightness for the associated display
+ */
+ void setTemporaryBrightness(float brightness);
+
+ /**
+ * Gets the associated {@link BrightnessInfo}
+ */
+ BrightnessInfo getBrightnessInfo();
+
+ /**
+ * Get the {@link BrightnessChangeEvent}s for the specified user.
+ */
+ ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(int userId, boolean hasUsageStats);
+
+ /**
+ * Sets up the logging for the associated {@link AutomaticBrightnessController}
+ * @param enabled Flag to represent if the logging is to be enabled
+ */
+ void setAutoBrightnessLoggingEnabled(boolean enabled);
+
+ /**
+ * Handles the changes to be done to update the brightness when the user is changed
+ * @param newUserId The new userId
+ */
+ void onSwitchUser(int newUserId);
+}
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
index 7a932ce..3413489 100644
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ b/services/core/java/com/android/server/display/HysteresisLevels.java
@@ -18,15 +18,12 @@
import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.PrintWriter;
import java.util.Arrays;
/**
* A helper class for handling access to illuminance hysteresis level values.
*/
-@VisibleForTesting
public class HysteresisLevels {
private static final String TAG = "HysteresisLevels";
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 16b5ee5..1c583be 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1522,8 +1522,17 @@
this.task = newTask;
if (shouldStartChangeTransition(newParent, oldParent)) {
- // Animate change transition on TaskFragment level to get the correct window crop.
- newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ // For Shell transition, call #initializeChangeTransition directly to take the
+ // screenshot at the Activity level. And Shell will be in charge of handling the
+ // surface reparent and crop.
+ initializeChangeTransition(getBounds());
+ } else {
+ // For legacy app transition, we want to take a screenshot of the Activity surface,
+ // but animate the change transition on TaskFragment level to get the correct window
+ // crop.
+ newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
+ }
}
super.onParentChanged(newParent, oldParent);
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 1fd66fc..d497d8c 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -141,15 +141,16 @@
return false;
} else {
- mResultActivities.add(r);
if (r.resultTo != null) {
// If this activity is sending a reply to a previous activity, we can't do
// anything with it now until we reach the start of the reply chain.
// NOTE: that we are assuming the result is always to the previous activity,
// which is almost always the case but we really shouldn't count on.
+ mResultActivities.add(r);
return false;
} else if (mTargetTaskFound && allowTaskReparenting && mTargetTask.affinity != null
&& mTargetTask.affinity.equals(r.taskAffinity)) {
+ mResultActivities.add(r);
// This activity has an affinity for our task. Either remove it if we are
// clearing or move it over to our task. Note that we currently punt on the case
// where we are resetting a task that is not at the top but who has activities
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 6b05d8f..267cff6 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -97,6 +97,16 @@
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
+ <!-- Set of thresholds that dictate the change needed for screen brightness
+ adaptations while in idle mode -->
+ <xs:element type="thresholds" name="displayBrightnessChangeThresholdsIdle" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- Set of thresholds that dictate the change needed for ambient brightness
+ adaptations while in idle mode -->
+ <xs:element type="thresholds" name="ambientBrightnessChangeThresholdsIdle" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
@@ -319,13 +329,13 @@
<!-- Thresholds for brightness changes. -->
<xs:complexType name="thresholds">
<xs:sequence>
- <!-- Brightening thresholds. -->
+ <!-- Brightening thresholds for active screen brightness mode. -->
<xs:element name="brighteningThresholds" type="brightnessThresholds" minOccurs="0"
maxOccurs="1" >
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
- <!-- Darkening thresholds. -->
+ <!-- Darkening thresholds for active screen brightness mode. -->
<xs:element name="darkeningThresholds" type="brightnessThresholds" minOccurs="0"
maxOccurs="1" >
<xs:annotation name="nonnull"/>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index fb7a920..f8bff75 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -61,11 +61,13 @@
public class DisplayConfiguration {
ctor public DisplayConfiguration();
method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds();
+ method public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholdsIdle();
method public final java.math.BigInteger getAmbientLightHorizonLong();
method public final java.math.BigInteger getAmbientLightHorizonShort();
method public com.android.server.display.config.AutoBrightness getAutoBrightness();
method @Nullable public final com.android.server.display.config.DensityMapping getDensityMapping();
method @NonNull public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholds();
+ method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle();
method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
method public final com.android.server.display.config.SensorDetails getLightSensor();
method public final com.android.server.display.config.SensorDetails getProxSensor();
@@ -80,11 +82,13 @@
method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
+ method public final void setAmbientBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
method public final void setAmbientLightHorizonLong(java.math.BigInteger);
method public final void setAmbientLightHorizonShort(java.math.BigInteger);
method public void setAutoBrightness(com.android.server.display.config.AutoBrightness);
method public final void setDensityMapping(@Nullable com.android.server.display.config.DensityMapping);
method public final void setDisplayBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
+ method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
method public final void setLightSensor(com.android.server.display.config.SensorDetails);
method public final void setProxSensor(com.android.server.display.config.SensorDetails);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 6a18dc1..9a4bb22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -233,4 +233,4 @@
});
when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
}
-}
+}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
index 538adb2..6f0efb0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -342,7 +342,6 @@
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
- setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
.that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
@@ -584,11 +583,19 @@
}
protected final void startDefaultProfile() {
- setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+ startUser(PROFILE_USER_ID);
}
protected final void stopDefaultProfile() {
- setUserState(PROFILE_USER_ID, UserState.STATE_STOPPING);
+ stopUser(PROFILE_USER_ID);
+ }
+
+ protected final void startUser(@UserIdInt int userId) {
+ setUserState(userId, UserState.STATE_RUNNING_UNLOCKED);
+ }
+
+ protected final void stopUser(@UserIdInt int userId) {
+ setUserState(userId, UserState.STATE_STOPPING);
}
// NOTE: should only called by tests that indirectly needs to check user assignments (like
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 8388a70..8b5921c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -88,6 +88,42 @@
.that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
}
+ @Test
+ public void testIsUserRunning_StartedUserShouldReturnTrue() {
+ addUser(USER_ID);
+ startUser(USER_ID);
+
+ assertWithMessage("isUserRunning(%s)", USER_ID)
+ .that(mUms.isUserRunning(USER_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserRunning_StoppedUserShouldReturnFalse() {
+ addUser(USER_ID);
+ stopUser(USER_ID);
+
+ assertWithMessage("isUserRunning(%s)", USER_ID)
+ .that(mUms.isUserRunning(USER_ID)).isFalse();
+ }
+
+ @Test
+ public void testIsUserRunning_CurrentUserStartedWorkProfileShouldReturnTrue() {
+ addDefaultProfileAndParent();
+ startDefaultProfile();
+
+ assertWithMessage("isUserRunning(%s)", PROFILE_USER_ID)
+ .that(mUms.isUserRunning(PROFILE_USER_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserRunning_CurrentUserStoppedWorkProfileShouldReturnFalse() {
+ addDefaultProfileAndParent();
+ stopDefaultProfile();
+
+ assertWithMessage("isUserRunning(%s)", PROFILE_USER_ID)
+ .that(mUms.isUserRunning(PROFILE_USER_ID)).isFalse();
+ }
+
@Override
protected boolean isUserVisible(int userId) {
return mUms.isUserVisibleUnchecked(userId);
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 9d82f1a..8280fc6 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -82,6 +82,8 @@
@Mock BrightnessMappingStrategy mIdleBrightnessMappingStrategy;
@Mock HysteresisLevels mAmbientBrightnessThresholds;
@Mock HysteresisLevels mScreenBrightnessThresholds;
+ @Mock HysteresisLevels mAmbientBrightnessThresholdsIdle;
+ @Mock HysteresisLevels mScreenBrightnessThresholdsIdle;
@Mock Handler mNoOpHandler;
@Mock HighBrightnessModeController mHbmController;
@Mock BrightnessThrottler mBrightnessThrottler;
@@ -129,6 +131,7 @@
INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
+ mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle,
mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy,
AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG
);
@@ -314,8 +317,9 @@
// Now let's do the same for idle mode
mController.switchToIdleMode();
- // Called once for init, and once when switching
- verify(mBrightnessMappingStrategy, times(2)).isForIdleMode();
+ // Called once for init, and once when switching,
+ // setAmbientLux() is called twice and once in updateAutoBrightness()
+ verify(mBrightnessMappingStrategy, times(5)).isForIdleMode();
// Ensure, after switching, original BMS is not used anymore
verifyNoMoreInteractions(mBrightnessMappingStrategy);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
new file mode 100644
index 0000000..ea5a5f8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class GameAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.GAME_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentNameMatcher =
+ ActivityOptions.GAME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+ launcherStrategy: ILauncherStrategy =
+ LauncherStrategyFactory.getInstance(instr).launcherStrategy,
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ /**
+ * Swipes down in the mock game app.
+ *
+ * @return true if the swipe operation is successful.
+ */
+ fun swipeDown(): Boolean {
+ val gameView = uiDevice.wait(
+ Until.findObject(By.res(getPackage(), GAME_APP_VIEW_RES)), WAIT_TIME_MS)
+ require(gameView != null) { "Mock game app view not found." }
+
+ val bound = gameView.getVisibleBounds()
+ return uiDevice.swipe(
+ bound.centerX(), bound.top, bound.centerX(), bound.centerY(), SWIPE_STEPS)
+ }
+
+ /**
+ * Switches to a recent app by quick switch gesture. This function can be used in both portrait
+ * and landscape mode.
+ *
+ * @param wmHelper Helper used to get window region.
+ * @param direction UiAutomator Direction enum to indicate the swipe direction.
+ *
+ * @return true if the swipe operation is successful.
+ */
+ fun switchToPreviousAppByQuickSwitchGesture(
+ wmHelper: WindowManagerStateHelper,
+ direction: Direction
+ ): Boolean {
+ val ratioForScreenBottom = 0.97
+ val fullView = wmHelper.getWindowRegion(componentMatcher)
+ require(!fullView.isEmpty) { "Target $componentMatcher view not found." }
+
+ val bound = fullView.bounds
+ val targetYPos = bound.bottom * ratioForScreenBottom
+ val endX = when (direction) {
+ Direction.LEFT -> bound.left
+ Direction.RIGHT -> bound.right
+ else -> {
+ throw IllegalStateException("Only left or right direction is allowed.")
+ }
+ }
+ return uiDevice.swipe(
+ bound.centerX(), targetYPos.toInt(), endX, targetYPos.toInt(), SWIPE_STEPS)
+ }
+
+ /**
+ * Waits for view idel with timeout, then checkes the target object whether visible on screen.
+ *
+ * @param packageName The targe application's package name.
+ * @param identifier The resource id of the target object.
+ * @param timeout The timeout duration in milliseconds.
+ *
+ * @return true if the target object exists.
+ */
+ @JvmOverloads
+ fun isTargetObjVisible(
+ packageName: String,
+ identifier: String,
+ timeout: Long = WAIT_TIME_MS
+ ): Boolean {
+ uiDevice.waitForIdle(timeout)
+ return uiDevice.hasObject(By.res(packageName, identifier))
+ }
+
+ companion object {
+ private const val GAME_APP_VIEW_RES = "container"
+ private const val WAIT_TIME_MS = 3_000L
+ private const val SWIPE_STEPS = 30
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index 354964d..9b1c541 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -62,19 +62,23 @@
get() = {
super.transition(this)
setup {
- tapl.setExpectedRotation(Surface.ROTATION_0)
+ if (testSpec.isTablet) {
+ tapl.setExpectedRotation(testSpec.startRotation)
+ } else {
+ tapl.setExpectedRotation(Surface.ROTATION_0)
+ }
RemoveAllTasksButHomeRule.removeAllTasksButHome()
this.setRotation(testSpec.startRotation)
}
- teardown {
- testApp.exit(wmHelper)
- }
transitions {
tapl.goHome()
.switchToAllApps()
.getAppIcon(testApp.launcherName)
.launch(testApp.`package`)
}
+ teardown {
+ testApp.exit(wmHelper)
+ }
}
/** {@inheritDoc} */