diff options
20 files changed, 478 insertions, 146 deletions
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 0e45787c1340..2eed993eb769 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -633,12 +633,13 @@ public abstract class CameraDevice implements AutoCloseable { * <style scoped> * #rb { border-right-width: thick; } * </style> + * + * <h5>LEGACY-level guaranteed configurations</h5> + * * <p>Legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at * least the following stream combinations: * - * <h5>LEGACY-level guaranteed configurations</h5> - * * <table> * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr> @@ -653,13 +654,13 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>LIMITED-level additional guaranteed configurations</h5> + * * <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices * support at least the following stream combinations in addition to those for * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices: * - * <h5>LIMITED-level additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> @@ -672,13 +673,13 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>FULL-level additional guaranteed configurations</h5> + * * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices * support at least the following stream combinations in addition to those for * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: * - * <h5>FULL-level additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> @@ -691,14 +692,14 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>RAW-capability additional guaranteed configurations</h5> + * * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support * at least the following stream combinations on both * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: * - * <h5>RAW-capability additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> @@ -713,6 +714,8 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>BURST-capability additional guaranteed configurations</h5> + * * <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices * support at least the below stream combinations in addition to those for @@ -721,8 +724,6 @@ public abstract class CameraDevice implements AutoCloseable { * list for FULL-level devices, so this table is only relevant for LIMITED-level devices that * support the BURST_CAPTURE capability. * - * <h5>BURST-capability additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> @@ -732,6 +733,8 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>LEVEL-3 additional guaranteed configurations</h5> + * * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3}) * support at least the following stream combinations in addition to the combinations for @@ -739,8 +742,6 @@ public abstract class CameraDevice implements AutoCloseable { * RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}): * - * <h5>LEVEL-3 additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> @@ -749,14 +750,16 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * - *<p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as described by - * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the + * <h5>Concurrent stream guaranteed configurations</h5> + * + * <p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as + * described by {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the * following guaranteed streams (when streaming concurrently with other devices)</p> + * * <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed * to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p> * - * <h5>Concurrent stream guaranteed configurations</h5> - * + * <p> * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> @@ -792,6 +795,8 @@ public abstract class CameraDevice implements AutoCloseable { * level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not * supported.</p> * + * <h5>LEGACY-level additional guaranteed combinations with multi-resolution outputs</h5> + * * <p>Devices capable of multi-resolution output for a particular format ( * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo} * returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM @@ -802,8 +807,6 @@ public abstract class CameraDevice implements AutoCloseable { * stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link * MultiResolutionImageReader} created based on the variable max resolutions supported): * - * <h5>LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</h5> - * * <table> * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr> @@ -812,8 +815,12 @@ public abstract class CameraDevice implements AutoCloseable { * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr> * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr> * </table><br> + * </p> + * + * <h5>LIMITED-level additional guaranteed configurations with multi-resolution outputs</h5> + * + * <p> * <table> - * <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr> @@ -821,11 +828,11 @@ public abstract class CameraDevice implements AutoCloseable { * The same logic applies to other hardware levels and capabilities. * </p> * - * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees - * which clients can take advantage of : </p> - * * <h5>Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</h5> * + * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees + * which clients can take advantage of: + * * <table> * <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th> <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr> @@ -833,6 +840,7 @@ public abstract class CameraDevice implements AutoCloseable { * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code RECORD}</td> <td>Ultra high res still capture with preview + app based RECORD size analysis</td> </tr> * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV / RAW}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code MAX}</td> <td>Ultra high res still image capture with preview + default sensor pixel mode analysis stream</td> </tr> * </table><br> + * </p> * * <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link @@ -842,17 +850,17 @@ public abstract class CameraDevice implements AutoCloseable { * Note: The same capture request must not mix targets from * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p> * - * <p> 10-bit output capable - * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} - * devices support at least the following stream combinations: </p> - * * <h5>10-bit output additional guaranteed configurations</h5> * + * <p>10-bit output capable + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} + * devices support at least the following stream combinations: + * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> - * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr> - * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr> * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr> * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr> * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processing.</td> </tr> @@ -860,6 +868,8 @@ public abstract class CameraDevice implements AutoCloseable { * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code YUV}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with in-app snapshot.</td> </tr> * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr> * </table><br> + * </p> + * * <p>Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel * format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or * {@link android.graphics.ImageFormat#YCBCR_P010}. @@ -895,13 +905,13 @@ public abstract class CameraDevice implements AutoCloseable { * {@link CameraDevice#isSessionConfigurationSupported} to ensure that this particular * configuration is supported.</p> * + * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5> + * * <p>Devices with the STREAM_USE_CASE capability ({@link * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional * stream combinations: * - * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr> @@ -921,12 +931,12 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5> + * * <p>Devices that include the {@link CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW} * stream use-case in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}, * support the additional stream combinations below: * - * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5> - * * <table> * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr> @@ -934,15 +944,17 @@ public abstract class CameraDevice implements AutoCloseable { * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td colspan="3" id="rb"></td> <td>Preview with cropped RAW still capture</td> </tr> * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Preview with YUV / JPEG and cropped RAW still capture</td> </tr> * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code VIDEO_RECORD / PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Video recording with preview and cropped RAW still capture</td> </tr> + * </table><br> + * </p> * + * <h5>Preview stabilization guaranteed stream configurations</h5> * - *<p> For devices where {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES} - * includes {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION}, + * <p>For devices where + * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES} includes + * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION}, * the following stream combinations are guaranteed, * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to - * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p> - * - * <h5>Preview stabilization guaranteed stream configurations</h5> + * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} * * <table> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr> @@ -951,6 +963,8 @@ public abstract class CameraDevice implements AutoCloseable { * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr> * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr> * </table><br> + * </p> + * * <p> * For the maximum size column, PREVIEW refers to the best size match to the device's screen * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d66ffcebae5e..0b486c00c2da 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4724,13 +4724,13 @@ public final class Settings { public static final String PEAK_REFRESH_RATE = "peak_refresh_rate"; /** - * Control whether to stay awake on fold + * Control lock behavior on fold * * If this isn't set, the system falls back to a device specific default. * @hide */ @Readable - public static final String STAY_AWAKE_ON_FOLD = "stay_awake_on_fold"; + public static final String FOLD_LOCK_BEHAVIOR = "fold_lock_behavior_setting"; /** * The amount of time in milliseconds before the device goes to sleep or begins diff --git a/core/java/com/android/internal/util/SettingsWrapper.java b/core/java/com/android/internal/util/SettingsWrapper.java new file mode 100644 index 000000000000..8cf6c18adb3a --- /dev/null +++ b/core/java/com/android/internal/util/SettingsWrapper.java @@ -0,0 +1,36 @@ +/* + * 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.internal.util; + +import android.content.ContentResolver; +import android.provider.Settings; + +/** + * A wrapper class for accessing and modifying system settings that would help with testing. + */ +public class SettingsWrapper { + + /** Retrieves the string value of a system setting */ + public String getStringForUser(ContentResolver contentResolver, String name, int userHandle) { + return Settings.System.getStringForUser(contentResolver, name, userHandle); + } + + /** Updates the string value of a system setting */ + public String putStringForUser(ContentResolver contentResolver, String name, int userHandle) { + return Settings.System.getStringForUser(contentResolver, name, userHandle); + } +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 478b01cfa385..2618fba800a2 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -925,6 +925,9 @@ without impacting power, performance, and app compatibility (e.g. protected content). --> <bool name="config_reduceBrightColorsAvailable">@bool/config_setColorTransformAccelerated</bool> + <!-- Whether to show Fold lock behavior setting feature in Settings App --> + <bool name="config_fold_lock_behavior">false</bool> + <string-array name="config_reduceBrightColorsCoefficientsNonlinear"> <!-- a-coefficient --> <item>-0.4429953456</item> <!-- b-coefficient --> <item>-0.2434077725</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 644597c190dc..c78af86f0f39 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -343,6 +343,7 @@ <java-symbol type="string" name="config_defaultHealthConnectApp" /> <java-symbol type="bool" name="config_sendAudioBecomingNoisy" /> <java-symbol type="bool" name="config_enableScreenshotChord" /> + <java-symbol type="bool" name="config_fold_lock_behavior" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" /> <java-symbol type="bool" name="config_useDevInputEventForAudioJack" /> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 6b0a9060d782..248c60cb4fe9 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -61,7 +61,7 @@ public class SystemSettings { Settings.System.TTY_MODE, Settings.System.MASTER_MONO, Settings.System.MASTER_BALANCE, - Settings.System.STAY_AWAKE_ON_FOLD, + Settings.System.FOLD_LOCK_BEHAVIOR, Settings.System.SOUND_EFFECTS_ENABLED, Settings.System.HAPTIC_FEEDBACK_ENABLED, Settings.System.POWER_SOUNDS_ENABLED, // moved to global diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index a08d07e1d778..3688d049d380 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -134,6 +134,7 @@ public class SystemSettingsValidators { VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(System.RINGTONE, URI_VALIDATOR); VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR); + VALIDATORS.put(System.FOLD_LOCK_BEHAVIOR, ANY_STRING_VALIDATOR); VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR); VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR); VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR); @@ -218,7 +219,6 @@ public class SystemSettingsValidators { VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR); VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR); VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR); - VALIDATORS.put(System.STAY_AWAKE_ON_FOLD, BOOLEAN_VALIDATOR); VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR); VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(System.CLOCKWORK_BLUETOOTH_SETTINGS_PREF, BOOLEAN_VALIDATOR); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 5a2c5d08bc2e..42cb739dba6a 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -112,7 +112,7 @@ object Flags { val BUILDER_EXTRAS_OVERRIDE = sysPropBooleanFlag( "persist.sysui.notification.builder_extras_override", - default = true + default = false ) /** Only notify group expansion listeners when a change happens. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index d01e0a6f933f..a82088285e84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -84,7 +84,7 @@ import java.util.function.Predicate; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) public class VolumeDialogImplTest extends SysuiTestCase { VolumeDialogImpl mDialog; View mActiveRinger; @@ -141,6 +141,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { getContext().addMockSystemService(KeyguardManager.class, mKeyguard); mTestableLooper = TestableLooper.get(this); + allowTestableLooperAsMainThread(); when(mPostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 6546f6e533c0..53921d4d83b5 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -143,6 +143,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.SettingsWrapper; import com.android.server.AnimationThread; import com.android.server.DisplayThread; import com.android.server.LocalServices; @@ -155,7 +156,7 @@ import com.android.server.display.layout.Layout; import com.android.server.display.mode.DisplayModeDirector; import com.android.server.display.utils.SensorUtils; import com.android.server.input.InputManagerInternal; -import com.android.server.utils.FoldSettingWrapper; +import com.android.server.utils.FoldSettingProvider; import com.android.server.wm.SurfaceAnimationThread; import com.android.server.wm.WindowManagerInternal; @@ -542,9 +543,9 @@ public final class DisplayManagerService extends SystemService { mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore); - mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo, - new LogicalDisplayListener(), mSyncRoot, mHandler, - new FoldSettingWrapper(mContext.getContentResolver())); + mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, + new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo, + new LogicalDisplayListener(), mSyncRoot, mHandler); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mBrightnessSynchronizer = new BrightnessSynchronizer(mContext); Resources resources = mContext.getResources(); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 26f8029cf5ac..f99c05179417 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -42,7 +42,7 @@ import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.layout.DisplayIdProducer; import com.android.server.display.layout.Layout; -import com.android.server.utils.FoldSettingWrapper; +import com.android.server.utils.FoldSettingProvider; import java.io.PrintWriter; import java.util.Arrays; @@ -143,7 +143,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final Listener mListener; private final DisplayManagerService.SyncRoot mSyncRoot; private final LogicalDisplayMapperHandler mHandler; - private final FoldSettingWrapper mFoldSettingWrapper; + private final FoldSettingProvider mFoldSettingProvider; private final PowerManager mPowerManager; /** @@ -189,25 +189,26 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private boolean mBootCompleted = false; private boolean mInteractive; - LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, + LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, + @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, - @NonNull Handler handler, FoldSettingWrapper foldSettingWrapper) { - this(context, repo, listener, syncRoot, handler, + @NonNull Handler handler) { + this(context, foldSettingProvider, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY - : sNextNonDefaultDisplayId++), foldSettingWrapper); + : sNextNonDefaultDisplayId++)); } - LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, + LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, + @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, - @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, - FoldSettingWrapper foldSettingWrapper) { + @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap) { mSyncRoot = syncRoot; mPowerManager = context.getSystemService(PowerManager.class); mInteractive = mPowerManager.isInteractive(); mHandler = new LogicalDisplayMapperHandler(handler.getLooper()); mDisplayDeviceRepo = repo; mListener = listener; - mFoldSettingWrapper = foldSettingWrapper; + mFoldSettingProvider = foldSettingProvider; mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mSupportsConcurrentInternalDisplays = context.getResources().getBoolean( com.android.internal.R.bool.config_supportsConcurrentInternalDisplays); @@ -479,10 +480,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { }); } else if (sleepDevice) { // Send the device to sleep when required. + int goToSleepFlag = + mFoldSettingProvider.shouldSleepOnFold() ? 0 + : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP; mHandler.post(() -> { mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD, - PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP); + goToSleepFlag); }); } } @@ -556,7 +560,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { && mDeviceStatesOnWhichToSleep.get(pendingState) && !mDeviceStatesOnWhichToSleep.get(currentState) && !isOverrideActive - && isInteractive && isBootCompleted && !mFoldSettingWrapper.shouldStayAwakeOnFold(); + && isInteractive && isBootCompleted + && !mFoldSettingProvider.shouldStayAwakeOnFold(); } private boolean areAllTransitioningDisplaysOffLocked() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 6509126dcc60..3812dd60cd70 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -119,6 +119,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; +import android.view.IWindowManager; import android.view.InputChannel; import android.view.InputDevice; import android.view.MotionEvent; @@ -126,6 +127,7 @@ import android.view.WindowManager; import android.view.WindowManager.DisplayImePolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; +import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputBinding; @@ -3072,7 +3074,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub "Waiting for the lazy init of mImeDrawsImeNavBarRes"); } final boolean canImeDrawsImeNavBar = - mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get(); + mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get() + && hasNavigationBarOnCurrentDisplay(); final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked( InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE); return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0) @@ -3080,6 +3083,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0); } + /** + * Whether the current display has a navigation bar. When this is {@code false} (e.g. emulator), + * the IME should <em>not</em> draw the IME navigation bar. + */ + @GuardedBy("ImfLock.class") + private boolean hasNavigationBarOnCurrentDisplay() { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + try { + return wm.hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY + ? mCurTokenDisplayId : DEFAULT_DISPLAY); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @GuardedBy("ImfLock.class") private boolean shouldShowImeSwitcherLocked(int visibility) { if (!mShowOngoingImeSwitcherForPhones) return false; diff --git a/services/core/java/com/android/server/utils/FoldSettingProvider.java b/services/core/java/com/android/server/utils/FoldSettingProvider.java new file mode 100644 index 000000000000..d62628b73019 --- /dev/null +++ b/services/core/java/com/android/server/utils/FoldSettingProvider.java @@ -0,0 +1,102 @@ +/* + * 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.server.utils; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.R; +import com.android.internal.util.SettingsWrapper; + +import java.util.Set; + +/** + * This class provides a convenient way to access the {@link Settings.System#FOLD_LOCK_BEHAVIOR}. + * The {@link Settings.System#FOLD_LOCK_BEHAVIOR} setting controls the behavior of the device when + * it is folded, and provides the user with three different options to choose from. Those are: + * 1. Stay awake on fold: The device will remain unlocked when it is folded. + * 2. Selective stay awake: The device will remain unlocked when it is folded only if there are + * apps with wakelocks running. This is also the set default behavior. + * 3. Sleep on fold: The device will lock when it is folded, regardless of which apps are running + * or whether any wakelocks are held. + * + * Keep the setting values in this class in sync with the values in + * {@link com.android.settings.display.FoldLockBehaviorSettings} + */ +public class FoldSettingProvider { + + public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key"; + public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key"; + public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key"; + private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE; + private static final Set<String> SETTING_VALUES = Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD, + SETTING_VALUE_SELECTIVE_STAY_AWAKE, SETTING_VALUE_SLEEP_ON_FOLD); + private static final String TAG = "FoldSettingProvider"; + + private final ContentResolver mContentResolver; + private final boolean mIsFoldLockBehaviorAvailable; + private final SettingsWrapper mSettingsWrapper; + + public FoldSettingProvider(Context context, SettingsWrapper settingsWrapper) { + mContentResolver = context.getContentResolver(); + mSettingsWrapper = settingsWrapper; + mIsFoldLockBehaviorAvailable = context.getResources().getBoolean( + R.bool.config_fold_lock_behavior); + } + + /** + * Returns whether the device should remain awake after folding. + */ + public boolean shouldStayAwakeOnFold() { + return getFoldSettingValue().equals(SETTING_VALUE_STAY_AWAKE_ON_FOLD); + } + + /** + * Returns whether the device should selective remain awake after folding. + */ + public boolean shouldSelectiveStayAwakeOnFold() { + return getFoldSettingValue().equals(SETTING_VALUE_SELECTIVE_STAY_AWAKE); + } + + /** + * Returns whether the device should strictly sleep after folding. + */ + public boolean shouldSleepOnFold() { + return getFoldSettingValue().equals(SETTING_VALUE_SLEEP_ON_FOLD); + } + + private String getFoldSettingValue() { + if (!mIsFoldLockBehaviorAvailable) { + return SETTING_VALUE_DEFAULT; + } + String foldSettingValue = mSettingsWrapper.getStringForUser( + mContentResolver, + Settings.System.FOLD_LOCK_BEHAVIOR, + UserHandle.USER_CURRENT); + foldSettingValue = (foldSettingValue != null) ? foldSettingValue : SETTING_VALUE_DEFAULT; + if (!SETTING_VALUES.contains(foldSettingValue)) { + Log.e(TAG, + "getFoldSettingValue: Invalid setting value, returning default setting value"); + foldSettingValue = SETTING_VALUE_DEFAULT; + } + + return foldSettingValue; + } +} diff --git a/services/core/java/com/android/server/utils/FoldSettingWrapper.java b/services/core/java/com/android/server/utils/FoldSettingWrapper.java deleted file mode 100644 index 97a1ac06e24c..000000000000 --- a/services/core/java/com/android/server/utils/FoldSettingWrapper.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.server.utils; - -import android.content.ContentResolver; -import android.provider.Settings; - -/** - * A wrapper class for the {@link Settings.System#STAY_AWAKE_ON_FOLD} setting. - * - * This class provides a convenient way to access the {@link Settings.System#STAY_AWAKE_ON_FOLD} - * setting for testing. - */ -public class FoldSettingWrapper { - private final ContentResolver mContentResolver; - - public FoldSettingWrapper(ContentResolver contentResolver) { - mContentResolver = contentResolver; - } - - /** - * Returns whether the device should remain awake after folding. - */ - public boolean shouldStayAwakeOnFold() { - try { - return (Settings.System.getIntForUser( - mContentResolver, - Settings.System.STAY_AWAKE_ON_FOLD, - 0) == 1); - } catch (Settings.SettingNotFoundException e) { - return false; - } - } -} diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 97b3e3280f2b..45cf10bd3f5e 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -80,10 +80,10 @@ final class LetterboxConfiguration { // Whether per-app user aspect ratio override settings is enabled private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS = - "enable_app_compat_user_aspect_ratio_settings"; + "enable_app_compat_aspect_ratio_user_settings"; // TODO(b/288142656): Enable user aspect ratio settings by default. - private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false; + private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true; // Whether per-app fullscreen user aspect ratio override option is enabled private static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b1041855a2dc..9515b7958355 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -241,6 +241,7 @@ import static android.provider.Telephony.Carriers.ENFORCE_KEY; import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI; import static android.provider.Telephony.Carriers.INVALID_APN_ID; import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION; + import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; @@ -11279,25 +11280,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void dumpPerUserData(IndentingPrintWriter pw) { + private void dumpPersonalAppInfoForSystemUserNoLock(IndentingPrintWriter pw) { + wtfIfInLock(); + PersonalAppsSuspensionHelper.forUser(mContext, UserHandle.USER_SYSTEM).dump(pw); + } + + private void dumpPerUserPolicyData(IndentingPrintWriter pw) { int userCount = mUserData.size(); for (int i = 0; i < userCount; i++) { int userId = mUserData.keyAt(i); DevicePolicyData policy = getUserData(userId); policy.dump(pw); pw.println(); - - if (userId == UserHandle.USER_SYSTEM) { - pw.increaseIndent(); - PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw); - pw.decreaseIndent(); - pw.println(); - } else { - // pm.getUnsuspendablePackages() will fail if it's called for a different user; - // as this dump is mostly useful for system user anyways, we can just ignore the - // others (rather than changing the permission check in the PM method) - Slogf.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId); - } } } @@ -11315,7 +11309,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { pw.println(); mDeviceAdminServiceController.dump(pw); pw.println(); - dumpPerUserData(pw); + dumpPerUserPolicyData(pw); pw.println(); mConstants.dump(pw); pw.println(); @@ -11342,6 +11336,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mStateCache.dump(pw); pw.println(); } + dumpPersonalAppInfoForSystemUserNoLock(pw); synchronized (mSubscriptionsChangedListenerLock) { pw.println("Subscription changed listener : " + mSubscriptionsChangedListener); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java index 9a8e421d5d12..8684dbe73947 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java @@ -111,7 +111,7 @@ public class RemoteBugreportManager { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID); + cancelNotification(); if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) { onBugreportSharingAccepted(); } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) { @@ -213,8 +213,7 @@ public class RemoteBugreportManager { mRemoteBugreportServiceIsActive.set(true); mRemoteBugreportSharingAccepted.set(false); registerRemoteBugreportReceivers(); - mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID, - buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL); + notify(NOTIFICATION_BUGREPORT_STARTED); mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS); return true; } catch (RemoteException re) { @@ -258,13 +257,10 @@ public class RemoteBugreportManager { final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH); if (mRemoteBugreportSharingAccepted.get()) { shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash); - mInjector.getNotificationManager().cancel(LOG_TAG, - NOTIFICATION_ID); + cancelNotification(); } else { mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash); - mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID, - buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), - UserHandle.ALL); + notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED); } mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver); } @@ -274,7 +270,7 @@ public class RemoteBugreportManager { mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE); mRemoteBugreportSharingAccepted.set(false); mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null); - mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID); + cancelNotification(); final Bundle extras = new Bundle(); extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON, DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING); @@ -289,9 +285,7 @@ public class RemoteBugreportManager { if (uriAndHash != null) { shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second); } else if (mRemoteBugreportServiceIsActive.get()) { - mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID, - buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED), - UserHandle.ALL); + notify(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED); } } @@ -340,7 +334,16 @@ public class RemoteBugreportManager { filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED); filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED); mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent); - mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID, - buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL); + notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED); + } + + private void notify(@RemoteBugreportNotificationType int type) { + mInjector.getNotificationManager() + .notifyAsUser(LOG_TAG, NOTIFICATION_ID, buildNotification(type), UserHandle.ALL); + } + + private void cancelNotification() { + mInjector.getNotificationManager() + .cancelAsUser(LOG_TAG, NOTIFICATION_ID, UserHandle.ALL); } } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index e8acb067f625..6ff7b2601b79 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -16,15 +16,20 @@ package com.android.inputmethodservice; +import static android.view.WindowInsets.Type.captionBar; + import static com.android.compatibility.common.util.SystemUtil.eventually; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import android.app.Instrumentation; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Insets; import android.os.RemoteException; import android.provider.Settings; import android.support.test.uiautomator.By; @@ -32,6 +37,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; import android.util.Log; +import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; @@ -592,6 +598,20 @@ public class InputMethodServiceTest { false /* orientationPortrait */); } + /** + * This checks that when the system navigation bar is not created (e.g. emulator), + * then the IME caption bar is also not created. + */ + @Test + public void testNoNavigationBar_thenImeNoCaptionBar() throws Exception { + boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService() + .hasNavigationBar(mInputMethodService.getDisplayId()); + assumeFalse("Must not have a navigation bar", hasNavigationBar); + + assertEquals(Insets.NONE, mInputMethodService.getWindow().getWindow().getDecorView() + .getRootWindowInsets().getInsetsIgnoringVisibility(captionBar())); + } + private void verifyInputViewStatus( Runnable runnable, boolean expected, boolean inputViewStarted) throws InterruptedException { diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java index 0fe6e64b3b54..13c107d0a91e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -42,8 +42,12 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -55,6 +59,7 @@ import android.os.IPowerManager; import android.os.IThermalService; import android.os.PowerManager; import android.os.Process; +import android.os.RemoteException; import android.os.test.TestLooper; import android.view.Display; import android.view.DisplayAddress; @@ -65,7 +70,7 @@ import androidx.test.filters.SmallTest; import com.android.server.display.layout.DisplayIdProducer; import com.android.server.display.layout.Layout; -import com.android.server.utils.FoldSettingWrapper; +import com.android.server.utils.FoldSettingProvider; import org.junit.Before; import org.junit.Test; @@ -87,6 +92,7 @@ public class LogicalDisplayMapperTest { private static int sUniqueTestDisplayId = 0; private static final int DEVICE_STATE_CLOSED = 0; private static final int DEVICE_STATE_OPEN = 2; + private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0; private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1; private static final File NON_EXISTING_FILE = new File("/non_existing_folder/should_not_exist"); @@ -101,7 +107,7 @@ public class LogicalDisplayMapperTest { @Mock LogicalDisplayMapper.Listener mListenerMock; @Mock Context mContextMock; - @Mock FoldSettingWrapper mFoldSettingWrapperMock; + @Mock FoldSettingProvider mFoldSettingProviderMock; @Mock Resources mResourcesMock; @Mock IPowerManager mIPowerManagerMock; @Mock IThermalService mIThermalServiceMock; @@ -111,7 +117,7 @@ public class LogicalDisplayMapperTest { @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor; @Before - public void setUp() { + public void setUp() throws RemoteException { // Share classloader to allow package private access. System.setProperty("dexmaker.share_classloader", "true"); MockitoAnnotations.initMocks(this); @@ -141,7 +147,9 @@ public class LogicalDisplayMapperTest { when(mContextMock.getSystemServiceName(PowerManager.class)) .thenReturn(Context.POWER_SERVICE); - when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(false); + when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(false); + when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false); + when(mIPowerManagerMock.isInteractive()).thenReturn(true); when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager); when(mContextMock.getResources()).thenReturn(mResourcesMock); when(mResourcesMock.getBoolean( @@ -156,9 +164,10 @@ public class LogicalDisplayMapperTest { mLooper = new TestLooper(); mHandler = new Handler(mLooper.getLooper()); - mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo, + mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock, + mDisplayDeviceRepo, mListenerMock, new DisplayManagerService.SyncRoot(), mHandler, - mDeviceStateToLayoutMapSpy, mFoldSettingWrapperMock); + mDeviceStateToLayoutMapSpy); } @@ -574,8 +583,8 @@ public class LogicalDisplayMapperTest { } @Test - public void testDeviceShouldNotSleepWhenFoldSettingTrue() { - when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(true); + public void testDeviceShouldNotSleepWhenStayAwakeSettingTrue() { + when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(true); assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED, DEVICE_STATE_OPEN, @@ -608,6 +617,26 @@ public class LogicalDisplayMapperTest { } @Test + public void testDeviceShouldPutToSleepWhenSleepSettingTrue() throws RemoteException { + when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(true); + + finishBootAndFoldDevice(); + + verify(mIPowerManagerMock, atLeastOnce()).goToSleep(anyLong(), anyInt(), + eq(FLAG_GO_TO_SLEEP_ON_FOLD)); + } + + @Test + public void testDeviceShouldNotBePutToSleepWhenSleepSettingFalse() throws RemoteException { + when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false); + + finishBootAndFoldDevice(); + + verify(mIPowerManagerMock, never()).goToSleep(anyLong(), anyInt(), + eq(FLAG_GO_TO_SLEEP_ON_FOLD)); + } + + @Test public void testDeviceStateLocked() { DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); @@ -859,6 +888,15 @@ public class LogicalDisplayMapperTest { // Helper Methods ///////////////// + private void finishBootAndFoldDevice() { + mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false); + advanceTime(1000); + mLogicalDisplayMapper.onBootCompleted(); + advanceTime(1000); + mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false); + advanceTime(1000); + } + private void createDefaultDisplay(Layout layout, DisplayDevice device) { createDefaultDisplay(layout, info(device).address); } diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java new file mode 100644 index 000000000000..3514276ccb5b --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java @@ -0,0 +1,143 @@ +/* + * 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.server.utils; + +import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SLEEP_ON_FOLD; +import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_STAY_AWAKE_ON_FOLD; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.R; +import com.android.internal.util.SettingsWrapper; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class FoldSettingProviderTest { + + private static final String SETTING_VALUE_INVALID = "invalid_fold_lock_behavior"; + + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private SettingsWrapper mSettingsWrapper; + private ContentResolver mContentResolver; + private FoldSettingProvider mFoldSettingProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContentResolver = + InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getResources()).thenReturn(mResources); + setFoldLockBehaviorAvailability(true); + + mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper); + } + + @Test + public void foldSettingNotAvailable_returnDefaultSetting() { + setFoldLockBehaviorAvailability(false); + setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD); + mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper); + + boolean shouldSelectiveStayAwakeOnFold = + mFoldSettingProvider.shouldSelectiveStayAwakeOnFold(); + + assertThat(shouldSelectiveStayAwakeOnFold).isTrue(); + } + + @Test + public void foldSettingNotAvailable_notReturnStayAwakeOnFoldTrue() { + setFoldLockBehaviorAvailability(false); + setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD); + mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper); + + boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold(); + + assertThat(shouldStayAwakeOnFold).isFalse(); + } + + @Test + public void foldSettingNotAvailable_notReturnSleepOnFoldTrue() { + setFoldLockBehaviorAvailability(false); + setFoldLockBehaviorSettingValue(SETTING_VALUE_SLEEP_ON_FOLD); + mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper); + + boolean shouldSleepOnFold = mFoldSettingProvider.shouldSleepOnFold(); + + assertThat(shouldSleepOnFold).isFalse(); + } + + @Test + public void foldSettingAvailable_returnCorrectFoldSetting() { + setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD); + + boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold(); + + assertThat(shouldStayAwakeOnFold).isTrue(); + } + + @Test + public void foldSettingInvalid_returnDefaultSetting() { + setFoldLockBehaviorSettingValue(SETTING_VALUE_INVALID); + + boolean shouldSelectiveStayAwakeOnFold = + mFoldSettingProvider.shouldSelectiveStayAwakeOnFold(); + + assertThat(shouldSelectiveStayAwakeOnFold).isTrue(); + } + + @Test + public void foldSettingNotDefined_returnDefaultSetting() { + setFoldLockBehaviorSettingValue(null); + + boolean shouldSelectiveStayAwakeOnFold = + mFoldSettingProvider.shouldSelectiveStayAwakeOnFold(); + + assertThat(shouldSelectiveStayAwakeOnFold).isTrue(); + } + + private void setFoldLockBehaviorAvailability(boolean isFoldLockBehaviorEnabled) { + when(mResources.getBoolean(R.bool.config_fold_lock_behavior)).thenReturn( + isFoldLockBehaviorEnabled); + } + + private void setFoldLockBehaviorSettingValue(String foldLockBehaviorSettingValue) { + when(mSettingsWrapper.getStringForUser(any(), + eq(Settings.System.FOLD_LOCK_BEHAVIOR), + eq(UserHandle.USER_CURRENT))).thenReturn(foldLockBehaviorSettingValue); + } +} |