Merge "Add support to render app on multiple displays"
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index 9d92e0f..b8857ec 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -1,5 +1,9 @@
# OWNERS of Multiuser related files
+annabauza@google.com
bookatz@google.com
+nykkumar@google.com
olilan@google.com
omakoto@google.com
+tetianameronyk@google.com
+tyk@google.com
yamasani@google.com
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index c3fc7b1..be0e025 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -235,6 +235,15 @@
public static final String KEY_JS_HARD_CONSUMPTION_LIMIT = "js_hard_consumption_limit";
// TODO: Add JobScheduler modifier keys
/** @hide */
+ public static final String KEY_JS_REWARD_APP_INSTALL_INSTANT =
+ "js_reward_app_install_instant";
+ /** @hide */
+ public static final String KEY_JS_REWARD_APP_INSTALL_ONGOING =
+ "js_reward_app_install_ongoing";
+ /** @hide */
+ public static final String KEY_JS_REWARD_APP_INSTALL_MAX =
+ "js_reward_app_install_max";
+ /** @hide */
public static final String KEY_JS_REWARD_TOP_ACTIVITY_INSTANT =
"js_reward_top_activity_instant";
/** @hide */
@@ -463,6 +472,12 @@
public static final long DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
// TODO: add JobScheduler modifier default values
/** @hide */
+ public static final long DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES = arcToCake(408);
+ /** @hide */
+ public static final long DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES = arcToCake(0);
+ /** @hide */
+ public static final long DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES = arcToCake(4000);
+ /** @hide */
public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
/** @hide */
public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES = CAKE_IN_ARC / 2;
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/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 3bbc5a3..d284a99 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -69,6 +69,11 @@
*/
private final ArraySet<JobStatus> mChangedJobs = new ArraySet<>();
+ @GuardedBy("mLock")
+ private Boolean mLastReportedStatsdBatteryNotLow = null;
+ @GuardedBy("mLock")
+ private Boolean mLastReportedStatsdStablePower = null;
+
public BatteryController(JobSchedulerService service,
FlexibilityController flexibilityController) {
super(service);
@@ -176,12 +181,25 @@
Slog.d(TAG, "maybeReportNewChargingStateLocked: "
+ powerConnected + "/" + stablePower + "/" + batteryNotLow);
}
+
+ if (mLastReportedStatsdStablePower == null
+ || mLastReportedStatsdStablePower != stablePower) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_CHARGING, stablePower);
+ mLastReportedStatsdStablePower = stablePower;
+ }
+ if (mLastReportedStatsdBatteryNotLow == null
+ || mLastReportedStatsdBatteryNotLow != stablePower) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_BATTERY_NOT_LOW,
+ batteryNotLow);
+ mLastReportedStatsdBatteryNotLow = batteryNotLow;
+ }
+
final long nowElapsed = sElapsedRealtimeClock.millis();
mFlexibilityController.setConstraintSatisfied(
JobStatus.CONSTRAINT_CHARGING, mService.isBatteryCharging(), nowElapsed);
mFlexibilityController.setConstraintSatisfied(
- JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow, nowElapsed);
+ JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow, nowElapsed);
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index f6de109..abbe177 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -153,6 +153,8 @@
changed = true;
}
mDeviceIdleMode = enabled;
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_DEVICE_NOT_DOZING,
+ !mDeviceIdleMode);
if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
mDeviceIdleUpdateFunctor.prepare();
if (enabled) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index dd06217..926cfc1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -96,6 +96,8 @@
@Override
public void reportNewIdleState(boolean isIdle) {
synchronized (mLock) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_IDLE, isIdle);
+
final long nowElapsed = sElapsedRealtimeClock.millis();
mFlexibilityController.setConstraintSatisfied(
JobStatus.CONSTRAINT_IDLE, isIdle, nowElapsed);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 4320db0..999a3c0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -170,13 +170,12 @@
*/
private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
| CONSTRAINT_DEADLINE
- | CONSTRAINT_IDLE
| CONSTRAINT_PREFETCH
| CONSTRAINT_TARE_WEALTH
| CONSTRAINT_TIMING_DELAY
| CONSTRAINT_WITHIN_QUOTA;
- // TODO(b/129954980)
+ // TODO(b/129954980): ensure this doesn't spam statsd, especially at boot
private static final boolean STATS_LOG_ENABLED = false;
// No override.
@@ -1982,7 +1981,7 @@
}
/** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
- private int getProtoConstraint(int constraint) {
+ static int getProtoConstraint(int constraint) {
switch (constraint) {
case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
@@ -1998,10 +1997,16 @@
return JobServerProtoEnums.CONSTRAINT_DEADLINE;
case CONSTRAINT_DEVICE_NOT_DOZING:
return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
+ case CONSTRAINT_FLEXIBLE:
+ return JobServerProtoEnums.CONSTRAINT_FLEXIBILITY;
case CONSTRAINT_IDLE:
return JobServerProtoEnums.CONSTRAINT_IDLE;
+ case CONSTRAINT_PREFETCH:
+ return JobServerProtoEnums.CONSTRAINT_PREFETCH;
case CONSTRAINT_STORAGE_NOT_LOW:
return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
+ case CONSTRAINT_TARE_WEALTH:
+ return JobServerProtoEnums.CONSTRAINT_TARE_WEALTH;
case CONSTRAINT_TIMING_DELAY:
return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
case CONSTRAINT_WITHIN_QUOTA:
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 2a2d602..8453e53 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -26,6 +26,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
import com.android.server.job.StateChangedListener;
@@ -165,6 +166,15 @@
return mService.areComponentsInPlaceLocked(jobStatus);
}
+ protected void logDeviceWideConstraintStateToStatsd(int constraint, boolean satisfied) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED,
+ JobStatus.getProtoConstraint(constraint),
+ satisfied
+ ? FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+ : FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+ }
+
public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate);
public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index b79cc5e4..7391bcf 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -120,6 +120,7 @@
REWARD_NOTIFICATION_INTERACTION,
REWARD_WIDGET_INTERACTION,
REWARD_OTHER_USER_INTERACTION,
+ JobSchedulerEconomicPolicy.REWARD_APP_INSTALL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UtilityReward {
@@ -430,6 +431,8 @@
return "REWARD_WIDGET_INTERACTION";
case REWARD_OTHER_USER_INTERACTION:
return "REWARD_OTHER_USER_INTERACTION";
+ case JobSchedulerEconomicPolicy.REWARD_APP_INSTALL:
+ return "REWARD_JOB_APP_INSTALL";
}
return "UNKNOWN_REWARD:" + Integer.toHexString(eventId);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
index da544bb..fcb3e67 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
@@ -17,9 +17,12 @@
package com.android.server.tare;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
-import android.os.UserHandle;
+import android.os.RemoteException;
/** POJO to cache only the information about installed packages that TARE cares about. */
class InstalledPackageInfo {
@@ -28,11 +31,21 @@
public final int uid;
public final String packageName;
public final boolean hasCode;
+ @Nullable
+ public final String installerPackageName;
InstalledPackageInfo(@NonNull PackageInfo packageInfo) {
final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
- this.uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
- this.packageName = packageInfo.packageName;
- this.hasCode = applicationInfo != null && applicationInfo.hasCode();
+ uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
+ packageName = packageInfo.packageName;
+ hasCode = applicationInfo != null && applicationInfo.hasCode();
+ InstallSourceInfo installSourceInfo = null;
+ try {
+ installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ installerPackageName =
+ installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 59d4ded..c13e1dd9 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -524,10 +524,15 @@
mPackageToUidCache.add(userId, pkgName, uid);
}
synchronized (mLock) {
- mPkgCache.add(userId, pkgName, new InstalledPackageInfo(packageInfo));
+ final InstalledPackageInfo ipo = new InstalledPackageInfo(packageInfo);
+ mPkgCache.add(userId, pkgName, ipo);
mUidToPackageCache.add(uid, pkgName);
// TODO: only do this when the user first launches the app (app leaves stopped state)
mAgent.grantBirthrightLocked(userId, pkgName);
+ if (ipo.installerPackageName != null) {
+ mAgent.noteInstantaneousEventLocked(userId, ipo.installerPackageName,
+ JobSchedulerEconomicPolicy.REWARD_APP_INSTALL, null);
+ }
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index cbb88c0..55cc352 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -43,6 +43,9 @@
import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
@@ -85,6 +88,9 @@
import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_ONGOING;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
@@ -137,6 +143,8 @@
public static final int ACTION_JOB_MIN_RUNNING = TYPE_ACTION | POLICY_JS | 9;
public static final int ACTION_JOB_TIMEOUT = TYPE_ACTION | POLICY_JS | 10;
+ public static final int REWARD_APP_INSTALL = TYPE_REWARD | POLICY_JS | 0;
+
private static final int[] COST_MODIFIERS = new int[]{
COST_MODIFIER_CHARGING,
COST_MODIFIER_DEVICE_IDLE,
@@ -374,6 +382,17 @@
getConstantAsCake(mParser, properties,
KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
+ mRewards.put(REWARD_APP_INSTALL,
+ new Reward(REWARD_APP_INSTALL,
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_APP_INSTALL_INSTANT,
+ DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_APP_INSTALL_ONGOING,
+ DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_APP_INSTALL_MAX,
+ DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES)));
}
@Override
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/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8f5457a..d899dab 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4216,23 +4216,13 @@
}
}*/
- /** @hide
- * Determines whether the given UID can access unexported components
- * @param uid the calling UID
- * @return true if the calling UID is ROOT or SYSTEM
- */
- public static boolean canAccessUnexportedComponents(int uid) {
- final int appId = UserHandle.getAppId(uid);
- return (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID);
- }
-
/** @hide */
@UnsupportedAppUsage
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
final int appId = UserHandle.getAppId(uid);
- if (canAccessUnexportedComponents(uid)) {
+ if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don't get any permissions.
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/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 0a6a405..2c0be87 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -541,7 +541,8 @@
}
public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
- obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
+ obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, Boolean.valueOf(mute))
+ .sendToTarget();
}
}
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/security/keymaster/OWNERS b/core/java/android/security/keymaster/OWNERS
index 65129a4..c4d605c 100644
--- a/core/java/android/security/keymaster/OWNERS
+++ b/core/java/android/security/keymaster/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 189335
swillden@google.com
-jdanis@google.com
+eranm@google.com
jbires@google.com
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 267b2ff..4d33bfd 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -91,6 +91,12 @@
public final int icon;
/**
+ * The maximum string length for any string contained in this condition.
+ * @hide
+ */
+ public static final int MAX_STRING_LENGTH = 1000;
+
+ /**
* An object representing the current state of a {@link android.app.AutomaticZenRule}.
* @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
* @param summary a user visible description of the rule state.
@@ -104,16 +110,19 @@
if (id == null) throw new IllegalArgumentException("id is required");
if (summary == null) throw new IllegalArgumentException("summary is required");
if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
- this.id = id;
- this.summary = summary;
- this.line1 = line1;
- this.line2 = line2;
+ this.id = getTrimmedUri(id);
+ this.summary = getTrimmedString(summary);
+ this.line1 = getTrimmedString(line1);
+ this.line2 = getTrimmedString(line2);
this.icon = icon;
this.state = state;
this.flags = flags;
}
public Condition(Parcel source) {
+ // This constructor passes all fields directly into the constructor that takes all the
+ // fields as arguments; that constructor will trim each of the input strings to
+ // max length if necessary.
this((Uri)source.readParcelable(Condition.class.getClassLoader(), android.net.Uri.class),
source.readString(),
source.readString(),
@@ -240,4 +249,25 @@
return new Condition[size];
}
};
+
+ /**
+ * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
+ */
+ private static String getTrimmedString(String input) {
+ if (input != null && input.length() > MAX_STRING_LENGTH) {
+ return input.substring(0, MAX_STRING_LENGTH);
+ }
+ return input;
+ }
+
+ /**
+ * Returns a truncated copy of the Uri by trimming the string representation to the maximum
+ * string length.
+ */
+ private static Uri getTrimmedUri(Uri input) {
+ if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
+ return Uri.parse(getTrimmedString(input.toString()));
+ }
+ return input;
+ }
}
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/View.java b/core/java/android/view/View.java
index 94ea206..b698316 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24512,8 +24512,9 @@
/**
* Set the current default focus highlight.
* @param highlight the highlight drawable, or {@code null} if it's no longer needed.
+ * @hide
*/
- private void setDefaultFocusHighlight(Drawable highlight) {
+ void setDefaultFocusHighlight(Drawable highlight) {
mDefaultFocusHighlight = highlight;
mDefaultFocusHighlightSizeChanged = true;
if (highlight != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 074cbe5..89a1557 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3815,6 +3815,13 @@
if (mAttachInfo.mTooltipHost != null) {
mAttachInfo.mTooltipHost.hideTooltip();
}
+ if (!hasWindowFocus) {
+ // Clear focus highlight if its window lost focus.
+ final View focused = mView.findFocus();
+ if (focused != null) {
+ focused.setDefaultFocusHighlight(null);
+ }
+ }
}
// Note: must be done after the focus change callbacks,
@@ -5846,7 +5853,13 @@
// be when the window is first being added, and mFocused isn't
// set yet.
final View focused = mView.findFocus();
- if (focused != null && !focused.isFocusableInTouchMode()) {
+ if (focused == null) {
+ return false;
+ }
+
+ // Clear default focus highlight if it entered touch mode.
+ focused.setDefaultFocusHighlight(null);
+ if (!focused.isFocusableInTouchMode()) {
final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
if (ancestorToTakeFocus != null) {
// there is an ancestor that wants focus after its
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/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 50dcca64..664aeee 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -98,6 +98,18 @@
native_getValues(mNativeObject, array);
}
+ /**
+ * Combines contained values into a smaller array by aggregating them
+ * according to an index map.
+ */
+ public boolean combineValues(long[] array, int[] indexMap) {
+ if (indexMap.length != mLength) {
+ throw new IllegalArgumentException(
+ "Wrong index map size " + indexMap.length + ", expected " + mLength);
+ }
+ return native_combineValues(mNativeObject, array, indexMap);
+ }
+
@Override
public String toString() {
final long[] array = new long[mLength];
@@ -116,6 +128,10 @@
@FastNative
private native void native_getValues(long nativeObject, long[] array);
+
+ @FastNative
+ private native boolean native_combineValues(long nativeObject, long[] array,
+ int[] indexMap);
}
private static final NativeAllocationRegistry sRegistry =
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index ea5f0b2..b1e7d15 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1001,24 +1001,16 @@
}
/**
- * This will enable jdwp by default for all apps. It is OK to cache this property
- * because we expect to reboot the system whenever this property changes
- */
- private static final boolean ENABLE_JDWP = SystemProperties.get(
- "persist.debuggable.dalvik.vm.jdwp.enabled").equals("1");
-
- /**
* Applies debugger system properties to the zygote arguments.
*
- * For eng builds all apps are debuggable. On userdebug and user builds
- * if persist.debuggable.dalvik.vm.jdwp.enabled is 1 all apps are
- * debuggable. Otherwise, the debugger state is specified via the
- * "--enable-jdwp" flag in the spawn request.
+ * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
+ * the debugger state is specified via the "--enable-jdwp" flag
+ * in the spawn request.
*
* @param args non-null; zygote spawner args
*/
static void applyDebuggerSystemProperty(ZygoteArguments args) {
- if (Build.IS_ENG || ENABLE_JDWP) {
+ if (RoSystemProperties.DEBUGGABLE) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
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/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 5b946d5..a95b6e3 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -244,6 +244,38 @@
std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
}
+static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+ jlongArray jarray, jintArray jindexMap) {
+ std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+ ScopedLongArrayRW scopedArray(env, jarray);
+ ScopedIntArrayRO scopedIndexMap(env, jindexMap);
+
+ const uint64_t *data = vector->data();
+ uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
+ const uint8_t size = scopedArray.size();
+
+ for (int i = 0; i < size; i++) {
+ array[i] = 0;
+ }
+
+ bool nonZero = false;
+ for (int i = 0; i < vector->size(); i++) {
+ jint index = scopedIndexMap[i];
+ if (index < 0 || index >= size) {
+ jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
+ "Index %d is out of bounds: [0, %d]", index, size - 1);
+ return false;
+ }
+
+ if (data[i] != 0L) {
+ array[index] += data[i];
+ nonZero = true;
+ }
+ }
+
+ return nonZero;
+}
+
static const JNINativeMethod g_LongArrayContainer_methods[] = {
// @CriticalNative
{"native_init", "(I)J", (void *)native_init_LongArrayContainer},
@@ -253,6 +285,8 @@
{"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
// @FastNative
{"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
+ // @FastNative
+ {"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer},
};
int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
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/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 1327d96..ea2b988 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -17,12 +17,6 @@
<resources>
<!-- This file defines Android telephony related resources -->
- <!-- Whether force disabling telephony new data stack or not.
- This flag and the old data stack code will be deleted in Android 14.
- -->
- <bool name="config_force_disable_telephony_new_data_stack">false</bool>
- <java-symbol type="bool" name="config_force_disable_telephony_new_data_stack" />
-
<!-- Configure tcp buffer sizes per network type in the form:
network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
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/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
new file mode 100644
index 0000000..42629ba
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.service.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConditionTest {
+ private static final String CLASS = "android.service.notification.Condition";
+
+ @Test
+ public void testLongFields_inConstructors() {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+ // Confirm strings are truncated via short constructor
+ Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE);
+
+ assertEquals(Condition.MAX_STRING_LENGTH, cond1.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond1.summary.length());
+
+ // Confirm strings are truncated via long constructor
+ Condition cond2 = new Condition(longUri, longString, longString, longString,
+ -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.summary.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.line1.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.line2.length());
+ }
+
+ @Test
+ public void testLongFields_viaParcel() {
+ // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+ // it gets truncated upon unparcelling.
+ Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
+ Condition.STATE_TRUE);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+ Field id = Class.forName(CLASS).getDeclaredField("id");
+ id.setAccessible(true);
+ id.set(cond, longUri);
+ Field summary = Class.forName(CLASS).getDeclaredField("summary");
+ summary.setAccessible(true);
+ summary.set(cond, longString);
+ Field line1 = Class.forName(CLASS).getDeclaredField("line1");
+ line1.setAccessible(true);
+ line1.set(cond, longString);
+ Field line2 = Class.forName(CLASS).getDeclaredField("line2");
+ line2.setAccessible(true);
+ line2.set(cond, longString);
+ } catch (NoSuchFieldException e) {
+ fail(e.toString());
+ } catch (ClassNotFoundException e) {
+ fail(e.toString());
+ } catch (IllegalAccessException e) {
+ fail(e.toString());
+ }
+
+ Parcel parcel = Parcel.obtain();
+ cond.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ Condition fromParcel = new Condition(parcel);
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.summary.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length());
+ }
+}
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/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index a22dd1c..516dee7 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -161,4 +161,33 @@
assertThrows(RuntimeException.class,
() -> LongArrayMultiStateCounter.CREATOR.createFromParcel(parcel));
}
+
+ @Test
+ public void combineValues() {
+ long[] values = new long[] {0, 1, 2, 3, 42};
+ LongArrayMultiStateCounter.LongArrayContainer container =
+ new LongArrayMultiStateCounter.LongArrayContainer(values.length);
+ container.setValues(values);
+
+ long[] out = new long[3];
+ int[] indexes = {2, 1, 1, 0, 0};
+ boolean nonZero = container.combineValues(out, indexes);
+ assertThat(nonZero).isTrue();
+ assertThat(out).isEqualTo(new long[]{45, 3, 0});
+
+ // All zeros
+ container.setValues(new long[]{0, 0, 0, 0, 0});
+ nonZero = container.combineValues(out, indexes);
+ assertThat(nonZero).isFalse();
+ assertThat(out).isEqualTo(new long[]{0, 0, 0});
+
+ // Index out of range
+ IndexOutOfBoundsException e1 = assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> container.combineValues(out, new int[]{0, 1, -1, 0, 0}));
+ assertThat(e1.getMessage()).isEqualTo("Index -1 is out of bounds: [0, 2]");
+ IndexOutOfBoundsException e2 = assertThrows(IndexOutOfBoundsException.class,
+ () -> container.combineValues(out, new int[]{0, 1, 4, 0, 0}));
+ assertThat(e2.getMessage()).isEqualTo("Index 4 is out of bounds: [0, 2]");
+ }
}
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/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 4c85d20..419e62d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -561,6 +561,10 @@
if (from == to) {
// No animation run, still callback to stop resizing.
mSplitLayoutHandler.onLayoutSizeChanged(this);
+
+ if (flingFinishedCallback != null) {
+ flingFinishedCallback.run();
+ }
InteractionJankMonitorUtils.endTracing(
CUJ_SPLIT_SCREEN_RESIZE);
return;
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/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
index e5bf8ca..e34fedd 100644
--- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -20,7 +20,8 @@
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_label"
- android:supportsRtl="true">
+ android:supportsRtl="true"
+ android:enableOnBackInvokedCallback="true">
<activity
android:name=".MainActivity"
android:exported="true">
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 104966d..418d6cb 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -59,6 +59,7 @@
}
dependencies {
+ api "androidx.appcompat:appcompat:1.6.0-rc01"
api "androidx.compose.material3:material3:$jetpack_compose_material3_version"
api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index ae15da6..e5a1862 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -22,7 +22,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
@@ -50,9 +53,6 @@
@Composable
private fun MainContent() {
- val destination =
- intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPageName()
-
val navController = rememberNavController()
CompositionLocalProvider(navController.localNavController()) {
NavHost(navController, ROOT_PAGE_NAME) {
@@ -70,13 +70,23 @@
}
}
}
+ }
+ InitialDestinationNavigator(navController)
+ }
+
+ @Composable
+ private fun InitialDestinationNavigator(navController: NavHostController) {
+ val destinationNavigated = rememberSaveable { mutableStateOf(false) }
+ if (destinationNavigated.value) return
+ destinationNavigated.value = true
+ LaunchedEffect(Unit) {
+ val destination =
+ intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPageName()
if (destination.isNotEmpty()) {
- LaunchedEffect(Unit) {
- navController.navigate(destination) {
- popUpTo(navController.graph.findStartDestination().id) {
- inclusive = true
- }
+ navController.navigate(destination) {
+ popUpTo(navController.graph.findStartDestination().id) {
+ inclusive = true
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 766c036..7353cc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -407,7 +407,7 @@
|| sessionInfo.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
}
- private void refreshDevices() {
+ private synchronized void refreshDevices() {
mMediaDevices.clear();
mCurrentConnectedDevice = null;
if (TextUtils.isEmpty(mPackageName)) {
@@ -437,7 +437,7 @@
return infos;
}
- private void buildAvailableRoutes() {
+ private synchronized void buildAvailableRoutes() {
for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
if (DEBUG) {
Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
@@ -447,7 +447,7 @@
}
}
- private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+ private synchronized List<MediaRoute2Info> getAvailableRoutes(String packageName) {
final List<MediaRoute2Info> infos = new ArrayList<>();
RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
if (routingSessionInfo != null) {
@@ -571,7 +571,7 @@
@Override
public void onSessionUpdated(RoutingSessionInfo sessionInfo) {
- dispatchDataChanged();
+ refreshDevices();
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index f4af6e8..33fb91d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -666,12 +666,22 @@
}
@Test
- public void onSessionUpdated_shouldDispatchDataChanged() {
+ public void onSessionUpdated_shouldDispatchDeviceListAdded() {
+ final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ when(info.getId()).thenReturn(TEST_ID);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(info.isSystemRoute()).thenReturn(true);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info);
+ mShadowRouter2Manager.setAllRoutes(routes);
+
+ mInfoMediaManager.mPackageName = "";
mInfoMediaManager.registerCallback(mCallback);
mInfoMediaManager.mMediaRouterCallback.onSessionUpdated(mock(RoutingSessionInfo.class));
- verify(mCallback).onDeviceAttributesChanged();
+ verify(mCallback).onDeviceListAdded(any());
}
@Test
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
new file mode 100644
index 0000000..5c0a7c8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="20"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+ android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="40"
+ android:propertyName="pathData"
+ android:startOffset="20"
+ android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="40"
+ android:propertyName="pathData"
+ android:startOffset="60"
+ android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueTo="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
new file mode 100644
index 0000000..a96b748
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+ android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="233"
+ android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueTo="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 32871f0..ac131ae 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -84,6 +84,10 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
+ <!-- Dimens for animation for the Bouncer PIN view -->
+ <dimen name="pin_view_trans_y_entry">120dp</dimen>
+ <dimen name="pin_view_trans_y_entry_offset">10dp</dimen>
+
<!-- Spacing around each button used for PIN view -->
<dimen name="num_pad_key_width">72dp</dimen>
<dimen name="num_pad_entry_row_margin_bottom">12dp</dimen>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
new file mode 100644
index 0000000..40bfd83
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners
+ android:radius="28dp"/>
+ <solid android:color="@color/media_dialog_background" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 93c16e4..b76de5a 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -20,6 +20,7 @@
android:id="@+id/media_output_dialog"
android:layout_width="@dimen/large_dialog_width"
android:layout_height="wrap_content"
+ android:background="@drawable/media_output_dialog_background"
android:orientation="vertical">
<LinearLayout
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index dd5987b..11dbe4a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -186,7 +186,7 @@
<color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
<color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
<color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
- <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_seekbar_progress">@android:color/system_accent1_200</color>
<color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
<color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
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/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
deleted file mode 100644
index 30c062b..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2018 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.shared.system;
-
-import android.graphics.HardwareRenderer;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.Message;
-import android.os.Trace;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.View;
-import android.view.ViewRootImpl;
-
-import java.util.function.Consumer;
-
-/**
- * Helper class to apply surface transactions in sync with RenderThread.
- *
- * NOTE: This is a modification of {@link android.view.SyncRtSurfaceTransactionApplier}, we can't
- * currently reference that class from the shared lib as it is hidden.
- */
-public class SyncRtSurfaceTransactionApplierCompat {
-
- public static final int FLAG_ALL = 0xffffffff;
- public static final int FLAG_ALPHA = 1;
- public static final int FLAG_MATRIX = 1 << 1;
- public static final int FLAG_WINDOW_CROP = 1 << 2;
- public static final int FLAG_LAYER = 1 << 3;
- public static final int FLAG_CORNER_RADIUS = 1 << 4;
- public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
- public static final int FLAG_VISIBILITY = 1 << 6;
- public static final int FLAG_RELATIVE_LAYER = 1 << 7;
- public static final int FLAG_SHADOW_RADIUS = 1 << 8;
-
- private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
-
- private final SurfaceControl mBarrierSurfaceControl;
- private final ViewRootImpl mTargetViewRootImpl;
- private final Handler mApplyHandler;
-
- private int mSequenceNumber = 0;
- private int mPendingSequenceNumber = 0;
- private Runnable mAfterApplyCallback;
-
- /**
- * @param targetView The view in the surface that acts as synchronization anchor.
- */
- public SyncRtSurfaceTransactionApplierCompat(View targetView) {
- mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
- mBarrierSurfaceControl = mTargetViewRootImpl != null
- ? mTargetViewRootImpl.getSurfaceControl() : null;
-
- mApplyHandler = new Handler(new Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
- onApplyMessage(msg.arg1);
- return true;
- }
- return false;
- }
- });
- }
-
- private void onApplyMessage(int seqNo) {
- mSequenceNumber = seqNo;
- if (mSequenceNumber == mPendingSequenceNumber && mAfterApplyCallback != null) {
- Runnable r = mAfterApplyCallback;
- mAfterApplyCallback = null;
- r.run();
- }
- }
-
- /**
- * Schedules applying surface parameters on the next frame.
- *
- * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
- * this method to avoid synchronization issues.
- */
- public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
- if (mTargetViewRootImpl == null || mTargetViewRootImpl.getView() == null) {
- return;
- }
-
- mPendingSequenceNumber++;
- final int toApplySeqNo = mPendingSequenceNumber;
- mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
- @Override
- public void onFrameDraw(long frame) {
- if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
- Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
- .sendToTarget();
- return;
- }
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Sync transaction frameNumber=" + frame);
- Transaction t = new Transaction();
- for (int i = params.length - 1; i >= 0; i--) {
- SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
- params[i];
- surfaceParams.applyTo(t);
- }
- if (mTargetViewRootImpl != null) {
- mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
- .sendToTarget();
- }
- });
-
- // Make sure a frame gets scheduled.
- mTargetViewRootImpl.getView().invalidate();
- }
-
- /**
- * Calls the runnable when any pending apply calls have completed
- */
- public void addAfterApplyCallback(final Runnable afterApplyCallback) {
- if (mSequenceNumber == mPendingSequenceNumber) {
- afterApplyCallback.run();
- } else {
- if (mAfterApplyCallback == null) {
- mAfterApplyCallback = afterApplyCallback;
- } else {
- final Runnable oldCallback = mAfterApplyCallback;
- mAfterApplyCallback = new Runnable() {
- @Override
- public void run() {
- afterApplyCallback.run();
- oldCallback.run();
- }
- };
- }
- }
- }
-
- public static void applyParams(TransactionCompat t,
- SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
- params.applyTo(t.mTransaction);
- }
-
- /**
- * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
- * attached if necessary.
- */
- public static void create(final View targetView,
- final Consumer<SyncRtSurfaceTransactionApplierCompat> callback) {
- if (targetView == null) {
- // No target view, no applier
- callback.accept(null);
- } else if (targetView.getViewRootImpl() != null) {
- // Already attached, we're good to go
- callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
- } else {
- // Haven't been attached before we can get the view root
- targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- targetView.removeOnAttachStateChangeListener(this);
- callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- // Do nothing
- }
- });
- }
- }
-
- public static class SurfaceParams {
- public static class Builder {
- final SurfaceControl surface;
- int flags;
- float alpha;
- float cornerRadius;
- int backgroundBlurRadius;
- Matrix matrix;
- Rect windowCrop;
- int layer;
- SurfaceControl relativeTo;
- int relativeLayer;
- boolean visible;
- float shadowRadius;
-
- /**
- * @param surface The surface to modify.
- */
- public Builder(SurfaceControl surface) {
- this.surface = surface;
- }
-
- /**
- * @param alpha The alpha value to apply to the surface.
- * @return this Builder
- */
- public Builder withAlpha(float alpha) {
- this.alpha = alpha;
- flags |= FLAG_ALPHA;
- return this;
- }
-
- /**
- * @param matrix The matrix to apply to the surface.
- * @return this Builder
- */
- public Builder withMatrix(Matrix matrix) {
- this.matrix = new Matrix(matrix);
- flags |= FLAG_MATRIX;
- return this;
- }
-
- /**
- * @param windowCrop The window crop to apply to the surface.
- * @return this Builder
- */
- public Builder withWindowCrop(Rect windowCrop) {
- this.windowCrop = new Rect(windowCrop);
- flags |= FLAG_WINDOW_CROP;
- return this;
- }
-
- /**
- * @param layer The layer to assign the surface.
- * @return this Builder
- */
- public Builder withLayer(int layer) {
- this.layer = layer;
- flags |= FLAG_LAYER;
- return this;
- }
-
- /**
- * @param relativeTo The surface that's set relative layer to.
- * @param relativeLayer The relative layer.
- * @return this Builder
- */
- public Builder withRelativeLayerTo(SurfaceControl relativeTo, int relativeLayer) {
- this.relativeTo = relativeTo;
- this.relativeLayer = relativeLayer;
- flags |= FLAG_RELATIVE_LAYER;
- return this;
- }
-
- /**
- * @param radius the Radius for rounded corners to apply to the surface.
- * @return this Builder
- */
- public Builder withCornerRadius(float radius) {
- this.cornerRadius = radius;
- flags |= FLAG_CORNER_RADIUS;
- return this;
- }
-
- /**
- * @param radius the Radius for the shadows to apply to the surface.
- * @return this Builder
- */
- public Builder withShadowRadius(float radius) {
- this.shadowRadius = radius;
- flags |= FLAG_SHADOW_RADIUS;
- return this;
- }
-
- /**
- * @param radius the Radius for blur to apply to the background surfaces.
- * @return this Builder
- */
- public Builder withBackgroundBlur(int radius) {
- this.backgroundBlurRadius = radius;
- flags |= FLAG_BACKGROUND_BLUR_RADIUS;
- return this;
- }
-
- /**
- * @param visible The visibility to apply to the surface.
- * @return this Builder
- */
- public Builder withVisibility(boolean visible) {
- this.visible = visible;
- flags |= FLAG_VISIBILITY;
- return this;
- }
-
- /**
- * @return a new SurfaceParams instance
- */
- public SurfaceParams build() {
- return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
- relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible,
- shadowRadius);
- }
- }
-
- private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
- Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
- float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) {
- this.flags = flags;
- this.surface = surface;
- this.alpha = alpha;
- this.matrix = matrix;
- this.windowCrop = windowCrop;
- this.layer = layer;
- this.relativeTo = relativeTo;
- this.relativeLayer = relativeLayer;
- this.cornerRadius = cornerRadius;
- this.backgroundBlurRadius = backgroundBlurRadius;
- this.visible = visible;
- this.shadowRadius = shadowRadius;
- }
-
- private final int flags;
- private final float[] mTmpValues = new float[9];
-
- public final SurfaceControl surface;
- public final float alpha;
- public final float cornerRadius;
- public final int backgroundBlurRadius;
- public final Matrix matrix;
- public final Rect windowCrop;
- public final int layer;
- public final SurfaceControl relativeTo;
- public final int relativeLayer;
- public final boolean visible;
- public final float shadowRadius;
-
- public void applyTo(SurfaceControl.Transaction t) {
- if ((flags & FLAG_MATRIX) != 0) {
- t.setMatrix(surface, matrix, mTmpValues);
- }
- if ((flags & FLAG_WINDOW_CROP) != 0) {
- t.setWindowCrop(surface, windowCrop);
- }
- if ((flags & FLAG_ALPHA) != 0) {
- t.setAlpha(surface, alpha);
- }
- if ((flags & FLAG_LAYER) != 0) {
- t.setLayer(surface, layer);
- }
- if ((flags & FLAG_CORNER_RADIUS) != 0) {
- t.setCornerRadius(surface, cornerRadius);
- }
- if ((flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
- t.setBackgroundBlurRadius(surface, backgroundBlurRadius);
- }
- if ((flags & FLAG_VISIBILITY) != 0) {
- if (visible) {
- t.show(surface);
- } else {
- t.hide(surface);
- }
- }
- if ((flags & FLAG_RELATIVE_LAYER) != 0) {
- t.setRelativeLayer(surface, relativeTo, relativeLayer);
- }
- if ((flags & FLAG_SHADOW_RADIUS) != 0) {
- t.setShadowRadius(surface, shadowRadius);
- }
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
deleted file mode 100644
index 43a882a5..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2018 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.shared.system;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-
-public class TransactionCompat {
-
- final Transaction mTransaction;
-
- final float[] mTmpValues = new float[9];
-
- public TransactionCompat() {
- mTransaction = new Transaction();
- }
-
- public void apply() {
- mTransaction.apply();
- }
-
- public TransactionCompat show(SurfaceControl surfaceControl) {
- mTransaction.show(surfaceControl);
- return this;
- }
-
- public TransactionCompat hide(SurfaceControl surfaceControl) {
- mTransaction.hide(surfaceControl);
- return this;
- }
-
- public TransactionCompat setPosition(SurfaceControl surfaceControl, float x, float y) {
- mTransaction.setPosition(surfaceControl, x, y);
- return this;
- }
-
- public TransactionCompat setSize(SurfaceControl surfaceControl, int w, int h) {
- mTransaction.setBufferSize(surfaceControl, w, h);
- return this;
- }
-
- public TransactionCompat setLayer(SurfaceControl surfaceControl, int z) {
- mTransaction.setLayer(surfaceControl, z);
- return this;
- }
-
- public TransactionCompat setAlpha(SurfaceControl surfaceControl, float alpha) {
- mTransaction.setAlpha(surfaceControl, alpha);
- return this;
- }
-
- public TransactionCompat setOpaque(SurfaceControl surfaceControl, boolean opaque) {
- mTransaction.setOpaque(surfaceControl, opaque);
- return this;
- }
-
- public TransactionCompat setMatrix(SurfaceControl surfaceControl, float dsdx, float dtdx,
- float dtdy, float dsdy) {
- mTransaction.setMatrix(surfaceControl, dsdx, dtdx, dtdy, dsdy);
- return this;
- }
-
- public TransactionCompat setMatrix(SurfaceControl surfaceControl, Matrix matrix) {
- mTransaction.setMatrix(surfaceControl, matrix, mTmpValues);
- return this;
- }
-
- public TransactionCompat setWindowCrop(SurfaceControl surfaceControl, Rect crop) {
- mTransaction.setWindowCrop(surfaceControl, crop);
- return this;
- }
-
- public TransactionCompat setCornerRadius(SurfaceControl surfaceControl, float radius) {
- mTransaction.setCornerRadius(surfaceControl, radius);
- return this;
- }
-
- public TransactionCompat setBackgroundBlurRadius(SurfaceControl surfaceControl, int radius) {
- mTransaction.setBackgroundBlurRadius(surfaceControl, radius);
- return this;
- }
-
- public TransactionCompat setColor(SurfaceControl surfaceControl, float[] color) {
- mTransaction.setColor(surfaceControl, color);
- return this;
- }
-
- public static void setRelativeLayer(Transaction t, SurfaceControl surfaceControl,
- SurfaceControl relativeTo, int z) {
- t.setRelativeLayer(surfaceControl, relativeTo, z);
- }
-}
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/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 20fa8f8..453072b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -48,6 +48,9 @@
private ConstraintLayout mContainer;
private int mDisappearYTranslation;
private View[][] mViews;
+ private int mYTrans;
+ private int mYTransOffset;
+ private View mBouncerMessageView;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public KeyguardPINView(Context context) {
@@ -67,6 +70,8 @@
mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
+ mYTrans = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry);
+ mYTransOffset = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry_offset);
}
@Override
@@ -138,6 +143,7 @@
super.onFinishInflate();
mContainer = findViewById(R.id.pin_container);
+ mBouncerMessageView = findViewById(R.id.bouncer_message_area);
mViews = new View[][]{
new View[]{
findViewById(R.id.row0), null, null
@@ -206,6 +212,12 @@
/** Animate subviews according to expansion or time. */
private void animate(float progress) {
+ Interpolator standardDecelerate = Interpolators.STANDARD_DECELERATE;
+ Interpolator legacyDecelerate = Interpolators.LEGACY_DECELERATE;
+
+ mBouncerMessageView.setTranslationY(
+ mYTrans - mYTrans * standardDecelerate.getInterpolation(progress));
+
for (int i = 0; i < mViews.length; i++) {
View[] row = mViews[i];
for (View view : row) {
@@ -213,14 +225,15 @@
continue;
}
- float scaledProgress = MathUtils.constrain(
+ float scaledProgress = legacyDecelerate.getInterpolation(MathUtils.constrain(
(progress - 0.075f * i) / (1f - 0.075f * mViews.length),
0f,
1f
- );
+ ));
view.setAlpha(scaledProgress);
- Interpolator interpolator = Interpolators.STANDARD_ACCELERATE;
- view.setTranslationY(40 - (40 * interpolator.getInterpolation(scaledProgress)));
+ int yDistance = mYTrans + mYTransOffset * i;
+ view.setTranslationY(
+ yDistance - (yDistance * standardDecelerate.getInterpolation(progress)));
if (view instanceof NumPadAnimationListener) {
((NumPadAnimationListener) view).setProgress(scaledProgress);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 9f4585f..89fcc47 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -82,6 +82,12 @@
}
@Override
+ public void startAppearAnimation() {
+ mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin);
+ super.startAppearAnimation();
+ }
+
+ @Override
public boolean startDisappearAnimation(Runnable finishRunnable) {
return mView.startDisappearAnimation(
mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
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/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index e0cafae..41111e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -86,7 +86,7 @@
public void setProgress(float progress) {
mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
- int height = (int) (mHeight * 0.8f + mHeight * 0.2 * progress);
+ int height = (int) (mHeight * 0.7f + mHeight * 0.3 * progress);
int difference = mHeight - height;
mBackground.setBounds(0, difference / 2, mHeight, mHeight - difference / 2);
}
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/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 78099d1f..3695df5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -98,7 +98,7 @@
* Flag to enable the usage of the new bouncer data source. This is a refactor of and
* eventual replacement of KeyguardBouncer.java.
*/
- public static final ReleasedFlag MODERN_BOUNCER = new ReleasedFlag(208);
+ public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
/** Whether UserSwitcherActivity should use modern architecture. */
public static final UnreleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index b39770d..2d09ddd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -310,6 +310,7 @@
if (icon.getType() != Icon.TYPE_BITMAP && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {
// icon doesn't support getBitmap, use default value for color scheme
updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
} else {
Configuration config = mContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
@@ -319,11 +320,14 @@
if (colorSetUpdated) {
mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
}
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
} else {
+ updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
mHeaderIcon.setVisibility(View.GONE);
}
if (appSourceIcon != null) {
@@ -381,11 +385,16 @@
private void updateButtonBackgroundColorFilter() {
ColorFilter buttonColorFilter = new PorterDuffColorFilter(
- mAdapter.getController().getColorButtonBackground(),
+ mMediaOutputController.getColorButtonBackground(),
PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
mStopButton.getBackground().setColorFilter(buttonColorFilter);
- mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
+ mDoneButton.setTextColor(mMediaOutputController.getColorPositiveButtonText());
+ }
+
+ private void updateDialogBackgroundColor() {
+ getDialogView().getBackground().setTint(mMediaOutputController.getColorDialogBackground());
+ mDeviceListLayout.setBackgroundColor(mMediaOutputController.getColorDialogBackground());
}
private Drawable resizeDrawable(Drawable drawable, int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 96817c9..f040e06 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -133,6 +133,7 @@
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
private MediaOutputMetricLogger mMetricLogger;
+ private int mCurrentState;
private int mColorItemContent;
private int mColorSeekbarProgress;
@@ -140,6 +141,7 @@
private int mColorItemBackground;
private int mColorConnectedItemBackground;
private int mColorPositiveButtonText;
+ private int mColorDialogBackground;
private float mInactiveRadius;
private float mActiveRadius;
@@ -188,6 +190,8 @@
R.dimen.media_output_dialog_background_radius);
mActiveRadius = mContext.getResources().getDimension(
R.dimen.media_output_dialog_active_background_radius);
+ mColorDialogBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_background);
}
void start(@NonNull Callback cb) {
@@ -204,6 +208,9 @@
if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
mMediaController = controller;
mMediaController.unregisterCallback(mCb);
+ if (mMediaController.getPlaybackState() != null) {
+ mCurrentState = mMediaController.getPlaybackState().getState();
+ }
mMediaController.registerCallback(mCb);
break;
}
@@ -461,6 +468,7 @@
mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
+ mColorDialogBackground = mCurrentColorScheme.getNeutral1().get(10); // N1-900
} else {
mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
@@ -468,6 +476,7 @@
mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
+ mColorDialogBackground = mCurrentColorScheme.getBackgroundColor();
}
}
@@ -487,6 +496,10 @@
return mColorPositiveButtonText;
}
+ public int getColorDialogBackground() {
+ return mColorDialogBackground;
+ }
+
public int getColorItemContent() {
return mColorItemContent;
}
@@ -976,10 +989,16 @@
@Override
public void onPlaybackStateChanged(PlaybackState playbackState) {
- final int state = playbackState.getState();
- if (state == PlaybackState.STATE_STOPPED || state == PlaybackState.STATE_PAUSED) {
+ final int newState =
+ playbackState == null ? PlaybackState.STATE_STOPPED : playbackState.getState();
+ if (mCurrentState == newState) {
+ return;
+ }
+
+ if (newState == PlaybackState.STATE_STOPPED || newState == PlaybackState.STATE_PAUSED) {
mCallback.onMediaStoppedOrPaused();
}
+ mCurrentState = newState;
}
};
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/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index e2964ea..f60e066 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import android.app.UiModeManager;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Handler;
@@ -60,9 +61,7 @@
ConfigurationController.ConfigurationListener,
BatteryController.BatteryStateChangeCallback {
public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a");
- private final Icon mIcon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_qs_ui_mode_night);
- private UiModeManager mUiModeManager;
+ private final UiModeManager mUiModeManager;
private final BatteryController mBatteryController;
private final LocationController mLocationController;
@Inject
@@ -82,7 +81,8 @@
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mBatteryController = batteryController;
- mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
+ mUiModeManager = (UiModeManager) host.getUserContext().getSystemService(
+ Context.UI_MODE_SERVICE);
mLocationController = locationController;
configurationController.observe(getLifecycle(), this);
batteryController.observe(getLifecycle(), this);
@@ -155,7 +155,6 @@
}
state.value = nightMode;
state.label = mContext.getString(R.string.quick_settings_ui_mode_night_label);
- state.icon = mIcon;
state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
? state.label
: TextUtils.concat(state.label, ", ", state.secondaryLabel);
@@ -164,6 +163,9 @@
} else {
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
+ state.icon = ResourceIcon.get(state.state == Tile.STATE_ACTIVE
+ ? R.drawable.qs_light_dark_theme_icon_on
+ : R.drawable.qs_light_dark_theme_icon_off);
state.showRippleEffect = false;
state.expandedAccessibilityClassName = Switch.class.getName();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index ba26cfa..df81c0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1369,6 +1369,8 @@
}
ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
+ LinearLayout actionListMarginTarget = layout.findViewById(
+ com.android.internal.R.id.notification_action_list_margin_target);
if (bubbleButton == null || actionContainer == null) {
return;
}
@@ -1393,6 +1395,16 @@
bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener());
bubbleButton.setVisibility(VISIBLE);
actionContainer.setVisibility(VISIBLE);
+ // Set notification_action_list_margin_target's bottom margin to 0 when showing bubble
+ if (actionListMarginTarget != null) {
+ ViewGroup.LayoutParams lp = actionListMarginTarget.getLayoutParams();
+ if (lp instanceof ViewGroup.MarginLayoutParams) {
+ final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+ if (mlp.bottomMargin > 0) {
+ mlp.setMargins(mlp.leftMargin, mlp.topMargin, mlp.rightMargin, 0);
+ }
+ }
+ }
} else {
bubbleButton.setVisibility(GONE);
}
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/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7463dac..9603de9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -99,11 +99,14 @@
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.widget.DateTimeView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -509,10 +512,17 @@
private CentralSurfacesComponent mCentralSurfacesComponent;
// Flags for disabling the status bar
- // Two variables becaseu the first one evidently ran out of room for new flags.
+ // Two variables because the first one evidently ran out of room for new flags.
private int mDisabled1 = 0;
private int mDisabled2 = 0;
+ /**
+ * This keeps track of whether we have (or haven't) registered the predictive back callback.
+ * Since we can have visible -> visible transitions, we need to avoid
+ * double-registering (or double-unregistering) our callback.
+ */
+ private boolean mIsBackCallbackRegistered = false;
+
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
@@ -636,6 +646,12 @@
private final InteractionJankMonitor mJankMonitor;
+ private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+ if (DEBUG) {
+ Log.d(TAG, "mOnBackInvokedCallback() called");
+ }
+ onBackPressed();
+ };
/**
* Public constructor for CentralSurfaces.
@@ -2731,9 +2747,38 @@
if (visibleToUser) {
handleVisibleToUserChangedImpl(visibleToUser);
mNotificationLogger.startNotificationLogging();
+
+ if (!mIsBackCallbackRegistered) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher()
+ .registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ mOnBackInvokedCallback);
+ mIsBackCallbackRegistered = true;
+ if (DEBUG) Log.d(TAG, "is now VISIBLE to user AND callback registered");
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "is now VISIBLE to user, BUT callback ALREADY unregistered");
+ }
} else {
mNotificationLogger.stopNotificationLogging();
handleVisibleToUserChangedImpl(visibleToUser);
+
+ if (mIsBackCallbackRegistered) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher()
+ .unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+ mIsBackCallbackRegistered = false;
+ if (DEBUG) Log.d(TAG, "is NOT VISIBLE to user, AND callback unregistered");
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG,
+ "is NOT VISIBLE to user, BUT NO callback (or callback ALREADY "
+ + "unregistered)");
+ }
+ }
}
}
@@ -3444,6 +3489,12 @@
return mNotificationPanelViewController.getKeyguardBottomAreaView();
}
+ protected ViewRootImpl getViewRootImpl() {
+ NotificationShadeWindowView nswv = getNotificationShadeWindowView();
+ if (nswv != null) return nswv.getViewRootImpl();
+
+ return null;
+ }
/**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
@@ -3761,6 +3812,12 @@
updateScrimController();
}
+ @VisibleForTesting
+ public void setNotificationShadeWindowViewController(
+ NotificationShadeWindowViewController nswvc) {
+ mNotificationShadeWindowViewController = nswvc;
+ }
+
/**
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index e63c383..44aef7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -220,6 +220,7 @@
&& !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
KeyguardUpdateMonitor.getCurrentUser())
&& !needsFullscreenBouncer()
+ && !mKeyguardUpdateMonitor.isFaceLockedOut()
&& !mKeyguardUpdateMonitor.userNeedsStrongAuth()
&& !mKeyguardBypassController.getBypassEnabled()) {
mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
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/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
new file mode 100644
index 0000000..9e5bfe5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.statusbar.policy.DevicePostureController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPinViewControllerTest : SysuiTestCase() {
+ @Mock private lateinit var keyguardPinView: KeyguardPINView
+
+ @Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea
+
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+ @Mock private lateinit var securityMode: SecurityMode
+
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+
+ @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+
+ @Mock
+ private lateinit var keyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+
+ @Mock
+ private lateinit var keyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+
+ @Mock private lateinit var mLatencyTracker: LatencyTracker
+
+ @Mock private lateinit var liftToActivateListener: LiftToActivateListener
+
+ @Mock private val mEmergencyButtonController: EmergencyButtonController? = null
+ private val falsingCollector: FalsingCollector = FalsingCollectorFake()
+ @Mock lateinit var postureController: DevicePostureController
+
+ lateinit var pinViewController: KeyguardPinViewController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ Mockito.`when`(keyguardPinView.requireViewById<View>(R.id.bouncer_message_area))
+ .thenReturn(keyguardMessageArea)
+ Mockito.`when`(
+ keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java))
+ )
+ .thenReturn(keyguardMessageAreaController)
+ pinViewController =
+ KeyguardPinViewController(
+ keyguardPinView,
+ keyguardUpdateMonitor,
+ securityMode,
+ lockPatternUtils,
+ mKeyguardSecurityCallback,
+ keyguardMessageAreaControllerFactory,
+ mLatencyTracker,
+ liftToActivateListener,
+ mEmergencyButtonController,
+ falsingCollector,
+ postureController
+ )
+ }
+
+ @Test
+ fun startAppearAnimation() {
+ pinViewController.startAppearAnimation()
+ verify(keyguardMessageAreaController).setMessageIfEmpty(R.string.keyguard_enter_your_pin)
+ }
+}
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/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
new file mode 100644
index 0000000..ea70c26
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.qs.tiles
+
+import android.app.UiModeManager
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.os.Handler
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.LocationController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class UiModeNightTileTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var uiModeManager: UiModeManager
+ @Mock
+ private lateinit var resources: Resources
+ @Mock
+ private lateinit var qsLogger: QSLogger
+ @Mock
+ private lateinit var qsHost: QSTileHost
+ @Mock
+ private lateinit var metricsLogger: MetricsLogger
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
+ @Mock
+ private lateinit var activityStarter: ActivityStarter
+ @Mock
+ private lateinit var configurationController: ConfigurationController
+ @Mock
+ private lateinit var batteryController: BatteryController
+ @Mock
+ private lateinit var locationController: LocationController
+
+ private val uiEventLogger = UiEventLoggerFake()
+ private val falsingManager = FalsingManagerFake()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var tile: UiModeNightTile
+ private lateinit var configuration: Configuration
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ configuration = Configuration()
+ mContext.addMockSystemService(Context.UI_MODE_SERVICE, uiModeManager)
+
+ `when`(qsHost.context).thenReturn(mockContext)
+ `when`(qsHost.userContext).thenReturn(mContext)
+ `when`(mockContext.resources).thenReturn(resources)
+ `when`(resources.configuration).thenReturn(configuration)
+ `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+
+ tile = UiModeNightTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ configurationController,
+ batteryController,
+ locationController)
+ }
+
+ @Test
+ fun testIcon_whenNightModeOn_isOnState() {
+ val state = QSTile.BooleanState()
+ setNightModeOn()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_on))
+ }
+
+ @Test
+ fun testIcon_whenNightModeOn_isOffState() {
+ val state = QSTile.BooleanState()
+ setNightModeOff()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_off))
+ }
+
+ private fun setNightModeOn() {
+ `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_YES)
+ configuration.uiMode = Configuration.UI_MODE_NIGHT_YES
+ }
+
+ private fun setNightModeOff() {
+ `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_NO)
+ configuration.uiMode = Configuration.UI_MODE_NIGHT_NO
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 14b7471..f510e48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -69,7 +70,11 @@
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -168,6 +173,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -279,6 +285,15 @@
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private DeviceStateManager mDeviceStateManager;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
+ /**
+ * The process of registering/unregistering a predictive back callback requires a
+ * ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
+ * To prevent an NPE during test execution, we explicitly craft and provide a fake ViewRootImpl.
+ */
+ @Mock private ViewRootImpl mViewRootImpl;
+ @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
+
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -368,10 +383,10 @@
return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
- mShadeController = new ShadeControllerImpl(mCommandQueue,
+ mShadeController = spy(new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
- () -> Optional.of(mCentralSurfaces), () -> mAssistManager);
+ () -> Optional.of(mCentralSurfaces), () -> mAssistManager));
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
@@ -460,7 +475,14 @@
mActivityLaunchAnimator,
mJankMonitor,
mDeviceStateManager,
- mWiredChargingRippleController, mDreamManager);
+ mWiredChargingRippleController, mDreamManager) {
+ @Override
+ protected ViewRootImpl getViewRootImpl() {
+ return mViewRootImpl;
+ }
+ };
+ when(mViewRootImpl.getOnBackInvokedDispatcher())
+ .thenReturn(mOnBackInvokedDispatcher);
when(mKeyguardViewMediator.registerCentralSurfaces(
any(CentralSurfacesImpl.class),
any(NotificationPanelViewController.class),
@@ -738,6 +760,43 @@
}
}
+ /**
+ * Do the following:
+ * 1. verify that a predictive back callback is registered when CSurf becomes visible
+ * 2. verify that the same callback is unregistered when CSurf becomes invisible
+ */
+ @Test
+ public void testPredictiveBackCallback_registration() {
+ mCentralSurfaces.handleVisibleToUserChanged(true);
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+ mOnBackInvokedCallback.capture());
+
+ mCentralSurfaces.handleVisibleToUserChanged(false);
+ verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
+ eq(mOnBackInvokedCallback.getValue()));
+ }
+
+ /**
+ * Do the following:
+ * 1. capture the predictive back callback during registration
+ * 2. call the callback directly
+ * 3. verify that the ShadeController's panel collapse animation is invoked
+ */
+ @Test
+ public void testPredictiveBackCallback_invocationCollapsesPanel() {
+ mCentralSurfaces.setNotificationShadeWindowViewController(
+ mNotificationShadeWindowViewController);
+ mCentralSurfaces.handleVisibleToUserChanged(true);
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+ mOnBackInvokedCallback.capture());
+
+ when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true);
+ mOnBackInvokedCallback.getValue().onBackInvoked();
+ verify(mShadeController).animateCollapsePanels();
+ }
+
@Test
public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 60a3d95..ab209d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -408,6 +408,16 @@
mBouncer.hide(false /* destroyView */);
verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
}
+
+ @Test
+ public void testShow_doesNotDelaysIfFaceAuthIsLockedOut() {
+ when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(true);
+ mBouncer.show(true /* reset */);
+
+ verify(mHandler, never()).postDelayed(any(), anyLong());
+ }
+
@Test
public void testShow_delaysIfFaceAuthIsRunning_unlessBypassEnabled() {
when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
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/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9f3f761..7ca6254 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -577,14 +577,6 @@
int filterCallingUid);
/**
- * Resolves an exported activity intent, allowing instant apps to be resolved.
- */
- public abstract ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags,
- @PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart,
- int filterCallingUid);
-
- /**
* Resolves a service intent, allowing instant apps to be resolved.
*/
public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index e21a3d7..6b3f5e2 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -98,12 +98,17 @@
}
private String getCallingPackageName() {
- final String[] packages = mContext.getPackageManager().getPackagesForUid(
- Binder.getCallingUid());
+ final PackageManager pm = mContext.getPackageManager();
+ final int uid = Binder.getCallingUid();
+ final String[] packages = pm.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
return packages[0];
}
- return "unknown";
+ final String name = pm.getNameForUid(uid);
+ if (name != null) {
+ return name;
+ }
+ return String.valueOf(uid);
}
private void dumpTempValues(String pkg, PrintWriter pw, int type,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2ccba56..842498d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -215,7 +215,6 @@
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
-import android.compat.annotation.EnabledAfter;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -586,17 +585,6 @@
private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
/**
- * Apps targeting Android U and above will need to export components in order to invoke them
- * through implicit intents.
- *
- * If a component is not exported and invoked, it will be removed from the list of receivers.
- * This applies specifically to activities and broadcasts.
- */
- @ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
- public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273;
-
- /**
* The maximum number of bytes that {@link #setProcessStateSummary} accepts.
*
* @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])}
@@ -12391,58 +12379,6 @@
}
/**
- * Filters out non-exported components in a given list of broadcast filters
- * @param intent the original intent
- * @param callingUid the calling UID
- * @param query the list of broadcast filters
- * @param platformCompat the instance of platform compat
- */
- private static void filterNonExportedComponents(Intent intent, int callingUid,
- List query, PlatformCompat platformCompat, String callerPackage) {
- if (query == null
- || intent.getPackage() != null
- || intent.getComponent() != null
- || ActivityManager.canAccessUnexportedComponents(callingUid)) {
- return;
- }
- for (int i = query.size() - 1; i >= 0; i--) {
- String componentInfo;
- ResolveInfo resolveInfo;
- BroadcastFilter broadcastFilter;
- if (query.get(i) instanceof ResolveInfo) {
- resolveInfo = (ResolveInfo) query.get(i);
- if (resolveInfo.getComponentInfo().exported) {
- continue;
- }
- componentInfo = resolveInfo.getComponentInfo()
- .getComponentName().flattenToShortString();
- } else if (query.get(i) instanceof BroadcastFilter) {
- broadcastFilter = (BroadcastFilter) query.get(i);
- if (broadcastFilter.exported) {
- continue;
- }
- componentInfo = broadcastFilter.packageName;
- } else {
- continue;
- }
- if (!platformCompat.isChangeEnabledByUid(
- IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid)) {
- Slog.w(TAG, "Non-exported component not filtered out "
- + "(will be filtered out once the app targets U+)- intent: "
- + intent.getAction() + ", component: "
- + componentInfo + ", sender: "
- + callerPackage);
- return;
- }
- Slog.w(TAG, "Non-exported component filtered out - intent: "
- + intent.getAction() + ", component: "
- + componentInfo + ", sender: "
- + callerPackage);
- query.remove(i);
- }
- }
-
- /**
* Main code for cleaning up a process when it has gone away. This is
* called both as a result of the process dying, or directly when stopping
* a process when running in single process mode.
@@ -14281,8 +14217,6 @@
}
}
- filterNonExportedComponents(intent, callingUid, registeredReceivers,
- mPlatformCompat, callerPackage);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
@@ -14385,8 +14319,6 @@
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
- filterNonExportedComponents(intent, callingUid, receivers,
- mPlatformCompat, callerPackage);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
@@ -16464,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/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 65e7ce1..34d6d29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -465,20 +465,6 @@
filterCallingUid);
}
- /**
- * @deprecated similar to {@link resolveIntent} but limits the matches to exported components.
- */
- @Override
- @Deprecated
- public final ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
- boolean resolveForStart, int filterCallingUid) {
- return getResolveIntentHelper().resolveIntentInternal(snapshot(),
- intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
- filterCallingUid, true);
- }
-
@Override
@Deprecated
public final ResolveInfo resolveService(Intent intent, String resolvedType,
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index fada577..c2fd637 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -52,7 +52,6 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.ArrayUtils;
-import com.android.server.am.ActivityManagerService;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -101,38 +100,6 @@
mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier;
}
- private static void filterNonExportedComponents(Intent intent, int filterCallingUid,
- List<ResolveInfo> query, PlatformCompat platformCompat, Computer computer) {
- if (query == null
- || intent.getPackage() != null
- || intent.getComponent() != null
- || ActivityManager.canAccessUnexportedComponents(filterCallingUid)) {
- return;
- }
- AndroidPackage caller = computer.getPackage(filterCallingUid);
- String callerPackage = caller == null ? "Not specified" : caller.getPackageName();
- for (int i = query.size() - 1; i >= 0; i--) {
- if (!query.get(i).getComponentInfo().exported) {
- if (!platformCompat.isChangeEnabledByUid(
- ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS,
- filterCallingUid)) {
- Slog.w(TAG, "Non-exported component not filtered out "
- + "(will be filtered out once the app targets U+)- intent: "
- + intent.getAction() + ", component: "
- + query.get(i).getComponentInfo()
- .getComponentName().flattenToShortString()
- + ", starter: " + callerPackage);
- return;
- }
- Slog.w(TAG, "Non-exported component filtered out - intent: "
- + intent.getAction() + ", component: "
- + query.get(i).getComponentInfo().getComponentName().flattenToShortString()
- + ", starter: " + callerPackage);
- query.remove(i);
- }
- }
- }
-
/**
* Normally instant apps can only be resolved when they're visible to the caller.
* However, if {@code resolveForStart} is {@code true}, all instant apps are visible
@@ -142,20 +109,6 @@
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
boolean resolveForStart, int filterCallingUid) {
- return resolveIntentInternal(computer, intent, resolvedType, flags,
- privateResolveFlags, userId, resolveForStart, filterCallingUid, false);
- }
-
- /**
- * Normally instant apps can only be resolved when they're visible to the caller.
- * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
- * since we need to allow the system to start any installed application.
- * Allows picking exported components only.
- */
- public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
- boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
@@ -171,10 +124,6 @@
final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent,
resolvedType, flags, privateResolveFlags, filterCallingUid, userId,
resolveForStart, true /*allowDynamicSplits*/);
- if (exportedComponentsOnly) {
- filterNonExportedComponents(intent, filterCallingUid, query,
- mPlatformCompat, computer);
- }
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final boolean queryMayBeFiltered =
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/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 28cd001..dc91c15 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -744,7 +744,7 @@
// (e.g. AMS.startActivityAsUser).
final long token = Binder.clearCallingIdentity();
try {
- return mService.getPackageManagerInternalLocked().resolveIntentExported(
+ return mService.getPackageManagerInternalLocked().resolveIntent(
intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true,
filterCallingUid);
} finally {
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/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 221e186..77d0f37 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -67,7 +67,7 @@
/** Which sync method to use for transition syncs. */
static final int SYNC_METHOD =
- android.os.SystemProperties.getBoolean("persist.wm.debug.shell_transit_blast", true)
+ android.os.SystemProperties.getBoolean("persist.wm.debug.shell_transit_blast", false)
? BLASTSyncEngine.METHOD_BLAST : BLASTSyncEngine.METHOD_NONE;
/** The same as legacy APP_TRANSITION_TIMEOUT_MS. */
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/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 3c68662..f05b1d4 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -218,6 +218,9 @@
BackgroundThread.get().getThreadHandler().post(
() -> {
try {
+ if (sSelfService.mIProfcollect == null) {
+ return;
+ }
sSelfService.mIProfcollect.process();
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to process profiles in background: "
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/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2b0e76c..85e5bfd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -379,8 +379,6 @@
doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(),
anyInt(), anyBoolean(), anyInt());
- doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(),
- anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt());
doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
// Never review permissions
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3023ec9..16f8fd9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -39,7 +39,6 @@
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.data.ApnSetting;
-import android.telephony.data.DataCallResponse;
import android.telephony.gba.TlsParams;
import android.telephony.gba.UaSecurityProtocolIdentifier;
import android.telephony.ims.ImsReasonInfo;
@@ -1136,27 +1135,6 @@
public static final String KEY_DEFAULT_MTU_INT = "default_mtu_int";
/**
- * The data call retry configuration for different types of APN.
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
- "carrier_data_call_retry_config_strings";
-
- /**
- * Delay in milliseconds between trying APN from the pool
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
- "carrier_data_call_apn_delay_default_long";
-
- /**
- * Faster delay in milliseconds between trying APN from the pool
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
- "carrier_data_call_apn_delay_faster_long";
-
- /**
* Delay in milliseconds for retrying APN after disconnect
* @hide
*/
@@ -1164,21 +1142,6 @@
"carrier_data_call_apn_retry_after_disconnect_long";
/**
- * The maximum times for telephony to retry data setup on the same APN requested by
- * network through the data setup response retry timer
- * {@link DataCallResponse#getRetryDurationMillis()}. This is to prevent that network keeps
- * asking device to retry data setup forever and causes power consumption issue. For infinite
- * retring same APN, configure this as 2147483647 (i.e. {@link Integer#MAX_VALUE}).
- *
- * Note if network does not suggest any retry timer, frameworks uses the retry configuration
- * from {@link #KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS}, and the maximum retry times could
- * be configured there.
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT =
- "carrier_data_call_retry_network_requested_max_count_int";
-
- /**
* Data call setup permanent failure causes by the carrier
*/
public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -1239,19 +1202,6 @@
"carrier_metered_roaming_apn_types_strings";
/**
- * APN types that are not allowed on cellular
- * @hide
- */
- public static final String KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
- "carrier_wwan_disallowed_apn_types_string_array";
-
- /**
- * APN types that are not allowed on IWLAN
- * @hide
- */
- public static final String KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
- "carrier_wlan_disallowed_apn_types_string_array";
- /**
* CDMA carrier ERI (Enhanced Roaming Indicator) file name
* @hide
*/
@@ -8470,7 +8420,6 @@
* "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
* 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
*
- * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS
* @hide
*/
public static final String KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY =
@@ -8872,27 +8821,13 @@
sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putInt(KEY_DEFAULT_MTU_INT, 1500);
- sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
- "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
- + "320000:5000,640000:5000,1280000:5000,1800000:5000",
- "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
- + "320000:5000,640000:5000,1280000:5000,1800000:5000",
- "ims:max_retries=10, 5000, 5000, 5000",
- "others:max_retries=3, 5000, 5000, 5000"});
- sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
- sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 3000);
- sDefaults.putInt(KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, 3);
sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
- sDefaults.putStringArray(KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
- new String[]{""});
- sDefaults.putStringArray(KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
- new String[]{""});
sDefaults.putIntArray(KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY,
new int[] {TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT,
TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A,
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3032bab..850d268 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2548,9 +2548,6 @@
CellIdentity getLastKnownCellIdentity(int subId, String callingPackage,
String callingFeatureId);
- /** Check if telephony new data stack is enabled. */
- boolean isUsingNewDataStack();
-
/**
* @return true if the modem service is set successfully, false otherwise.
*/
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/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
new file mode 100644
index 0000000..807e672
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.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.UiObject2
+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
+
+class MailAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.MAIL_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentNameMatcher =
+ ActivityOptions.MAIL_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ fun openMail(rowIdx: Int) {
+ val rowSel = By.res(getPackage(), "mail_row_item_text")
+ .textEndsWith(String.format("%04d", rowIdx))
+ var row: UiObject2? = null
+ for (i in 1..1000) {
+ row = uiDevice.wait(Until.findObject(rowSel), SHORT_WAIT_TIME_MS)
+ if (row != null) break
+ scrollDown()
+ }
+ require(row != null) {""}
+ row.click()
+ uiDevice.wait(Until.gone(By.res(getPackage(), MAIL_LIST_RES_ID)), FIND_TIMEOUT)
+ }
+
+ fun scrollDown() {
+ val listView = waitForMailList()
+ listView.scroll(Direction.DOWN, 1.0f)
+ }
+
+ fun waitForMailList(): UiObject2 {
+ var sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
+ val ret = uiDevice.wait(Until.findObject(sel), FIND_TIMEOUT)
+ require(ret != null) {""}
+ return ret
+ }
+
+ companion object {
+ private const val SHORT_WAIT_TIME_MS = 5000L
+ private const val MAIL_LIST_RES_ID = "mail_recycle_view"
+ }
+}
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} */
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 72a02f2..cae3df4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -101,6 +101,10 @@
FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
+ public static final String MAIL_ACTIVITY_LAUNCHER_NAME = "MailActivity";
+ public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
+
public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
diff --git a/tests/TouchLatency/OWNERS b/tests/TouchLatency/OWNERS
new file mode 100644
index 0000000..2b7de25
--- /dev/null
+++ b/tests/TouchLatency/OWNERS
@@ -0,0 +1,2 @@
+include platform/frameworks/base:/graphics/java/android/graphics/OWNERS
+include platform/frameworks/native:/services/surfaceflinger/OWNERS
\ No newline at end of file