summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/TaskInfo.java11
-rw-r--r--core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl1
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java3
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java2
-rw-r--r--core/java/android/os/BatteryStats.java9
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java50
-rw-r--r--core/java/com/android/internal/app/procstats/UidState.java1
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java55
-rw-r--r--core/java/com/android/internal/os/PhonePowerCalculator.java25
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java69
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt7
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java3
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java1
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java9
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java85
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java36
-rw-r--r--services/core/java/com/android/server/wm/Task.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java43
42 files changed, 588 insertions, 232 deletions
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 8ee23aa8e67b..aba4b2c0d591 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -188,6 +188,14 @@ public class TaskInfo {
public int launchIntoPipHostTaskId;
/**
+ * The task id of the parent Task of the launch-into-pip Activity, i.e., if task have more than
+ * one activity it will create new task for this activity, this id is the origin task id and
+ * the pip activity will be reparent to origin task when it exit pip mode.
+ * @hide
+ */
+ public int lastParentTaskIdBeforePip;
+
+ /**
* The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
* (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
* {@code null} otherwise.
@@ -503,6 +511,7 @@ public class TaskInfo {
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
shouldDockBigOverlays = source.readBoolean();
launchIntoPipHostTaskId = source.readInt();
+ lastParentTaskIdBeforePip = source.readInt();
displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
isResizeable = source.readBoolean();
@@ -549,6 +558,7 @@ public class TaskInfo {
dest.writeTypedObject(pictureInPictureParams, flags);
dest.writeBoolean(shouldDockBigOverlays);
dest.writeInt(launchIntoPipHostTaskId);
+ dest.writeInt(lastParentTaskIdBeforePip);
dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
dest.writeBoolean(isResizeable);
@@ -589,6 +599,7 @@ public class TaskInfo {
+ " pictureInPictureParams=" + pictureInPictureParams
+ " shouldDockBigOverlays=" + shouldDockBigOverlays
+ " launchIntoPipHostTaskId=" + launchIntoPipHostTaskId
+ + " lastParentTaskIdBeforePip=" + lastParentTaskIdBeforePip
+ " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
+ " launchCookies=" + launchCookies
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
index 34d016adbc06..7c54a9b01dde 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -36,4 +36,5 @@ parcelable CameraOutputConfig
int surfaceGroupId;
String physicalCameraId;
List<CameraOutputConfig> sharedSurfaceConfigs;
+ boolean isMultiResolutionOutput;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index c8dc2d0b0b91..77def20179ae 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -226,6 +226,9 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
OutputConfiguration cameraOutput = new OutputConfiguration(output.surfaceGroupId,
outputSurface);
+ if (output.isMultiResolutionOutput) {
+ cameraOutput.setMultiResolutionOutput();
+ }
if ((output.sharedSurfaceConfigs != null) && !output.sharedSurfaceConfigs.isEmpty()) {
cameraOutput.enableSurfaceSharing();
for (CameraOutputConfig sharedOutputConfig : output.sharedSurfaceConfigs) {
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 90e92dbe2ab0..9868d87460e0 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -421,7 +421,7 @@ public final class OutputConfiguration implements Parcelable {
* call, or no non-negative group ID has been set.
* @hide
*/
- void setMultiResolutionOutput() {
+ public void setMultiResolutionOutput() {
if (mIsShared) {
throw new IllegalStateException("Multi-resolution output flag must not be set for " +
"configuration with surface sharing");
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 76475f2142c0..4f49f12691d0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2808,6 +2808,15 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getMobileRadioMeasuredBatteryConsumptionUC();
/**
+ * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device
+ * power measurement data.
+ * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+ *
+ * {@hide}
+ */
+ public abstract long getPhoneEnergyConsumptionUC();
+
+ /**
* Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 36e0dc35cb8e..b02e123e5254 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -141,12 +141,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private int mRingerMode;
private int mZenMode;
private boolean mPlaySample;
+ private final boolean mDeviceHasProductStrategies;
private static final int MSG_SET_STREAM_VOLUME = 0;
private static final int MSG_START_SAMPLE = 1;
private static final int MSG_STOP_SAMPLE = 2;
private static final int MSG_INIT_SAMPLE = 3;
+ private static final int MSG_UPDATE_SLIDER_MAYBE_LATER = 4;
private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+ private static final int CHECK_UPDATE_SLIDER_LATER_MS = 500;
private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000);
@@ -170,6 +173,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
boolean playSample) {
mContext = context;
mAudioManager = context.getSystemService(AudioManager.class);
+ mDeviceHasProductStrategies = hasAudioProductStrategies();
mNotificationManager = context.getSystemService(NotificationManager.class);
mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
@@ -186,7 +190,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
mZenMode = mNotificationManager.getZenMode();
- if (hasAudioProductStrategies()) {
+ if (mDeviceHasProductStrategies) {
mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType);
mAttributes = getAudioAttributesForLegacyStreamType(
mStreamType);
@@ -213,6 +217,12 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
mDefaultUri = defaultUri;
}
+ /**
+ * DO NOT CALL every time this is needed, use once in constructor,
+ * read mDeviceHasProductStrategies instead
+ * @return true if stream types are used for volume management, false if volume groups are
+ * used for volume management
+ */
private boolean hasAudioProductStrategies() {
return AudioManager.getAudioProductStrategies().size() > 0;
}
@@ -330,6 +340,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
onInitSample();
}
break;
+ case MSG_UPDATE_SLIDER_MAYBE_LATER:
+ onUpdateSliderMaybeLater();
+ break;
default:
Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
}
@@ -353,6 +366,21 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
: isDelay() ? START_SAMPLE_DELAY_MS : 0);
}
+ private void onUpdateSliderMaybeLater() {
+ if (isDelay()) {
+ postUpdateSliderMaybeLater();
+ return;
+ }
+ updateSlider();
+ }
+
+ private void postUpdateSliderMaybeLater() {
+ if (mHandler == null) return;
+ mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SLIDER_MAYBE_LATER),
+ CHECK_UPDATE_SLIDER_LATER_MS);
+ }
+
// After stop volume it needs to add a small delay when playing volume or set stream.
// It is because the call volume is from the earpiece and the alarm/ring/media
// is from the speaker. If play the alarm volume or set alarm stream right after stop
@@ -422,7 +450,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
postStopSample();
mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
mReceiver.setListening(false);
- if (hasAudioProductStrategies()) {
+ if (mDeviceHasProductStrategies) {
unregisterVolumeGroupCb();
}
mSeekBar.setOnSeekBarChangeListener(null);
@@ -442,7 +470,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]),
false, mVolumeObserver);
mReceiver.setListening(true);
- if (hasAudioProductStrategies()) {
+ if (mDeviceHasProductStrategies) {
registerVolumeGroupCb();
}
}
@@ -466,6 +494,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
mLastProgress = progress;
mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
mHandler.removeMessages(MSG_START_SAMPLE);
+ mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME),
isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0);
}
@@ -608,7 +637,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
- if (hasAudioProductStrategies() && !isDelay()) {
+ if (mDeviceHasProductStrategies && !isDelay()) {
updateVolumeSlider(streamType, streamValue);
}
} else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
@@ -620,9 +649,16 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
} else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
- if (hasAudioProductStrategies() && !isDelay()) {
- int streamVolume = mAudioManager.getStreamVolume(streamType);
- updateVolumeSlider(streamType, streamVolume);
+
+ if (mDeviceHasProductStrategies) {
+ if (isDelay()) {
+ // not the right time to update the sliders, try again later
+ postUpdateSliderMaybeLater();
+ } else {
+ int streamVolume = mAudioManager.getStreamVolume(streamType);
+ updateVolumeSlider(streamType, streamVolume);
+ }
+
} else {
int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType);
if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
diff --git a/core/java/com/android/internal/app/procstats/UidState.java b/core/java/com/android/internal/app/procstats/UidState.java
index 8761b7470cd3..49113465c26a 100644
--- a/core/java/com/android/internal/app/procstats/UidState.java
+++ b/core/java/com/android/internal/app/procstats/UidState.java
@@ -150,6 +150,7 @@ public final class UidState {
public void resetSafely(long now) {
mDurations.resetTable();
mStartTime = now;
+ mProcesses.removeIf(p -> !p.isInUse());
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6fed26c4a81d..e1e57de15346 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -166,8 +166,8 @@ public class BatteryStatsImpl extends BatteryStats {
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
- // Current on-disk Parcel version
- static final int VERSION = 210;
+ // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
+ public static final int VERSION = 211;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -6491,6 +6491,9 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);
+ if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) {
+ scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO);
+ }
}
}
@@ -6509,6 +6512,7 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mPhoneOn = false;
mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);
+ scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO);
}
}
@@ -8475,6 +8479,12 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
@Override
+ public long getPhoneEnergyConsumptionUC() {
+ return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_PHONE);
+ }
+
+ @GuardedBy("this")
+ @Override
public long getScreenOnMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
}
@@ -13717,18 +13727,36 @@ public class BatteryStatsImpl extends BatteryStats {
}
synchronized (this) {
+ final long totalRadioDurationMs =
+ mMobileRadioActiveTimer.getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
+ final long phoneOnDurationMs = Math.min(totalRadioDurationMs,
+ mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000);
+ mPhoneOnTimer.setMark(elapsedRealtimeMs);
+
if (!mOnBatteryInternal || mIgnoreNextExternalStats) {
return;
}
final SparseDoubleArray uidEstimatedConsumptionMah;
+ final long dataConsumedChargeUC;
if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null
&& mGlobalMeasuredEnergyStats != null) {
+ // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the
+ // numerator for long rounding.
+ final long phoneConsumedChargeUC =
+ (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2)
+ / totalRadioDurationMs;
+ dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC;
mGlobalMeasuredEnergyStats.updateStandardBucket(
- MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
+ MeasuredEnergyStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC);
+ mGlobalMeasuredEnergyStats.updateStandardBucket(
+ MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC);
uidEstimatedConsumptionMah = new SparseDoubleArray();
} else {
uidEstimatedConsumptionMah = null;
+ dataConsumedChargeUC = POWER_DATA_UNAVAILABLE;
}
if (deltaInfo != null) {
@@ -13888,14 +13916,9 @@ public class BatteryStatsImpl extends BatteryStats {
// Update the MeasuredEnergyStats information.
if (uidEstimatedConsumptionMah != null) {
double totalEstimatedConsumptionMah = 0.0;
-
- // Estimate total active radio power consumption since last mark.
- final long totalRadioTimeMs = mMobileRadioActiveTimer.getTimeSinceMarkLocked(
- elapsedRealtimeMs * 1000) / 1000;
- mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
- totalRadioTimeMs);
+ totalRadioDurationMs);
// Estimate idle power consumption at each signal strength level
final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
@@ -13919,7 +13942,7 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO,
- consumedChargeUC, uidEstimatedConsumptionMah,
+ dataConsumedChargeUC, uidEstimatedConsumptionMah,
totalEstimatedConsumptionMah, elapsedRealtimeMs);
}
@@ -16651,6 +16674,8 @@ public class BatteryStatsImpl extends BatteryStats {
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
public static final String KEY_BATTERY_CHARGED_DELAY_MS =
"battery_charged_delay_ms";
+ public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
+ "phone_on_external_stats_collection";
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -16663,6 +16688,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
+ private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
/* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -16678,6 +16704,8 @@ public class BatteryStatsImpl extends BatteryStats {
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
+ public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
+ DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -16754,6 +16782,11 @@ public class BatteryStatsImpl extends BatteryStats {
DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
+
+ PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean(
+ KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION,
+ DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION);
+
updateBatteryChargedDelayMsLocked();
}
}
@@ -16808,6 +16841,8 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(MAX_HISTORY_BUFFER/1024);
pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
pw.println(BATTERY_CHARGED_DELAY_MS);
+ pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
+ pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION);
}
}
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index cb893defab14..f1c4ffe07788 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -40,14 +40,27 @@ public class PhonePowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC();
+ final int powerModel = getPowerModel(energyConsumerUC, query);
+
final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED) / 1000;
- final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
- if (phoneOnPower != 0) {
- builder.getAggregateBatteryConsumerBuilder(
- BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
- .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+ final double phoneOnPower;
+ switch (powerModel) {
+ case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+ phoneOnPower = uCtoMah(energyConsumerUC);
+ break;
+ case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+ default:
+ phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
}
+
+ if (phoneOnPower == 0.0) return;
+
+ builder.getAggregateBatteryConsumerBuilder(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel)
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+
}
}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 7fb8696a217d..5bfdd62592c8 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -59,7 +59,9 @@ public class MeasuredEnergyStats {
public static final int POWER_BUCKET_BLUETOOTH = 5;
public static final int POWER_BUCKET_GNSS = 6;
public static final int POWER_BUCKET_MOBILE_RADIO = 7;
- public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom.
+ public static final int POWER_BUCKET_CAMERA = 8;
+ public static final int POWER_BUCKET_PHONE = 9;
+ public static final int NUMBER_STANDARD_POWER_BUCKETS = 10; // Buckets above this are custom.
@IntDef(prefix = {"POWER_BUCKET_"}, value = {
POWER_BUCKET_UNKNOWN,
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
index d4276efe39c2..61899143b9c5 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
@@ -186,4 +186,19 @@ public class ProcessStatsTest extends TestCase {
eq(0),
eq(APP_1_PROCESS_NAME));
}
+
+ @SmallTest
+ public void testSafelyResetClearsProcessInUidState() throws Exception {
+ ProcessStats processStats = new ProcessStats();
+ ProcessState processState =
+ processStats.getProcessStateLocked(
+ APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+ processState.makeActive();
+ UidState uidState = processStats.mUidStates.get(APP_1_UID);
+ assertTrue(uidState.isInUse());
+ processState.makeInactive();
+ uidState.resetSafely(NOW_MS);
+ processState.makeActive();
+ assertFalse(uidState.isInUse());
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 00ac1985f897..0bdf491e6377 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -245,6 +245,8 @@ public class MobileRadioPowerCalculatorTest {
stats.noteNetworkInterfaceForTransports("cellular",
new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+ stats.notePhoneOnLocked(9800, 9800);
+
// Note application network activity
NetworkStats networkStats = new NetworkStats(10000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
@@ -257,27 +259,33 @@ public class MobileRadioPowerCalculatorTest {
mStatsRule.setTime(12_000, 12_000);
- MobileRadioPowerCalculator calculator =
+ MobileRadioPowerCalculator mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
- mStatsRule.apply(calculator);
+ PhonePowerCalculator phonePowerCalculator =
+ new PhonePowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(1.53934);
+ .isWithin(PRECISION).of(1.38541);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.77778);
+ .isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+ assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isWithin(PRECISION).of(0.27778);
+ assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(1.53934);
+ .isWithin(PRECISION).of(1.38541);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
index cb1a6e7ace6b..ac6e4c2a6521 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
@@ -59,7 +59,7 @@ public class TabletopModeController implements
*/
private static final boolean ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
SystemProperties.getBoolean(
- "persist.wm.debug.enable_move_floating_window_in_tabletop", false);
+ "persist.wm.debug.enable_move_floating_window_in_tabletop", true);
/**
* Prefer the {@link #PREFERRED_TABLETOP_HALF_TOP} if this flag is enabled,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 6831a47c3f1a..1dd2ef94a959 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -538,6 +539,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
return;
}
+ if (mSplitScreenOptional.isPresent()) {
+ // If pip activity will reparent to origin task case and if the origin task still under
+ // split root, just exit split screen here to ensure it could expand to fullscreen.
+ SplitScreenController split = mSplitScreenOptional.get();
+ if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
+ split.exitSplitScreen(INVALID_TASK_ID,
+ SplitScreenController.EXIT_REASON_APP_FINISHED);
+ }
+ }
mSyncTransactionQueue.queue(wct);
mSyncTransactionQueue.runInSync(t -> {
// Make sure to grab the latest source hint rect as it could have been
@@ -1481,9 +1491,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
applyFinishBoundsResize(wct, direction, false);
}
} else {
- final boolean isPipTopLeft =
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft();
- applyFinishBoundsResize(wct, direction, isPipTopLeft);
+ applyFinishBoundsResize(wct, direction, isPipToTopLeft());
+ // Use sync transaction to apply finish transaction for enter split case.
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ mSyncTransactionQueue.runInSync(t -> {
+ t.merge(tx);
+ });
+ }
}
finishResizeForMenu(destinationBounds);
@@ -1520,7 +1534,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper.round(tx, mLeash, isInPip());
wct.setBounds(mToken, taskBounds);
- wct.setBoundsChangeTransaction(mToken, tx);
+ // Pip to split should use sync transaction to sync split bounds change.
+ if (direction != TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ wct.setBoundsChangeTransaction(mToken, tx);
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 979b7c7dc31f..167c0321d3ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -282,7 +282,8 @@ public class PipMenuView extends FrameLayout {
public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
final boolean isSplitScreen = mSplitScreenControllerOptional.isPresent()
- && mSplitScreenControllerOptional.get().isTaskInSplitScreen(taskInfo.taskId);
+ && mSplitScreenControllerOptional.get().isTaskInSplitScreenForeground(
+ taskInfo.taskId);
mFocusedTaskAllowSplitScreen = isSplitScreen
|| (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& taskInfo.supportsMultiWindow
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 94b9e907fa76..7d5ab8428a3e 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
@@ -31,7 +31,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -89,7 +88,6 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
@@ -329,9 +327,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return mTaskOrganizer.getRunningTaskInfo(taskId);
}
+ /** Check task is under split or not by taskId. */
public boolean isTaskInSplitScreen(int taskId) {
- return isSplitScreenVisible()
- && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
+ return mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
+ }
+
+ /** Check split is foreground and task is under split or not by taskId. */
+ public boolean isTaskInSplitScreenForeground(int taskId) {
+ return isTaskInSplitScreen(taskId) && isSplitScreenVisible();
}
public @SplitPosition int getSplitPosition(int taskId) {
@@ -339,8 +342,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
- return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
- new WindowContainerTransaction());
+ return moveToStage(taskId, sideStagePosition, new WindowContainerTransaction());
}
/**
@@ -351,13 +353,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.updateSurfaces(transaction);
}
- private boolean moveToStage(int taskId, @StageType int stageType,
- @SplitPosition int stagePosition, WindowContainerTransaction wct) {
+ private boolean moveToStage(int taskId, @SplitPosition int stagePosition,
+ WindowContainerTransaction wct) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task == null) {
throw new IllegalArgumentException("Unknown taskId" + taskId);
}
- return mStageCoordinator.moveToStage(task, stageType, stagePosition, wct);
+ return mStageCoordinator.moveToStage(task, stagePosition, wct);
}
public boolean removeFromSideStage(int taskId) {
@@ -382,10 +384,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
- final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
final int stagePosition =
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
- moveToStage(taskId, stageType, stagePosition, wct);
+ moveToStage(taskId, stagePosition, wct);
}
public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
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 71ee690146f9..e2d7a7764808 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
@@ -399,56 +399,43 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return STAGE_TYPE_UNDEFINED;
}
- boolean moveToStage(ActivityManager.RunningTaskInfo task, @StageType int stageType,
- @SplitPosition int stagePosition, WindowContainerTransaction wct) {
+ boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
+ WindowContainerTransaction wct) {
StageTaskListener targetStage;
int sideStagePosition;
- if (stageType == STAGE_TYPE_MAIN) {
- targetStage = mMainStage;
- sideStagePosition = reverseSplitPosition(stagePosition);
- } else if (stageType == STAGE_TYPE_SIDE) {
+ if (isSplitScreenVisible()) {
+ // If the split screen is foreground, retrieves target stage based on position.
+ targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
+ sideStagePosition = mSideStagePosition;
+ } else {
targetStage = mSideStage;
sideStagePosition = stagePosition;
- } else {
- if (isSplitScreenVisible()) {
- // If the split screen is activated, retrieves target stage based on position.
- targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
- sideStagePosition = mSideStagePosition;
- } else {
- // Exit split if it running background.
- exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
-
- targetStage = mSideStage;
- sideStagePosition = stagePosition;
- }
}
if (!isSplitActive()) {
- // prevent the fling divider to center transitioni if split screen didn't active.
- mIsDropEntering = true;
- }
-
- setSideStagePosition(sideStagePosition, wct);
- final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- targetStage.evictAllChildren(evictWct);
-
- // Apply surface bounds before animation start.
- SurfaceControl.Transaction startT = mTransactionPool.acquire();
- if (startT != null) {
- updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */);
- startT.apply();
- mTransactionPool.release(startT);
+ mSplitLayout.init();
+ prepareEnterSplitScreen(wct, task, stagePosition);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ });
+ } else {
+ setSideStagePosition(sideStagePosition, wct);
+ targetStage.addTask(task, wct);
+ targetStage.evictAllChildren(wct);
+ if (!isSplitScreenVisible()) {
+ final StageTaskListener anotherStage = targetStage == mMainStage
+ ? mSideStage : mMainStage;
+ anotherStage.reparentTopTask(wct);
+ anotherStage.evictAllChildren(wct);
+ wct.reorder(mRootTaskInfo.token, true);
+ }
+ setRootForceTranslucent(false, wct);
+ mSyncQueue.queue(wct);
}
- // reparent the task to an invisible split root will make the activity invisible. Reorder
- // the root task to front to make the entering transition from pip to split smooth.
- wct.reorder(mRootTaskInfo.token, true);
- wct.reorder(targetStage.mRootTaskInfo.token, true);
- targetStage.addTask(task, wct);
- if (!evictWct.isEmpty()) {
- wct.merge(evictWct, true /* transfer */);
- }
- mTaskOrganizer.applyTransaction(wct);
+ // Due to drag already pip task entering split by this method so need to reset flag here.
+ mIsDropEntering = false;
return true;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 0bb809d354dc..0b528ba3a9ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -144,39 +144,48 @@ public class StageCoordinatorTests extends ShellTestCase {
}
@Test
- public void testMoveToStage() {
+ public void testMoveToStage_splitActiveBackground() {
+ when(mStageCoordinator.isSplitActive()).thenReturn(true);
+
+ final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ verify(mSideStage).addTask(eq(task), eq(wct));
+ assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
+ assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
+ }
+
+ @Test
+ public void testMoveToStage_splitActiveForeground() {
+ when(mStageCoordinator.isSplitActive()).thenReturn(true);
+ when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
+ // Assume current side stage is top or left.
+ mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
+
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
- mStageCoordinator.moveToStage(task, STAGE_TYPE_MAIN, SPLIT_POSITION_BOTTOM_OR_RIGHT,
- new WindowContainerTransaction());
- verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
+ mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ verify(mMainStage).addTask(eq(task), eq(wct));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
+ assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
- mStageCoordinator.moveToStage(task, STAGE_TYPE_SIDE, SPLIT_POSITION_BOTTOM_OR_RIGHT,
- new WindowContainerTransaction());
- verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
- assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
+ mStageCoordinator.moveToStage(task, SPLIT_POSITION_TOP_OR_LEFT, wct);
+ verify(mSideStage).addTask(eq(task), eq(wct));
+ assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
+ assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
}
@Test
- public void testMoveToUndefinedStage() {
+ public void testMoveToStage_splitInctive() {
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Verify move to undefined stage while split screen not activated moves task to side stage.
- when(mStageCoordinator.isSplitScreenVisible()).thenReturn(false);
- mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
- mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_BOTTOM_OR_RIGHT,
- new WindowContainerTransaction());
- verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
+ mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
-
- // Verify move to undefined stage after split screen activated moves task based on position.
- when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
- assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
- mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT,
- new WindowContainerTransaction());
- verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
- assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index fc3263fd3d11..f0aefb5bc0df 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -398,7 +398,8 @@ public class DozeMachine {
}
if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
|| mState == State.DOZE_AOD || mState == State.DOZE
- || mState == State.DOZE_AOD_DOCKED) && requestedState == State.DOZE_PULSE_DONE) {
+ || mState == State.DOZE_AOD_DOCKED || mState == State.DOZE_SUSPEND_TRIGGERS)
+ && requestedState == State.DOZE_PULSE_DONE) {
Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
return mState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index e15ca46b6c59..cc56c488aa4f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -258,20 +258,12 @@ object Flags {
// TODO(b/270223352): Tracking Bug
@JvmField
val HIDE_SMARTSPACE_ON_DREAM_OVERLAY =
- unreleasedFlag(
- 404,
- "hide_smartspace_on_dream_overlay",
- teamfood = true
- )
+ releasedFlag(404, "hide_smartspace_on_dream_overlay")
// TODO(b/271460958): Tracking Bug
@JvmField
val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY =
- unreleasedFlag(
- 405,
- "show_weather_complication_on_dream_overlay",
- teamfood = true
- )
+ releasedFlag(405, "show_weather_complication_on_dream_overlay")
// 500 - quick settings
@@ -425,7 +417,7 @@ object Flags {
@JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
// TODO(b/270882464): Tracking Bug
- val ENABLE_DOCK_SETUP_V2 = unreleasedFlag(1005, "enable_dock_setup_v2", teamfood = true)
+ val ENABLE_DOCK_SETUP_V2 = releasedFlag(1005, "enable_dock_setup_v2")
// TODO(b/265045965): Tracking Bug
val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
@@ -527,7 +519,7 @@ object Flags {
@JvmField
val ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
sysPropBooleanFlag(
- 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = false)
+ 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = true)
// 1200 - predictive back
@Keep
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 98b6d70317b8..60192b8c33df 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -152,6 +152,14 @@ public class LogModule {
return factory.create("QSLog", 700 /* maxSize */, false /* systrace */);
}
+ /** Provides a logging buffer for logs related to Quick Settings configuration. */
+ @Provides
+ @SysUISingleton
+ @QSConfigLog
+ public static LogBuffer provideQSConfigLogBuffer(LogBufferFactory factory) {
+ return factory.create("QSConfigLog", 100 /* maxSize */, true /* systrace */);
+ }
+
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
new file mode 100644
index 000000000000..295bf88d498f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for QS configuration changed messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface QSConfigLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 2668d2e36731..fdab9b16c7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -91,16 +91,19 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
new QSPanel.OnConfigurationChangedListener() {
@Override
public void onConfigurationChange(Configuration newConfig) {
- mQSLogger.logOnConfigurationChanged(
- /* lastOrientation= */ mLastOrientation,
- /* newOrientation= */ newConfig.orientation,
- /* containerName= */ mView.getDumpableTag());
-
- boolean previousSplitShadeState = mShouldUseSplitNotificationShade;
+ final boolean previousSplitShadeState = mShouldUseSplitNotificationShade;
+ final int previousOrientation = mLastOrientation;
mShouldUseSplitNotificationShade =
- LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+ LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
mLastOrientation = newConfig.orientation;
+ mQSLogger.logOnConfigurationChanged(
+ /* oldOrientation= */ previousOrientation,
+ /* newOrientation= */ mLastOrientation,
+ /* oldShouldUseSplitShade= */ previousSplitShadeState,
+ /* newShouldUseSplitShade= */ mShouldUseSplitNotificationShade,
+ /* containerName= */ mView.getDumpableTag());
+
switchTileLayoutIfNeeded();
onConfigurationChanged();
if (previousSplitShadeState != mShouldUseSplitNotificationShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 23c41db6d5a6..5b461a6d8bad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -16,8 +16,12 @@
package com.android.systemui.qs.logging
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.content.res.Configuration.Orientation
import android.service.quicksettings.Tile
import android.view.View
+import com.android.systemui.log.dagger.QSConfigLog
import com.android.systemui.log.dagger.QSLog
import com.android.systemui.plugins.log.ConstantStringsLogger
import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
@@ -32,8 +36,12 @@ import javax.inject.Inject
private const val TAG = "QSLog"
-class QSLogger @Inject constructor(@QSLog private val buffer: LogBuffer) :
- ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
+class QSLogger
+@Inject
+constructor(
+ @QSLog private val buffer: LogBuffer,
+ @QSConfigLog private val configChangedBuffer: LogBuffer,
+) : ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
fun logException(@CompileTimeConstant logMsg: String, ex: Exception) {
buffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
@@ -264,19 +272,28 @@ class QSLogger @Inject constructor(@QSLog private val buffer: LogBuffer) :
}
fun logOnConfigurationChanged(
- lastOrientation: Int,
- newOrientation: Int,
+ @Orientation oldOrientation: Int,
+ @Orientation newOrientation: Int,
+ newShouldUseSplitShade: Boolean,
+ oldShouldUseSplitShade: Boolean,
containerName: String
) {
- buffer.log(
+ configChangedBuffer.log(
TAG,
DEBUG,
{
str1 = containerName
- int1 = lastOrientation
+ int1 = oldOrientation
int2 = newOrientation
+ bool1 = oldShouldUseSplitShade
+ bool2 = newShouldUseSplitShade
},
- { "configuration change: $str1 orientation was $int1, now $int2" }
+ {
+ "config change: " +
+ "$str1 orientation=${toOrientationString(int2)} " +
+ "(was ${toOrientationString(int1)}), " +
+ "splitShade=$bool2 (was $bool1)"
+ }
)
}
@@ -353,3 +370,11 @@ class QSLogger @Inject constructor(@QSLog private val buffer: LogBuffer) :
}
}
}
+
+private inline fun toOrientationString(@Orientation orientation: Int): String {
+ return when (orientation) {
+ ORIENTATION_LANDSCAPE -> "land"
+ ORIENTATION_PORTRAIT -> "port"
+ else -> "undefined"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 2dc15d09afe2..71e2e405d071 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1452,11 +1452,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public boolean onTouch(MotionEvent event) {
boolean handledTouch = false;
if (mAlternateBouncerInteractor.isVisibleState()) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ final boolean downThenUp = event.getActionMasked() == MotionEvent.ACTION_UP
+ && mAlternateBouncerReceivedDownTouch;
+ final boolean outsideTouch = event.getActionMasked() == MotionEvent.ACTION_OUTSIDE;
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mAlternateBouncerReceivedDownTouch = true;
- } else if (event.getAction() == MotionEvent.ACTION_UP
- && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()
- && mAlternateBouncerReceivedDownTouch) {
+ } else if ((downThenUp || outsideTouch)
+ && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
showPrimaryBouncer(true);
}
handledTouch = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index f866d65e2d2d..d0c6215a55d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -105,10 +105,14 @@ class MobileConnectionRepositoryImpl(
* The reason we need to do this is because TelephonyManager limits the number of registered
* listeners per-process, so we don't want to create a new listener for every callback.
*
- * A note on the design for back pressure here: We use the [coalesce] operator here to change
- * the backpressure strategy to store exactly the last callback event of _each type_ here, as
- * opposed to the default strategy which is to drop the oldest event (regardless of type). This
- * means that we should never miss any single event as long as the flow has been started.
+ * A note on the design for back pressure here: We don't control _which_ telephony callback
+ * comes in first, since we register every relevant bit of information as a batch. E.g., if a
+ * downstream starts collecting on a field which is backed by
+ * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_
+ * callback comes in -- the first callback could very well be
+ * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep
+ * it tracked. We use the [scan] operator here to track the most recent callback of _each type_
+ * here. See [TelephonyCallbackState] to see how the callbacks are stored.
*/
private val callbackEvents: StateFlow<TelephonyCallbackState> = run {
val initial = TelephonyCallbackState()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 2ee52325ca4a..654ba04eba7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -57,6 +57,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.concurrent.GuardedBy;
+
/**
* Default implementation of a {@link BatteryController}. This controller monitors for battery
* level change events that are broadcasted by the system.
@@ -94,7 +96,10 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
private boolean mTestMode = false;
@VisibleForTesting
boolean mHasReceivedBattery = false;
+ @GuardedBy("mEstimateLock")
private Estimate mEstimate;
+ private final Object mEstimateLock = new Object();
+
private boolean mFetchingEstimate = false;
// Use AtomicReference because we may request it from a different thread
@@ -321,7 +326,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
@Nullable
private String generateTimeRemainingString() {
- synchronized (mFetchCallbacks) {
+ synchronized (mEstimateLock) {
if (mEstimate == null) {
return null;
}
@@ -340,7 +345,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
mFetchingEstimate = true;
mBgHandler.post(() -> {
// Only fetch the estimate if they are enabled
- synchronized (mFetchCallbacks) {
+ synchronized (mEstimateLock) {
mEstimate = null;
if (mEstimates.isHybridNotificationEnabled()) {
updateEstimate();
@@ -363,6 +368,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
}
@WorkerThread
+ @GuardedBy("mEstimateLock")
private void updateEstimate() {
Assert.isNotMainThread();
// if the estimate has been cached we can just use that, otherwise get a new one and
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index a636b7f43648..b87647ef9839 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -408,6 +408,17 @@ public class DozeMachineTest extends SysuiTestCase {
}
@Test
+ public void testPulsing_dozeSuspendTriggers_pulseDone_doesntCrash() {
+ mMachine.requestState(INITIALIZED);
+
+ mMachine.requestState(DOZE);
+ mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+ mMachine.requestState(DOZE_SUSPEND_TRIGGERS);
+ mMachine.requestState(DOZE_PULSE_DONE);
+ }
+
+ @Test
public void testSuppressingPulse_doesntCrash() {
mMachine.requestState(INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 61286a43217c..346b90c1bd88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -786,4 +786,20 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
// THEN the alternateBouncer doesn't hide
verify(mAlternateBouncerInteractor, never()).hide();
}
+
+ @Test
+ public void testAlternateBouncerOnTouch_actionOutside_hidesAlternateBouncer() {
+ reset(mAlternateBouncerInteractor);
+
+ // GIVEN the alternate bouncer has shown for a minimum amount of time
+ when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+ // WHEN only ACTION_OUTSIDE touch event comes
+ mStatusBarKeyguardViewManager.onTouch(
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_OUTSIDE, 0f, 0f, 0));
+
+ // THEN the alternateBouncer hides
+ verify(mAlternateBouncerInteractor).hide();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 542b688b162d..934e1c64c6da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -25,7 +25,6 @@ import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.DataActivityListener
import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
import android.telephony.TelephonyManager
@@ -68,6 +67,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -392,13 +392,17 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
- val type = NETWORK_TYPE_UNKNOWN
- val expected = UnknownNetworkType
- val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
+ val ti =
+ telephonyDisplayInfo(
+ networkType = NETWORK_TYPE_UNKNOWN,
+ overrideNetworkType = NETWORK_TYPE_UNKNOWN,
+ )
+
callback.onDisplayInfoChanged(ti)
+ val expected = UnknownNetworkType
assertThat(latest).isEqualTo(expected)
- assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(type))
+ assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN))
job.cancel()
}
@@ -412,14 +416,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val overrideType = OVERRIDE_NETWORK_TYPE_NONE
val type = NETWORK_TYPE_LTE
- val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
- val ti =
- mock<TelephonyDisplayInfo>().also {
- whenever(it.overrideNetworkType).thenReturn(overrideType)
- whenever(it.networkType).thenReturn(type)
- }
+ val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType)
callback.onDisplayInfoChanged(ti)
+ val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
assertThat(latest).isEqualTo(expected)
job.cancel()
@@ -433,14 +433,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
- val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
- val ti =
- mock<TelephonyDisplayInfo>().also {
- whenever(it.networkType).thenReturn(type)
- whenever(it.overrideNetworkType).thenReturn(type)
- }
+ val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type)
callback.onDisplayInfoChanged(ti)
+ val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
assertThat(latest).isEqualTo(expected)
job.cancel()
@@ -455,14 +451,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val unknown = NETWORK_TYPE_UNKNOWN
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
- val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
- val ti =
- mock<TelephonyDisplayInfo>().also {
- whenever(it.networkType).thenReturn(unknown)
- whenever(it.overrideNetworkType).thenReturn(type)
- }
+ val ti = telephonyDisplayInfo(unknown, type)
callback.onDisplayInfoChanged(ti)
+ val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
assertThat(latest).isEqualTo(expected)
job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index bbf04ed28fd7..9da9ff72d380 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -64,10 +64,14 @@ import org.mockito.MockitoAnnotations
*
* Kind of like an interaction test case build just for [TelephonyCallback]
*
- * The list of telephony callbacks we use is: [TelephonyCallback.CarrierNetworkListener]
- * [TelephonyCallback.DataActivityListener] [TelephonyCallback.DataConnectionStateListener]
- * [TelephonyCallback.DataEnabledListener] [TelephonyCallback.DisplayInfoListener]
- * [TelephonyCallback.ServiceStateListener] [TelephonyCallback.SignalStrengthsListener]
+ * The list of telephony callbacks we use is:
+ * - [TelephonyCallback.CarrierNetworkListener]
+ * - [TelephonyCallback.DataActivityListener]
+ * - [TelephonyCallback.DataConnectionStateListener]
+ * - [TelephonyCallback.DataEnabledListener]
+ * - [TelephonyCallback.DisplayInfoListener]
+ * - [TelephonyCallback.ServiceStateListener]
+ * - [TelephonyCallback.SignalStrengthsListener]
*
* Because each of these callbacks comes in on the same callbackFlow, collecting on a field backed
* by only a single callback can immediately create backpressure on the other fields related to a
@@ -201,7 +205,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
200 /* unused */
)
- // Send a bunch of events that we don't care about, to overrun the replay buffer
flipActivity(100, activityCallback)
val connectionJob = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
@@ -225,7 +228,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
enabledCallback.onDataEnabledChanged(true, 1 /* unused */)
- // Send a bunch of events that we don't care about, to overrun the replay buffer
flipActivity(100, activityCallback)
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
@@ -252,7 +254,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
displayInfoCallback.onDisplayInfoChanged(ti)
- // Send a bunch of events that we don't care about, to overrun the replay buffer
flipActivity(100, activityCallback)
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
index d07b96f6609e..cf815c27a0bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.telephony.CellSignalStrengthCdma
import android.telephony.SignalStrength
import android.telephony.TelephonyCallback
+import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -48,6 +49,12 @@ object MobileTelephonyHelpers {
return signalStrength
}
+ fun telephonyDisplayInfo(networkType: Int, overrideNetworkType: Int) =
+ mock<TelephonyDisplayInfo>().also {
+ whenever(it.networkType).thenReturn(networkType)
+ whenever(it.overrideNetworkType).thenReturn(overrideNetworkType)
+ }
+
inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
assertThat(cbs.size).isEqualTo(1)
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 3d24588c9763..aafcd9dcbff9 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -19,7 +19,6 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.graphics.Camera;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -1855,6 +1854,7 @@ public class CameraExtensionsProxyService extends Service {
ret.outputId.id = output.getId();
ret.physicalCameraId = output.getPhysicalCameraId();
ret.surfaceGroupId = output.getSurfaceGroupId();
+ ret.isMultiResolutionOutput = false;
if (output instanceof SurfaceOutputConfigImpl) {
SurfaceOutputConfigImpl surfaceConfig = (SurfaceOutputConfigImpl) output;
ret.type = CameraOutputConfig.TYPE_SURFACE;
@@ -1874,6 +1874,7 @@ public class CameraExtensionsProxyService extends Service {
ret.type = CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
ret.imageFormat = multiResReaderConfig.getImageFormat();
ret.capacity = multiResReaderConfig.getMaxImages();
+ ret.isMultiResolutionOutput = true;
} else {
throw new IllegalStateException("Unknown output config type!");
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 702526a4beab..dc1ef7eee0b6 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -891,6 +891,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
break;
case EnergyConsumerType.MOBILE_RADIO:
buckets[MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO] = true;
+ buckets[MeasuredEnergyStats.POWER_BUCKET_PHONE] = true;
break;
case EnergyConsumerType.DISPLAY:
buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ff18167ee86f..158492056fb5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1017,9 +1017,14 @@ public class AudioService extends IAudioService.Stub
mSfxHelper = new SoundEffectsHelper(mContext, playerBase -> ignorePlayerLogs(playerBase));
- final boolean headTrackingDefault = mContext.getResources().getBoolean(
+ final boolean binauralEnabledDefault = SystemProperties.getBoolean(
+ "ro.audio.spatializer_binaural_enabled_default", true);
+ final boolean transauralEnabledDefault = SystemProperties.getBoolean(
+ "ro.audio.spatializer_transaural_enabled_default", true);
+ final boolean headTrackingEnabledDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default);
- mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault);
+ mSpatializerHelper = new SpatializerHelper(this, mAudioSystem,
+ binauralEnabledDefault, transauralEnabledDefault, headTrackingEnabledDefault);
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 2b566668a7c7..a9e7d4b0bac8 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -171,13 +171,17 @@ public class SpatializerHelper {
// initialization
@SuppressWarnings("StaticAssignmentInConstructor")
SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa,
- boolean headTrackingEnabledByDefault) {
+ boolean binauralEnabledDefault,
+ boolean transauralEnabledDefault,
+ boolean headTrackingEnabledDefault) {
mAudioService = mother;
mASA = asa;
// "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being
// constructed here is the factory for SADeviceState, thus SADeviceState and its
// private static field sHeadTrackingEnabledDefault should never be accessed directly.
- SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault;
+ SADeviceState.sBinauralEnabledDefault = binauralEnabledDefault;
+ SADeviceState.sTransauralEnabledDefault = transauralEnabledDefault;
+ SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledDefault;
}
synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) {
@@ -1539,10 +1543,12 @@ public class SpatializerHelper {
}
/*package*/ static final class SADeviceState {
+ private static boolean sBinauralEnabledDefault = true;
+ private static boolean sTransauralEnabledDefault = true;
private static boolean sHeadTrackingEnabledDefault = false;
final @AudioDeviceInfo.AudioDeviceType int mDeviceType;
final @NonNull String mDeviceAddress;
- boolean mEnabled = true; // by default, SA is enabled on any device
+ boolean mEnabled;
boolean mHasHeadTracker = false;
boolean mHeadTrackerEnabled;
static final String SETTING_FIELD_SEPARATOR = ",";
@@ -1558,6 +1564,12 @@ public class SpatializerHelper {
SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) {
mDeviceType = deviceType;
mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : "";
+ final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
+ mEnabled = spatMode == SpatializationMode.SPATIALIZER_BINAURAL
+ ? sBinauralEnabledDefault
+ : spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL
+ ? sTransauralEnabledDefault
+ : false;
mHeadTrackerEnabled = sHeadTrackingEnabledDefault;
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 1bbdc20c81e5..8c83be3ea8dd 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -1230,13 +1230,12 @@ public class DisplayModeDirector {
}
public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
- if (defaultPeakRefreshRate == null) {
- defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
- R.integer.config_defaultPeakRefreshRate);
- }
-
- if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (defaultPeakRefreshRate == null) {
+ setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig,
+ /* attemptLoadingFromDeviceConfig= */ false);
+ updateRefreshRateSettingLocked();
+ } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
mDefaultPeakRefreshRate = defaultPeakRefreshRate;
updateRefreshRateSettingLocked();
}
@@ -1869,11 +1868,20 @@ public class DisplayModeDirector {
mLowDisplayBrightnessThresholds = displayThresholds;
mLowAmbientBrightnessThresholds = ambientThresholds;
} else {
- // Invalid or empty. Use device default.
- mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
- R.array.config_brightnessThresholdsOfPeakRefreshRate);
- mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
- R.array.config_ambientThresholdsOfPeakRefreshRate);
+ DisplayDeviceConfig displayDeviceConfig;
+ synchronized (mLock) {
+ displayDeviceConfig = mDefaultDisplayDeviceConfig;
+ }
+ mLowDisplayBrightnessThresholds = loadBrightnessThresholds(
+ () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(),
+ () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(),
+ R.array.config_brightnessThresholdsOfPeakRefreshRate,
+ displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
+ mLowAmbientBrightnessThresholds = loadBrightnessThresholds(
+ () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(),
+ () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(),
+ R.array.config_ambientThresholdsOfPeakRefreshRate,
+ displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
}
restartObserver();
}
@@ -1883,24 +1891,41 @@ public class DisplayModeDirector {
* DeviceConfig properties.
*/
public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
- if (refreshRate != mRefreshRateInLowZone) {
+ if (refreshRate == -1) {
+ // Given there is no value available in DeviceConfig, lets not attempt loading it
+ // from there.
+ synchronized (mLock) {
+ loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig,
+ /* attemptLoadingFromDeviceConfig= */ false);
+ }
+ restartObserver();
+ } else if (refreshRate != mRefreshRateInLowZone) {
mRefreshRateInLowZone = refreshRate;
restartObserver();
}
}
- public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
+ private void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
int[] ambientThresholds) {
if (displayThresholds != null && ambientThresholds != null
&& displayThresholds.length == ambientThresholds.length) {
mHighDisplayBrightnessThresholds = displayThresholds;
mHighAmbientBrightnessThresholds = ambientThresholds;
} else {
- // Invalid or empty. Use device default.
- mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
- R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
- mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
- R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ DisplayDeviceConfig displayDeviceConfig;
+ synchronized (mLock) {
+ displayDeviceConfig = mDefaultDisplayDeviceConfig;
+ }
+ mHighDisplayBrightnessThresholds = loadBrightnessThresholds(
+ () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(),
+ () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(),
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate,
+ displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
+ mHighAmbientBrightnessThresholds = loadBrightnessThresholds(
+ () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(),
+ () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(),
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate,
+ displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
}
restartObserver();
}
@@ -1910,7 +1935,15 @@ public class DisplayModeDirector {
* DeviceConfig properties.
*/
public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
- if (refreshRate != mRefreshRateInHighZone) {
+ if (refreshRate == -1) {
+ // Given there is no value available in DeviceConfig, lets not attempt loading it
+ // from there.
+ synchronized (mLock) {
+ loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig,
+ /* attemptLoadingFromDeviceConfig= */ false);
+ }
+ restartObserver();
+ } else if (refreshRate != mRefreshRateInHighZone) {
mRefreshRateInHighZone = refreshRate;
restartObserver();
}
@@ -2870,10 +2903,8 @@ public class DisplayModeDirector {
new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
.sendToTarget();
- if (refreshRateInLowZone != -1) {
- mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone,
- 0).sendToTarget();
- }
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone,
+ 0).sendToTarget();
int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
@@ -2883,10 +2914,8 @@ public class DisplayModeDirector {
new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
.sendToTarget();
- if (refreshRateInHighZone != -1) {
- mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone,
- 0).sendToTarget();
- }
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone,
+ 0).sendToTarget();
synchronized (mLock) {
final int refreshRateInHbmSunlight =
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 3404279d2c59..c0ed08d2607d 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -88,6 +88,10 @@ import java.util.Set;
public class DisplayRotation {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
+ // Delay in milliseconds when updating config due to folding events. This prevents
+ // config changes and unexpected jumps while folding the device to closed state.
+ private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800;
+
private static class RotationAnimationPair {
@AnimRes
int mEnter;
@@ -1618,6 +1622,7 @@ public class DisplayRotation {
private boolean mInHalfFoldTransition = false;
private final boolean mIsDisplayAlwaysSeparatingHinge;
private final Set<Integer> mTabletopRotations;
+ private final Runnable mActivityBoundsUpdateCallback;
FoldController() {
mTabletopRotations = new ArraySet<>();
@@ -1652,6 +1657,26 @@ public class DisplayRotation {
}
mIsDisplayAlwaysSeparatingHinge = mContext.getResources().getBoolean(
R.bool.config_isDisplayHingeAlwaysSeparating);
+
+ mActivityBoundsUpdateCallback = new Runnable() {
+ public void run() {
+ if (mDeviceState == DeviceStateController.DeviceState.OPEN
+ || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) {
+ synchronized (mLock) {
+ final Task topFullscreenTask =
+ mDisplayContent.getTask(
+ t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
+ if (topFullscreenTask != null) {
+ final ActivityRecord top =
+ topFullscreenTask.topRunningActivity();
+ if (top != null) {
+ top.recomputeConfiguration();
+ }
+ }
+ }
+ }
+ }
+ };
}
boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
@@ -1723,14 +1748,9 @@ public class DisplayRotation {
false /* forceRelayout */);
}
// Alert the activity of possible new bounds.
- final Task topFullscreenTask =
- mDisplayContent.getTask(t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
- if (topFullscreenTask != null) {
- final ActivityRecord top = topFullscreenTask.topRunningActivity();
- if (top != null) {
- top.recomputeConfiguration();
- }
- }
+ UiThread.getHandler().removeCallbacks(mActivityBoundsUpdateCallback);
+ UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback,
+ FOLDING_RECOMPUTE_CONFIG_DELAY_MS);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3461bc27b40c..18d6dea927c1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3448,6 +3448,8 @@ class Task extends TaskFragment {
&& info.pictureInPictureParams.isLaunchIntoPip()
&& top.getLastParentBeforePip() != null)
? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
+ info.lastParentTaskIdBeforePip = top != null && top.getLastParentBeforePip() != null
+ ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays;
info.mTopActivityLocusId = top != null ? top.getLocusId() : null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 41e0fd715889..2d849b3a6b95 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2049,16 +2049,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* Like isOnScreen(), but we don't return true if the window is part
- * of a transition that has not yet been started.
+ * of a transition but has not yet started animating.
*/
boolean isReadyForDisplay() {
- if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) {
+ if (!mHasSurface || mDestroying || !isVisibleByPolicy()) {
+ return false;
+ }
+ if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()
+ && !isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
return false;
}
final boolean parentAndClientVisible = !isParentWindowHidden()
&& mViewVisibility == View.VISIBLE && mToken.isVisible();
- return mHasSurface && isVisibleByPolicy() && !mDestroying
- && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
+ return parentAndClientVisible || isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_ALL);
}
boolean isFullyTransparent() {
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index 428eaff9e5bc..dea31d764522 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -56,7 +56,9 @@ public class SpatializerHelperTest {
mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem,
- false /*headTrackingEnabledByDefault*/);
+ true /*binauralEnabledDefault*/,
+ true /*transauralEnabledDefault*/,
+ false /*headTrackingEnabledDefault*/);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index ff37564f46a4..58f3db959afe 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -1905,7 +1905,7 @@ public class DisplayModeDirectorTest {
// We don't expect any interaction with DeviceConfig when the director is initialized
// because we explicitly avoid doing this as this can lead to a latency spike in the
// startup of DisplayManagerService
- // Verify all the loaded values are from DisplayDeviceConfig
+ // Verify all the loaded values are from config.xml
assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 45, 0.0);
assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 75,
0.0);
@@ -1937,6 +1937,7 @@ public class DisplayModeDirectorTest {
when(displayDeviceConfig.getDefaultRefreshRateInHbmSunlight()).thenReturn(75);
director.defaultDisplayDeviceUpdated(displayDeviceConfig);
+ // Verify the new values are from the freshly loaded DisplayDeviceConfig.
assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65,
0.0);
@@ -1966,6 +1967,7 @@ public class DisplayModeDirectorTest {
config.setRefreshRateInHbmSunlight(80);
director.defaultDisplayDeviceUpdated(displayDeviceConfig);
+ // Verify the values are loaded from the DeviceConfig.
assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 60,
0.0);
@@ -1981,6 +1983,35 @@ public class DisplayModeDirectorTest {
new int[]{20});
assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 70);
assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 80);
+
+ // Reset the DeviceConfig
+ config.setDefaultPeakRefreshRate(null);
+ config.setRefreshRateInHighZone(null);
+ config.setRefreshRateInLowZone(null);
+ config.setLowAmbientBrightnessThresholds(new int[]{});
+ config.setLowDisplayBrightnessThresholds(new int[]{});
+ config.setHighDisplayBrightnessThresholds(new int[]{});
+ config.setHighAmbientBrightnessThresholds(new int[]{});
+ config.setRefreshRateInHbmHdr(null);
+ config.setRefreshRateInHbmSunlight(null);
+ waitForIdleSync();
+
+ // verify the new values now fallback to DisplayDeviceConfig
+ assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
+ assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65,
+ 0.0);
+ assertEquals(director.getBrightnessObserver().getRefreshRateInHighZone(), 55);
+ assertEquals(director.getBrightnessObserver().getRefreshRateInLowZone(), 50);
+ assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(),
+ new int[]{210});
+ assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(),
+ new int[]{2100});
+ assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(),
+ new int[]{25});
+ assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(),
+ new int[]{30});
+ assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 65);
+ assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 75);
}
@Test
@@ -2140,18 +2171,18 @@ public class DisplayModeDirectorTest {
super.addOnPropertiesChangedListener(namespace, executor, listener);
}
- void setRefreshRateInLowZone(int fps) {
+ void setRefreshRateInLowZone(Integer fps) {
putPropertyAndNotify(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
String.valueOf(fps));
}
- void setRefreshRateInHbmSunlight(int fps) {
+ void setRefreshRateInHbmSunlight(Integer fps) {
putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps));
}
- void setRefreshRateInHbmHdr(int fps) {
+ void setRefreshRateInHbmHdr(Integer fps) {
putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps));
}
@@ -2187,13 +2218,13 @@ public class DisplayModeDirectorTest {
thresholds);
}
- void setRefreshRateInHighZone(int fps) {
+ void setRefreshRateInHighZone(Integer fps) {
putPropertyAndNotify(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
String.valueOf(fps));
}
- void setDefaultPeakRefreshRate(int fps) {
+ void setDefaultPeakRefreshRate(Integer fps) {
putPropertyAndNotify(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_PEAK_REFRESH_RATE_DEFAULT,
String.valueOf(fps));