summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PREUPLOAD.cfg2
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/statsd/src/atoms.proto18
-rw-r--r--core/java/android/app/ActivityThread.java76
-rw-r--r--core/java/android/app/ApplicationExitInfo.java2
-rw-r--r--core/java/android/content/IntentFilter.java7
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java2
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java3
-rw-r--r--core/java/android/os/Binder.java1
-rw-r--r--core/java/android/os/HwBinder.java9
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java12
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java30
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java16
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/jni/android_os_HwBinder.cpp7
-rw-r--r--core/jni/android_util_Binder.cpp3
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp18
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-eu/strings.xml2
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml2
-rw-r--r--core/res/res/values-kk/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml10
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java40
-rw-r--r--location/java/android/location/LocationManager.java2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp2
-rw-r--r--packages/CarSystemUI/Android.bp10
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java27
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java5
-rw-r--r--packages/SystemUI/Android.bp8
-rw-r--r--packages/SystemUI/docs/dagger.md20
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java157
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozePauser.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java37
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java129
-rw-r--r--services/core/java/com/android/server/VibratorService.java154
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java11
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java37
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java12
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java9
-rw-r--r--services/core/java/com/android/server/location/util/SystemAppOpsHelper.java22
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java57
-rw-r--r--services/core/java/com/android/server/rollback/AppDataRollbackHelper.java10
-rw-r--r--services/core/java/com/android/server/rollback/Rollback.java10
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java6
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java173
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java19
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java18
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java48
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java4
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java19
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java17
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java17
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java13
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/AndroidManifest.xml3
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java607
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java292
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java30
-rw-r--r--telephony/java/android/telephony/CellLocation.java24
-rw-r--r--telephony/java/android/telephony/SmsMessage.java22
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java67
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl23
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java4
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java32
-rw-r--r--tests/FlickerTests/Android.bp2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java174
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java76
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java75
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java79
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java98
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java399
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt446
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java193
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt188
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java146
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt137
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java80
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt72
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java73
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java73
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/PipTestBase.java75
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java66
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java64
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java200
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt131
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java175
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java102
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt (renamed from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java)23
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt (renamed from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java)18
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java51
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt40
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java47
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt36
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt71
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt71
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt86
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt107
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt78
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt89
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt89
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt81
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt65
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt63
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt85
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt146
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt78
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt202
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt111
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java26
-rw-r--r--tools/stats_log_api_gen/Collation.cpp53
-rw-r--r--tools/stats_log_api_gen/Collation.h10
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp326
-rw-r--r--tools/stats_log_api_gen/test.proto41
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp64
178 files changed, 5280 insertions, 3617 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2fd2e33bbc37..9b290c6a4760 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -12,8 +12,6 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
services/incremental/
[Hook Scripts]
-checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
-
strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/api/test-current.txt b/api/test-current.txt
index f77922812ba1..ab0761374570 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5004,7 +5004,6 @@ package android.util {
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
- field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8c54c242e04a..02c0d933b3cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -4590,7 +4590,7 @@ message GeneralExternalStorageAccessStats {
// Includes file path and ContentResolver accesses
optional uint32 secondary_storage_accesses = 4;
// Comma-separated list of mime types that were accessed.
- optional MimeTypes mime_types_accessed = 5;
+ optional MimeTypes mime_types_accessed = 5 [(log_mode) = MODE_BYTES];
}
/**
@@ -6174,7 +6174,7 @@ message ProcessStatsAvailablePagesProto {
* Pulled from ProcessStatsService.java
*/
message ProcStats {
- optional ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
// Data pulled from device into this is sometimes sharded across multiple atoms to work around
// a size limit. When this happens, this shard ID will contain an increasing 1-indexed integer
// with the number of this shard.
@@ -6185,7 +6185,7 @@ message ProcStats {
* Pulled from ProcessStatsService.java
*/
message ProcStatsPkgProc {
- optional ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
}
// Next Tag: 2
@@ -6203,7 +6203,7 @@ message NotificationRemoteViewsProto {
* Pulled from NotificationManagerService.java
*/
message NotificationRemoteViews {
- optional NotificationRemoteViewsProto notification_remote_views = 1;
+ optional NotificationRemoteViewsProto notification_remote_views = 1 [(log_mode) = MODE_BYTES];
}
/**
@@ -6271,7 +6271,7 @@ message DNDModeProto {
// May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
optional string id = 5;
optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other
- optional DNDPolicyProto policy = 7;
+ optional DNDPolicyProto policy = 7 [(log_mode) = MODE_BYTES];
}
/**
@@ -6436,7 +6436,7 @@ message PowerProfileProto {
* Pulled from PowerProfile.java
*/
message PowerProfile {
- optional PowerProfileProto power_profile = 1;
+ optional PowerProfileProto power_profile = 1 [(log_mode) = MODE_BYTES];
}
/**
@@ -8131,7 +8131,7 @@ message DeviceIdentifierAccessDenied {
message TrainInfo {
optional int64 train_version_code = 1;
- optional TrainExperimentIds train_experiment_id = 2;
+ optional TrainExperimentIds train_experiment_id = 2 [(log_mode) = MODE_BYTES];
optional string train_name = 3;
@@ -11179,8 +11179,8 @@ message BlobInfo {
optional int64 expiry_timestamp_millis = 3;
// List of committers of this Blob
- optional BlobCommitterListProto committers = 4;
+ optional BlobCommitterListProto committers = 4 [(log_mode) = MODE_BYTES];
// List of leasees of this Blob
- optional BlobLeaseeListProto leasees = 5;
+ optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES];
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a2947a967d88..9b13d256aea6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -271,9 +271,6 @@ public final class ActivityThread extends ClientTransactionHandler {
/** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
public static final int SERVICE_DONE_EXECUTING_STOP = 2;
- // Whether to invoke an activity callback after delivering new configuration.
- private static final boolean REPORT_TO_ACTIVITY = true;
-
/** Use foreground GC policy (less pause time) and higher JIT weight. */
private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
/** Use background GC policy and default JIT threshold. */
@@ -4973,7 +4970,8 @@ public final class ActivityThread extends ClientTransactionHandler {
private void relaunchAllActivities(boolean preserveWindows) {
for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
final ActivityClientRecord r = entry.getValue();
- if (!r.activity.mFinished) {
+ // Schedule relaunch the activity if it is not a local object or finishing.
+ if (!r.activity.mFinished && !(r.token instanceof Binder)) {
if (preserveWindows && r.window != null) {
r.mPreserveWindow = true;
}
@@ -5539,18 +5537,14 @@ public final class ActivityThread extends ClientTransactionHandler {
}
/**
- * Updates the configuration for an Activity. The ActivityClientRecord's
- * {@link ActivityClientRecord#overrideConfig} is used to compute the final Configuration for
- * that Activity. {@link ActivityClientRecord#tmpConfig} is used as a temporary for delivering
- * the updated Configuration.
- * @param r ActivityClientRecord representing the Activity.
- * @param newBaseConfig The new configuration to use. This may be augmented with
- * {@link ActivityClientRecord#overrideConfig}.
+ * Updates the configuration for an Activity in its current display.
+ *
+ * @see #performConfigurationChangedForActivity(ActivityClientRecord, Configuration, int,
+ * boolean)
*/
private void performConfigurationChangedForActivity(ActivityClientRecord r,
Configuration newBaseConfig) {
- performConfigurationChangedForActivity(r, newBaseConfig, r.activity.getDisplayId(),
- false /* movedToDifferentDisplay */);
+ performConfigurationChangedForActivity(r, newBaseConfig, r.activity.getDisplayId());
}
/**
@@ -5562,17 +5556,16 @@ public final class ActivityThread extends ClientTransactionHandler {
* @param newBaseConfig The new configuration to use. This may be augmented with
* {@link ActivityClientRecord#overrideConfig}.
* @param displayId The id of the display where the Activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
* @return {@link Configuration} instance sent to client, null if not sent.
*/
private Configuration performConfigurationChangedForActivity(ActivityClientRecord r,
- Configuration newBaseConfig, int displayId, boolean movedToDifferentDisplay) {
+ Configuration newBaseConfig, int displayId) {
r.tmpConfig.setTo(newBaseConfig);
if (r.overrideConfig != null) {
r.tmpConfig.updateFrom(r.overrideConfig);
}
final Configuration reportedConfig = performActivityConfigurationChanged(r.activity,
- r.tmpConfig, r.overrideConfig, displayId, movedToDifferentDisplay);
+ r.tmpConfig, r.overrideConfig, displayId);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
return reportedConfig;
}
@@ -5599,10 +5592,6 @@ public final class ActivityThread extends ClientTransactionHandler {
* @param newConfig The new configuration.
*/
private void performConfigurationChanged(ComponentCallbacks2 cb, Configuration newConfig) {
- if (!REPORT_TO_ACTIVITY) {
- return;
- }
-
// ContextThemeWrappers may override the configuration for that context. We must check and
// apply any overrides defined.
Configuration contextThemeWrapperOverrideConfig = null;
@@ -5627,12 +5616,10 @@ public final class ActivityThread extends ClientTransactionHandler {
* from the base global configuration. This is supplied by
* ActivityManager.
* @param displayId Id of the display where activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
* @return Configuration sent to client, null if no changes and not moved to different display.
*/
private Configuration performActivityConfigurationChanged(Activity activity,
- Configuration newConfig, Configuration amOverrideConfig, int displayId,
- boolean movedToDifferentDisplay) {
+ Configuration newConfig, Configuration amOverrideConfig, int displayId) {
if (activity == null) {
throw new IllegalArgumentException("No activity provided.");
}
@@ -5645,6 +5632,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
handleWindowingModeChangeIfNeeded(activity, newConfig);
+ final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
boolean shouldReportChange = false;
if (activity.mCurrentConfig == null) {
shouldReportChange = true;
@@ -5658,8 +5646,7 @@ public final class ActivityThread extends ClientTransactionHandler {
amOverrideConfig)) {
// Nothing significant, don't proceed with updating and reporting.
return null;
- } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0
- || !REPORT_TO_ACTIVITY) {
+ } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
// If this activity doesn't handle any of the config changes, then don't bother
// calling onConfigurationChanged. Otherwise, report to the activity for the
// changes.
@@ -5693,11 +5680,6 @@ public final class ActivityThread extends ClientTransactionHandler {
final Configuration configToReport = createNewConfigAndUpdateIfNotNull(newConfig,
contextThemeWrapperOverrideConfig);
- if (!REPORT_TO_ACTIVITY) {
- // Not configured to report to activity.
- return configToReport;
- }
-
if (movedToDifferentDisplay) {
activity.dispatchMovedToDisplay(displayId, configToReport);
}
@@ -5990,8 +5972,6 @@ public final class ActivityThread extends ClientTransactionHandler {
if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r);
return;
}
- final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
- && displayId != r.activity.getDisplayId();
synchronized (r) {
if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
@@ -6005,6 +5985,7 @@ public final class ActivityThread extends ClientTransactionHandler {
r.mPendingOverrideConfig = null;
}
+ final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
&& !movedToDifferentDisplay) {
if (DEBUG_CONFIGURATION) {
@@ -6020,29 +6001,34 @@ public final class ActivityThread extends ClientTransactionHandler {
final ViewRootImpl viewRoot = r.activity.mDecor != null
? r.activity.mDecor.getViewRootImpl() : null;
- if (movedToDifferentDisplay) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:"
- + r.activityInfo.name + ", displayId=" + displayId
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Handle activity config changed, activity:"
+ + r.activityInfo.name + ", displayId=" + r.activity.getDisplayId()
+ + (movedToDifferentDisplay ? (", newDisplayId=" + displayId) : "")
+ ", config=" + overrideConfig);
-
- final Configuration reportedConfig = performConfigurationChangedForActivity(r,
- mCompatConfiguration, displayId, true /* movedToDifferentDisplay */);
- if (viewRoot != null) {
- viewRoot.onMovedToDisplay(displayId, reportedConfig);
- }
- } else {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
- + r.activityInfo.name + ", config=" + overrideConfig);
- performConfigurationChangedForActivity(r, mCompatConfiguration);
}
+ final Configuration reportedConfig = performConfigurationChangedForActivity(r,
+ mCompatConfiguration,
+ movedToDifferentDisplay ? displayId : r.activity.getDisplayId());
// Notify the ViewRootImpl instance about configuration changes. It may have initiated this
// update to make sure that resources are updated before updating itself.
if (viewRoot != null) {
+ if (movedToDifferentDisplay) {
+ viewRoot.onMovedToDisplay(displayId, reportedConfig);
+ }
viewRoot.updateConfiguration(displayId);
}
mSomeActivitiesChanged = true;
}
+ /**
+ * Checks if the display id of activity is different from the given one. Note that
+ * {@link #INVALID_DISPLAY} means no difference.
+ */
+ private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
+ return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
+ }
+
final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
if (start) {
try {
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index cfe0aff05d4a..e7b3e14bfda7 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -502,7 +502,7 @@ public final class ApplicationExitInfo implements Parcelable {
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
* {@link #getPackageUid}, if an external service has the
* {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
- * to <code>true<code> and was bound with the flag
+ * to <code>true</code> and was bound with the flag
* {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
* be the kernel user identifier of the external service provider.
*/
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 79da1f6ab282..ee9bd3d259fb 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1168,7 +1168,12 @@ public class IntentFilter implements Parcelable {
public int match(Uri data, boolean wildcardSupported) {
String host = data.getHost();
if (host == null) {
- return NO_MATCH_DATA;
+ if (wildcardSupported && mWild) {
+ // special case, if no host is provided, but the Authority is wildcard, match
+ return MATCH_CATEGORY_HOST;
+ } else {
+ return NO_MATCH_DATA;
+ }
}
if (false) Log.v("IntentFilter",
"Match host " + host + ": " + mHost);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 431c5d7310f1..3688f1bda979 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1510,7 +1510,7 @@ public class ParsingPackageUtils {
Uri data = null;
String dataType = null;
- String host = IntentFilter.WILDCARD;
+ String host = null;
final int numActions = intentInfo.countActions();
final int numSchemes = intentInfo.countDataSchemes();
final int numTypes = intentInfo.countDataTypes();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5647bf90d2fb..c5a11abe1136 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -605,9 +605,6 @@ public class InputMethodService extends AbstractInputMethodService {
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
+ " ic=" + mInputConnection);
// Unbind input is per process per display.
- // TODO(b/150902448): free-up IME surface when target is changing.
- // e.g. DisplayContent#setInputMethodTarget()
- removeImeSurface();
onUnbindInput();
mInputBinding = null;
mInputConnection = null;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 0c81e5a23291..a0207c8497c8 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -127,6 +127,7 @@ public class Binder implements IBinder {
*
* @hide
*/
+ @CriticalNative
public static native int getNativeTid();
// Use a Holder to allow static initialization of Binder in the boot image, and
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 7c42c36e7747..64ab1d711765 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -96,6 +96,15 @@ public abstract class HwBinder implements IHwBinder {
throws RemoteException, NoSuchElementException;
/**
+ * This allows getService to bypass the VINTF manifest for testing only.
+ *
+ * Disabled on user builds.
+ * @hide
+ */
+ public static native final void setTrebleTestingOverride(
+ boolean testingOverride);
+
+ /**
* Configures how many threads the process-wide hwbinder threadpool
* has to process incoming requests.
*
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0abf8ae352af..6b5eb16d7bff 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -86,7 +86,6 @@ import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.DataUnit;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -161,11 +160,6 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
/** {@hide} */
- public static final String PROP_FUSE = "persist.sys.fuse";
- /** {@hide} */
- public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG;
- /** {@hide} */
public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST =
"forced_scoped_storage_whitelist";
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 537498c44d5e..e338fd977f27 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,7 +41,6 @@ public class FeatureFlagUtils {
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
- public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
/** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
@@ -52,7 +51,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
- DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "true");
DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index ef9d990168d2..c1998c6009cf 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -119,11 +119,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
// this code here means that we now got control, so we can start the animation immediately.
// If client window is trying to control IME and IME is already visible, it is immediate.
- if (fromIme || mState.getSource(getType()).isVisible()) {
+ if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
return ShowResult.SHOW_IMMEDIATELY;
}
- return getImm().requestImeShow(null /* resultReceiver */)
+ return getImm().requestImeShow(mController.getHost().getWindowToken())
? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
}
@@ -132,12 +132,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
*/
@Override
void notifyHidden() {
- getImm().notifyImeHidden();
+ getImm().notifyImeHidden(mController.getHost().getWindowToken());
}
@Override
public void removeSurface() {
- getImm().removeImeSurface();
+ final IBinder window = mController.getHost().getWindowToken();
+ if (window != null) {
+ getImm().removeImeSurface(window);
+ }
}
@Override
@@ -146,6 +149,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
super.setControl(control, showTypes, hideTypes);
if (control == null && !mIsRequestedVisibleAwaitingControl) {
hide();
+ removeSurface();
}
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 40e6f4b2fce8..700dc66fab55 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -153,6 +153,9 @@ public class InsetsSourceConsumer {
if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
applyHiddenToControl();
}
+ if (!requestedVisible && !mIsAnimationPending) {
+ removeSurface();
+ }
}
}
if (lastControl != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 81a78dc177ec..b022d2af7772 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2717,7 +2717,6 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.isEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- notifySurfaceDestroyed();
} else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
&& mSurfaceHolder == null
@@ -2948,6 +2947,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ if (surfaceDestroyed) {
+ notifySurfaceDestroyed();
+ }
+
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -9382,6 +9385,11 @@ public final class ViewRootImpl implements ViewParent,
return mInputEventReceiver.getToken();
}
+ @NonNull
+ public IBinder getWindowToken() {
+ return mAttachInfo.mWindowToken;
+ }
+
/**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 864c40f8a740..fa92e29cbf58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2111,28 +2111,36 @@ public final class InputMethodManager {
/**
* Call showSoftInput with currently focused view.
- * @return {@code true} if IME can be shown.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored and returns {@code false}.
+ *
+ * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
* @hide
*/
- public boolean requestImeShow(ResultReceiver resultReceiver) {
+ public boolean requestImeShow(IBinder windowToken) {
synchronized (mH) {
final View servedView = getServedViewLocked();
- if (servedView == null) {
+ if (servedView == null || servedView.getWindowToken() != windowToken) {
return false;
}
- showSoftInput(servedView, 0 /* flags */, resultReceiver);
+ showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */);
return true;
}
}
/**
* Notify IME directly that it is no longer visible.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored.
* @hide
*/
- public void notifyImeHidden() {
+ public void notifyImeHidden(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
+ if (mCurMethod != null && mCurRootView != null
+ && mCurRootView.getWindowToken() == windowToken) {
mCurMethod.notifyImeHidden();
}
} catch (RemoteException re) {
@@ -2142,15 +2150,15 @@ public final class InputMethodManager {
/**
* Notify IME directly to remove surface as it is no longer visible.
+ * @param windowToken The client window token that requests the IME to remove its surface.
* @hide
*/
- public void removeImeSurface() {
+ public void removeImeSurface(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
- mCurMethod.removeImeSurface();
- }
- } catch (RemoteException re) {
+ mService.removeImeSurfaceFromWindow(windowToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 0b46658d5a06..0a3fe096279d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -21,8 +21,6 @@ import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COM
import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -34,8 +32,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -146,17 +142,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if ((view.getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) {
return new Pair<>(Insets.NONE, insets);
}
-
- boolean includeIme = (view.getViewRootImpl().mWindowAttributes.softInputMode
- & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
- Insets insetsToApply;
- if (ViewRootImpl.sNewInsetsMode == 0) {
- insetsToApply = insets.getSystemWindowInsets();
- } else {
- insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0));
- }
- insets = insets.inset(insetsToApply);
+ Insets insetsToApply = insets.getSystemWindowInsets();
return new Pair<>(insetsToApply,
insets.inset(insetsToApply).consumeSystemWindowInsets());
};
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 8ec51b89d240..a1cbd3fcae79 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -73,5 +73,8 @@ interface IInputMethodManager {
in float[] matrixValues);
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
+ /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
void removeImeSurface();
+ /** Remove the IME surface. Requires passing the currently focused window. */
+ void removeImeSurfaceFromWindow(in IBinder windowToken);
}
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index b6427c9aa01c..48f33a6a3d77 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -339,6 +339,10 @@ static jobject JHwBinder_native_getService(
return JHwRemoteBinder::NewObject(env, service);
}
+void JHwBinder_native_setTrebleTestingOverride(JNIEnv*, jclass, jboolean testingOverride) {
+ hardware::details::setTrebleTestingOverride(testingOverride);
+}
+
void JHwBinder_native_configureRpcThreadpool(JNIEnv *, jclass,
jlong maxThreads, jboolean callerWillJoin) {
CHECK(maxThreads > 0);
@@ -368,6 +372,9 @@ static JNINativeMethod gMethods[] = {
{ "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
+ { "setTrebleTestingOverride", "(Z)V",
+ (void *)JHwBinder_native_setTrebleTestingOverride },
+
{ "configureRpcThreadpool", "(JZ)V",
(void *)JHwBinder_native_configureRpcThreadpool },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index aef53a4b3318..885b0a33e43c 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1048,7 +1048,7 @@ static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject ext
jbh->setExtension(extension);
}
-JNIEXPORT jint JNICALL android_os_Binder_getNativeTid(JNIEnv* env, jobject clazz) {
+static jint android_os_Binder_getNativeTid() {
return (jint)android::base::GetThreadId();
}
@@ -1083,6 +1083,7 @@ static const JNINativeMethod gBinderMethods[] = {
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
{ "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
{ "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
+ // @CriticalNative
{ "getNativeTid", "()I", (void*)android_os_Binder_getNativeTid },
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 6e49c0dda1ad..b7c5289043d6 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -124,7 +124,6 @@ typedef const std::function<void(std::string)>& fail_fn_t;
static pid_t gSystemServerPid = 0;
static constexpr const char* kVoldAppDataIsolation = "persist.sys.vold_app_data_isolation_enabled";
-static constexpr const char* kPropFuse = "persist.sys.fuse";
static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
static jclass gZygoteClass;
static jmethodID gCallPostForkSystemServerHooks;
@@ -836,29 +835,20 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
- bool isFuse = GetBoolProperty(kPropFuse, false);
bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);
- if (isFuse) {
- if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
+ if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
PrepareDir(pass_through_source, 0710, AID_ROOT, AID_MEDIA_RW, fail_fn);
BindMount(pass_through_source, "/storage", fail_fn);
- } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
+ } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
const std::string installer_source = StringPrintf("/mnt/installer/%d", user_id);
BindMount(installer_source, "/storage", fail_fn);
- } else if (isAppDataIsolationEnabled && mount_mode == MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ } else if (isAppDataIsolationEnabled && mount_mode == MOUNT_EXTERNAL_ANDROID_WRITABLE) {
const std::string writable_source = StringPrintf("/mnt/androidwritable/%d", user_id);
BindMount(writable_source, "/storage", fail_fn);
- } else {
- BindMount(user_source, "/storage", fail_fn);
- }
} else {
- const std::string& storage_source = ExternalStorageViews[mount_mode];
- BindMount(storage_source, "/storage", fail_fn);
-
- // Mount user-specific symlink helper into place
- BindMount(user_source, "/storage/self", fail_fn);
+ BindMount(user_source, "/storage", fail_fn);
}
}
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ce08e43cb1af..d312d859a58c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1152,7 +1152,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Capturar imagen con %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagen"</string>
<string name="alwaysUse" msgid="3153558199076112903">"Usar siempre para esta acción"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"Utiliza otra aplicación"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"Usar otra aplicación"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"Para borrar los valores predeterminados, accede a Ajustes del sistema &gt; Aplicaciones &gt; Descargadas."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Selecciona una acción"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Elegir una aplicación para el dispositivo USB"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index eb675ddb06a5..485f5bf08224 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1926,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"Ezarri ordua"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"Idatzi balio duen ordu bat"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"Idatzi ordua"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Aldatu testu modura ordua zehazteko."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Ordua idazteko, aldatu testua idazteko metodora."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Aldatu erloju modura ordua zehazteko."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Betetze automatikoaren aukerak"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Gorde betetze automatikoarekin erabiltzeko"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 8d9df1f2b09b..bd328b542966 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -857,7 +857,7 @@
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emerxencia"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Bloqueada pola rede"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"A tarxeta SIM está bloqueada con código PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía do usuario ou ponte en contacto co servizo de asistencia ao cliente."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía para usuarios ou ponte en contacto co servizo de asistencia ao cliente."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"A tarxeta SIM está bloqueada."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Desbloqueando tarxeta SIM…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e74157f2e02b..eabf37c50878 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1152,7 +1152,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"「%1$s」を使用して画像をキャプチャ"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"画像をキャプチャ"</string>
<string name="alwaysUse" msgid="3153558199076112903">"常にこの操作で使用する"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリの使用"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリを使用"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"[システム設定]&gt;[アプリ]&gt;[ダウンロード済み]でデフォルト設定をクリアします。"</string>
<string name="chooseActivity" msgid="8563390197659779956">"操作の選択"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USBデバイス用アプリを選択"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index affbc838048b..351790d44b7b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жіберілуде..."</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Браузер қосылсын ба?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Қоңырауды қабылдау?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Үнемі"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Әрқашан"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бір рет қана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жұмыс профилін қолдамайды"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e250b50e9821..f1bea56a62fd 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -538,7 +538,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Сиз экениңизди ырастаңыз"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string>
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жөнөтүлүүдө…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Серепчи иштетилсинби?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Чалуу кабыл алынсынбы?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Дайыма"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Ар дайым"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бир жолу гана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жумуш профилин колдоого албайт"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 51737ba80550..6ccfc09a46a0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2000,9 +2000,9 @@
<string name="notification_feedback_indicator" msgid="663476517711323016">"提供意見"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用節約耗電量模式以延長電池續航力"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"節約耗電量"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"節約耗電量模式已關閉"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"省電模式"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"省電模式已關閉"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手機電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"平板電腦電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"裝置電力充足,各項功能不再受到限制。"</string>
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 1b3272572db0..7efd616c5607 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -71,6 +71,9 @@ public class InsetsSourceConsumerTest {
private SurfaceControl mLeash;
@Mock Transaction mMockTransaction;
private InsetsSource mSpyInsetsSource;
+ private boolean mRemoveSurfaceCalled = false;
+ private InsetsController mController;
+ private InsetsState mState;
@Before
public void setup() {
@@ -89,13 +92,19 @@ public class InsetsSourceConsumerTest {
} catch (BadTokenException e) {
// activity isn't running, lets ignore BadTokenException.
}
- InsetsState state = new InsetsState();
+ mState = new InsetsState();
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
- state.addSource(mSpyInsetsSource);
-
- mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
- () -> mMockTransaction,
- new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
+ mState.addSource(mSpyInsetsSource);
+
+ mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
+ mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
+ () -> mMockTransaction, mController) {
+ @Override
+ public void removeSurface() {
+ super.removeSurface();
+ mRemoveSurfaceCalled = true;
+ }
+ };
});
instrumentation.waitForIdleSync();
@@ -171,6 +180,25 @@ public class InsetsSourceConsumerTest {
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
new int[1], hideTypes);
assertEquals(statusBars(), hideTypes[0]);
+ assertFalse(mRemoveSurfaceCalled);
+ });
+ }
+
+ @Test
+ public void testRestore_noAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mConsumer.hide();
+ mController.onStateChanged(mState);
+ mConsumer.setControl(null, new int[1], new int[1]);
+ reset(mMockTransaction);
+ verifyZeroInteractions(mMockTransaction);
+ mRemoveSurfaceCalled = false;
+ int[] hideTypes = new int[1];
+ mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+ new int[1], hideTypes);
+ assertTrue(mRemoveSurfaceCalled);
+ assertEquals(0, hideTypes[0]);
});
+
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index aa9dd40f5e0f..c0b8e1bf3bbe 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -260,7 +260,9 @@ public class LocationManager {
* {@code OP_MONITOR_HIGH_POWER_LOCATION}.
*
* @hide
+ * @deprecated This action is unnecessary from Android S forward.
*/
+ @Deprecated
public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
"android.location.HIGH_POWER_REQUEST_CHANGE";
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 515d610109ab..df022d562768 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -447,7 +447,7 @@ jobjectArray FilterCallback::getMediaEvent(
if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
new MediaEvent(mIFilter, mediaEvent.avMemory,
- mediaEvent.avDataId, dataLength, obj);
+ mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
mediaEventSp->incStrong(obj);
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 32b33a758535..8598f74e1441 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -49,7 +49,7 @@ android_library {
"androidx.lifecycle_lifecycle-extensions",
"SystemUI-tags",
"SystemUI-proto",
- "dagger2-2.19",
+ "dagger2",
"//external/kotlinc:kotlin-annotations",
],
@@ -59,7 +59,7 @@ android_library {
manifest: "AndroidManifest.xml",
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
@@ -104,7 +104,7 @@ android_library {
"mockito-target-inline-minus-junit4",
"testables",
"truth-prebuilt",
- "dagger2-2.19",
+ "dagger2",
"//external/kotlinc:kotlin-annotations",
],
libs: [
@@ -118,7 +118,7 @@ android_library {
"com.android.systemui",
],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
android_app {
@@ -157,7 +157,7 @@ android_app {
kotlincflags: ["-Xjvm-default=enable"],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
required: ["privapp_whitelist_com.android.systemui"],
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index eca51e34995c..232df2eced39 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.content.Intent;
import android.os.Handler;
@@ -44,14 +46,19 @@ import org.junit.runner.RunWith;
public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final String BLUETOOTH_REMOTE_ADDRESS = "00:11:22:33:44:55";
private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
+ private TestableLooper mTestableLooper;
private Handler mTestHandler;
+ private BluetoothDevice mBluetoothDevice;
@Before
public void setUp() throws Exception {
- TestableLooper testableLooper = TestableLooper.get(this);
- mTestHandler = spy(new Handler(testableLooper.getLooper()));
+ mTestableLooper = TestableLooper.get(this);
+ mTestHandler = spy(new Handler(mTestableLooper.getLooper()));
+ mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
+ BLUETOOTH_REMOTE_ADDRESS);
mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
mContext, mTestHandler);
mVoiceRecognitionNotifier.onBootCompleted();
@@ -61,8 +68,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
public void testReceiveIntent_started_showToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, VOICE_RECOGNITION_STARTED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler).post(any());
}
@@ -71,8 +80,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
public void testReceiveIntent_invalidExtra_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
@@ -80,8 +91,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
@Test
public void testReceiveIntent_noExtra_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
@@ -89,8 +102,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
@Test
public void testReceiveIntent_invalidIntent_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index 9ae31989eeb2..5a756fe50209 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -46,7 +46,7 @@ public class RecommendationServiceImpl extends RecommendationService
private static final String LOG_TAG = "PrintServiceRecService";
/** All registered plugins */
- private ArrayList<RemotePrintServicePlugin> mPlugins;
+ private final ArrayList<RemotePrintServicePlugin> mPlugins = new ArrayList<>();
/** Lock to keep multi-cast enabled */
private WifiManager.MulticastLock mMultiCastLock;
@@ -62,8 +62,6 @@ public class RecommendationServiceImpl extends RecommendationService
mMultiCastLock.acquire();
}
- mPlugins = new ArrayList<>();
-
try {
for (VendorConfig config : VendorConfig.getAllConfigs(this)) {
try {
@@ -138,6 +136,7 @@ public class RecommendationServiceImpl extends RecommendationService
Log.e(LOG_TAG, "Could not stop plugin", e);
}
}
+ mPlugins.clear();
if (mMultiCastLock != null) {
mMultiCastLock.release();
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7a27676237a1..6ecf303c6dc8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -68,14 +68,14 @@ android_library {
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
- "dagger2-2.19",
+ "dagger2",
"jsr330"
],
manifest: "AndroidManifest.xml",
kotlincflags: ["-Xjvm-default=enable"],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
filegroup {
@@ -139,7 +139,7 @@ android_library {
"mockito-target-extended-minus-junit4",
"testables",
"truth-prebuilt",
- "dagger2-2.19",
+ "dagger2",
"jsr330"
],
libs: [
@@ -151,7 +151,7 @@ android_library {
"--extra-packages",
"com.android.systemui",
],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
android_app {
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index c440fba10135..bb68647ceb00 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -206,11 +206,31 @@ public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet a
## Updating Dagger2
+We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
+when that repository is updated.
+
+*Deprecated:*
+
Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
into
[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
+The following commands should work, substituting in the version that you are looking for:
+
+````
+cd prebuilts/tools/common/m2/repository/com/google/dagger/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.28.1/
+````
+Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars.
+
## TODO List
- Eliminate usages of Dependency#get
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index f474a36b99b7..732758a2ded2 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<com.google.android.systemui.udfps.UdfpsView
+<com.android.systemui.biometrics.UdfpsView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/udfps_view"
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 941de2dc63ec..5fd7b53435cf 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -21,9 +21,9 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -57,12 +57,11 @@ public class AppOpsControllerImpl implements AppOpsController,
private static final long NOTED_OP_TIME_DELAY_MS = 5000;
private static final String TAG = "AppOpsControllerImpl";
private static final boolean DEBUG = false;
- private final Context mContext;
private final AppOpsManager mAppOps;
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
- private final ArrayMap<Integer, Set<Callback>> mCallbacksByCode = new ArrayMap<>();
+ private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
private boolean mListening;
@GuardedBy("mActiveItems")
@@ -71,6 +70,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private final List<AppOpItem> mNotedItems = new ArrayList<>();
protected static final int[] OPS = new int[] {
+ AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
AppOpsManager.OP_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
@@ -83,7 +83,6 @@ public class AppOpsControllerImpl implements AppOpsController,
Context context,
@Background Looper bgLooper,
DumpManager dumpManager) {
- mContext = context;
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mBGHandler = new H(bgLooper);
final int numOps = OPS.length;
@@ -131,7 +130,7 @@ public class AppOpsControllerImpl implements AppOpsController,
boolean added = false;
final int numCodes = opsCodes.length;
for (int i = 0; i < numCodes; i++) {
- if (mCallbacksByCode.containsKey(opsCodes[i])) {
+ if (mCallbacksByCode.contains(opsCodes[i])) {
mCallbacksByCode.get(opsCodes[i]).add(callback);
added = true;
} else {
@@ -155,7 +154,7 @@ public class AppOpsControllerImpl implements AppOpsController,
public void removeCallback(int[] opsCodes, AppOpsController.Callback callback) {
final int numCodes = opsCodes.length;
for (int i = 0; i < numCodes; i++) {
- if (mCallbacksByCode.containsKey(opsCodes[i])) {
+ if (mCallbacksByCode.contains(opsCodes[i])) {
mCallbacksByCode.get(opsCodes[i]).remove(callback);
}
}
@@ -312,7 +311,7 @@ public class AppOpsControllerImpl implements AppOpsController,
}
private void notifySuscribers(int code, int uid, String packageName, boolean active) {
- if (mCallbacksByCode.containsKey(code)) {
+ if (mCallbacksByCode.contains(code)) {
if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
cb.onActiveStateChanged(code, uid, packageName, active);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index c82e1debf185..97e97ffaae0c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -22,6 +22,8 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
@@ -44,6 +46,7 @@ class UdfpsController {
private final Context mContext;
private final IFingerprintService mFingerprintService;
private final WindowManager mWindowManager;
+ private final Handler mHandler;
private UdfpsView mView;
private WindowManager.LayoutParams mLayoutParams;
@@ -96,6 +99,7 @@ class UdfpsController {
mContext = context;
mFingerprintService = fingerprintService;
mWindowManager = windowManager;
+ mHandler = new Handler(Looper.getMainLooper());
start();
}
@@ -138,23 +142,27 @@ class UdfpsController {
}
private void showUdfpsOverlay() {
- Log.v(TAG, "showUdfpsOverlay | adding window");
- if (!mIsOverlayShowing) {
- try {
- mWindowManager.addView(mView, mLayoutParams);
- mIsOverlayShowing = true;
- } catch (RuntimeException e) {
- Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
+ mHandler.post(() -> {
+ Log.v(TAG, "showUdfpsOverlay | adding window");
+ if (!mIsOverlayShowing) {
+ try {
+ mWindowManager.addView(mView, mLayoutParams);
+ mIsOverlayShowing = true;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
+ }
}
- }
+ });
}
private void hideUdfpsOverlay() {
- Log.v(TAG, "hideUdfpsOverlay | removing window");
- if (mIsOverlayShowing) {
- mWindowManager.removeView(mView);
- mIsOverlayShowing = false;
- }
+ mHandler.post(() -> {
+ Log.v(TAG, "hideUdfpsOverlay | removing window");
+ if (mIsOverlayShowing) {
+ mWindowManager.removeView(mView);
+ mIsOverlayShowing = false;
+ }
+ });
}
private void onFingerDown(int x, int y, float minor, float major) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 40a93e1cdc47..57e2362bd511 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -24,7 +24,6 @@ import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -95,9 +94,16 @@ public class BubbleIconFactory extends BaseIconFactory {
Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(),
userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());
Canvas c = new Canvas(badgeAndRing);
- Rect dest = new Rect((int) ringStrokeWidth, (int) ringStrokeWidth,
- c.getHeight() - (int) ringStrokeWidth, c.getWidth() - (int) ringStrokeWidth);
- c.drawBitmap(userBadgedBitmap, null, dest, null);
+
+ final int bitmapTop = (int) ringStrokeWidth;
+ final int bitmapLeft = (int) ringStrokeWidth;
+ final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth;
+ final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth;
+
+ Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth,
+ bitmapHeight, /* filter */ true);
+ c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null);
+
Paint ringPaint = new Paint();
ringPaint.setStyle(Paint.Style.STROKE);
ringPaint.setColor(importantConversationColor);
@@ -105,6 +111,7 @@ public class BubbleIconFactory extends BaseIconFactory {
ringPaint.setStrokeWidth(ringStrokeWidth);
c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2 - ringStrokeWidth,
ringPaint);
+
shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);
return createIconBitmap(badgeAndRing);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 0873328c2382..4bd046e23dab 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
@@ -68,6 +69,7 @@ import dagger.Provides;
},
subcomponents = {StatusBarComponent.class,
NotificationRowComponent.class,
+ DozeComponent.class,
ExpandableNotificationRowComponent.class})
public abstract class SystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index 4fea45c39d5d..60ee806d0a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -51,6 +51,14 @@ public class AlwaysOnDisplayPolicy {
static final String KEY_WALLPAPER_VISIBILITY_MS = "wallpaper_visibility_timeout";
static final String KEY_WALLPAPER_FADE_OUT_MS = "wallpaper_fade_out_duration";
+
+ /**
+ * Integer used to dim the screen while dozing.
+ *
+ * @see R.integer.config_screenBrightnessDoze
+ */
+ public int defaultDozeBrightness;
+
/**
* Integer array to map ambient brightness type to real screen brightness.
*
@@ -165,6 +173,8 @@ public class AlwaysOnDisplayPolicy {
DEFAULT_WALLPAPER_FADE_OUT_MS);
wallpaperVisibilityDuration = mParser.getLong(KEY_WALLPAPER_VISIBILITY_MS,
DEFAULT_WALLPAPER_VISIBILITY_MS);
+ defaultDozeBrightness = resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze);
screenBrightnessArray = mParser.getIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
resources.getIntArray(
R.array.config_doze_brightness_sensor_to_brightness));
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
index abd41d4318bd..5eb9808ebd7c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
@@ -16,20 +16,22 @@
package com.android.systemui.doze;
-import android.content.Context;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
+import com.android.systemui.doze.dagger.DozeScope;
+
+import javax.inject.Inject;
/**
* Controls removing Keyguard authorization when the phone goes to sleep.
*/
+@DozeScope
public class DozeAuthRemover implements DozeMachine.Part {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- public DozeAuthRemover(Context context) {
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
+ @Inject
+ public DozeAuthRemover(KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 554457b3564a..2a3d67fd7a8d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -22,33 +22,41 @@ import android.util.Log;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
+import com.android.systemui.doze.dagger.DozeScope;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Handles dock events for ambient state changes.
*/
+@DozeScope
public class DozeDockHandler implements DozeMachine.Part {
private static final String TAG = "DozeDockHandler";
private static final boolean DEBUG = DozeService.DEBUG;
private final AmbientDisplayConfiguration mConfig;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final DockManager mDockManager;
private final DockEventListener mDockEventListener;
private int mDockState = DockManager.STATE_NONE;
- DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine,
- DockManager dockManager) {
- mMachine = machine;
+ @Inject
+ DozeDockHandler(AmbientDisplayConfiguration config, DockManager dockManager) {
mConfig = config;
mDockManager = dockManager;
mDockEventListener = new DockEventListener();
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case INITIALIZED:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
deleted file mode 100644
index 3bac196ca59f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 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.doze;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.IWallpaperManager;
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.util.sensors.AsyncSensorManager;
-import com.android.systemui.util.sensors.ProximitySensor;
-import com.android.systemui.util.wakelock.DelayedWakeLock;
-import com.android.systemui.util.wakelock.WakeLock;
-
-import javax.inject.Inject;
-
-public class DozeFactory {
-
- private final FalsingManager mFalsingManager;
- private final DozeLog mDozeLog;
- private final DozeParameters mDozeParameters;
- private final BatteryController mBatteryController;
- private final AsyncSensorManager mAsyncSensorManager;
- private final AlarmManager mAlarmManager;
- private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final DockManager mDockManager;
- private final IWallpaperManager mWallpaperManager;
- private final ProximitySensor mProximitySensor;
- private final ProximitySensor.ProximityCheck mProximityCheck;
- private final DelayedWakeLock.Builder mDelayedWakeLockBuilder;
- private final Handler mHandler;
- private final BiometricUnlockController mBiometricUnlockController;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final DozeHost mDozeHost;
-
- @Inject
- public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
- DozeParameters dozeParameters, BatteryController batteryController,
- AsyncSensorManager asyncSensorManager, AlarmManager alarmManager,
- WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
- DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
- ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proximityCheck,
- DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
- BiometricUnlockController biometricUnlockController,
- BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
- mFalsingManager = falsingManager;
- mDozeLog = dozeLog;
- mDozeParameters = dozeParameters;
- mBatteryController = batteryController;
- mAsyncSensorManager = asyncSensorManager;
- mAlarmManager = alarmManager;
- mWakefulnessLifecycle = wakefulnessLifecycle;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mDockManager = dockManager;
- mWallpaperManager = wallpaperManager;
- mProximitySensor = proximitySensor;
- mProximityCheck = proximityCheck;
- mDelayedWakeLockBuilder = delayedWakeLockBuilder;
- mHandler = handler;
- mBiometricUnlockController = biometricUnlockController;
- mBroadcastDispatcher = broadcastDispatcher;
- mDozeHost = dozeHost;
- }
-
- /** Creates a DozeMachine with its parts for {@code dozeService}. */
- DozeMachine assembleMachine(DozeService dozeService) {
- AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(dozeService);
- WakeLock wakeLock = mDelayedWakeLockBuilder.setHandler(mHandler).setTag("Doze").build();
-
- DozeMachine.Service wrappedService = dozeService;
- wrappedService = new DozeBrightnessHostForwarder(wrappedService, mDozeHost);
- wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
- wrappedService, mDozeParameters);
- wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
- wrappedService, mDozeParameters);
-
- DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
- mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager,
- mDozeHost);
- machine.setParts(new DozeMachine.Part[]{
- new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
- new DozeFalsingManagerAdapter(mFalsingManager),
- createDozeTriggers(dozeService, mAsyncSensorManager, mDozeHost,
- mAlarmManager, config, mDozeParameters, wakeLock,
- machine, mDockManager, mDozeLog, mProximityCheck),
- createDozeUi(dozeService, mDozeHost, wakeLock, machine, mHandler,
- mAlarmManager, mDozeParameters, mDozeLog),
- new DozeScreenState(wrappedService, mHandler, mDozeHost, mDozeParameters,
- wakeLock),
- createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager,
- mDozeHost, mDozeParameters, mHandler),
- new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
- mDozeParameters),
- new DozeDockHandler(config, machine, mDockManager),
- new DozeAuthRemover(dozeService)
- });
-
- return machine;
- }
-
- private DozeMachine.Part createDozeScreenBrightness(Context context,
- DozeMachine.Service service, SensorManager sensorManager, DozeHost host,
- DozeParameters params, Handler handler) {
- Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
- context.getString(R.string.doze_brightness_sensor_type));
- return new DozeScreenBrightness(context, service, sensorManager, sensor,
- mBroadcastDispatcher, host, handler, params.getPolicy());
- }
-
- private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
- DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
- DozeParameters params, WakeLock wakeLock,
- DozeMachine machine, DockManager dockManager, DozeLog dozeLog,
- ProximitySensor.ProximityCheck proximityCheck) {
- boolean allowPulseTriggers = true;
- return new DozeTriggers(context, machine, host, alarmManager, config, params,
- sensorManager, wakeLock, allowPulseTriggers, dockManager,
- mProximitySensor, proximityCheck, dozeLog, mBroadcastDispatcher);
-
- }
-
- private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
- DozeMachine machine, Handler handler, AlarmManager alarmManager,
- DozeParameters params, DozeLog dozeLog) {
- return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params,
- mKeyguardUpdateMonitor, dozeLog);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
index 250308d4c3a6..94b8ba305d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
@@ -16,15 +16,20 @@
package com.android.systemui.doze;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.plugins.FalsingManager;
+import javax.inject.Inject;
+
/**
* Notifies FalsingManager of whether or not AOD is showing.
*/
+@DozeScope
public class DozeFalsingManagerAdapter implements DozeMachine.Part {
private final FalsingManager mFalsingManager;
+ @Inject
public DozeFalsingManagerAdapter(FalsingManager falsingManager) {
mFalsingManager = falsingManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index ae7d82ac4a5e..b9d23ade2ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -28,6 +28,8 @@ import android.view.Display;
import com.android.internal.util.Preconditions;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -38,6 +40,8 @@ import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
import java.util.ArrayList;
+import javax.inject.Inject;
+
/**
* Orchestrates all things doze.
*
@@ -46,6 +50,7 @@ import java.util.ArrayList;
*
* During state transitions and in certain states, DozeMachine holds a wake lock.
*/
+@DozeScope
public class DozeMachine {
static final String TAG = "DozeMachine";
@@ -146,9 +151,11 @@ public class DozeMachine {
private boolean mWakeLockHeldForCurrentState = false;
private DockManager mDockManager;
- public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock,
- WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController,
- DozeLog dozeLog, DockManager dockManager, DozeHost dozeHost) {
+ @Inject
+ public DozeMachine(@WrappedService Service service, AmbientDisplayConfiguration config,
+ WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
+ BatteryController batteryController, DozeLog dozeLog, DockManager dockManager,
+ DozeHost dozeHost, Part[] parts) {
mDozeService = service;
mConfig = config;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -157,6 +164,10 @@ public class DozeMachine {
mDozeLog = dozeLog;
mDockManager = dockManager;
mDozeHost = dozeHost;
+ mParts = parts;
+ for (Part part : parts) {
+ part.setDozeMachine(this);
+ }
}
/**
@@ -168,12 +179,6 @@ public class DozeMachine {
}
}
- /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
- public void setParts(Part[] parts) {
- Preconditions.checkState(mParts == null);
- mParts = parts;
- }
-
/**
* Requests transitioning to {@code requestedState}.
*
@@ -432,6 +437,9 @@ public class DozeMachine {
/** Alerts that the screenstate is being changed. */
default void onScreenState(int state) {}
+
+ /** Sets the {@link DozeMachine} when this Part is associated with one. */
+ default void setDozeMachine(DozeMachine dozeMachine) {}
}
/** A wrapper interface for {@link android.service.dreams.DreamService} */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
index 58f144830650..2b4067865415 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -19,25 +19,35 @@ package com.android.systemui.doze;
import android.app.AlarmManager;
import android.os.Handler;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.util.AlarmTimeout;
+import javax.inject.Inject;
+
/**
* Moves the doze machine from the pausing to the paused state after a timeout.
*/
+@DozeScope
public class DozePauser implements DozeMachine.Part {
public static final String TAG = DozePauser.class.getSimpleName();
private final AlarmTimeout mPauseTimeout;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final AlwaysOnDisplayPolicy mPolicy;
- public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager,
+ @Inject
+ public DozePauser(@Main Handler handler, AlarmManager alarmManager,
AlwaysOnDisplayPolicy policy) {
- mMachine = machine;
mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
mPolicy = policy;
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD_PAUSING:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 64cfb4bcd058..342818de3d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -19,7 +19,6 @@ package com.android.systemui.doze;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -31,12 +30,17 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.view.Display;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.doze.dagger.BrightnessSensor;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+
+import javax.inject.Inject;
/**
* Controls the screen brightness when dozing.
*/
+@DozeScope
public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachine.Part,
SensorEventListener {
private static final boolean DEBUG_AOD_BRIGHTNESS = SystemProperties
@@ -51,10 +55,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private final Handler mHandler;
private final SensorManager mSensorManager;
private final Sensor mLightSensor;
- private final BroadcastDispatcher mBroadcastDispatcher;
private final int[] mSensorToBrightness;
private final int[] mSensorToScrimOpacity;
- private final boolean mDebuggable;
private boolean mRegistered;
private int mDefaultDozeBrightness;
@@ -71,40 +73,20 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private int mDebugBrightnessBucket = -1;
private DozeMachine.State mState;
- @VisibleForTesting
- public DozeScreenBrightness(Context context, DozeMachine.Service service,
- SensorManager sensorManager, Sensor lightSensor,
- BroadcastDispatcher broadcastDispatcher, DozeHost host,
- Handler handler, int defaultDozeBrightness, int[] sensorToBrightness,
- int[] sensorToScrimOpacity, boolean debuggable) {
+ @Inject
+ public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service,
+ AsyncSensorManager sensorManager, @BrightnessSensor Sensor lightSensor,
+ DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
mLightSensor = lightSensor;
- mBroadcastDispatcher = broadcastDispatcher;
mDozeHost = host;
mHandler = handler;
- mDebuggable = debuggable;
-
- mDefaultDozeBrightness = defaultDozeBrightness;
- mSensorToBrightness = sensorToBrightness;
- mSensorToScrimOpacity = sensorToScrimOpacity;
-
- if (mDebuggable) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_AOD_BRIGHTNESS);
- mBroadcastDispatcher.registerReceiverWithHandler(this, filter, handler, UserHandle.ALL);
- }
- }
- public DozeScreenBrightness(Context context, DozeMachine.Service service,
- SensorManager sensorManager, Sensor lightSensor,
- BroadcastDispatcher broadcastDispatcher, DozeHost host, Handler handler,
- AlwaysOnDisplayPolicy policy) {
- this(context, service, sensorManager, lightSensor, broadcastDispatcher, host, handler,
- context.getResources().getInteger(
- com.android.internal.R.integer.config_screenBrightnessDoze),
- policy.screenBrightnessArray, policy.dimmingScrimArray, DEBUG_AOD_BRIGHTNESS);
+ mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness;
+ mSensorToBrightness = alwaysOnDisplayPolicy.screenBrightnessArray;
+ mSensorToScrimOpacity = alwaysOnDisplayPolicy.dimmingScrimArray;
}
@Override
@@ -139,9 +121,6 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private void onDestroy() {
setLightSensorEnabled(false);
- if (mDebuggable) {
- mBroadcastDispatcher.unregisterReceiver(this);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 915359374bfe..8c50a16b566f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -26,13 +26,19 @@ import android.os.Handler;
import android.util.Log;
import android.view.Display;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
+import javax.inject.Inject;
+
/**
* Controls the screen when dozing.
*/
+@DozeScope
public class DozeScreenState implements DozeMachine.Part {
private static final boolean DEBUG = DozeService.DEBUG;
@@ -59,8 +65,9 @@ public class DozeScreenState implements DozeMachine.Part {
private int mPendingScreenState = Display.STATE_UNKNOWN;
private SettableWakeLock mWakeLock;
- public DozeScreenState(DozeMachine.Service service, Handler handler, DozeHost host,
- DozeParameters parameters, WakeLock wakeLock) {
+ @Inject
+ public DozeScreenState(@WrappedService DozeMachine.Service service, @Main Handler handler,
+ DozeHost host, DozeParameters parameters, WakeLock wakeLock) {
mDozeService = service;
mHandler = handler;
mParameters = parameters;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index aebf41b884c4..37bdda8a06a1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -21,7 +21,6 @@ import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_
import android.annotation.AnyThread;
import android.app.ActivityManager;
-import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -64,10 +63,8 @@ public class DozeSensors {
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
private final Context mContext;
- private final AlarmManager mAlarmManager;
private final AsyncSensorManager mSensorManager;
private final ContentResolver mResolver;
- private final DozeParameters mDozeParameters;
private final AmbientDisplayConfiguration mConfig;
private final WakeLock mWakeLock;
private final Consumer<Boolean> mProxCallback;
@@ -98,14 +95,12 @@ public class DozeSensors {
}
}
- public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
+ DozeSensors(Context context, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
ProximitySensor proximitySensor) {
mContext = context;
- mAlarmManager = alarmManager;
mSensorManager = sensorManager;
- mDozeParameters = dozeParameters;
mConfig = config;
mWakeLock = wakeLock;
mProxCallback = proxCallback;
@@ -206,7 +201,10 @@ public class DozeSensors {
return findSensorWithType(mSensorManager, type);
}
- static Sensor findSensorWithType(SensorManager sensorManager, String type) {
+ /**
+ * Utility method to find a {@link Sensor} for the supplied string type.
+ */
+ public static Sensor findSensorWithType(SensorManager sensorManager, String type) {
if (TextUtils.isEmpty(type)) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d2bebb7b27d1..19b0ea1db04e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -22,6 +22,7 @@ import android.os.SystemClock;
import android.service.dreams.DreamService;
import android.util.Log;
+import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
import com.android.systemui.plugins.PluginListener;
@@ -36,16 +37,16 @@ public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final DozeFactory mDozeFactory;
+ private final DozeComponent.Builder mDozeComponentBuilder;
private DozeMachine mDozeMachine;
private DozeServicePlugin mDozePlugin;
private PluginManager mPluginManager;
@Inject
- public DozeService(DozeFactory dozeFactory, PluginManager pluginManager) {
+ public DozeService(DozeComponent.Builder dozeComponentBuilder, PluginManager pluginManager) {
+ mDozeComponentBuilder = dozeComponentBuilder;
setDebug(DEBUG);
- mDozeFactory = dozeFactory;
mPluginManager = pluginManager;
}
@@ -56,7 +57,8 @@ public class DozeService extends DreamService
setWindowless(true);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- mDozeMachine = mDozeFactory.assembleMachine(this);
+ DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
+ mDozeMachine = dozeComponent.getDozeMachine();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index eb2463b02ae4..0800a201bd92 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
import com.android.systemui.util.sensors.AsyncSensorManager;
@@ -51,9 +52,12 @@ import java.io.PrintWriter;
import java.util.Optional;
import java.util.function.Consumer;
+import javax.inject.Inject;
+
/**
* Handles triggers for ambient state changes.
*/
+@DozeScope
public class DozeTriggers implements DozeMachine.Part {
private static final String TAG = "DozeTriggers";
@@ -73,7 +77,7 @@ public class DozeTriggers implements DozeMachine.Part {
private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500;
private final Context mContext;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final DozeLog mDozeLog;
private final DozeSensors mDozeSensors;
private final DozeHost mDozeHost;
@@ -153,21 +157,21 @@ public class DozeTriggers implements DozeMachine.Part {
}
}
- public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
+ @Inject
+ public DozeTriggers(Context context, DozeHost dozeHost,
AlarmManager alarmManager, AmbientDisplayConfiguration config,
DozeParameters dozeParameters, AsyncSensorManager sensorManager,
- WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
+ WakeLock wakeLock, DockManager dockManager,
ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
mContext = context;
- mMachine = machine;
mDozeHost = dozeHost;
mConfig = config;
mDozeParameters = dozeParameters;
mSensorManager = sensorManager;
mWakeLock = wakeLock;
- mAllowPulseTriggers = allowPulseTriggers;
- mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
+ mAllowPulseTriggers = true;
+ mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters,
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mDockManager = dockManager;
@@ -177,6 +181,11 @@ public class DozeTriggers implements DozeMachine.Part {
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void destroy() {
mDozeSensors.destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 1c056215f1cb..0fdaae82e2d0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -29,15 +29,20 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
import java.util.Calendar;
+import javax.inject.Inject;
+
/**
* The policy controlling doze.
*/
+@DozeScope
public class DozeUi implements DozeMachine.Part {
private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
@@ -45,7 +50,7 @@ public class DozeUi implements DozeMachine.Part {
private final DozeHost mHost;
private final Handler mHandler;
private final WakeLock mWakeLock;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final AlarmTimeout mTimeTicker;
private final boolean mCanAnimateTransition;
private final DozeParameters mDozeParameters;
@@ -64,12 +69,12 @@ public class DozeUi implements DozeMachine.Part {
private long mLastTimeTickElapsed = 0;
- public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
- WakeLock wakeLock, DozeHost host, Handler handler,
+ @Inject
+ public DozeUi(Context context, AlarmManager alarmManager,
+ WakeLock wakeLock, DozeHost host, @Main Handler handler,
DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
DozeLog dozeLog) {
mContext = context;
- mMachine = machine;
mWakeLock = wakeLock;
mHost = host;
mHandler = handler;
@@ -80,6 +85,11 @@ public class DozeUi implements DozeMachine.Part {
mDozeLog = dozeLog;
}
+ @Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
/**
* Decide if we're taking over the screen-off animation
* when the device was configured to skip doze after screen off.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 7aeb7851bbd1..d5b6cb1a6250 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -21,15 +21,19 @@ import android.app.IWallpaperManager;
import android.os.RemoteException;
import android.util.Log;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Propagates doze state to wallpaper engine.
*/
+@DozeScope
public class DozeWallpaperState implements DozeMachine.Part {
private static final String TAG = "DozeWallpaperState";
@@ -41,8 +45,9 @@ public class DozeWallpaperState implements DozeMachine.Part {
private final BiometricUnlockController mBiometricUnlockController;
private boolean mIsAmbientMode;
+ @Inject
public DozeWallpaperState(
- IWallpaperManager wallpaperManagerService,
+ @Nullable IWallpaperManager wallpaperManagerService,
BiometricUnlockController biometricUnlockController,
DozeParameters parameters) {
mWallpaperManagerService = wallpaperManagerService;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java
new file mode 100644
index 000000000000..5af8af366b69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BrightnessSensor {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
new file mode 100644
index 000000000000..e925927e7564
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze.dagger;
+
+import com.android.systemui.doze.DozeMachine;
+import com.android.systemui.doze.DozeService;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Dagger component for items that require a {@link DozeService}.
+ */
+@Subcomponent(modules = {DozeModule.class})
+@DozeScope
+public interface DozeComponent {
+ /** Simple Builder for {@link DozeComponent}. */
+ @Subcomponent.Factory
+ interface Builder {
+ DozeComponent build(@BindsInstance DozeService dozeService);
+ }
+
+ /** Supply a {@link DozeMachine}. */
+ @DozeScope
+ DozeMachine getDozeMachine();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
new file mode 100644
index 000000000000..a12e280fcca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze.dagger;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.os.Handler;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.DozeAuthRemover;
+import com.android.systemui.doze.DozeBrightnessHostForwarder;
+import com.android.systemui.doze.DozeDockHandler;
+import com.android.systemui.doze.DozeFalsingManagerAdapter;
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeMachine;
+import com.android.systemui.doze.DozePauser;
+import com.android.systemui.doze.DozeScreenBrightness;
+import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.doze.DozeScreenStatePreventingAdapter;
+import com.android.systemui.doze.DozeSensors;
+import com.android.systemui.doze.DozeService;
+import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter;
+import com.android.systemui.doze.DozeTriggers;
+import com.android.systemui.doze.DozeUi;
+import com.android.systemui.doze.DozeWallpaperState;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.wakelock.DelayedWakeLock;
+import com.android.systemui.util.wakelock.WakeLock;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Dagger module for use with {@link com.android.systemui.doze.dagger.DozeComponent}. */
+@Module
+public abstract class DozeModule {
+ @Provides
+ @DozeScope
+ @WrappedService
+ static DozeMachine.Service providesWrappedService(DozeService dozeService, DozeHost dozeHost,
+ DozeParameters dozeParameters) {
+ DozeMachine.Service wrappedService = dozeService;
+ wrappedService = new DozeBrightnessHostForwarder(wrappedService, dozeHost);
+ wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, dozeParameters);
+ wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, dozeParameters);
+
+ return wrappedService;
+ }
+
+ @Provides
+ @DozeScope
+ static WakeLock providesDozeWakeLock(DelayedWakeLock.Builder delayedWakeLockBuilder,
+ @Main Handler handler) {
+ return delayedWakeLockBuilder.setHandler(handler).setTag("Doze").build();
+ }
+
+ @Provides
+ static DozeMachine.Part[] providesDozeMachinePartes(DozePauser dozePauser,
+ DozeFalsingManagerAdapter dozeFalsingManagerAdapter, DozeTriggers dozeTriggers,
+ DozeUi dozeUi, DozeScreenState dozeScreenState,
+ DozeScreenBrightness dozeScreenBrightness, DozeWallpaperState dozeWallpaperState,
+ DozeDockHandler dozeDockHandler, DozeAuthRemover dozeAuthRemover) {
+ return new DozeMachine.Part[]{
+ dozePauser,
+ dozeFalsingManagerAdapter,
+ dozeTriggers,
+ dozeUi,
+ dozeScreenState,
+ dozeScreenBrightness,
+ dozeWallpaperState,
+ dozeDockHandler,
+ dozeAuthRemover
+ };
+ }
+
+ @Provides
+ @BrightnessSensor
+ static Sensor providesBrightnessSensor(AsyncSensorManager sensorManager, Context context) {
+ return DozeSensors.findSensorWithType(sensorManager,
+ context.getString(R.string.doze_brightness_sensor_type));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
new file mode 100644
index 000000000000..7a8b8166a969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+@Documented
+@Retention(RUNTIME)
+@Scope
+public @interface DozeScope {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java
new file mode 100644
index 000000000000..ca8a158f21a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface WrappedService {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index e8f0e069c98d..d0642ccf9714 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -33,23 +33,31 @@ class MediaDataCombineLatest @Inject constructor(
init {
dataSource.addListener(object : MediaDataManager.Listener {
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
- if (oldKey != null && !oldKey.equals(key)) {
- val s = entries[oldKey]?.second
- entries[key] = data to entries[oldKey]?.second
- entries.remove(oldKey)
+ if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
+ entries[key] = data to entries.remove(oldKey)?.second
+ update(key, oldKey)
} else {
entries[key] = data to entries[key]?.second
+ update(key, key)
}
- update(key, oldKey)
}
override fun onMediaDataRemoved(key: String) {
remove(key)
}
})
deviceSource.addListener(object : MediaDeviceManager.Listener {
- override fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) {
- entries[key] = entries[key]?.first to data
- update(key, key)
+ override fun onMediaDeviceChanged(
+ key: String,
+ oldKey: String?,
+ data: MediaDeviceData?
+ ) {
+ if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
+ entries[key] = entries.remove(oldKey)?.first to data
+ update(key, oldKey)
+ } else {
+ entries[key] = entries[key]?.first to data
+ update(key, key)
+ }
}
override fun onKeyRemoved(key: String) {
remove(key)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 7ae2dc5c0941..143f8496e7aa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -71,7 +71,8 @@ class MediaDeviceManager @Inject constructor(
val controller = data.token?.let {
MediaController(context, it)
}
- entry = Token(key, controller, localMediaManagerFactory.create(data.packageName))
+ entry = Token(key, oldKey, controller,
+ localMediaManagerFactory.create(data.packageName))
entries[key] = entry
entry.start()
}
@@ -98,23 +99,24 @@ class MediaDeviceManager @Inject constructor(
}
}
- private fun processDevice(key: String, device: MediaDevice?) {
+ private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) {
val enabled = device != null
val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
listeners.forEach {
- it.onMediaDeviceChanged(key, data)
+ it.onMediaDeviceChanged(key, oldKey, data)
}
}
interface Listener {
/** Called when the route has changed for a given notification. */
- fun onMediaDeviceChanged(key: String, data: MediaDeviceData?)
+ fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?)
/** Called when the notification was removed. */
fun onKeyRemoved(key: String)
}
private inner class Token(
val key: String,
+ val oldKey: String?,
val controller: MediaController?,
val localMediaManager: LocalMediaManager
) : LocalMediaManager.DeviceCallback {
@@ -125,7 +127,7 @@ class MediaDeviceManager @Inject constructor(
set(value) {
if (!started || value != field) {
field = value
- processDevice(key, value)
+ processDevice(key, oldKey, value)
}
}
fun start() {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
index 20ab114a97ec..1926c44abcba 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
@@ -19,11 +19,10 @@ package com.android.systemui.onehanded;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
-import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
import androidx.annotation.VisibleForTesting;
@@ -53,7 +52,7 @@ public class OneHandedAnimationController {
public @interface TransitionDirection {
}
- private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mOvershootInterpolator;
private final OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private final HashMap<SurfaceControl, OneHandedTransitionAnimator> mAnimatorMap =
new HashMap<>();
@@ -62,11 +61,10 @@ public class OneHandedAnimationController {
* Constructor of OneHandedAnimationController
*/
@Inject
- public OneHandedAnimationController(Context context,
+ public OneHandedAnimationController(
OneHandedSurfaceTransactionHelper surfaceTransactionHelper) {
mSurfaceTransactionHelper = surfaceTransactionHelper;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
+ mOvershootInterpolator = new OvershootInterpolator();
}
@SuppressWarnings("unchecked")
@@ -104,7 +102,7 @@ public class OneHandedAnimationController {
OneHandedTransitionAnimator setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator animator) {
animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(mOvershootInterpolator);
animator.setFloatValues(FRACTION_START, FRACTION_END);
return animator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 673aa3903156..85a3bc91dc7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -142,7 +142,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
.expandableNotificationRow(row)
.notificationEntry(entry)
.onDismissRunnable(onDismissRunnable)
- .rowContentBindStage(mRowContentBindStage)
.onExpandClickListener(mPresenter)
.build();
ExpandableNotificationRowController rowController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
index 9846f2dcd170..321656df504a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
@@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.phone.StatusBar;
import dagger.Binds;
@@ -57,8 +56,6 @@ public interface ExpandableNotificationRowComponent {
@BindsInstance
Builder onDismissRunnable(@DismissRunnable Runnable runnable);
@BindsInstance
- Builder rowContentBindStage(RowContentBindStage rowContentBindStage);
- @BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
ExpandableNotificationRowComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index f5999f5c8294..f5ea1c880a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -211,8 +211,4 @@ public class DozeParameters implements TunerService.Tunable,
public void onTuningChanged(String key, String newValue) {
mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
}
-
- public AlwaysOnDisplayPolicy getPolicy() {
- return mAlwaysOnPolicy;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 3bd33ccca911..251693e162d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+
import static com.android.settingslib.Utils.updateLocationEnabled;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -36,8 +36,9 @@ import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.BootCompleteCache;
+import com.android.systemui.appops.AppOpItem;
+import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.Utils;
@@ -51,41 +52,32 @@ import javax.inject.Singleton;
* A controller to manage changes of location related states and update the views accordingly.
*/
@Singleton
-public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
-
- private static final int[] mHighPowerRequestAppOpArray
- = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
+public class LocationControllerImpl extends BroadcastReceiver implements LocationController,
+ AppOpsController.Callback {
- private Context mContext;
+ private final Context mContext;
+ private final AppOpsController mAppOpsController;
+ private final BootCompleteCache mBootCompleteCache;
+ private final H mHandler;
- private AppOpsManager mAppOpsManager;
- private StatusBarManager mStatusBarManager;
- private BroadcastDispatcher mBroadcastDispatcher;
- private BootCompleteCache mBootCompleteCache;
private boolean mAreActiveLocationRequests;
- private final H mHandler;
-
@Inject
- public LocationControllerImpl(Context context, @Main Looper mainLooper,
- @Background Looper bgLooper, BroadcastDispatcher broadcastDispatcher,
+ public LocationControllerImpl(Context context, AppOpsController appOpsController,
+ @Main Looper mainLooper, BroadcastDispatcher broadcastDispatcher,
BootCompleteCache bootCompleteCache) {
mContext = context;
- mBroadcastDispatcher = broadcastDispatcher;
+ mAppOpsController = appOpsController;
mBootCompleteCache = bootCompleteCache;
mHandler = new H(mainLooper);
// Register to listen for changes in location settings.
IntentFilter filter = new IntentFilter();
- filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
- mBroadcastDispatcher.registerReceiverWithHandler(this, filter,
- new Handler(bgLooper), UserHandle.ALL);
+ broadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, UserHandle.ALL);
- mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mStatusBarManager
- = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mAppOpsController.addCallback(new int[]{OP_MONITOR_HIGH_POWER_LOCATION}, this);
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -160,27 +152,12 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
*/
@VisibleForTesting
protected boolean areActiveHighPowerLocationRequests() {
- List<AppOpsManager.PackageOps> packages
- = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
- // AppOpsManager can return null when there is no requested data.
- if (packages != null) {
- final int numPackages = packages.size();
- for (int packageInd = 0; packageInd < numPackages; packageInd++) {
- AppOpsManager.PackageOps packageOp = packages.get(packageInd);
- List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
- if (opEntries != null) {
- final int numOps = opEntries.size();
- for (int opInd = 0; opInd < numOps; opInd++) {
- AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
- // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
- // of the mHighPowerRequestAppOpArray filter, but checking defensively.
- if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
- if (opEntry.isRunning()) {
- return true;
- }
- }
- }
- }
+ List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
+
+ final int numItems = appOpsItems.size();
+ for (int i = 0; i < numItems; i++) {
+ if (appOpsItems.get(i).getCode() == OP_MONITOR_HIGH_POWER_LOCATION) {
+ return true;
}
}
@@ -198,14 +175,16 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
@Override
public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
- updateActiveLocationRequests();
- } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
- mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
+ if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())) {
+ mHandler.locationSettingsChanged();
}
}
+ @Override
+ public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
+ updateActiveLocationRequests();
+ }
+
private final class H extends Handler {
private static final int MSG_LOCATION_SETTINGS_CHANGED = 1;
private static final int MSG_LOCATION_ACTIVE_CHANGED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 3078e19c54f9..38b20c030116 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -226,6 +226,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
&& mAnimation != null) {
startAnimation(mImeShowing, true /* forceRestart */);
+ } else if (!mImeShowing) {
+ removeImeSurface();
}
});
}
@@ -375,16 +377,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
dispatchEndPositioning(mDisplayId, mCancelled, t);
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
t.hide(mImeSourceControl.getLeash());
- final IInputMethodManager imms = getImms();
- if (imms != null) {
- try {
- // Remove the IME surface to make the insets invisible for
- // non-client controlled insets.
- imms.removeImeSurface();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to remove IME surface.", e);
- }
- }
+ removeImeSurface();
}
t.apply();
mTransactionPool.release(t);
@@ -407,6 +400,19 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
+ void removeImeSurface() {
+ final IInputMethodManager imms = getImms();
+ if (imms != null) {
+ try {
+ // Remove the IME surface to make the insets invisible for
+ // non-client controlled insets.
+ imms.removeImeSurface();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to remove IME surface.", e);
+ }
+ }
+ }
+
/**
* Allows other things to synchronize with the ime position
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 00d333fb593b..c591c1bd42bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -16,13 +16,13 @@
package com.android.systemui.doze;
-import android.hardware.display.AmbientDisplayConfiguration;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.hardware.display.AmbientDisplayConfiguration;
+
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.sensors.FakeSensorManager;
@@ -37,7 +37,6 @@ public class DozeConfigurationUtil {
when(params.getPulseOnSigMotion()).thenReturn(false);
when(params.getPickupVibrationThreshold()).thenReturn(0);
when(params.getProxCheckBeforePulse()).thenReturn(true);
- when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
when(params.getDisplayNeedsBlanking()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index dc027997578f..5c2b153bf452 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -57,7 +57,8 @@ public class DozeDockHandlerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mConfig = DozeConfigurationUtil.createMockConfig();
mDockManagerFake = spy(new DockManagerFake());
- mDockHandler = new DozeDockHandler(mConfig, mMachine, mDockManagerFake);
+ mDockHandler = new DozeDockHandler(mConfig, mDockManagerFake);
+ mDockHandler.setDozeMachine(mMachine);
when(mMachine.getState()).thenReturn(State.DOZE_AOD);
doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
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 1f07f46bf764..8078b6c8bda4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -88,8 +88,7 @@ public class DozeMachineTest extends SysuiTestCase {
mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager,
- mHost);
- mMachine.setParts(new DozeMachine.Part[]{mPartMock});
+ mHost, new DozeMachine.Part[]{mPartMock});
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 3ef60274cd76..3e60e016a0a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -40,14 +40,17 @@ import android.content.Intent;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
import android.view.Display;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeSensorManager;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -55,22 +58,24 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidJUnit4.class)
@SmallTest
+@RunWith(AndroidTestingRunner.class)
public class DozeScreenBrightnessTest extends SysuiTestCase {
- static final int DEFAULT_BRIGHTNESS = 10;
- static final int[] SENSOR_TO_BRIGHTNESS = new int[]{-1, 1, 2, 3, 4};
- static final int[] SENSOR_TO_OPACITY = new int[]{-1, 10, 0, 0, 0};
+ private static final int DEFAULT_BRIGHTNESS = 10;
+ private static final int[] SENSOR_TO_BRIGHTNESS = new int[]{-1, 1, 2, 3, 4};
+ private static final int[] SENSOR_TO_OPACITY = new int[]{-1, 10, 0, 0, 0};
- DozeServiceFake mServiceFake;
- FakeSensorManager.FakeGenericSensor mSensor;
- FakeSensorManager mSensorManager;
+ private DozeServiceFake mServiceFake;
+ private FakeSensorManager.FakeGenericSensor mSensor;
+ private AsyncSensorManager mSensorManager;
+ private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
@Mock
DozeHost mDozeHost;
- @Mock
- BroadcastDispatcher mBroadcastDispatcher;
- DozeScreenBrightness mScreen;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+ private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
+
+ private DozeScreenBrightness mScreen;
@Before
public void setUp() throws Exception {
@@ -83,12 +88,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
return null;
}).when(mDozeHost).prepareForGentleSleep(any());
mServiceFake = new DozeServiceFake();
- mSensorManager = new FakeSensorManager(mContext);
- mSensor = mSensorManager.getFakeLightSensor();
+ FakeSensorManager fakeSensorManager = new FakeSensorManager(mContext);
+ mSensorManager = new AsyncSensorManager(fakeSensorManager, mFakeThreadFactory, null);
+
+ mAlwaysOnDisplayPolicy = new AlwaysOnDisplayPolicy(mContext);
+ mAlwaysOnDisplayPolicy.defaultDozeBrightness = DEFAULT_BRIGHTNESS;
+ mAlwaysOnDisplayPolicy.screenBrightnessArray = SENSOR_TO_BRIGHTNESS;
+ mAlwaysOnDisplayPolicy.dimmingScrimArray = SENSOR_TO_OPACITY;
+ mSensor = fakeSensorManager.getFakeLightSensor();
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- mSensor.getSensor(), mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ mSensor.getSensor(), mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.onScreenState(Display.STATE_ON);
}
@@ -106,6 +116,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(3);
@@ -116,6 +127,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
public void testAod_usesDebugValue() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
Intent intent = new Intent(DozeScreenBrightness.ACTION_AOD_BRIGHTNESS);
intent.putExtra(DozeScreenBrightness.BRIGHTNESS_BUCKET, 1);
@@ -141,6 +154,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -153,9 +167,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ null /* sensor */, mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
reset(mDozeHost);
@@ -174,6 +187,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
mScreen.transitionTo(DOZE_PULSE_DONE, DOZE);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -183,9 +197,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ null /* sensor */, mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
@@ -198,6 +211,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.transitionTo(DOZE_AOD, FINISH);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -205,10 +219,11 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
- public void testNonPositiveBrightness_keepsPreviousBrightnessAndScrim() throws Exception {
+ public void testNonPositiveBrightness_keepsPreviousBrightnessAndScrim() {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
mSensor.sendSensorEvent(0);
@@ -222,6 +237,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
@@ -233,6 +249,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
reset(mDozeHost);
mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
verify(mDozeHost).setAodDimmingScrim(eq(0f));
}
@@ -242,6 +259,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING);
@@ -251,4 +269,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD);
verify(mDozeHost).setAodDimmingScrim(eq(0f));
}
+
+ private void waitForSensorManager() {
+ mFakeExecutor.runAllReady();
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index ebd2c3afe646..7ebead8a33fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -152,7 +152,7 @@ public class DozeSensorsTest extends SysuiTestCase {
private class TestableDozeSensors extends DozeSensors {
TestableDozeSensors() {
- super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
+ super(getContext(), mSensorManager, mDozeParameters,
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
mProximitySensor);
for (TriggerSensor sensor : mSensors) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index d259d3685ea6..d3af835873e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -97,9 +97,10 @@ public class DozeTriggersTest extends SysuiTestCase {
thresholdSensor.setLoaded(true);
mProximitySensor = new FakeProximitySensor(thresholdSensor, null, mExecutor);
- mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
- asyncSensorManager, wakeLock, true, mDockManager, mProximitySensor,
+ mTriggers = new DozeTriggers(mContext, mHost, mAlarmManager, config, parameters,
+ asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher);
+ mTriggers.setDozeMachine(mMachine);
waitForSensorManager();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index c5bddc1f096f..069699c271f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -81,8 +81,9 @@ public class DozeUiTest extends SysuiTestCase {
mWakeLock = new WakeLockFake();
mHandler = mHandlerThread.getThreadHandler();
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
+ mDozeUi.setDozeMachine(mMachine);
}
@After
@@ -136,8 +137,9 @@ public class DozeUiTest extends SysuiTestCase {
reset(mDozeParameters);
reset(mHost);
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
+ mDozeUi.setDozeMachine(mMachine);
// Never animate if display doesn't support it.
mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index dbc5596d9f4e..492b33e3c4a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.graphics.Color;
@@ -47,6 +48,7 @@ import java.util.Map;
public class MediaDataCombineLatestTest extends SysuiTestCase {
private static final String KEY = "TEST_KEY";
+ private static final String OLD_KEY = "TEST_KEY_OLD";
private static final String APP = "APP";
private static final String PACKAGE = "PKG";
private static final int BG_COLOR = Color.RED;
@@ -97,7 +99,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void eventNotEmittedWithoutMedia() {
// WHEN device source emits an event without media data
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN an event isn't emitted
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@@ -105,7 +107,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void emitEventAfterDeviceFirst() {
// GIVEN that a device event has already been received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN media event is received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the listener receives a combined event
@@ -119,7 +121,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that media event has already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// WHEN device event is received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
@@ -127,6 +129,64 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
}
@Test
+ public void migrateKeyMediaFirst() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ reset(mListener);
+ // WHEN a key migration event is received
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ // THEN the listener receives a combined event
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyDeviceFirst() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ reset(mListener);
+ // WHEN a key migration event is received
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ // THEN the listener receives a combined event
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyMediaAfter() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ reset(mListener);
+ // WHEN a second key migration event is received for media
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ // THEN the key has already been migrated
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyDeviceAfter() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ reset(mListener);
+ // WHEN a second key migration event is received for the device
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ // THEN the key has already be migrated
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
public void mediaDataRemoved() {
// WHEN media data is removed without first receiving device or data
mDataListener.onMediaDataRemoved(KEY);
@@ -143,7 +203,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void mediaDataRemovedAfterDeviceEvent() {
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
mDataListener.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY));
}
@@ -152,7 +212,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void mediaDataKeyUpdated() {
// GIVEN that device and media events have already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN the key is changed
mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData);
// THEN the listener gets a load event with the correct keys
@@ -163,7 +223,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void getDataIncludesDevice() {
// GIVEN that device and media events have been received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the result of getData includes device info
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index fc22eeb3ea68..3c6e19f0ec6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -166,7 +166,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the listener for the old key should removed.
verify(lmm).unregisterCallback(any())
// AND a new device event emitted
- val data = captureDeviceData(KEY)
+ val data = captureDeviceData(KEY, KEY_OLD)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME)
}
@@ -179,13 +179,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// WHEN the new key is the same as the old key
manager.onMediaDataLoaded(KEY, KEY, mediaData)
// THEN no event should be emitted
- verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
}
@Test
fun unknownOldKey() {
- manager.onMediaDataLoaded(KEY, "unknown", mediaData)
- verify(listener).onMediaDeviceChanged(eq(KEY), any())
+ val oldKey = "unknown"
+ manager.onMediaDataLoaded(KEY, oldKey, mediaData)
+ verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any())
}
@Test
@@ -223,7 +224,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
manager.removeListener(listener)
// THEN it doesn't receive device events
manager.onMediaDataLoaded(KEY, null, mediaData)
- verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
}
@Test
@@ -318,9 +319,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
return captor.getValue()
}
- fun captureDeviceData(key: String): MediaDeviceData {
+ fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
- verify(listener).onMediaDeviceChanged(eq(key), captor.capture())
+ verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
return captor.getValue()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
index 86f4414009b6..583d0692565f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
@@ -52,7 +52,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mOneHandedAnimationController = new OneHandedAnimationController(mContext,
+ mOneHandedAnimationController = new OneHandedAnimationController(
new OneHandedSurfaceTransactionHelper(mContext));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
index 7d4700f5f38a..b6b2217837b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
@@ -82,7 +82,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
final OneHandedSurfaceTransactionHelper transactionHelper =
new OneHandedSurfaceTransactionHelper(mContext);
final OneHandedAnimationController animationController = new OneHandedAnimationController(
- mContext, transactionHelper);
+ transactionHelper);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
mContext, mMockDisplayController, animationController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index dd747871b1a5..c5374b2eb049 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -87,6 +87,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -121,8 +122,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
- @Mock private ExpandableNotificationRowComponent.Builder
- mExpandableNotificationRowComponentBuilder;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private ExpandableNotificationRowComponent.Builder mExpandableNotificationRowComponentBuilder;
@Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
@Mock private FalsingManager mFalsingManager;
@Mock private KeyguardBypassController mKeyguardBypassController;
@@ -211,21 +212,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
when(mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(viewCaptor.capture()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .notificationEntry(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .onDismissRunnable(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .rowContentBindStage(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .onExpandClickListener(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
-
when(mExpandableNotificationRowComponentBuilder.build())
.thenReturn(mExpandableNotificationRowComponent);
+
when(mExpandableNotificationRowComponent.getExpandableNotificationRowController())
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 5ce209b1f249..4d6922c02c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -15,12 +15,13 @@
package com.android.systemui.statusbar.policy;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Intent;
import android.location.LocationManager;
import android.testing.AndroidTestingRunner;
@@ -31,12 +32,15 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -46,11 +50,15 @@ public class LocationControllerImplTest extends SysuiTestCase {
private LocationControllerImpl mLocationController;
private TestableLooper mTestableLooper;
+ @Mock private AppOpsController mAppOpsController;
+
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
+
mTestableLooper = TestableLooper.get(this);
mLocationController = spy(new LocationControllerImpl(mContext,
- mTestableLooper.getLooper(),
+ mAppOpsController,
mTestableLooper.getLooper(),
mock(BroadcastDispatcher.class),
mock(BootCompleteCache.class)));
@@ -67,12 +75,12 @@ public class LocationControllerImplTest extends SysuiTestCase {
mLocationController.addCallback(callback);
mLocationController.addCallback(mock(LocationChangeCallback.class));
- when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(false);
- mLocationController.onReceive(mContext, new Intent(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
- when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(true);
- mLocationController.onReceive(mContext, new Intent(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+ doReturn(false).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", false);
+ doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", true);
mTestableLooper.processAllMessages();
}
@@ -107,11 +115,22 @@ public class LocationControllerImplTest extends SysuiTestCase {
LocationChangeCallback callback = mock(LocationChangeCallback.class);
mLocationController.addCallback(callback);
+
+ mTestableLooper.processAllMessages();
+
mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
mTestableLooper.processAllMessages();
verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
+
+ doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", true);
+
+ mTestableLooper.processAllMessages();
+
+ verify(callback, times(1)).onLocationActiveChanged(anyBoolean());
}
@Test
@@ -124,6 +143,8 @@ public class LocationControllerImplTest extends SysuiTestCase {
verify(callback).onLocationSettingsChanged(anyBoolean());
mLocationController.removeCallback(callback);
+ mTestableLooper.processAllMessages();
+
mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
mTestableLooper.processAllMessages();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 18fb7a3144cf..84bd59b7730e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -43,8 +43,6 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
import static android.os.storage.StorageManager.PROP_FORCED_SCOPED_STORAGE_WHITELIST;
-import static android.os.storage.StorageManager.PROP_FUSE;
-import static android.os.storage.StorageManager.PROP_SETTINGS_FUSE;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -131,7 +129,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -233,13 +230,6 @@ class StorageManagerService extends IStorageManager.Stub
*/
private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
- /**
- * If {@code 1}, enables FuseDaemon to intercept file system ops. If {@code -1},
- * disables FuseDaemon. If {@code 0}, uses the default value from the build system.
- */
- private static final String FUSE_ENABLED = "fuse_enabled";
- private static final boolean DEFAULT_FUSE_ENABLED = true;
-
@GuardedBy("mLock")
private final Set<Integer> mFuseMountedUser = new ArraySet<>();
@@ -609,8 +599,6 @@ class StorageManagerService extends IStorageManager.Stub
// Not guarded by a lock.
private final StorageSessionController mStorageSessionController;
- private final boolean mIsFuseEnabled;
-
private final boolean mVoldAppDataIsolationEnabled;
@GuardedBy("mLock")
@@ -926,7 +914,6 @@ class StorageManagerService extends IStorageManager.Stub
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
mContext.getMainExecutor(), (properties) -> {
refreshIsolatedStorageSettings();
- refreshFuseSettings();
});
refreshIsolatedStorageSettings();
}
@@ -993,27 +980,6 @@ class StorageManagerService extends IStorageManager.Stub
}
/**
- * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
- * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
- * whenever the user reboots.
- */
- private void refreshFuseSettings() {
- int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- FUSE_ENABLED, 0);
- if (isFuseEnabled == 1) {
- Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
- SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
- } else if (isFuseEnabled == -1) {
- Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
- SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
- }
- // else, keep the build config.
- // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
- }
-
- /**
* MediaProvider has a ton of code that makes assumptions about storage
* paths never changing, so we outright kill them to pick up new state.
*/
@@ -1091,13 +1057,9 @@ class StorageManagerService extends IStorageManager.Stub
final UserManager userManager = mContext.getSystemService(UserManager.class);
final List<UserInfo> users = userManager.getUsers();
- if (mIsFuseEnabled) {
- mStorageSessionController.onReset(mVold, () -> {
- mHandler.removeCallbacksAndMessages(null);
- });
- } else {
- killMediaProvider(users);
- }
+ mStorageSessionController.onReset(mVold, () -> {
+ mHandler.removeCallbacksAndMessages(null);
+ });
final int[] systemUnlockedUsers;
synchronized (mLock) {
@@ -1490,8 +1452,7 @@ class StorageManagerService extends IStorageManager.Stub
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
- if (mIsFuseEnabled && vol.mountUserId >= 0
- && !amInternal.isUserRunning(vol.mountUserId, 0)) {
+ if (vol.mountUserId >= 0 && !amInternal.isUserRunning(vol.mountUserId, 0)) {
Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user "
+ Integer.toString(vol.mountUserId) + " is no longer running.");
return;
@@ -1803,11 +1764,7 @@ class StorageManagerService extends IStorageManager.Stub
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
- // If there is no value in the property yet (first boot after data wipe), this value may be
- // incorrect until #updateFusePropFromSettings where we set the correct value and reboot if
- // different
- mIsFuseEnabled = SystemProperties.getBoolean(PROP_FUSE, DEFAULT_FUSE_ENABLED);
- mVoldAppDataIsolationEnabled = mIsFuseEnabled && SystemProperties.getBoolean(
+ mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mContext = context;
mResolver = mContext.getContentResolver();
@@ -1821,7 +1778,7 @@ class StorageManagerService extends IStorageManager.Stub
// Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
- mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
+ mStorageSessionController = new StorageSessionController(mContext);
mInstaller = new Installer(mContext);
mInstaller.onStart();
@@ -1869,26 +1826,6 @@ class StorageManagerService extends IStorageManager.Stub
PackageManager.FEATURE_AUTOMOTIVE);
}
- /**
- * Checks if user changed the persistent settings_fuse flag from Settings UI
- * and updates PROP_FUSE (reboots if changed).
- */
- private void updateFusePropFromSettings() {
- boolean settingsFuseFlag = SystemProperties.getBoolean(PROP_SETTINGS_FUSE,
- DEFAULT_FUSE_ENABLED);
- Slog.d(TAG, "FUSE flags. Settings: " + settingsFuseFlag
- + ". Default: " + DEFAULT_FUSE_ENABLED);
-
- if (mIsFuseEnabled != settingsFuseFlag) {
- Slog.i(TAG, "Toggling persist.sys.fuse to " + settingsFuseFlag);
- // Set prop_fuse to match prop_settings_fuse because it is used by native daemons like
- // init, zygote, installd and vold
- SystemProperties.set(PROP_FUSE, Boolean.toString(settingsFuseFlag));
- // Then perform hard reboot to kick policy into place
- mContext.getSystemService(PowerManager.class).reboot("fuse_prop");
- }
- }
-
private void start() {
connectStoraged();
connectVold();
@@ -1987,15 +1924,6 @@ class StorageManagerService extends IStorageManager.Stub
if (provider != null) {
mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
-
- if (!mIsFuseEnabled) {
- try {
- mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null,
- mAppOpsCallback);
- mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
- } catch (RemoteException e) {
- }
- }
}
private ProviderInfo getProviderInfo(String authority) {
@@ -2071,7 +1999,6 @@ class StorageManagerService extends IStorageManager.Stub
private void bootCompleted() {
mBootCompleted = true;
mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
- updateFusePropFromSettings();
}
private void handleBootCompleted() {
@@ -4269,14 +4196,14 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (mIsFuseEnabled && mStorageManagerInternal.isExternalStorageService(uid)) {
+ if (mStorageManagerInternal.isExternalStorageService(uid)) {
// Determine if caller requires pass_through mount; note that we do this for
// all processes that share a UID with MediaProvider; but this is fine, since
// those processes anyway share the same rights as MediaProvider.
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
- if (mIsFuseEnabled && (mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
+ if ((mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
|| mExternalStorageAuthorityAppId == UserHandle.getAppId(uid))) {
// DownloadManager can write in app-private directories on behalf of apps;
// give it write access to Android/
@@ -4286,7 +4213,7 @@ class StorageManagerService extends IStorageManager.Stub
final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
PERMISSION_GRANTED;
- if (mIsFuseEnabled && hasMtp) {
+ if (hasMtp) {
ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
0, UserHandle.getUserId(uid));
if (ai != null && ai.isSignedWithPlatformKey()) {
@@ -4749,27 +4676,25 @@ class StorageManagerService extends IStorageManager.Stub
public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode) {
final long token = Binder.clearCallingIdentity();
try {
- if (mIsFuseEnabled) {
- // When using FUSE, we may need to kill the app if the op changes
- switch(code) {
- case OP_REQUEST_INSTALL_PACKAGES:
- // Always kill regardless of op change, to remount apps /storage
+ // When using FUSE, we may need to kill the app if the op changes
+ switch(code) {
+ case OP_REQUEST_INSTALL_PACKAGES:
+ // Always kill regardless of op change, to remount apps /storage
+ killAppForOpChange(code, uid);
+ return;
+ case OP_MANAGE_EXTERNAL_STORAGE:
+ if (mode != MODE_ALLOWED) {
+ // Only kill if op is denied, to lose external_storage gid
+ // Killing when op is granted to pickup the gid automatically,
+ // results in a bad UX, especially since the gid only gives access
+ // to unreliable volumes, USB OTGs that are rarely mounted. The app
+ // will get the external_storage gid on next organic restart.
killAppForOpChange(code, uid);
- return;
- case OP_MANAGE_EXTERNAL_STORAGE:
- if (mode != MODE_ALLOWED) {
- // Only kill if op is denied, to lose external_storage gid
- // Killing when op is granted to pickup the gid automatically,
- // results in a bad UX, especially since the gid only gives access
- // to unreliable volumes, USB OTGs that are rarely mounted. The app
- // will get the external_storage gid on next organic restart.
- killAppForOpChange(code, uid);
- }
- return;
- case OP_LEGACY_STORAGE:
- updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
- return;
- }
+ }
+ return;
+ case OP_LEGACY_STORAGE:
+ updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
+ return;
}
if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 4ff9eb11c142..72f29b431880 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -43,6 +43,7 @@ import android.os.IBinder;
import android.os.IExternalVibratorService;
import android.os.IVibratorService;
import android.os.IVibratorStateListener;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
@@ -70,6 +71,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -134,7 +136,7 @@ public class VibratorService extends IVibratorService.Stub
private final SparseArray<VibrationEffect> mFallbackEffects;
private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
private final WorkSource mTmpWorkSource = new WorkSource();
- private final Handler mH = new Handler();
+ private final Handler mH;
private final Object mLock = new Object();
private final Context mContext;
@@ -147,6 +149,7 @@ public class VibratorService extends IVibratorService.Stub
private Vibrator mVibrator;
private SettingsObserver mSettingObserver;
+ private final NativeWrapper mNativeWrapper;
private volatile VibrateThread mThread;
// mInputDeviceVibrators lock should be acquired after mLock, if both are
@@ -208,7 +211,12 @@ public class VibratorService extends IVibratorService.Stub
}
};
- private class Vibration implements IBinder.DeathRecipient {
+ /**
+ * Holder for a vibration to be played. This class can be shared with native methods for
+ * hardware callback support.
+ */
+ @VisibleForTesting
+ public final class Vibration implements IBinder.DeathRecipient {
public final IBinder token;
// Start time in CLOCK_BOOTTIME base.
public final long startTime;
@@ -248,9 +256,9 @@ public class VibratorService extends IVibratorService.Stub
}
}
- // Called by native
- @SuppressWarnings("unused")
- private void onComplete() {
+ /** Callback for when vibration is complete, to be called by native. */
+ @VisibleForTesting
+ public void onComplete() {
synchronized (mLock) {
if (this == mCurrentVibration) {
doCancelVibrateLocked();
@@ -354,15 +362,23 @@ public class VibratorService extends IVibratorService.Stub
}
VibratorService(Context context) {
- vibratorInit();
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ VibratorService(Context context, Injector injector) {
+ mNativeWrapper = injector.getNativeWrapper();
+ mH = injector.createHandler(Looper.myLooper());
+
+ mNativeWrapper.vibratorInit();
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
- vibratorOff();
+ mNativeWrapper.vibratorOff();
- mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
- mSupportsExternalControl = vibratorSupportsExternalControl();
- mSupportedEffects = asList(vibratorGetSupportedEffects());
- mCapabilities = vibratorGetCapabilities();
+ mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
+ mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
+ mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
+ mCapabilities = mNativeWrapper.vibratorGetCapabilities();
mContext = context;
PowerManager pm = context.getSystemService(PowerManager.class);
@@ -419,7 +435,7 @@ public class VibratorService extends IVibratorService.Stub
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
- ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
+ injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
}
private VibrationEffect createEffectFromResource(int resId) {
@@ -642,7 +658,7 @@ public class VibratorService extends IVibratorService.Stub
if (effect == null) {
synchronized (mLock) {
mAlwaysOnEffects.delete(alwaysOnId);
- vibratorAlwaysOnDisable(alwaysOnId);
+ mNativeWrapper.vibratorAlwaysOnDisable(alwaysOnId);
}
} else {
if (!verifyVibrationEffect(effect)) {
@@ -1198,11 +1214,11 @@ public class VibratorService extends IVibratorService.Stub
private void updateAlwaysOnLocked(int id, Vibration vib) {
final int intensity = getCurrentIntensityLocked(vib);
if (!shouldVibrate(vib, intensity)) {
- vibratorAlwaysOnDisable(id);
+ mNativeWrapper.vibratorAlwaysOnDisable(id);
} else {
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
final int strength = intensityToEffectStrength(intensity);
- vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
+ mNativeWrapper.vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
}
}
@@ -1238,7 +1254,7 @@ public class VibratorService extends IVibratorService.Stub
//synchronized (mInputDeviceVibrators) {
// return !mInputDeviceVibrators.isEmpty() || vibratorExists();
//}
- return vibratorExists();
+ return mNativeWrapper.vibratorExists();
}
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
@@ -1262,7 +1278,7 @@ public class VibratorService extends IVibratorService.Stub
// Note: ordering is important here! Many haptic drivers will reset their
// amplitude when enabled, so we always have to enable first, then set the
// amplitude.
- vibratorOn(millis);
+ mNativeWrapper.vibratorOn(millis);
doVibratorSetAmplitude(amplitude);
}
}
@@ -1273,7 +1289,7 @@ public class VibratorService extends IVibratorService.Stub
private void doVibratorSetAmplitude(int amplitude) {
if (mSupportsAmplitudeControl) {
- vibratorSetAmplitude(amplitude);
+ mNativeWrapper.vibratorSetAmplitude(amplitude);
}
}
@@ -1291,7 +1307,7 @@ public class VibratorService extends IVibratorService.Stub
mInputDeviceVibrators.get(i).cancel();
}
} else {
- vibratorOff();
+ mNativeWrapper.vibratorOff();
}
}
} finally {
@@ -1310,7 +1326,7 @@ public class VibratorService extends IVibratorService.Stub
}
// Input devices don't support prebaked effect, so skip trying it with them.
if (!usingInputDeviceVibrators) {
- long duration = vibratorPerformEffect(prebaked.getId(),
+ long duration = mNativeWrapper.vibratorPerformEffect(prebaked.getId(),
prebaked.getEffectStrength(), vib,
hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
long timeout = duration;
@@ -1363,7 +1379,7 @@ public class VibratorService extends IVibratorService.Stub
PrimitiveEffect[] primitiveEffects =
composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
- vibratorPerformComposedEffect(primitiveEffects, vib);
+ mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
// Composed effects don't actually give us an estimated duration, so we just guess here.
noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
@@ -1454,7 +1470,7 @@ public class VibratorService extends IVibratorService.Stub
}
}
mVibratorUnderExternalControl = externalControl;
- vibratorSetExternalControl(externalControl);
+ mNativeWrapper.vibratorSetExternalControl(externalControl);
}
private void dumpInternal(PrintWriter pw) {
@@ -1688,6 +1704,100 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ /** Wrapper around the static-native methods of {@link VibratorService} for tests. */
+ @VisibleForTesting
+ public static class NativeWrapper {
+
+ /** Checks if vibrator exists on device. */
+ public boolean vibratorExists() {
+ return VibratorService.vibratorExists();
+ }
+
+ /** Initializes connection to vibrator HAL service. */
+ public void vibratorInit() {
+ VibratorService.vibratorInit();
+ }
+
+ /** Turns vibrator on for given time. */
+ public void vibratorOn(long milliseconds) {
+ VibratorService.vibratorOn(milliseconds);
+ }
+
+ /** Turns vibrator off. */
+ public void vibratorOff() {
+ VibratorService.vibratorOff();
+ }
+
+ /** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
+ public boolean vibratorSupportsAmplitudeControl() {
+ return VibratorService.vibratorSupportsAmplitudeControl();
+ }
+
+ /** Sets the amplitude for the vibrator to run. */
+ public void vibratorSetAmplitude(int amplitude) {
+ VibratorService.vibratorSetAmplitude(amplitude);
+ }
+
+ /** Returns all predefined effects supported by the device vibrator. */
+ public int[] vibratorGetSupportedEffects() {
+ return VibratorService.vibratorGetSupportedEffects();
+ }
+
+ /** Turns vibrator on to perform one of the supported effects. */
+ public long vibratorPerformEffect(long effect, long strength, Vibration vibration,
+ boolean withCallback) {
+ return VibratorService.vibratorPerformEffect(effect, strength, vibration, withCallback);
+ }
+
+ /** Turns vibrator on to perform one of the supported composed effects. */
+ public void vibratorPerformComposedEffect(
+ VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
+ VibratorService.vibratorPerformComposedEffect(effect, vibration);
+ }
+
+ /** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
+ public boolean vibratorSupportsExternalControl() {
+ return VibratorService.vibratorSupportsExternalControl();
+ }
+
+ /** Enabled the device vibrator to be controlled by another service. */
+ public void vibratorSetExternalControl(boolean enabled) {
+ VibratorService.vibratorSetExternalControl(enabled);
+ }
+
+ /** Returns all capabilities of the device vibrator. */
+ public long vibratorGetCapabilities() {
+ return VibratorService.vibratorGetCapabilities();
+ }
+
+ /** Enable always-on vibration with given id and effect. */
+ public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
+ VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
+ }
+
+ /** Disable always-on vibration for given id. */
+ public void vibratorAlwaysOnDisable(long id) {
+ VibratorService.vibratorAlwaysOnDisable(id);
+ }
+ }
+
+ /** Point of injection for test dependencies */
+ @VisibleForTesting
+ static class Injector {
+
+ NativeWrapper getNativeWrapper() {
+ return new NativeWrapper();
+ }
+
+ Handler createHandler(Looper looper) {
+ return new Handler(looper);
+ }
+
+ void addService(String name, IBinder service) {
+ ServiceManager.addService(name, service);
+ }
+ }
+
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ce66b2cbf114..25e6eb6e943f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -232,7 +232,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
-import android.location.LocationManager;
import android.media.audiofx.AudioEffect;
import android.net.Proxy;
import android.net.Uri;
@@ -15863,7 +15862,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|| Intent.ACTION_FACTORY_RESET.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
- || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
|| TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
|| SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
|| AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5124c4a4797e..a2eea1348d5c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -470,22 +470,23 @@ public final class BroadcastQueue {
// if this receiver was slow, impose deferral policy on the app. This will kick in
// when processNextBroadcastLocked() next finds this uid as a receiver identity.
if (!r.timeoutExempt) {
- if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+ // r.curApp can be null if finish has raced with process death - benign
+ // edge case, and we just ignore it because we're already cleaning up
+ // as expected.
+ if (r.curApp != null
+ && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
// Core system packages are exempt from deferral policy
if (!UserHandle.isCore(r.curApp.uid)) {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
+ " was slow: " + receiver + " br=" + r);
}
- if (r.curApp != null) {
- mDispatcher.startDeferring(r.curApp.uid);
- } else {
- Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
- }
+ mDispatcher.startDeferring(r.curApp.uid);
} else {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
- + " receiver was slow but not deferring: " + receiver + " br=" + r);
+ + " receiver was slow but not deferring: "
+ + receiver + " br=" + r);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5a0ea7586301..ebff0691c1f7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -110,7 +110,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.RuntimeInit;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -155,9 +154,6 @@ public final class ProcessList {
static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
- // A system property to control if fuse is enabled.
- static final String ANDROID_FUSE_ENABLED = "persist.sys.fuse";
-
// The minimum time we allow between crashes, for us to consider this
// application to be bad and stop and its services and reject broadcasts.
static final int MIN_CRASH_INTERVAL = 60 * 1000;
@@ -719,13 +715,8 @@ public final class ProcessList {
// want some apps enabled while some apps disabled
mAppDataIsolationEnabled =
SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
- boolean fuseEnabled = SystemProperties.getBoolean(ANDROID_FUSE_ENABLED, false);
- boolean voldAppDataIsolationEnabled = SystemProperties.getBoolean(
+ mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
- if (!fuseEnabled && voldAppDataIsolationEnabled) {
- Slog.e(TAG, "Fuse is not enabled while vold app data isolation is enabled");
- }
- mVoldAppDataIsolationEnabled = fuseEnabled && voldAppDataIsolationEnabled;
mAppDataIsolationWhitelistedApps = new ArrayList<>(
SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4fd9ae256592..c8e4ee02e603 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1320,6 +1320,11 @@ public class AudioService extends IAudioService.Stub
device, caller, true /*hasModifyAudioSettings*/);
}
mStreamStates[streamType].checkFixedVolumeDevices();
+
+ // Unmute streams if device is full volume
+ if (mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
+ }
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 70f0399d1070..05cf40a091b6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -120,6 +120,11 @@ public abstract class InputMethodManagerInternal {
public abstract void reportImeControl(@Nullable IBinder windowToken);
/**
+ * Destroys the IME surface.
+ */
+ public abstract void removeImeSurface();
+
+ /**
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
*/
private static final InputMethodManagerInternal NOP =
@@ -166,6 +171,10 @@ public abstract class InputMethodManagerInternal {
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c027ebcfd568..d8ee32e7bd74 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -211,6 +211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_INITIALIZE_IME = 1040;
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_REMOVE_IME_SURFACE = 1060;
+ static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
static final int MSG_START_INPUT = 2000;
@@ -4005,6 +4006,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
}
+ @Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ // No permission check, because we'll only execute the request if the calling window is
+ // also the current IME client.
+ mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
+ }
+
@BinderThread
private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
@@ -4278,11 +4286,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return true;
}
case MSG_REMOVE_IME_SURFACE: {
- try {
- if (mEnabledSession != null && mEnabledSession.session != null) {
- mEnabledSession.session.removeImeSurface();
+ synchronized (mMethodMap) {
+ try {
+ if (mEnabledSession != null && mEnabledSession.session != null
+ && !mShowRequested) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ return true;
+ }
+ case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
+ IBinder windowToken = (IBinder) msg.obj;
+ synchronized (mMethodMap) {
+ try {
+ if (windowToken == mCurFocusedWindow
+ && mEnabledSession != null && mEnabledSession.session != null) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
return true;
}
@@ -5116,6 +5140,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void reportImeControl(@Nullable IBinder windowToken) {
mService.reportImeControl(windowToken);
}
+
+ @Override
+ public void removeImeSurface() {
+ mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
+ }
}
@BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 23392db0690d..2516e289f099 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -226,6 +226,11 @@ public final class MultiClientInputMethodManagerService {
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ reportNotSupported();
+ }
});
}
@@ -1482,6 +1487,12 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ reportNotSupported();
+ }
+
+ @BinderThread
+ @Override
public boolean showSoftInput(
IInputMethodClient client, IBinder token, int flags,
ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 5c1d1826b88a..f69c8239762d 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -25,7 +25,6 @@ import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
-import static android.location.LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION;
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.MODE_CHANGED_ACTION;
@@ -1222,21 +1221,10 @@ public class LocationManagerService extends ILocationManager.Stub {
false);
// Now update monitoring of high power requests only.
- boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
mOpHighPowerMonitoring = updateMonitoring(
requestingHighPowerLocation,
mOpHighPowerMonitoring,
true);
- if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
- long identity = Binder.clearCallingIdentity();
- try {
- // Send an intent to notify that a high power request has been added/removed.
- Intent intent = new Intent(HIGH_POWER_REQUEST_CHANGE_ACTION);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
}
private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
diff --git a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
index 70d83a9dd7dd..631dbbf0f1fd 100644
--- a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
@@ -27,7 +27,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -582,17 +581,9 @@ class GnssVisibilityControl {
mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, uid, proxyAppPkgName);
mAppOps.finishOp(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, uid, proxyAppPkgName);
}
- sendHighPowerMonitoringBroadcast();
return true;
}
- private void sendHighPowerMonitoringBroadcast() {
- // Send an intent to notify that a high power request has been added/removed so that
- // the SystemUi checks the state of AppOps and updates the location icon accordingly.
- Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
-
private void handleEmergencyNfwNotification(NfwNotification nfwNotification) {
boolean isPermissionMismatched = false;
if (!nfwNotification.isRequestAccepted()) {
diff --git a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
index 78af79b533d8..a95383695ae8 100644
--- a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
@@ -16,12 +16,8 @@
package com.android.server.location.util;
-import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
-
import android.app.AppOpsManager;
import android.content.Context;
-import android.content.Intent;
-import android.location.LocationManager;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
@@ -66,22 +62,13 @@ public class SystemAppOpsHelper extends AppOpsHelper {
long identity = Binder.clearCallingIdentity();
try {
- boolean allowed = mAppOps.startOpNoThrow(
+ return mAppOps.startOpNoThrow(
appOp,
callerIdentity.getUid(),
callerIdentity.getPackageName(),
false,
callerIdentity.getAttributionTag(),
callerIdentity.getListenerId()) == AppOpsManager.MODE_ALLOWED;
-
- if (allowed && appOp == OP_MONITOR_HIGH_POWER_LOCATION) {
- // notify of possible location icon change
- mContext.sendBroadcast(
- new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION).addFlags(
- Intent.FLAG_RECEIVER_FOREGROUND));
- }
-
- return allowed;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -98,13 +85,6 @@ public class SystemAppOpsHelper extends AppOpsHelper {
callerIdentity.getUid(),
callerIdentity.getPackageName(),
callerIdentity.getAttributionTag());
-
- if (appOp == OP_MONITOR_HIGH_POWER_LOCATION) {
- // notify of possible location icon change
- mContext.sendBroadcast(
- new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION).addFlags(
- Intent.FLAG_RECEIVER_FOREGROUND));
- }
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 951f462ed201..592db83b8721 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -77,6 +77,8 @@ public abstract class ApexManager {
public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
+ private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
+
private static final Singleton<ApexManager> sApexManagerSingleton =
new Singleton<ApexManager>() {
@Override
@@ -342,8 +344,17 @@ public abstract class ApexManager {
public abstract boolean destroyDeSnapshots(int rollbackId);
/**
+ * Deletes snapshots of the credential encrypted apex data directories for the specified user,
+ * for the given rollback id as long as the user is credential unlocked.
+ *
+ * @return boolean true if the delete was successful
+ */
+ public abstract boolean destroyCeSnapshots(int userId, int rollbackId);
+
+ /**
* Deletes snapshots of the credential encrypted apex data directories for the specified user,
- * where the rollback id is not included in {@code retainRollbackIds}.
+ * where the rollback id is not included in {@code retainRollbackIds} as long as the user is
+ * credential unlocked.
*
* @return boolean true if the delete was successful
*/
@@ -526,7 +537,9 @@ public abstract class ApexManager {
activePackagesSet.add(packageInfo.packageName);
}
if (ai.isFactory) {
- if (factoryPackagesSet.contains(packageInfo.packageName)) {
+ // Don't throw when the duplicating APEX is VNDK APEX
+ if (factoryPackagesSet.contains(packageInfo.packageName)
+ && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
throw new IllegalStateException(
"Two factory packages have the same name: "
+ packageInfo.packageName);
@@ -875,6 +888,17 @@ public abstract class ApexManager {
}
@Override
+ public boolean destroyCeSnapshots(int userId, int rollbackId) {
+ try {
+ waitForApexService().destroyCeSnapshots(userId, rollbackId);
+ return true;
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
+ }
+ }
+
+ @Override
public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
try {
waitForApexService().destroyCeSnapshotsNotSpecified(userId, retainRollbackIds);
@@ -1136,6 +1160,11 @@ public abstract class ApexManager {
}
@Override
+ public boolean destroyCeSnapshots(int userId, int rollbackId) {
+ return true;
+ }
+
+ @Override
public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
return true;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ddc5e14bfeb3..312dcddd577d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -84,6 +84,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -201,6 +203,27 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
};
+ private static final class Lifecycle extends SystemService {
+ private final PackageInstallerService mPackageInstallerService;
+
+ Lifecycle(Context context, PackageInstallerService service) {
+ super(context);
+ mPackageInstallerService = service;
+ }
+
+ @Override
+ public void onStart() {
+ // no-op
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mPackageInstallerService.onBroadcastReady();
+ }
+ }
+ }
+
public PackageInstallerService(Context context, PackageManagerService pm,
Supplier<PackageParser2> apexParserSupplier) {
mContext = context;
@@ -222,6 +245,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mApexManager = ApexManager.getInstance();
mStagingManager = new StagingManager(this, context, apexParserSupplier);
+
+ LocalServices.getService(SystemServiceManager.class).startService(
+ new Lifecycle(context, this));
}
boolean okToSendBroadcasts() {
@@ -259,6 +285,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ private void onBroadcastReady() {
+ // Broadcasts are not sent while we restore sessions on boot, since no processes would be
+ // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will
+ // be rejected by ActivityManagerService if its systemReady() is not completed.
+ mOkToSendBroadcasts = true;
+ }
+
void restoreAndApplyStagedSessionIfNeeded() {
List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
synchronized (mSessions) {
@@ -281,16 +314,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
mStagingManager.restoreSession(session, isDeviceUpgrading);
}
- // Broadcasts are not sent while we restore sessions on boot, since no processes would be
- // ready to listen to them. From now on, we greedily assume that broadcasts requests are
- // safe to send out. The worst that can happen is that a broadcast is attempted before
- // ActivityManagerService completes its own systemReady(), in which case it will be rejected
- // with an otherwise harmless exception.
- // A more appropriate way to do this would be to wait until the correct boot phase is
- // reached, but since we are not a SystemService we can't override onBootPhase.
- // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
- // way either.
- mOkToSendBroadcasts = true;
}
@GuardedBy("mSessions")
@@ -592,12 +615,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
- if (mBypassNextStagedInstallerCheck) {
- mBypassNextStagedInstallerCheck = false;
- } else if (params.isStaged
- && !isCalledBySystemOrShell(callingUid)
- && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) {
- throw new SecurityException("Installer not allowed to commit staged install");
+ if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
+ if (mBypassNextStagedInstallerCheck) {
+ mBypassNextStagedInstallerCheck = false;
+ } else if (!isStagedInstallerAllowed(requestedInstallerPackageName)) {
+ throw new SecurityException("Installer not allowed to commit staged install");
+ }
}
if (!params.isMultiPackage) {
@@ -729,7 +752,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
|| callingUid == Process.SHELL_UID;
}
- private boolean isWhitelistedStagedInstaller(String installerName) {
+ private boolean isStagedInstallerAllowed(String installerName) {
return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
}
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 88938b204f6c..c8e36481c738 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -206,6 +206,16 @@ public class AppDataRollbackHelper {
}
/**
+ * Deletes snapshots of the credential encrypted apex data directories for the specified user,
+ * for the given rollback id. This method will be a no-op if the user is not unlocked.
+ */
+ public void destroyApexCeSnapshots(int userId, int rollbackId) {
+ if (!isUserCredentialLocked(userId)) {
+ mApexManager.destroyCeSnapshots(userId, rollbackId);
+ }
+ }
+
+ /**
* Commits the pending backups and restores for a given {@code userId} and {@code rollback}. If
* the rollback has a pending backup, it is updated with a mapping from {@code userId} to inode
* of the CE user data snapshot.
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index c3477804fb64..2db6043f1c0a 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -42,6 +42,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.ext.SdkExtensions;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -61,9 +62,9 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Consumer;
-
/**
* Information about a rollback available for a set of atomically installed packages.
*
@@ -699,11 +700,13 @@ class Rollback {
void delete(AppDataRollbackHelper dataHelper) {
assertInWorkerThread();
boolean containsApex = false;
+ Set<Integer> apexUsers = new ArraySet<>();
for (PackageRollbackInfo pkgInfo : info.getPackages()) {
+ List<Integer> snapshottedUsers = pkgInfo.getSnapshottedUsers();
if (pkgInfo.isApex()) {
containsApex = true;
+ apexUsers.addAll(snapshottedUsers);
} else {
- List<Integer> snapshottedUsers = pkgInfo.getSnapshottedUsers();
for (int i = 0; i < snapshottedUsers.size(); i++) {
// Destroy app data snapshot.
int userId = snapshottedUsers.get(i);
@@ -714,6 +717,9 @@ class Rollback {
}
if (containsApex) {
dataHelper.destroyApexDeSnapshots(info.getRollbackId());
+ for (int user : apexUsers) {
+ dataHelper.destroyApexCeSnapshots(user, info.getRollbackId());
+ }
}
RollbackStore.deleteRollback(this);
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 37df5481d3c4..6dc1d6921dbb 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -53,16 +53,14 @@ public final class StorageSessionController {
private final Context mContext;
@GuardedBy("mLock")
private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
- private final boolean mIsFuseEnabled;
private volatile ComponentName mExternalStorageServiceComponent;
private volatile String mExternalStorageServicePackageName;
private volatile int mExternalStorageServiceAppId;
private volatile boolean mIsResetting;
- public StorageSessionController(Context context, boolean isFuseEnabled) {
+ public StorageSessionController(Context context) {
mContext = Objects.requireNonNull(context);
- mIsFuseEnabled = isFuseEnabled;
}
/**
@@ -361,6 +359,6 @@ public final class StorageSessionController {
}
private boolean shouldHandle(@Nullable VolumeInfo vol) {
- return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+ return !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
}
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 5f6323369d0a..f5eed30a19bf 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -114,7 +114,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
private static final boolean DEBUG = false;
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
- private static final int MAX_PERSISTED_URI_GRANTS = 128;
+ private static final int MAX_PERSISTED_URI_GRANTS = 512;
private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 57e696320ec8..4e1d789bebd8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4006,8 +4006,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
ActivityRecord record = ActivityRecord.isInStackLocked(token);
if (record == null) {
- throw new IllegalArgumentException("reportSizeConfigurations: ActivityRecord not "
- + "found for: " + token);
+ return;
}
record.setSizeConfigurations(horizontalSizeConfiguration,
verticalSizeConfigurations, smallestSizeConfigurations);
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index e692ba6905b7..465d089e7904 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -23,20 +23,24 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiFunction;
/**
* A builder for instantiating a complex {@link DisplayAreaPolicy}
@@ -70,22 +74,93 @@ import java.util.Objects;
*/
class DisplayAreaPolicyBuilder {
@Nullable private HierarchyBuilder mRootHierarchyBuilder;
+ private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
- /** Defines the root hierarchy. */
+ /**
+ * When a window is created, the policy will use this function to select the
+ * {@link RootDisplayArea} to place that window in. The selected root can be either the one of
+ * the {@link #mRootHierarchyBuilder} or the one of any of the
+ * {@link #mDisplayAreaGroupHierarchyBuilders}.
+ **/
+ @Nullable private BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+
+ /** Defines the root hierarchy for the whole logical display. */
DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
- // TODO(b/157683117): Add method to add sub root and root choosing func.
mRootHierarchyBuilder = rootHierarchyBuilder;
return this;
}
+ /**
+ * Defines a DisplayAreaGroup hierarchy. Its root will be added as a child of the root
+ * hierarchy.
+ */
+ DisplayAreaPolicyBuilder addDisplayAreaGroupHierarchy(
+ HierarchyBuilder displayAreaGroupHierarchy) {
+ mDisplayAreaGroupHierarchyBuilders.add(displayAreaGroupHierarchy);
+ return this;
+ }
+
+ /** The policy will use this function to find the root to place windows in. */
+ DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
+ BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc) {
+ mSelectRootForWindowFunc = selectRootForWindowFunc;
+ return this;
+ }
+
+ /** Makes sure the setting meets the requirement. */
+ private void validate() {
+ if (mRootHierarchyBuilder == null) {
+ throw new IllegalStateException("Root must be set for the display area policy.");
+ }
+
+ boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
+ boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
+ for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
+ HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+ if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
+ throw new IllegalStateException(
+ "DisplayAreaGroup must contain at least one TaskDisplayArea.");
+ }
+
+ containsImeContainer = containsImeContainer || hierarchyBuilder.mImeContainer != null;
+ containsDefaultTda = containsDefaultTda
+ || containsDefaultTaskDisplayArea(hierarchyBuilder);
+ }
+
+ if (!containsImeContainer) {
+ throw new IllegalStateException("IME container must be set.");
+ }
+
+ if (!containsDefaultTda) {
+ throw new IllegalStateException("There must be a default TaskDisplayArea.");
+ }
+ }
+
+ /** Checks if the given hierarchy contains the default {@link TaskDisplayArea}. */
+ private static boolean containsDefaultTaskDisplayArea(HierarchyBuilder displayAreaHierarchy) {
+ for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
+ if (displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId
+ == FEATURE_DEFAULT_TASK_CONTAINER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
Result build(WindowManagerService wmService) {
- Objects.requireNonNull(mRootHierarchyBuilder,
- "Root must be set for the display area policy.");
- Objects.requireNonNull(mRootHierarchyBuilder.mImeContainer, "Ime must not be null");
- Preconditions.checkCollectionNotEmpty(mRootHierarchyBuilder.mTaskDisplayAreas,
- "TaskDisplayAreas must not be empty");
- mRootHierarchyBuilder.build();
- return new Result(wmService, mRootHierarchyBuilder.mRoot);
+ validate();
+
+ // Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
+ mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
+ List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
+ mDisplayAreaGroupHierarchyBuilders.size());
+ for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
+ HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+ hierarchyBuilder.build();
+ displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
+ }
+ return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
+ mSelectRootForWindowFunc);
}
/**
@@ -131,6 +206,14 @@ class DisplayAreaPolicyBuilder {
/** Builds the {@link DisplayArea} hierarchy below root. */
private void build() {
+ build(null /* displayAreaGroupHierarchyBuilders */);
+ }
+
+ /**
+ * Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
+ * {@link HierarchyBuilder} as children.
+ */
+ private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
final int maxWindowLayerCount = policy.getMaxWindowLayer();
final DisplayArea.Tokens[] displayAreaForLayer =
@@ -215,7 +298,9 @@ class DisplayAreaPolicyBuilder {
if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
// We use the passed in TaskDisplayAreas for task container type of layer.
// Skip creating Tokens even if there is no TDA.
- addTaskDisplayAreasToLayer(areaForLayer[layer]);
+ addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
+ addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
+ displayAreaGroupHierarchyBuilders);
leafArea.mSkipTokens = true;
} else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
// We use the passed in ImeContainer for ime container type of layer.
@@ -234,11 +319,11 @@ class DisplayAreaPolicyBuilder {
// Notify the root that we have finished attaching all the DisplayAreas. Cache all the
// feature related collections there for fast access.
- mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas, mTaskDisplayAreas);
+ mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
}
- /** Adds all {@link TaskDisplayArea} to the specified layer */
- private void addTaskDisplayAreasToLayer(PendingArea parentPendingArea) {
+ /** Adds all {@link TaskDisplayArea} to the application layer. */
+ private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
final int count = mTaskDisplayAreas.size();
for (int i = 0; i < count; i++) {
PendingArea leafArea =
@@ -249,6 +334,24 @@ class DisplayAreaPolicyBuilder {
}
}
+ /** Adds roots of the DisplayAreaGroups to the application layer. */
+ private void addDisplayAreaGroupsToApplicationLayer(
+ DisplayAreaPolicyBuilder.PendingArea parentPendingArea,
+ @Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
+ if (displayAreaGroupHierarchyBuilders == null) {
+ return;
+ }
+ final int count = displayAreaGroupHierarchyBuilders.size();
+ for (int i = 0; i < count; i++) {
+ DisplayAreaPolicyBuilder.PendingArea
+ leafArea = new DisplayAreaPolicyBuilder.PendingArea(
+ null /* feature */, APPLICATION_LAYER, parentPendingArea);
+ leafArea.mExisting = displayAreaGroupHierarchyBuilders.get(i).mRoot;
+ leafArea.mMaxLayer = APPLICATION_LAYER;
+ parentPendingArea.mChildren.add(leafArea);
+ }
+ }
+
private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
if (layer == APPLICATION_LAYER) {
return LEAF_TYPE_TASK_CONTAINERS;
@@ -401,9 +504,20 @@ class DisplayAreaPolicyBuilder {
}
static class Result extends DisplayAreaPolicy {
+ final List<RootDisplayArea> mDisplayAreaGroupRoots;
+ final BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
- Result(WindowManagerService wmService, RootDisplayArea root) {
+ Result(WindowManagerService wmService, RootDisplayArea root,
+ List<RootDisplayArea> displayAreaGroupRoots,
+ @Nullable BiFunction<WindowToken, Bundle, RootDisplayArea>
+ selectRootForWindowFunc) {
super(wmService, root);
+ mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
+ mSelectRootForWindowFunc = selectRootForWindowFunc == null
+ // Always return the highest level root of the logical display when the func is
+ // not specified.
+ ? (window, options) -> mRoot
+ : selectRootForWindowFunc;
}
@Override
@@ -414,27 +528,38 @@ class DisplayAreaPolicyBuilder {
@VisibleForTesting
DisplayArea.Tokens findAreaForToken(WindowToken token) {
- // TODO(b/157683117): Choose root/sub root from OEM provided func.
- return mRoot.findAreaForToken(token);
+ return mSelectRootForWindowFunc.apply(token, token.mOptions).findAreaForToken(token);
}
@VisibleForTesting
List<Feature> getFeatures() {
- // TODO(b/157683117): Also get feature from sub root.
- return new ArrayList<>(mRoot.mFeatures);
+ Set<Feature> features = new ArraySet<>();
+ features.addAll(mRoot.mFeatures);
+ for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
+ features.addAll(mDisplayAreaGroupRoots.get(i).mFeatures);
+ }
+ return new ArrayList<>(features);
}
@Override
public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(int featureId) {
- // TODO(b/157683117): Also get display areas from sub root.
- List<Feature> features = getFeatures();
+ List<DisplayArea<? extends WindowContainer>> displayAreas = new ArrayList<>();
+ getDisplayAreas(mRoot, featureId, displayAreas);
+ for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
+ getDisplayAreas(mDisplayAreaGroupRoots.get(i), featureId, displayAreas);
+ }
+ return displayAreas;
+ }
+
+ private static void getDisplayAreas(RootDisplayArea root, int featureId,
+ List<DisplayArea<? extends WindowContainer>> displayAreas) {
+ List<Feature> features = root.mFeatures;
for (int i = 0; i < features.size(); i++) {
Feature feature = features.get(i);
if (feature.mId == featureId) {
- return new ArrayList<>(mRoot.mFeatureToDisplayAreas.get(feature));
+ displayAreas.addAll(root.mFeatureToDisplayAreas.get(feature));
}
}
- return new ArrayList<>();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7991d2b33a94..0a3b884f79d0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -71,6 +71,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
@@ -910,7 +911,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* @param root {@link RootWindowContainer}
*/
DisplayContent(Display display, RootWindowContainer root) {
- super(root.mWindowManager);
+ super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
if (mWmService.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists="
@@ -3493,12 +3494,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- private void updateImeControlTarget() {
+ void updateImeControlTarget() {
mInputMethodControlTarget = computeImeControlTarget();
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
- final WindowState win = mInputMethodControlTarget != null
- ? mInputMethodControlTarget.getWindow() : null;
+ final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.post(() ->
@@ -3522,6 +3522,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
return mRemoteInsetsControlTarget;
} else {
+ // Now, a special case -- if the last target's window is in the process of exiting, but
+ // not removed, keep on the last target to avoid IME flicker.
+ final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
+ if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing()
+ && !cur.isActivityTypeHome()) {
+ if (DEBUG_INPUT_METHOD) {
+ Slog.v(TAG_WM, "Not changing control while current window"
+ + " is closing and not removed");
+ }
+ return cur;
+ }
// Otherwise, we just use the ime target as received from IME.
return mInputMethodInputTarget;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 8298763c1392..99ee5e121b7a 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -18,13 +18,14 @@ package com.android.server.wm;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
-import android.graphics.PixelFormat;
import android.view.InsetsSource;
import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.protolog.common.ProtoLog;
+import java.io.PrintWriter;
+
/**
* Controller for IME inset source on the server. It's called provider as it provides the
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
@@ -132,8 +133,17 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
- // If IME target is transparent but control target matches requesting window.
- || (controlTarget == mImeTargetFromIme
- && PixelFormat.formatHasAlpha(dcTarget.mAttrs.format));
+ || (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ super.dump(pw, prefix);
+ if (mImeTargetFromIme != null) {
+ pw.print(prefix);
+ pw.print("showImePostLayout pending for mImeTargetFromIme=");
+ pw.print(mImeTargetFromIme);
+ pw.println();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8734b5efa45d..0216db471843 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,13 +16,14 @@
package com.android.server.wm;
-import static android.os.Process.myPid;
-import static android.os.Process.myUid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
@@ -477,12 +478,18 @@ final class InputMonitor {
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
+ final int type = w.mAttrs.type;
+ final boolean isVisible = w.isVisibleLw();
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
|| (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
+ // Assign an InputInfo with type to the overlay window which can't receive input
+ // event. This is used to omit Surfaces from occlusion detection.
+ populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
- mInvalidInputWindow);
+ w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
+ mInvalidInputWindow);
+ return;
}
// Skip this window because it cannot possibly receive input.
return;
@@ -490,9 +497,7 @@ final class InputMonitor {
final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
- final int type = w.mAttrs.type;
final boolean hasFocus = w.isFocused();
- final boolean isVisible = w.isVisibleLw();
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
@@ -555,6 +560,26 @@ final class InputMonitor {
}
}
+ // This would reset InputWindowHandle fields to prevent it could be found by input event.
+ // We need to check if any new field of InputWindowHandle could impact the result.
+ private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
+ final String name, final int type, final boolean isVisible) {
+ inputWindowHandle.name = name;
+ inputWindowHandle.layoutParamsType = type;
+ inputWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ inputWindowHandle.visible = isVisible;
+ inputWindowHandle.canReceiveKeys = false;
+ inputWindowHandle.hasFocus = false;
+ inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
+ inputWindowHandle.scaleFactor = 1;
+ inputWindowHandle.layoutParamsFlags =
+ FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
+ inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
+ inputWindowHandle.touchableRegion.setEmpty();
+ inputWindowHandle.setTouchableRegionCrop(null);
+ }
+
/**
* Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
* info will not have an input channel or be touchable, but is used to omit Surfaces
@@ -564,16 +589,7 @@ final class InputMonitor {
static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
int displayId, String name) {
InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
- inputWindowHandle.name = name;
- inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY;
- inputWindowHandle.dispatchingTimeoutNanos = -1;
- inputWindowHandle.visible = true;
- inputWindowHandle.canReceiveKeys = false;
- inputWindowHandle.hasFocus = false;
- inputWindowHandle.ownerPid = myPid();
- inputWindowHandle.ownerUid = myUid();
- inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
- inputWindowHandle.scaleFactor = 1;
+ populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
t.setInputWindowInfo(sc, inputWindowHandle);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index c50f296504fc..3ffc26a7a8ad 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -62,4 +62,8 @@ interface InsetsControlTarget {
return false;
}
+ /** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
+ static WindowState asWindowOrNull(InsetsControlTarget target) {
+ return target != null ? target.getWindow() : null;
+ }
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 63083faaddb1..9c978fd0c867 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -44,6 +45,7 @@ import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -74,7 +76,21 @@ class InsetsStateController {
w.notifyInsetsChanged();
}
};
- private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
+ private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() {
+ @Override
+ public void notifyInsetsControlChanged() {
+ InsetsSourceControl[] controls = getControlsForDispatch(this);
+ if (controls == null) {
+ return;
+ }
+ for (InsetsSourceControl control : controls) {
+ if (control.getType() == ITYPE_IME) {
+ mDisplayContent.mWmService.mH.post(() ->
+ InputMethodManagerInternal.get().removeImeSurface());
+ }
+ }
+ }
+ };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -171,6 +187,7 @@ class InsetsStateController {
state = new InsetsState(state);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_NAVIGATION_BAR);
+ state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
}
if (aboveIme) {
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index 9d408540c838..faed7fa99fdd 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
-import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
@@ -44,19 +43,11 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
/** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */
private DisplayArea.Tokens[] mAreaForLayer;
- /**
- * List of {@link TaskDisplayArea} that are attached to this {@link DisplayArea} hierarchy. The
- * order is the same as their z-order.
- *
- * TODO(b/157683117): Instead of caching the TDAs, always traverse the hierarchy to get them.
- */
- ArrayList<TaskDisplayArea> mTaskDisplayAreas;
-
/** Whether the hierarchy has been built. */
private boolean mHasBuiltHierarchy;
- RootDisplayArea(WindowManagerService wms) {
- super(wms, Type.ANY, "RootDisplayArea", FEATURE_ROOT);
+ RootDisplayArea(WindowManagerService wms, String name, int featureId) {
+ super(wms, Type.ANY, name, featureId);
}
/** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
@@ -73,15 +64,13 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
/** Callback after {@link DisplayArea} hierarchy has been built. */
void onHierarchyBuilt(ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer,
- Map<Feature, List<DisplayArea<? extends WindowContainer>>> featureToDisplayAreas,
- ArrayList<TaskDisplayArea> taskDisplayAreas) {
+ Map<Feature, List<DisplayArea<? extends WindowContainer>>> featureToDisplayAreas) {
if (mHasBuiltHierarchy) {
throw new IllegalStateException("Root should only build the hierarchy once");
}
mHasBuiltHierarchy = true;
mFeatures = Collections.unmodifiableList(features);
mAreaForLayer = areaForLayer;
- mTaskDisplayAreas = taskDisplayAreas;
mFeatureToDisplayAreas = featureToDisplayAreas;
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 132d00ac91c1..c27d0cda22ab 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -24,6 +25,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -44,7 +46,13 @@ class WallpaperWindowToken extends WindowToken {
WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
DisplayContent dc, boolean ownerCanManageAppTokens) {
- super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens);
+ this(service, token, explicit, dc, ownerCanManageAppTokens, null /* options */);
+ }
+
+ WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
+ DisplayContent dc, boolean ownerCanManageAppTokens, @Nullable Bundle options) {
+ super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens, INVALID_UID,
+ false /* roundedCornerOverlay */, false /* fromClientToken */, options);
dc.mWallpaperController.addWallpaperToken(this);
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bc4d505bbfca..85972bffd755 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2670,10 +2670,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
// TODO(window-container): Clean up dead tokens
if (type == TYPE_WALLPAPER) {
- new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens);
+ new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens,
+ options);
} else {
new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens,
- callingUid, false /* roundedCornerOverlay */, fromClientToken);
+ callingUid, false /* roundedCornerOverlay */, fromClientToken, options);
}
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bac921816e3f..86bc0a227ac1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2191,6 +2191,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isInputMethodTarget()) {
dc.computeImeTarget(true /* updateImeTarget */);
}
+ if (dc.mInputMethodControlTarget == this) {
+ dc.updateImeControlTarget();
+ }
final int type = mAttrs.type;
if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 86aacf308068..2c1bb3ec51eb 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -40,10 +40,12 @@ import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
+import android.annotation.Nullable;
import android.app.IWindowToken;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
@@ -78,6 +80,13 @@ class WindowToken extends WindowContainer<WindowState> {
// The type of window this token is for, as per WindowManager.LayoutParams.
final int windowType;
+ /**
+ * Options that will be used to determine which {@link RootDisplayArea} this window should be
+ * attached to.
+ */
+ @Nullable
+ final Bundle mOptions;
+
/** {@code true} if this holds the rounded corner overlay */
final boolean mRoundedCornerOverlay;
@@ -233,9 +242,17 @@ class WindowToken extends WindowContainer<WindowState> {
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
boolean roundedCornerOverlay, boolean fromClientToken) {
+ this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, ownerUid,
+ roundedCornerOverlay, fromClientToken, null /* options */);
+ }
+
+ WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
+ DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
+ boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
+ mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mOwnerUid = ownerUid;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
index 04a9cca7fa51..f40d3168cf98 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
@@ -41,8 +41,6 @@ import static org.mockito.MockitoAnnotations.initMocks;
import android.app.AppOpsManager;
import android.content.Context;
-import android.content.Intent;
-import android.location.LocationManager;
import android.location.util.identity.CallerIdentity;
import android.platform.test.annotations.Presubmit;
@@ -52,7 +50,6 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.ArrayList;
@@ -183,11 +180,6 @@ public class SystemAppOpsHelperTest {
eq(false), eq("myfeature"), nullable(String.class));
assertThat(mHelper.startHighPowerLocationMonitoring(identity)).isTrue();
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).sendBroadcast(intentCaptor.capture());
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
-
doReturn(MODE_IGNORED).when(
mAppOps).startOpNoThrow(eq(OP_MONITOR_HIGH_POWER_LOCATION), eq(1000),
eq("mypackage"),
@@ -209,11 +201,6 @@ public class SystemAppOpsHelperTest {
mHelper.stopHighPowerLocationMonitoring(identity);
verify(mAppOps).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, 1000, "mypackage", "myfeature");
-
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).sendBroadcast(intentCaptor.capture());
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
}
@Test
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index ac2ec58fae2a..7fc6bbd70000 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -59,6 +59,7 @@ android_test {
libs: [
"android.hardware.power-java",
"android.hardware.tv.cec-V1.0-java",
+ "android.hardware.vibrator-java",
"android.hidl.manager-V1.0-java",
"android.test.mock",
"android.test.base",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 6915220d3fb7..90e1cfcd305a 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -81,6 +81,9 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE"/>
+ <uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
new file mode 100644
index 000000000000..c6922536f61a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManagerInternal;
+import android.hardware.vibrator.IVibrator;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IVibratorStateListener;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+/**
+ * Tests for {@link VibratorService}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibratorServiceTest
+ */
+@Presubmit
+public class VibratorServiceTest {
+
+ private static final int UID = Process.ROOT_UID;
+ private static final String PACKAGE_NAME = "package";
+ private static final VibrationAttributes ALARM_ATTRS =
+ new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
+ private static final VibrationAttributes HAPTIC_FEEDBACK_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_TOUCH).build();
+ private static final VibrationAttributes NOTIFICATION_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_NOTIFICATION).build();
+ private static final VibrationAttributes RINGTONE_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_RINGTONE).build();
+
+ @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock private PackageManagerInternal mPackageManagerInternalMock;
+ @Mock private PowerManagerInternal mPowerManagerInternalMock;
+ @Mock private PowerSaveState mPowerSaveStateMock;
+ @Mock private Vibrator mVibratorMock;
+ @Mock private VibratorService.NativeWrapper mNativeWrapperMock;
+ @Mock private IVibratorStateListener mVibratorStateListenerMock;
+ @Mock private IBinder mVibratorStateListenerBinderMock;
+
+ private TestLooper mTestLooper;
+ private ContextWrapper mContextSpy;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestLooper = new TestLooper();
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+
+ MockContentResolver contentResolver = new MockContentResolver(mContextSpy);
+ contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+
+ when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+ when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+ when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorMock.getDefaultRingVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
+ when(mPackageManagerInternalMock.getSystemUiServiceComponent())
+ .thenReturn(new ComponentName("", ""));
+ when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
+ .thenReturn(mPowerSaveStateMock);
+
+ addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
+ addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+ FakeSettingsProvider.clearSettingsProvider();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ FakeSettingsProvider.clearSettingsProvider();
+ }
+
+ private VibratorService createService() {
+ return new VibratorService(mContextSpy,
+ new VibratorService.Injector() {
+ @Override
+ VibratorService.NativeWrapper getNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ Handler createHandler(Looper looper) {
+ return new Handler(mTestLooper.getLooper());
+ }
+
+ @Override
+ void addService(String name, IBinder service) {
+ // ignore
+ }
+ });
+ }
+
+ @Test
+ public void createService_initializesNativeService() {
+ createService();
+ verify(mNativeWrapperMock).vibratorInit();
+ verify(mNativeWrapperMock).vibratorOff();
+ }
+
+ @Test
+ public void hasVibrator_withVibratorHalPresent_returnsTrue() {
+ when(mNativeWrapperMock.vibratorExists()).thenReturn(true);
+ assertTrue(createService().hasVibrator());
+ }
+
+ @Test
+ public void hasVibrator_withNoVibratorHalPresent_returnsFalse() {
+ when(mNativeWrapperMock.vibratorExists()).thenReturn(false);
+ assertFalse(createService().hasVibrator());
+ }
+
+ @Test
+ public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ assertTrue(createService().hasAmplitudeControl());
+ }
+
+ @Test
+ public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
+ assertFalse(createService().hasAmplitudeControl());
+ }
+
+ @Test
+ public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
+ when(mNativeWrapperMock.vibratorGetSupportedEffects()).thenReturn(null);
+ assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
+ createService().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
+ }
+
+ @Test
+ public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
+ int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
+
+ when(mNativeWrapperMock.vibratorGetSupportedEffects())
+ .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ assertArrayEquals(
+ new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+ Vibrator.VIBRATION_EFFECT_SUPPORT_NO},
+ createService().areEffectsSupported(effects));
+ }
+
+ @Test
+ public void arePrimitivesSupported_withoutComposeCapability_returnsAlwaysFalse() {
+ assertArrayEquals(new boolean[]{false, false},
+ createService().arePrimitivesSupported(new int[]{
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_TICK
+ }));
+ }
+
+ @Test
+ public void arePrimitivesSupported_withComposeCapability_returnsAlwaysTrue() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ assertArrayEquals(new boolean[]{true, true},
+ createService().arePrimitivesSupported(new int[]{
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
+ }));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withCapabilityAndValidEffect_enablesAlwaysOnEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
+ verify(mNativeWrapperMock).vibratorAlwaysOnEnable(
+ eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withNonPrebakedEffect_ignoresEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.createOneShot(100, 255), ALARM_ATTRS));
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withNullEffect_disablesAlwaysOnEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
+ verify(mNativeWrapperMock).vibratorAlwaysOnDisable(eq(1L));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withoutCapability_ignoresEffect() {
+ assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorOn(eq(100L));
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
+ }
+
+ @Test
+ public void vibrate_withOneShotAndNoAmplitudeControl_turnsVibratorOnAndIgnoresAmplitude() {
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorOn(eq(100L));
+ verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
+ }
+
+ @Test
+ public void vibrate_withPrebaked_performsEffect() {
+ when(mNativeWrapperMock.vibratorGetSupportedEffects())
+ .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
+ any(VibratorService.Vibration.class), eq(false));
+ }
+
+ @Test
+ public void vibrate_withComposed_performsEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
+ ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ primitivesCaptor.capture(), any(VibratorService.Vibration.class));
+
+ // Check all primitive effect fields are passed down to the HAL.
+ assertEquals(1, primitivesCaptor.getValue().length);
+ VibrationEffect.Composition.PrimitiveEffect primitive = primitivesCaptor.getValue()[0];
+ assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.id);
+ assertEquals(0.5f, primitive.scale, /* delta= */ 1e-2);
+ assertEquals(10, primitive.delay);
+ }
+
+ @Test
+ public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
+ throws Exception {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ VibrationEffect effect = VibrationEffect.createWaveform(
+ new long[] { 10, 10, 10 }, new int[] { 100, 200, 50 }, -1);
+ vibrate(service, effect);
+
+ verify(mNativeWrapperMock).vibratorOff();
+
+ Thread.sleep(5);
+ verify(mNativeWrapperMock).vibratorOn(eq(30L));
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+
+ Thread.sleep(10);
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200));
+
+ Thread.sleep(10);
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50));
+ }
+
+ @Test
+ public void vibrate_withCallback_finishesVibrationWhenCallbackTriggered() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ doAnswer(invocation -> {
+ ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
+ return null;
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(), any(VibratorService.Vibration.class));
+
+ // Use vibration with delay so there is time for the callback to be triggered.
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ // Vibration canceled once before perform and once by native callback.
+ verify(mNativeWrapperMock, times(2)).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(VibrationEffect.Composition.PrimitiveEffect[].class),
+ any(VibratorService.Vibration.class));
+ }
+
+ @Test
+ public void vibrate_whenBinderDies_cancelsVibration() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ doAnswer(invocation -> {
+ ((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
+ return null;
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(), any(VibratorService.Vibration.class));
+
+ // Use vibration with delay so there is time for the callback to be triggered.
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ // Vibration canceled once before perform and once by native binder death.
+ verify(mNativeWrapperMock, times(2)).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(VibrationEffect.Composition.PrimitiveEffect[].class),
+ any(VibratorService.Vibration.class));
+ }
+
+ @Test
+ public void cancelVibrate_withDeviceVibrating_callsVibratorOff() {
+ VibratorService service = createService();
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ service.cancelVibrate(service);
+ assertFalse(service.isVibrating());
+ verify(mNativeWrapperMock).vibratorOff();
+ }
+
+ @Test
+ public void cancelVibrate_withDeviceNotVibrating_ignoresCall() {
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ service.cancelVibrate(service);
+ assertFalse(service.isVibrating());
+ verify(mNativeWrapperMock, never()).vibratorOff();
+ }
+
+ @Test
+ public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
+ VibratorService service = createService();
+
+ service.registerVibratorStateListener(mVibratorStateListenerMock);
+ verify(mVibratorStateListenerMock).onVibrating(false);
+
+ vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
+ verify(mVibratorStateListenerMock).onVibrating(true);
+
+ // Run the scheduled callback to finish one-shot vibration.
+ mTestLooper.moveTimeForward(10);
+ mTestLooper.dispatchAll();
+ verify(mVibratorStateListenerMock, times(2)).onVibrating(false);
+ }
+
+ @Test
+ public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
+ VibratorService service = createService();
+
+ service.registerVibratorStateListener(mVibratorStateListenerMock);
+ verify(mVibratorStateListenerMock).onVibrating(false);
+
+ vibrate(service, VibrationEffect.createOneShot(5, VibrationEffect.DEFAULT_AMPLITUDE));
+ verify(mVibratorStateListenerMock).onVibrating(true);
+
+ service.unregisterVibratorStateListener(mVibratorStateListenerMock);
+ Mockito.clearInvocations(mVibratorStateListenerMock);
+
+ vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
+ verifyNoMoreInteractions(mVibratorStateListenerMock);
+ }
+
+ @Test
+ public void scale_withPrebaked_userIntensitySettingAsEffectStrength() {
+ // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+ VibratorService service = createService();
+ service.systemReady();
+
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
+ ALARM_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK),
+ NOTIFICATION_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK),
+ HAPTIC_FEEDBACK_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK),
+ RINGTONE_ATTRS);
+
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any(), anyBoolean());
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_TICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any(), anyBoolean());
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any(), anyBoolean());
+ verify(mNativeWrapperMock, never()).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any(), anyBoolean());
+ }
+
+ @Test
+ public void scale_withOneShotAndWaveform_usesScaleLevelOnAmplitude() throws Exception {
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_HIGH);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ service.systemReady();
+
+ vibrate(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
+ vibrate(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
+ vibrate(service, VibrationEffect.createOneShot(20, 255), RINGTONE_ATTRS);
+ vibrate(service, VibrationEffect.createWaveform(new long[] { 10 }, new int[] { 100 }, -1),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // Waveform effect runs on a separate thread.
+ Thread.sleep(5);
+
+ // Alarm vibration is never scaled.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+ // Notification vibrations will be scaled with SCALE_VERY_HIGH.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(intThat(amplitude -> amplitude > 150));
+ // Haptic feedback vibrations will be scaled with SCALE_LOW.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(
+ intThat(amplitude -> amplitude < 100 && amplitude > 50));
+ // Ringtone vibration is off.
+ verify(mNativeWrapperMock, never()).vibratorSetAmplitude(eq(255));
+ }
+
+ @Test
+ public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() {
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_HIGH);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ service.systemReady();
+
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
+ .compose();
+ ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
+ ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
+
+ vibrate(service, effect, ALARM_ATTRS);
+ vibrate(service, effect, NOTIFICATION_ATTRS);
+ vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
+ vibrate(service, effect, RINGTONE_ATTRS);
+
+ // Ringtone vibration is off, so only the other 3 are propagated to native.
+ verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
+ primitivesCaptor.capture(), any());
+
+ List<VibrationEffect.Composition.PrimitiveEffect[]> values =
+ primitivesCaptor.getAllValues();
+
+ // Alarm vibration is never scaled.
+ assertEquals(1f, values.get(0)[0].scale, /* delta= */ 1e-2);
+ assertEquals(0.5f, values.get(0)[1].scale, /* delta= */ 1e-2);
+
+ // Notification vibrations will be scaled with SCALE_VERY_HIGH.
+ assertEquals(1f, values.get(1)[0].scale, /* delta= */ 1e-2);
+ assertTrue(0.7 < values.get(1)[1].scale);
+
+ // Haptic feedback vibrations will be scaled with SCALE_LOW.
+ assertTrue(0.5 < values.get(2)[0].scale);
+ assertTrue(0.5 > values.get(2)[1].scale);
+ }
+
+ private void vibrate(VibratorService service, VibrationEffect effect) {
+ vibrate(service, effect, ALARM_ATTRS);
+ }
+
+ private void vibrate(VibratorService service, VibrationEffect effect,
+ VibrationAttributes attributes) {
+ service.vibrate(UID, PACKAGE_NAME, effect, attributes, "some reason", service);
+ }
+
+ private void mockVibratorCapabilities(int capabilities) {
+ when(mNativeWrapperMock.vibratorGetCapabilities()).thenReturn((long) capabilities);
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private void setVibrationIntensityUserSetting(String settingName, int value) {
+ Settings.System.putIntForUser(
+ mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 6d9b43a967c4..cd2c9230221c 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -252,6 +252,7 @@ public class RollbackUnitTest {
verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(111));
verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(222));
verify(mMockDataHelper, never()).destroyApexDeSnapshots(anyInt());
+ verify(mMockDataHelper, never()).destroyApexCeSnapshots(anyInt(), anyInt());
assertThat(rollback.isDeleted()).isTrue();
}
@@ -273,6 +274,8 @@ public class RollbackUnitTest {
verify(mMockDataHelper, never())
.destroyAppDataSnapshot(anyInt(), pkgRollbackInfoFor(PKG_2), anyInt());
verify(mMockDataHelper).destroyApexDeSnapshots(123);
+ verify(mMockDataHelper).destroyApexCeSnapshots(111, 123);
+ verify(mMockDataHelper).destroyApexCeSnapshots(222, 123);
assertThat(rollback.isDeleted()).isTrue();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 290b0e5036bb..a8fc66da9bd0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -16,15 +16,19 @@
package com.android.server.wm;
+import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
@@ -33,13 +37,18 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
import static java.util.stream.Collectors.toList;
import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
+import com.google.android.collect.Lists;
+
import org.hamcrest.CustomTypeSafeMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -74,6 +83,10 @@ public class DisplayAreaPolicyBuilderTest {
private DisplayContent mDisplayContent;
private TaskDisplayArea mDefaultTaskDisplayArea;
private List<TaskDisplayArea> mTaskDisplayAreaList;
+ private RootDisplayArea mGroupRoot1;
+ private RootDisplayArea mGroupRoot2;
+ private TaskDisplayArea mTda1;
+ private TaskDisplayArea mTda2;
@Before
public void setup() {
@@ -85,6 +98,10 @@ public class DisplayAreaPolicyBuilderTest {
FEATURE_DEFAULT_TASK_CONTAINER);
mTaskDisplayAreaList = new ArrayList<>();
mTaskDisplayAreaList.add(mDefaultTaskDisplayArea);
+ mGroupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1", FEATURE_VENDOR_FIRST + 1);
+ mGroupRoot2 = new SurfacelessDisplayAreaRoot(mWms, "group2", FEATURE_VENDOR_FIRST + 2);
+ mTda1 = new TaskDisplayArea(mDisplayContent, mWms, "tda1", FEATURE_VENDOR_FIRST + 3);
+ mTda2 = new TaskDisplayArea(mDisplayContent, mWms, "tda2", FEATURE_VENDOR_FIRST + 4);
}
@Test
@@ -191,6 +208,271 @@ public class DisplayAreaPolicyBuilderTest {
}
}
+ @Test
+ public void testBuilder_singleRoot_validateSettings() {
+ final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
+
+ // Root must be set.
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // IME must be set.
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // Default TaskDisplayArea must be set.
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // No exception
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ builder.build(mWms);
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_validateSettings() {
+ final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
+
+ // IME must be set to one of the roots.
+ builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder1.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
+
+ // Default TaskDisplayArea must be set.
+ final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+ builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
+
+ // Each DisplayAreaGroup must have at least one TaskDisplayArea.
+ final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
+ builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+ builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2));
+
+ assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
+
+ // No exception
+ final DisplayAreaPolicyBuilder builder4 = new DisplayAreaPolicyBuilder();
+ builder4.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+ builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ builder4.build(mWms);
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_attachDisplayAreas() {
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1)))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2)))
+ .build(mWms);
+
+ assertThat(mDefaultTaskDisplayArea.isDescendantOf(mRoot)).isTrue();
+ assertThat(mGroupRoot1.isDescendantOf(mRoot)).isTrue();
+ assertThat(mGroupRoot2.isDescendantOf(mRoot)).isTrue();
+ assertThat(mImeContainer.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(mTda1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(mTda2.isDescendantOf(mGroupRoot2)).isTrue();
+ assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot1)).isTrue();
+ assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot2)).isTrue();
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_createFeatureOnGroup() {
+ final Feature feature1 = new Feature.Builder(mWms.mPolicy, "feature1",
+ FEATURE_VENDOR_FIRST + 5)
+ .all()
+ .except(TYPE_STATUS_BAR)
+ .build();
+ final Feature feature2 = new Feature.Builder(mWms.mPolicy, "feature2",
+ FEATURE_VENDOR_FIRST + 6)
+ .upTo(TYPE_STATUS_BAR)
+ .and(TYPE_NAVIGATION_BAR)
+ .build();
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1))
+ .addFeature(feature1))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2))
+ .addFeature(feature2))
+ .build(mWms);
+
+ List<DisplayArea<? extends WindowContainer>> feature1DAs =
+ policy.getDisplayAreas(feature1.getId());
+ List<DisplayArea<? extends WindowContainer>> feature2DAs =
+ policy.getDisplayAreas(feature2.getId());
+ for (DisplayArea<? extends WindowContainer> da : feature1DAs) {
+ assertThat(da.isDescendantOf(mGroupRoot1)).isTrue();
+ }
+ for (DisplayArea<? extends WindowContainer> da : feature2DAs) {
+ assertThat(da.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_defaultFunc() {
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1)))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2)))
+ .build(mWms);
+
+ final WindowToken token = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ policy.addWindow(token);
+
+ // By default, window are always added to the root.
+ assertThat(token.isDescendantOf(mRoot)).isTrue();
+ assertThat(token.isDescendantOf(mGroupRoot1)).isFalse();
+ assertThat(token.isDescendantOf(mGroupRoot2)).isFalse();
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnType() {
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1));
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2));
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(hierarchy1)
+ .addDisplayAreaGroupHierarchy(hierarchy2)
+ .setSelectRootForWindowFunc((token, options) -> {
+ if (token.windowType == TYPE_STATUS_BAR) {
+ return mGroupRoot1;
+ }
+ return mGroupRoot2;
+ })
+ .build(mWms);
+
+ final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_WALLPAPER, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ policy.addWindow(token1);
+ policy.addWindow(token2);
+
+ assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnOptions() {
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList);
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1));
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2));
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(hierarchy0)
+ .addDisplayAreaGroupHierarchy(hierarchy1)
+ .addDisplayAreaGroupHierarchy(hierarchy2)
+ .setSelectRootForWindowFunc((token, options) -> {
+ if (options == null) {
+ return mRoot;
+ }
+ if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot1.mFeatureId) {
+ return mGroupRoot1;
+ }
+ if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot2.mFeatureId) {
+ return mGroupRoot2;
+ }
+ return mRoot;
+ })
+ .build(mWms);
+
+ final Bundle options1 = new Bundle();
+ options1.putInt("HIERARCHY_ROOT_ID", mGroupRoot1.mFeatureId);
+ final Bundle options2 = new Bundle();
+ options2.putInt("HIERARCHY_ROOT_ID", mGroupRoot2.mFeatureId);
+ final WindowToken token0 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options1);
+ final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options2);
+
+ policy.addWindow(token0);
+ policy.addWindow(token1);
+ policy.addWindow(token2);
+
+ assertThat(token0.isDescendantOf(mRoot)).isTrue();
+ assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+
private static Resources resourcesWithProvider(String provider) {
Resources mock = mock(Resources.class);
when(mock.getString(
@@ -260,6 +542,10 @@ public class DisplayAreaPolicyBuilderTest {
};
}
+ private boolean isSibling(WindowContainer da1, WindowContainer da2) {
+ return da1.getParent() != null && da1.getParent() == da2.getParent();
+ }
+
private WindowToken tokenOfType(int type) {
WindowToken m = mock(WindowToken.class);
when(m.getWindowLayerFromType()).thenReturn(
@@ -293,7 +579,11 @@ public class DisplayAreaPolicyBuilderTest {
static class SurfacelessDisplayAreaRoot extends RootDisplayArea {
SurfacelessDisplayAreaRoot(WindowManagerService wms) {
- super(wms);
+ this(wms, "SurfacelessDisplayAreaRoot", FEATURE_ROOT);
+ }
+
+ SurfacelessDisplayAreaRoot(WindowManagerService wms, String name, int featureId) {
+ super(wms, name, featureId);
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 9bf0a0d381d1..018b3027bdff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -947,6 +947,26 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testComputeImeControlTarget_exitingApp() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+
+ WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app");
+ makeWindowVisible(exitingWin);
+ exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ exitingWin.mAnimatingExit = true;
+
+ dc.mInputMethodControlTarget = exitingWin;
+ dc.mInputMethodTarget = dc.mInputMethodInputTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, "starting app");
+
+ assertEquals(exitingWin, dc.computeImeControlTarget());
+
+ exitingWin.removeImmediately();
+
+ assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
+ }
+
+ @Test
public void testComputeImeControlTarget_splitscreen() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index d07f4f117278..1266c50d368e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -149,7 +149,6 @@ public class WindowManagerServiceTests extends WindowTestsBase {
TaskDisplayArea secondTda =
new TaskDisplayArea(display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST);
display.addChild(secondTda, 1);
- display.mTaskDisplayAreas.add(secondTda);
// Current focused window
ActivityStack focusedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 23a097eb0c7c..5264e9aaba27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -20,16 +20,21 @@ import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
+import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +43,8 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.function.BiFunction;
+
/**
* Tests for the {@link WindowToken} class.
*
@@ -205,4 +212,27 @@ public class WindowTokenTests extends WindowTestsBase {
false /* fromClientToken */);
assertNotNull(nonClientToken.mSurfaceControl);
}
+
+ @Test
+ public void testWindowAttachedWithOptions() {
+ BiFunction<WindowToken, Bundle, RootDisplayArea> selectFunc =
+ ((DisplayAreaPolicyBuilder.Result) mDisplayContent.mDisplayAreaPolicy)
+ .mSelectRootForWindowFunc;
+ spyOn(selectFunc);
+
+ final WindowToken token1 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+
+ verify(selectFunc).apply(token1, null);
+
+ final Bundle options = new Bundle();
+ final WindowToken token2 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ false /* fromClientToken */, options /* options */);
+
+ verify(selectFunc).apply(token2, options);
+ }
}
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 2d0bd52f84ee..4e4abd0f63b0 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -16,7 +16,9 @@
package android.telephony;
+import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.cdma.CdmaCellLocation;
@@ -31,11 +33,25 @@ import com.android.internal.telephony.PhoneConstants;
public abstract class CellLocation {
/**
- * Request an update of the current location. If the location has changed,
- * a broadcast will be sent to everyone registered with {@link
- * PhoneStateListener#LISTEN_CELL_LOCATION}.
+ * This method will not do anything.
+ *
+ * Whenever location changes, a callback will automatically be be sent to
+ * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}.
+ *
+ * <p>This method is a no-op for callers targeting SDK level 31 or greater.
+ * <p>This method is a no-op for callers that target SDK level 29 or 30 and lack
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
+ * <p>This method is a no-op for callers that target SDK level 28 or below and lack
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
+ *
+ * Callers wishing to request a single location update should use
+ * {@link TelephonyManager#requestCellInfoUpdate}.
*/
public static void requestLocationUpdate() {
+ // Since this object doesn't have a context, this is the best we can do.
+ final Context appContext = ActivityThread.currentApplication();
+ if (appContext == null) return; // should never happen
+
try {
ITelephony phone = ITelephony.Stub.asInterface(
TelephonyFrameworkInitializer
@@ -43,7 +59,7 @@ public abstract class CellLocation {
.getTelephonyServiceRegisterer()
.get());
if (phone != null) {
- phone.updateServiceLocation();
+ phone.updateServiceLocationWithPackageName(appContext.getOpPackageName());
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 347dcc81ce4e..717a9b155cbf 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -255,28 +255,6 @@ public class SmsMessage {
}
/**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [&lt;alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging and for RIL
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(byte[] pdu) {
- // received SMS in 3GPP format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.gsm.SmsMessage.newFromCMT(pdu);
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
- return null;
- }
- }
-
- /**
* Creates an SmsMessage from an SMS EF record.
*
* @param index Index of SMS EF record.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3104c20b0063..d96e024d4c60 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2341,58 +2341,6 @@ public class TelephonyManager {
}
/**
- * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void enableLocationUpdates() {
- enableLocationUpdates(getSubId());
- }
-
- /**
- * Enables location update notifications for a subscription.
- * {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @param subId for which the location updates are enabled
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void enableLocationUpdates(int subId) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.enableLocationUpdatesForSubscriber(subId);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- }
-
- /**
- * Disables location update notifications. {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void disableLocationUpdates() {
- disableLocationUpdates(getSubId());
- }
-
- /** @hide */
- public void disableLocationUpdates(int subId) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.disableLocationUpdatesForSubscriber(subId);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- }
-
- /**
* Returns the neighboring cell information of the device.
*
* @return List of NeighboringCellInfo or null if info unavailable.
@@ -9290,17 +9238,14 @@ public class TelephonyManager {
return RADIO_POWER_UNAVAILABLE;
}
- /** @hide */
+ /**
+ * This method should not be used due to privacy and stability concerns.
+ *
+ * @hide
+ */
@SystemApi
- @SuppressLint("Doclava125")
public void updateServiceLocation() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.updateServiceLocation();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#updateServiceLocation", e);
- }
+ Log.e(TAG, "Do not call TelephonyManager#updateServiceLocation()");
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4276e713561b..e2de5c82940f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -222,42 +222,29 @@ interface ITelephony {
boolean setRadioPower(boolean turnOn);
/**
- * Request to update location information in service state
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void updateServiceLocation();
/**
- * Request to update location information for a subscrition in service state
- * @param subId user preferred subId.
+ * Version of updateServiceLocation that records the caller and validates permissions.
*/
- void updateServiceLocationForSubscriber(int subId);
+ void updateServiceLocationWithPackageName(String callingPkg);
/**
- * Enable location update notifications.
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void enableLocationUpdates();
/**
- * Enable location update notifications.
- * @param subId user preferred subId.
- */
- void enableLocationUpdatesForSubscriber(int subId);
-
- /**
- * Disable location update notifications.
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void disableLocationUpdates();
/**
- * Disable location update notifications.
- * @param subId user preferred subId.
- */
- void disableLocationUpdatesForSubscriber(int subId);
-
- /**
* Allow mobile data connections.
*/
@UnsupportedAppUsage
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d41a6c889afb..d216162cc257 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -171,8 +171,8 @@ public class TelephonyIntents {
* if not specified </dd>
* </dl>
*
- * <p class="note">
- * Requires the READ_PHONE_STATE permission.
+ * <p class="note">This is a sticky broadcast, and therefore requires no permissions to listen
+ * to. Do not add any additional information to this broadcast.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index ccb14749109d..e4205aaae5b6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -139,38 +139,6 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [&lt;alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /** @hide */
- public static SmsMessage newFromCDS(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /**
* Creates an SmsMessage from an SMS EF record.
*
* @param index Index of SMS EF record.
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index baff952edc72..070dacbcd91f 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -16,7 +16,7 @@
android_test {
name: "FlickerTests",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
manifest: "AndroidManifest.xml",
test_config: "AndroidTest.xml",
platform_apis: true,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
deleted file mode 100644
index ed6f33e62031..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.WindowUtils.getStatusBarPosition;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations.
- * To run this test: {@code atest FlickerTest:ChangeAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class ChangeAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
-
- public ChangeAppRotationTest(String beginRotationName, String endRotationName,
- int beginRotation, int endRotation) {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}-{1}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- params.add(new Object[]{rotationToString(begin), rotationToString(end), begin,
- end});
- }
- }
- }
- return params;
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return changeAppRotation(mTestApp, mUiDevice, mBeginRotation, mEndRotation)
- .includeJankyRuns().build();
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- Log.e(TAG, "startingPos=" + startingPos + " endingPos=" + endingPos);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), startingPos).inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_statusBarLayerScales() {
- Rect startingPos = getStatusBarPosition(mBeginRotation);
- Rect endingPos = getStatusBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @Ignore("Flaky. Pending debug")
- @Test
- public void checkVisibility_screenshotLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .replaceVisibleLayer(mTestApp.getPackage(), SCREENSHOT_LAYER)
- .then()
- .showsLayer(mTestApp.getPackage()).and().showsLayer(SCREENSHOT_LAYER)
- .then()
- .replaceVisibleLayer(SCREENSHOT_LAYER, mTestApp.getPackage())
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
deleted file mode 100644
index 58dcb9948c85..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToAppTest extends CloseImeWindowToAppTest {
-
- public CloseImeAutoOpenWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return editTextLoseFocusToApp((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- super.checkVisibility_imeAppLayerIsAlwaysVisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- super.checkVisibility_imeAppWindowIsAlwaysVisible();
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
deleted file mode 100644
index 7f610a695e7e..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToHomeTest extends CloseImeWindowToHomeTest {
-
- public CloseImeAutoOpenWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return editTextLoseFocusToHome((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- super.checkVisibility_imeWindowBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-
- @FlakyTest(bugId = 157449248)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppWindowBecomesInvisible() {
- super.checkVisibility_imeAppWindowBecomesInvisible();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
deleted file mode 100644
index 57ad7e76e540..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToAppTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return editTextLoseFocusToApp((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Ignore("Flaky. Pending debug")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
deleted file mode 100644
index 12d11794c1bd..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing to home transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToHomeTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToHomeTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return editTextLoseFocusToHome((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsImeWindow(IME_WINDOW_TITLE)
- .then()
- .hidesImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 153739621)
- @Ignore
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 153739621)
- @Ignore
- @Test
- public void checkVisibility_imeAppLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .then()
- .hidesAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
deleted file mode 100644
index b1854c3294de..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.os.SystemClock.sleep;
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.clearRecents;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.expandPipWindow;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.launchSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.stopPackage;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.platform.helpers.IAppHelper;
-import android.util.Rational;
-import android.view.Surface;
-
-import androidx.annotation.Nullable;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder;
-import com.android.server.wm.flicker.helpers.AutomationUtils;
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-/**
- * Collection of common transitions which can be used to test different apps or scenarios.
- */
-class CommonTransitions {
-
- public static final int ITERATIONS = 1;
- private static final String TAG = "FLICKER";
- private static final long APP_LAUNCH_TIMEOUT = 10000;
-
- private static void setRotation(UiDevice device, int rotation) {
- try {
- switch (rotation) {
- case Surface.ROTATION_270:
- device.setOrientationLeft();
- break;
-
- case Surface.ROTATION_90:
- device.setOrientationRight();
- break;
-
- case Surface.ROTATION_0:
- default:
- device.setOrientationNatural();
- }
- // Wait for animation to complete
- sleep(1000);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param rotation Initial screen rotation
- *
- * @return test tag with pattern <NAME>__<APP>__<ROTATION>
- */
- private static String buildTestTag(String testName, IAppHelper app, int rotation) {
- return buildTestTag(
- testName, app, /* app2 */ null, rotation, rotation, /* description */ "");
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
- */
- private static String buildTestTag(String testName, IAppHelper app, int beginRotation,
- int endRotation) {
- return buildTestTag(
- testName, app, /* app2 */ null, beginRotation, endRotation, /* description */ "");
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param app2 Second app being launched (if any)
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP(S)>__<ROTATION(S)>[__<EXTRA>]
- */
- private static String buildTestTag(String testName, IAppHelper app, @Nullable IAppHelper app2,
- int beginRotation, int endRotation, String extraInfo) {
- StringBuilder testTag = new StringBuilder();
- testTag.append(testName)
- .append("__")
- .append(app.getLauncherName());
-
- if (app2 != null) {
- testTag.append("-")
- .append(app2.getLauncherName());
- }
-
- testTag.append("__")
- .append(rotationToString(beginRotation));
-
- if (endRotation != beginRotation) {
- testTag.append("-")
- .append(rotationToString(endRotation));
- }
-
- if (!extraInfo.isEmpty()) {
- testTag.append("__")
- .append(extraInfo);
- }
-
- return testTag.toString();
- }
-
- static TransitionBuilder openAppWarm(IAppHelper testApp, UiDevice
- device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("openAppWarm", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(testApp::open)
- .runBefore(device::pressHome)
- .runBefore(device::waitForIdle)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithBackKey(IAppHelper testApp, UiDevice
- device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("closeAppWithBackKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithHomeKey(IAppHelper testApp, UiDevice
- device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("closeAppWithHomeKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder openAppCold(IAppHelper testApp,
- UiDevice device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("openAppCold", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::exit)
- .runBefore(device::waitForIdle)
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(IAppHelper testApp, UiDevice
- device, int beginRotation, int endRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("changeAppRotation", testApp, beginRotation, endRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(testApp::open)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(Intent intent, String intentId, Context context,
- UiDevice device, int beginRotation, int endRotation) {
- final String testTag = "changeAppRotation_" + intentId + "_" +
- rotationToString(beginRotation) + "_" + rotationToString(endRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> {
- context.startActivity(intent);
- device.wait(Until.hasObject(By.pkg(intent.getComponent()
- .getPackageName()).depth(0)), APP_LAUNCH_TIMEOUT);
- }
- )
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(() -> stopPackage(context, intent.getComponent().getPackageName()))
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("appToSplitScreen", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> sleep(500))
- .run(() -> launchSplitScreen(device))
- .runAfter(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder splitScreenToLauncher(IAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("splitScreenToLauncher", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .run(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextSetFocus(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("editTextSetFocus", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.openIME(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder resizeSplitScreen(Instrumentation instr, IAppHelper testAppTop,
- ImeAppHelper testAppBottom, UiDevice device, int beginRotation, Rational startRatio,
- Rational stopRatio) {
- String description = startRatio.toString().replace("/", "-") + "_to_"
- + stopRatio.toString().replace("/", "-");
- String testTag = buildTestTag("resizeSplitScreen", testAppTop, testAppBottom,
- beginRotation, beginRotation, description);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(() -> clearRecents(instr))
- .runBefore(testAppBottom::open)
- .runBefore(device::pressHome)
- .runBefore(testAppTop::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .runBefore(() -> {
- UiObject2 snapshot = device.findObject(
- By.res(device.getLauncherPackageName(), "snapshot"));
- snapshot.click();
- })
- .runBefore(() -> testAppBottom.openIME(device))
- .runBefore(device::pressBack)
- .runBefore(() -> AutomationUtils.resizeSplitScreen(device, startRatio))
- .run(() -> AutomationUtils.resizeSplitScreen(device, stopRatio))
- .runAfter(() -> exitSplitScreen(device))
- .runAfter(device::pressHome)
- .runAfterAll(testAppTop::exit)
- .runAfterAll(testAppBottom::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToHome(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("editTextLoseFocusToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.openIME(device))
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToApp(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("editTextLoseFocusToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.openIME(device))
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("enterPipMode", testApp, beginRotation))
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .runAfter(() -> testApp.closePipWindow(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("exitPipModeToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .run(() -> testApp.closePipWindow(device))
- .run(device::waitForIdle)
- .run(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag(buildTestTag("exitPipModeToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .run(device::pressHome)
- .run(() -> setRotation(device, beginRotation))
- .run(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .run(() -> expandPipWindow(device))
- .run(device::waitForIdle)
- .run(testApp::exit)
- .repeat(ITERATIONS);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
new file mode 100644
index 000000000000..b69e6a9736a3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.app.Instrumentation
+import android.content.Context
+import android.content.Intent
+import android.os.RemoteException
+import android.os.SystemClock
+import android.platform.helpers.IAppHelper
+import android.util.Rational
+import android.view.Surface
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
+
+/**
+ * Collection of common transitions which can be used to test different apps or scenarios.
+ */
+internal object CommonTransitions {
+ private const val ITERATIONS = 1
+ private const val APP_LAUNCH_TIMEOUT: Long = 10000
+ private fun setRotation(device: UiDevice, rotation: Int) {
+ try {
+ when (rotation) {
+ Surface.ROTATION_270 -> device.setOrientationLeft()
+ Surface.ROTATION_90 -> device.setOrientationRight()
+ Surface.ROTATION_0 -> device.setOrientationNatural()
+ else -> device.setOrientationNatural()
+ }
+ // Wait for animation to complete
+ SystemClock.sleep(1000)
+ } catch (e: RemoteException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param rotation Initial screen rotation
+ *
+ * @return test tag with pattern <NAME>__<APP>__<ROTATION>
+ </ROTATION></APP></NAME> */
+ private fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
+ return buildTestTag(
+ testName, app, rotation, rotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+ </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+ private fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int
+ ): String {
+ return buildTestTag(
+ testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param app2 Second app being launched (if any)
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
+ </EXTRA></NAME> */
+ private fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int,
+ app2: IAppHelper?,
+ extraInfo: String
+ ): String {
+ val testTag = StringBuilder()
+ testTag.append(testName)
+ .append("__")
+ .append(app.launcherName)
+ if (app2 != null) {
+ testTag.append("-")
+ .append(app2.launcherName)
+ }
+ testTag.append("__")
+ .append(Surface.rotationToString(beginRotation))
+ if (endRotation != beginRotation) {
+ testTag.append("-")
+ .append(Surface.rotationToString(endRotation))
+ }
+ if (extraInfo.isNotEmpty()) {
+ testTag.append("__")
+ .append(extraInfo)
+ }
+ return testTag.toString()
+ }
+
+ fun openAppWarm(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("openAppWarm", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBeforeAll { setRotation(device, beginRotation) }
+ .runBeforeAll { testApp.open() }
+ .runBefore { device.pressHome() }
+ .runBefore { device.waitForIdle() }
+ .runBefore { setRotation(device, beginRotation) }
+ .run { testApp.open() }
+ .runAfterAll { testApp.exit() }
+ .runAfterAll { AutomationUtils.setDefaultWait() }
+ .repeat(ITERATIONS)
+ }
+
+ fun closeAppWithBackKey(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("closeAppWithBackKey", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { testApp.open() }
+ .runBefore { device.waitForIdle() }
+ .run { device.pressBack() }
+ .run { device.waitForIdle() }
+ .runAfterAll { testApp.exit() }
+ .runAfterAll { AutomationUtils.setDefaultWait() }
+ .repeat(ITERATIONS)
+ }
+
+ fun closeAppWithHomeKey(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("closeAppWithHomeKey", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { testApp.open() }
+ .runBefore { device.waitForIdle() }
+ .run { device.pressHome() }
+ .run { device.waitForIdle() }
+ .runAfterAll { testApp.exit() }
+ .runAfterAll { AutomationUtils.setDefaultWait() }
+ .repeat(ITERATIONS)
+ }
+
+ fun openAppCold(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("openAppCold", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBeforeAll { setRotation(device, beginRotation) }
+ .runBefore { testApp.exit() }
+ .runBefore { device.waitForIdle() }
+ .run { testApp.open() }
+ .runAfterAll { testApp.exit() }
+ .runAfterAll { setRotation(device, Surface.ROTATION_0) }
+ .repeat(ITERATIONS)
+ }
+
+ fun changeAppRotation(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int,
+ endRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("changeAppRotation", testApp, beginRotation, endRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBeforeAll { testApp.open() }
+ .runBefore { setRotation(device, beginRotation) }
+ .run { setRotation(device, endRotation) }
+ .runAfterAll { testApp.exit() }
+ .runAfterAll { setRotation(device, Surface.ROTATION_0) }
+ .repeat(ITERATIONS)
+ }
+
+ fun changeAppRotation(
+ intent: Intent,
+ intentId: String,
+ context: Context,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int,
+ endRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ val testTag = "changeAppRotation_" + intentId + "_" +
+ Surface.rotationToString(beginRotation) + "_" +
+ Surface.rotationToString(endRotation)
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(testTag)
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBeforeAll {
+ context.startActivity(intent)
+ device.wait(Until.hasObject(By.pkg(intent.component?.packageName)
+ .depth(0)), APP_LAUNCH_TIMEOUT)
+ }
+ .runBefore { setRotation(device, beginRotation) }
+ .run { setRotation(device, endRotation) }
+ .runAfterAll { AutomationUtils.stopPackage(context, intent.component?.packageName) }
+ .runAfterAll { setRotation(device, Surface.ROTATION_0) }
+ .repeat(ITERATIONS)
+ }
+
+ fun appToSplitScreen(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("appToSplitScreen", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBeforeAll { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .runBefore { device.waitForIdle() }
+ .runBefore { SystemClock.sleep(500) }
+ .run { AutomationUtils.launchSplitScreen(device) }
+ .runAfter { AutomationUtils.exitSplitScreen(device) }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun splitScreenToLauncher(
+ testApp: IAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("splitScreenToLauncher", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { testApp.open() }
+ .runBefore { device.waitForIdle() }
+ .runBefore { AutomationUtils.launchSplitScreen(device) }
+ .run { AutomationUtils.exitSplitScreen(device) }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun editTextSetFocus(
+ testApp: ImeAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("editTextSetFocus", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBefore { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .run { testApp.openIME(device) }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun resizeSplitScreen(
+ testAppTop: IAppHelper,
+ testAppBottom: ImeAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int,
+ startRatio: Rational,
+ stopRatio: Rational
+ ): TransitionRunner.TransitionBuilder {
+ val description = (startRatio.toString().replace("/", "-") + "_to_" +
+ stopRatio.toString().replace("/", "-"))
+ val testTag = buildTestTag("resizeSplitScreen", testAppTop, beginRotation,
+ beginRotation, testAppBottom, description)
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(testTag)
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBeforeAll { setRotation(device, beginRotation) }
+ .runBeforeAll { AutomationUtils.clearRecents(instrumentation) }
+ .runBefore { testAppBottom.open() }
+ .runBefore { device.pressHome() }
+ .runBefore { testAppTop.open() }
+ .runBefore { device.waitForIdle() }
+ .runBefore { AutomationUtils.launchSplitScreen(device) }
+ .runBefore {
+ val snapshot = device.findObject(
+ By.res(device.launcherPackageName, "snapshot"))
+ snapshot.click()
+ }
+ .runBefore { testAppBottom.openIME(device) }
+ .runBefore { device.pressBack() }
+ .runBefore { AutomationUtils.resizeSplitScreen(device, startRatio) }
+ .run { AutomationUtils.resizeSplitScreen(device, stopRatio) }
+ .runAfter { AutomationUtils.exitSplitScreen(device) }
+ .runAfter { device.pressHome() }
+ .runAfterAll { testAppTop.exit() }
+ .runAfterAll { testAppBottom.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun editTextLoseFocusToHome(
+ testApp: ImeAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("editTextLoseFocusToHome", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBefore { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .runBefore { testApp.openIME(device) }
+ .run { device.pressHome() }
+ .run { device.waitForIdle() }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun editTextLoseFocusToApp(
+ testApp: ImeAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("editTextLoseFocusToApp", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBefore { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .runBefore { testApp.openIME(device) }
+ .run { device.pressBack() }
+ .run { device.waitForIdle() }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun enterPipMode(
+ testApp: PipAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("enterPipMode", testApp, beginRotation))
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBefore { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .run { testApp.clickEnterPipButton(device) }
+ .runAfter { testApp.closePipWindow(device) }
+ .runAfterAll { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun exitPipModeToHome(
+ testApp: PipAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("exitPipModeToHome", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .runBefore { device.pressHome() }
+ .runBefore { setRotation(device, beginRotation) }
+ .runBefore { testApp.open() }
+ .run { testApp.clickEnterPipButton(device) }
+ .run { testApp.closePipWindow(device) }
+ .run { device.waitForIdle() }
+ .run { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+
+ fun exitPipModeToApp(
+ testApp: PipAppHelper,
+ instrumentation: Instrumentation,
+ device: UiDevice,
+ beginRotation: Int
+ ): TransitionRunner.TransitionBuilder {
+ return TransitionRunner.TransitionBuilder(instrumentation)
+ .withTag(buildTestTag("exitPipModeToApp", testApp, beginRotation))
+ .recordAllRuns()
+ .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
+ .run { device.pressHome() }
+ .run { setRotation(device, beginRotation) }
+ .run { testApp.open() }
+ .run { testApp.clickEnterPipButton(device) }
+ .run { AutomationUtils.expandPipWindow(device) }
+ .run { device.waitForIdle() }
+ .run { testApp.exit() }
+ .repeat(ITERATIONS)
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
deleted file mode 100644
index dec5680e17f5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import android.app.Instrumentation;
-import android.platform.helpers.IAppHelper;
-import android.util.Rational;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiDevice;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Tests to help debug individual transitions, capture video recordings and create test cases.
- */
-@LargeTest
-@Ignore("Used for debugging transitions used in FlickerTests.")
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class DebugTest {
- private IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- private UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- /**
- * atest FlickerTests:DebugTest#openAppCold
- */
- @Test
- public void openAppCold() {
- CommonTransitions.openAppCold(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppWarm
- */
- @Test
- public void openAppWarm() {
- CommonTransitions.openAppWarm(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
- */
- @Test
- public void changeOrientationFromNaturalToLeft() {
- CommonTransitions.changeAppRotation(testApp, uiDevice, Surface.ROTATION_0,
- Surface.ROTATION_270).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithBackKey
- */
- @Test
- public void closeAppWithBackKey() {
- CommonTransitions.closeAppWithBackKey(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithHomeKey
- */
- @Test
- public void closeAppWithHomeKey() {
- CommonTransitions.closeAppWithHomeKey(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppToSplitScreen
- */
- @Test
- public void openAppToSplitScreen() {
- CommonTransitions.appToSplitScreen(testApp, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#splitScreenToLauncher
- */
- @Test
- public void splitScreenToLauncher() {
- CommonTransitions.splitScreenToLauncher(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#resizeSplitScreen
- */
- @Test
- public void resizeSplitScreen() {
- Instrumentation instr = InstrumentationRegistry.getInstrumentation();
- ImeAppHelper bottomApp = new ImeAppHelper(instr);
- CommonTransitions.resizeSplitScreen(instr, testApp, bottomApp, uiDevice, Surface.ROTATION_0,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().build().run();
- }
-
- // IME tests
-
- /**
- * atest FlickerTests:DebugTest#editTextSetFocus
- */
- @Test
- public void editTextSetFocus() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToHome
- */
- @Test
- public void editTextLoseFocusToHome() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToApp
- */
- @Test
- public void editTextLoseFocusToApp() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- // PIP tests
-
- /**
- * atest FlickerTests:DebugTest#enterPipMode
- */
- @Test
- public void enterPipMode() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.enterPipMode(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToHome
- */
- @Test
- public void exitPipModeToHome() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToApp
- */
- @Test
- public void exitPipModeToApp() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToApp(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns()
- .build().run();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
new file mode 100644
index 000000000000..f871ea59ea71
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.platform.helpers.IAppHelper
+import android.util.Rational
+import android.view.Surface
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+
+/**
+ * Tests to help debug individual transitions, capture video recordings and create test cases.
+ */
+@LargeTest
+@Ignore("Used for debugging transitions used in FlickerTests.")
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class DebugTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp: IAppHelper = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ private val uiDevice = UiDevice.getInstance(instrumentation)
+
+ /**
+ * atest FlickerTests:DebugTest#openAppCold
+ */
+ @Test
+ fun openAppCold() {
+ CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#openAppWarm
+ */
+ @Test
+ fun openAppWarm() {
+ CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
+ */
+ @Test
+ fun changeOrientationFromNaturalToLeft() {
+ CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice, Surface.ROTATION_0,
+ Surface.ROTATION_270).recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#closeAppWithBackKey
+ */
+ @Test
+ fun closeAppWithBackKey() {
+ CommonTransitions.closeAppWithBackKey(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#closeAppWithHomeKey
+ */
+ @Test
+ fun closeAppWithHomeKey() {
+ CommonTransitions.closeAppWithHomeKey(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#openAppToSplitScreen
+ */
+ @Test
+ fun openAppToSplitScreen() {
+ CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).includeJankyRuns().recordAllRuns()
+ .build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#splitScreenToLauncher
+ */
+ @Test
+ fun splitScreenToLauncher() {
+ CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).includeJankyRuns().recordAllRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#resizeSplitScreen
+ */
+ @Test
+ fun resizeSplitScreen() {
+ val bottomApp = ImeAppHelper(instrumentation)
+ CommonTransitions.resizeSplitScreen(
+ testApp,
+ bottomApp,
+ instrumentation,
+ uiDevice,
+ Surface.ROTATION_0,
+ Rational(1, 3), Rational(2, 3)
+ ).includeJankyRuns().build().run()
+ }
+ // IME tests
+ /**
+ * atest FlickerTests:DebugTest#editTextSetFocus
+ */
+ @Test
+ fun editTextSetFocus() {
+ val testApp = ImeAppHelper(instrumentation)
+ CommonTransitions.editTextSetFocus(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .includeJankyRuns()
+ .build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#editTextLoseFocusToHome
+ */
+ @Test
+ fun editTextLoseFocusToHome() {
+ val testApp = ImeAppHelper(instrumentation)
+ CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).includeJankyRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#editTextLoseFocusToApp
+ */
+ @Test
+ fun editTextLoseFocusToApp() {
+ val testApp = ImeAppHelper(instrumentation)
+ CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).includeJankyRuns().build().run()
+ }
+ // PIP tests
+ /**
+ * atest FlickerTests:DebugTest#enterPipMode
+ */
+ @Test
+ fun enterPipMode() {
+ val testApp = PipAppHelper(instrumentation)
+ CommonTransitions.enterPipMode(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .includeJankyRuns().build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#exitPipModeToHome
+ */
+ @Test
+ fun exitPipModeToHome() {
+ val testApp = PipAppHelper(instrumentation)
+ CommonTransitions.exitPipModeToHome(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .includeJankyRuns()
+ .build().run()
+ }
+
+ /**
+ * atest FlickerTests:DebugTest#exitPipModeToApp
+ */
+ @Test
+ fun exitPipModeToApp() {
+ val testApp = PipAppHelper(instrumentation)
+ CommonTransitions.exitPipModeToApp(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
+ .includeJankyRuns().build().run()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
deleted file mode 100644
index 6bbf684d567f..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.setDefaultWait;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.platform.helpers.IAppHelper;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.uiautomator.UiDevice;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionResult;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Base class of all Flicker test that performs common functions for all flicker tests:
- * <p>
- * - Caches transitions so that a transition is run once and the transition results are used by
- * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
- * multiple times.
- * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
- * - Fails tests if results are not available for any test due to jank.
- */
-public abstract class FlickerTestBase {
- public static final String TAG = "FLICKER";
- static final String SCREENSHOT_LAYER = "RotationLayer";
- static final String NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar";
- static final String STATUS_BAR_WINDOW_TITLE = "StatusBar";
- static final String DOCKED_STACK_DIVIDER = "DockedStackDivider";
- private static HashMap<String, List<TransitionResult>> transitionResults =
- new HashMap<>();
- IAppHelper mTestApp;
- UiDevice mUiDevice;
- private List<TransitionResult> mResults;
- private TransitionResult mLastResult = null;
-
- @Before
- public void setUp() {
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- }
-
- /**
- * Teardown any system settings and clean up test artifacts from the file system.
- *
- * Note: test artifacts for failed tests will remain on the device.
- */
- @AfterClass
- public static void teardown() {
- setDefaultWait();
- transitionResults.values().stream()
- .flatMap(List::stream)
- .forEach(result -> {
- if (result.canDelete()) {
- result.delete();
- } else {
- if (result.layersTraceExists()) {
- Log.e(TAG, "Layers trace saved to " + result.getLayersTracePath());
- }
- if (result.windowManagerTraceExists()) {
- Log.e(TAG, "WindowManager trace saved to " + result
- .getWindowManagerTracePath
- ());
- }
- if (result.screenCaptureVideoExists()) {
- Log.e(TAG, "Screen capture video saved to " + result
- .screenCaptureVideoPath().toString());
- }
- }
- });
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- void run(TransitionRunner transition) {
- if (transitionResults.containsKey(transition.getTestTag())) {
- mResults = transitionResults.get(transition.getTestTag());
- return;
- }
- mResults = transition.run().getResults();
- /* Fail if we don't have any results due to jank */
- assertWithMessage("No results to test because all transition runs were invalid because "
- + "of Jank").that(mResults).isNotEmpty();
- transitionResults.put(transition.getTestTag(), mResults);
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- @Before
- public void runTransition() {
- run(getTransitionToRun());
- }
-
- /**
- * Gets the transition that will be executed
- */
- abstract TransitionRunner getTransitionToRun();
-
- /**
- * Goes through a list of transition results and checks assertions on each result.
- */
- void checkResults(Consumer<TransitionResult> assertion) {
-
- for (TransitionResult result : mResults) {
- mLastResult = result;
- assertion.accept(result);
- }
- mLastResult = null;
- }
-
- /**
- * Kludge to mark a file for saving. If {@code checkResults} fails, the last result is not
- * cleared. This indicates the assertion failed for the result, so mark it for saving.
- */
- @After
- public void markArtifactsForSaving() {
- if (mLastResult != null) {
- mLastResult.flagForSaving();
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
new file mode 100644
index 000000000000..d7586d0db915
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.platform.helpers.IAppHelper
+import android.util.Log
+import androidx.test.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.google.common.truth.Truth
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Before
+
+/**
+ * Base class of all Flicker test that performs common functions for all flicker tests:
+ *
+ *
+ * - Caches transitions so that a transition is run once and the transition results are used by
+ * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
+ * multiple times.
+ * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
+ * - Fails tests if results are not available for any test due to jank.
+ */
+abstract class FlickerTestBase {
+ lateinit var testApp: IAppHelper
+ open val instrumentation by lazy {
+ InstrumentationRegistry.getInstrumentation()
+ }
+ val uiDevice by lazy {
+ UiDevice.getInstance(instrumentation)
+ }
+ lateinit var tesults: List<TransitionResult>
+ private var lastResult: TransitionResult? = null
+
+ /**
+ * Runs a transition, returns a cached result if the transition has run before.
+ */
+ fun run(transition: TransitionRunner) {
+ if (transitionResults.containsKey(transition.testTag)) {
+ tesults = transitionResults[transition.testTag]
+ ?: throw IllegalStateException("Results do not contain test tag " +
+ transition.testTag)
+ return
+ }
+ tesults = transition.run().results
+ /* Fail if we don't have any results due to jank */
+ Truth.assertWithMessage("No results to test because all transition runs were invalid " +
+ "because of Jank").that(tesults).isNotEmpty()
+ transitionResults[transition.testTag] = tesults
+ }
+
+ /**
+ * Runs a transition, returns a cached result if the transition has run before.
+ */
+ @Before
+ fun runTransition() {
+ run(transitionToRun)
+ }
+
+ /**
+ * Gets the transition that will be executed
+ */
+ abstract val transitionToRun: TransitionRunner
+
+ /**
+ * Goes through a list of transition results and checks assertions on each result.
+ */
+ fun checkResults(assertion: (TransitionResult) -> Unit) {
+ for (result in tesults) {
+ lastResult = result
+ assertion(result)
+ }
+ lastResult = null
+ }
+
+ /**
+ * Kludge to mark a file for saving. If `checkResults` fails, the last result is not
+ * cleared. This indicates the assertion failed for the result, so mark it for saving.
+ */
+ @After
+ fun markArtifactsForSaving() {
+ lastResult?.flagForSaving()
+ }
+
+ companion object {
+ const val TAG = "FLICKER"
+ const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
+ const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
+ const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+ private val transitionResults = mutableMapOf<String, List<TransitionResult>>()
+
+ /**
+ * Teardown any system settings and clean up test artifacts from the file system.
+ *
+ * Note: test artifacts for failed tests will remain on the device.
+ */
+ @AfterClass
+ @JvmStatic
+ fun teardown() {
+ AutomationUtils.setDefaultWait()
+ transitionResults.values
+ .flatten()
+ .forEach {
+ if (it.canDelete()) {
+ it.delete()
+ } else {
+ if (it.layersTraceExists()) {
+ Log.e(TAG, "Layers trace saved to ${it.layersTracePath}")
+ }
+ if (it.windowManagerTraceExists()) {
+ Log.e(TAG,
+ "WindowManager trace saved to ${it.windowManagerTracePath}")
+ }
+ if (it.screenCaptureVideoExists()) {
+ Log.e(TAG,
+ "Screen capture video saved to ${it.screenCaptureVideoPath()}")
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
deleted file mode 100644
index 54941dc0f585..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.filters.FlakyTest;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-public abstract class NonRotationTestBase extends FlickerTestBase {
-
- int mBeginRotation;
-
- public NonRotationTestBase(String beginRotationName, int beginRotation) {
- this.mBeginRotation = beginRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- for (int begin : supportedRotations) {
- params.add(new Object[]{rotationToString(begin), begin});
- }
-
- return params;
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect displayBounds = getDisplayBounds(mBeginRotation);
- checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
- displayBounds).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
new file mode 100644
index 000000000000..653fecd5219f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runners.Parameterized
+
+abstract class NonRotationTestBase(
+ beginRotationName: String,
+ protected val beginRotation: Int
+) : FlickerTestBase() {
+ @FlakyTest(bugId = 141361128)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkCoveredRegion_noUncoveredRegions() {
+ val displayBounds = WindowUtils.getDisplayBounds(beginRotation)
+ checkResults {
+ LayersTraceSubject.assertThat(it).coversRegion(
+ displayBounds).forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 141361128)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_navBarLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 141361128)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_statusBarLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ val params: MutableCollection<Array<Any>> = ArrayList()
+ for (begin in supportedRotations) {
+ params.add(arrayOf(Surface.rotationToString(begin), begin))
+ }
+ return params
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
deleted file mode 100644
index c150e0994316..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppCold;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test cold launch app from launcher.
- * To run this test: {@code atest FlickerTests:OpenAppColdTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppColdTest extends NonRotationTestBase {
-
- public OpenAppColdTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return openAppCold(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_wallpaperWindowBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
deleted file mode 100644
index 00da62fe2ee5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.appToSplitScreen;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:OpenAppToSplitScreenTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppToSplitScreenTest extends NonRotationTestBase {
-
- public OpenAppToSplitScreenTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return appToSplitScreen(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns()
- .build();
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
deleted file mode 100644
index 62ae254709b1..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppWarm;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test warm launch app.
- * To run this test: {@code atest FlickerTests:OpenAppWarmTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppWarmTest extends NonRotationTestBase {
-
- public OpenAppWarmTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return openAppWarm(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_wallpaperBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
deleted file mode 100644
index fcb022c280da..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window opening transitions.
- * To run this test: {@code atest FlickerTests:OpenImeWindowTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenImeWindowTest extends NonRotationTestBase {
-
- private static final String IME_WINDOW_TITLE = "InputMethod";
-
- public OpenImeWindowTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return editTextSetFocus((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .hidesImeWindow(IME_WINDOW_TITLE)
- .then()
- .showsImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipTestBase.java
deleted file mode 100644
index cf51d780d7d2..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/PipTestBase.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.closePipWindow;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.hasPipWindow;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.uiautomator.UiDevice;
-
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.AfterClass;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public abstract class PipTestBase extends NonRotationTestBase {
- static final String sPipWindowTitle = "PipMenuActivity";
-
- public PipTestBase(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @AfterClass
- public static void teardown() {
- UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- if (hasPipWindow(device)) {
- closePipWindow(device);
- }
- }
-
- @Test
- public void checkVisibility_pipWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .hidesAppWindow(sPipWindowTitle)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_pipLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsLayer(sPipWindowTitle)
- .then()
- .hidesLayer(sPipWindowTitle)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java
deleted file mode 100644
index 5e67ada5ff55..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToApp;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test Pip launch.
- * To run this test: {@code atest FlickerTests:PipToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 152738416)
-@Ignore("Waiting bug feedback")
-public class PipToAppTest extends PipTestBase {
- public PipToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return exitPipModeToApp((PipAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .then()
- .hidesAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java
deleted file mode 100644
index af713c7b39b7..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToHome;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test Pip launch.
- * To run this test: {@code atest FlickerTests:PipToHomeTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 152738416)
-@Ignore("Waiting bug feedback")
-public class PipToHomeTest extends PipTestBase {
- public PipToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build();
- }
-
- @Ignore
- @Test
- public void checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop("Wallpaper")
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
deleted file mode 100644
index 9516af624f6f..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.resizeSplitScreen;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getDockedStackDividerInset;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarHeight;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.isInSplitScreen;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.Instrumentation;
-import android.graphics.Rect;
-import android.util.Rational;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiDevice;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.AfterClass;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test split screen resizing window transitions.
- * To run this test: {@code atest FlickerTests:ResizeSplitScreenTest}
- *
- * Currently it runs only in 0 degrees because of b/156100803
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 159096424)
-@Ignore("Waiting bug feedback")
-public class ResizeSplitScreenTest extends FlickerTestBase {
-
- private static String sSimpleActivity = "SimpleActivity";
- private static String sImeActivity = "ImeActivity";
-
- public ResizeSplitScreenTest() {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- Instrumentation instr = InstrumentationRegistry.getInstrumentation();
- ImeAppHelper bottomApp = new ImeAppHelper(instr);
- return resizeSplitScreen(instr, mTestApp, bottomApp, mUiDevice, Surface.ROTATION_0,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkVisibility_topAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_bottomAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sImeActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- @Ignore("Waiting feedback")
- public void checkPosition_appsStartingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath(), result.getLayersTraceChecksum());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect startingDividerBounds = entries.getEntries().get(0).getVisibleBounds
- (DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, startingDividerBounds.right,
- startingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- startingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
- .inTheBeginning();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
- .inTheBeginning();
- });
- }
-
- @Test
- @Ignore("Waiting feedback")
- public void checkPosition_appsEndingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath(), result.getLayersTraceChecksum());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect endingDividerBounds = entries.getEntries().get(
- entries.getEntries().size() - 1).getVisibleBounds(
- DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, endingDividerBounds.right,
- endingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- endingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
- .atTheEnd();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
- .atTheEnd();
- });
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- @FlakyTest(bugId = 156223549)
- @Ignore("Waiting bug feedback")
- public void checkVisibility_topAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- @FlakyTest(bugId = 156223549)
- @Ignore("Waiting bug feedback")
- public void checkVisibility_bottomAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sImeActivity)
- .forAllEntries());
- }
-
- @AfterClass
- public static void teardown() {
- UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- if (isInSplitScreen(device)) {
- exitSplitScreen(device);
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
new file mode 100644
index 000000000000..873d60771cb4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runners.Parameterized
+
+abstract class RotationTestBase(
+ beginRotationName: String,
+ endRotationName: String,
+ protected val beginRotation: Int,
+ protected val endRotation: Int
+) : FlickerTestBase() {
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_navBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_statusBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkPosition_navBarLayerRotatesAndScales() {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+ if (startingPos == endingPos) {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ .forAllEntries()
+ }
+ } else {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ .inTheBeginning()
+ }
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ .atTheEnd()
+ }
+ }
+ }
+
+ @Test
+ fun checkPosition_statusBarLayerRotatesScales() {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
+ .inTheBeginning()
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd()
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_navBarLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkVisibility_statusBarLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ companion object {
+ const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}-{1}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ val params: MutableCollection<Array<Any>> = mutableListOf()
+ for (begin in supportedRotations) {
+ for (end in supportedRotations) {
+ if (begin != end) {
+ params.add(arrayOf(
+ Surface.rotationToString(begin),
+ Surface.rotationToString(end),
+ begin,
+ end
+ ))
+ }
+ }
+ }
+ return params
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
deleted file mode 100644
index 3cff8683eca5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.EXTRA_STARVE_UI_THREAD;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME;
-
-import android.content.Intent;
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations using seamless rotations.
- * To run this test: {@code atest FlickerTests:SeamlessAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 147659548)
-@Ignore("Waiting bug feedback")
-public class SeamlessAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
- private Intent mIntent;
-
- public SeamlessAppRotationTest(String testId, Intent intent, int beginRotation,
- int endRotation) {
- this.mIntent = intent;
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- ArrayList<Intent> testIntents = new ArrayList<>();
-
- // launch test activity that supports seamless rotation
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(SEAMLESS_ACTIVITY_COMPONENT_NAME);
- testIntents.add(intent);
-
- // launch test activity that supports seamless rotation with a busy UI thread to miss frames
- // when the app is asked to redraw
- intent = new Intent(intent);
- intent.putExtra(EXTRA_STARVE_UI_THREAD, true);
- testIntents.add(intent);
-
- for (Intent testIntent : testIntents) {
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- String testId = rotationToString(begin) + "_" + rotationToString(end);
- if (testIntent.getExtras() != null &&
- testIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- testId += "_" + "BUSY_UI_THREAD";
- }
- params.add(new Object[]{testId, testIntent, begin, end});
- }
- }
- }
- }
- return params;
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- String intentId = "";
- if (mIntent.getExtras() != null &&
- mIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- intentId = "BUSY_UI_THREAD";
- }
-
- return changeAppRotation(mIntent, intentId, InstrumentationRegistry.getContext(),
- mUiDevice, mBeginRotation, mEndRotation).build();
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning());
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- .atTheEnd());
- }
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .then()
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), endingPos)
- .forAllEntries());
- }
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect startingBounds = getDisplayBounds(mBeginRotation);
- Rect endingBounds = getDisplayBounds(mEndRotation);
- if (startingBounds.equals(endingBounds)) {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .forAllEntries());
- } else {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .then()
- .coversRegion(endingBounds)
- .forAllEntries());
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
deleted file mode 100644
index 9e9c82903b51..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.splitScreenToLauncher;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.isInSplitScreen;
-
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiDevice;
-
-import org.junit.AfterClass;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:SplitScreenToLauncherTest}
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class SplitScreenToLauncherTest extends FlickerTestBase {
-
- public SplitScreenToLauncherTest() {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Override
- TransitionRunner getTransitionToRun() {
- return splitScreenToLauncher(mTestApp, mUiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build();
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(getDisplayBounds()).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_appLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @AfterClass
- public static void teardown() {
- UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- if (isInSplitScreen(device)) {
- exitSplitScreen(device);
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
index 42977f549162..e579533d2bb7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.helpers;
+package com.android.server.wm.flicker.helpers
-import android.app.Instrumentation;
+import android.app.Instrumentation
+import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.StandardAppHelper;
-
-public abstract class FlickerAppHelper extends StandardAppHelper {
-
- static int sFindTimeout = 10000;
- static String sFlickerPackage = "com.android.server.wm.flicker.testapp";
-
- public FlickerAppHelper(Instrumentation instr, String launcherName) {
- super(instr, sFlickerPackage, launcherName);
+abstract class FlickerAppHelper(
+ instr: Instrumentation,
+ launcherName: String
+) : StandardAppHelper(instr, sFlickerPackage, launcherName) {
+ companion object {
+ var sFindTimeout = 10000
+ var sFlickerPackage = "com.android.server.wm.flicker.testapp"
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index 1b2c48405f6e..d587f1e383c5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,19 +14,13 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.helpers;
+package com.android.server.wm.flicker.helpers
-import android.app.Instrumentation;
+import android.app.Instrumentation
+import androidx.test.uiautomator.UiDevice
-import androidx.test.uiautomator.UiDevice;
-
-public class ImeAppAutoFocusHelper extends ImeAppHelper {
-
- public ImeAppAutoFocusHelper(Instrumentation instr) {
- super(instr, "ImeAppAutoFocus");
- }
-
- public void openIME(UiDevice device) {
+class ImeAppAutoFocusHelper(instr: Instrumentation) : ImeAppHelper(instr, "ImeAppAutoFocus") {
+ override fun openIME(device: UiDevice) {
// do nothing (the app is focused automatically)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
deleted file mode 100644
index 095722d59fc7..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-public class ImeAppHelper extends FlickerAppHelper {
-
- ImeAppHelper(Instrumentation instr, String launcherName) {
- super(instr, launcherName);
- }
-
- public ImeAppHelper(Instrumentation instr) {
- this(instr, "ImeApp");
- }
-
- public void openIME(UiDevice device) {
- UiObject2 editText = device.wait(
- Until.findObject(By.res(getPackage(), "plain_text_input")),
- AutomationUtils.FIND_TIMEOUT);
- assertNotNull("Text field not found, this usually happens when the device was left "
- + "in an unknown state (e.g. in split screen)", editText);
- editText.click();
-
- if (!AutomationUtils.waitForIME(device)) {
- fail("IME did not appear");
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
new file mode 100644
index 000000000000..979cbeaca539
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import org.junit.Assert
+
+open class ImeAppHelper(
+ instr: Instrumentation,
+ launcherName: String = "ImeApp"
+) : FlickerAppHelper(instr, launcherName) {
+ open fun openIME(device: UiDevice) {
+ val editText = device.wait(
+ Until.findObject(By.res(getPackage(), "plain_text_input")),
+ AutomationUtils.FIND_TIMEOUT)
+ Assert.assertNotNull("Text field not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", editText)
+ editText.click()
+ if (!AutomationUtils.waitForIME(device)) {
+ Assert.fail("IME did not appear")
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
deleted file mode 100644
index f2b7a7e351fc..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.hasPipWindow;
-
-import static org.junit.Assert.assertNotNull;
-
-import android.app.Instrumentation;
-
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-
-public class PipAppHelper extends FlickerAppHelper {
-
- public PipAppHelper(Instrumentation instr) {
- super(instr, "PipApp");
- }
-
- public void clickEnterPipButton(UiDevice device) {
- UiObject2 enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"));
- assertNotNull("Pip button not found, this usually happens when the device was left "
- + "in an unknown state (e.g. in split screen)", enterPipButton);
- enterPipButton.click();
- hasPipWindow(device);
- }
-
- public void closePipWindow(UiDevice device) {
- AutomationUtils.closePipWindow(device);
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
new file mode 100644
index 000000000000..daee810b6899
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import org.junit.Assert
+
+class PipAppHelper(instr: Instrumentation) : FlickerAppHelper(instr, "PipApp") {
+ fun clickEnterPipButton(device: UiDevice) {
+ val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
+ Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", enterPipButton)
+ enterPipButton.click()
+ AutomationUtils.hasPipWindow(device)
+ }
+
+ fun closePipWindow(device: UiDevice) {
+ AutomationUtils.closePipWindow(device)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
new file mode 100644
index 000000000000..6946618806b8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseImeAutoOpenWindowToAppTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : CloseImeWindowToAppTest(beginRotationName, beginRotation) {
+ init {
+ testApp = ImeAppAutoFocusHelper(instrumentation)
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppAutoFocusHelper,
+ instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @FlakyTest(bugId = 141458352)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeLayerBecomesInvisible() {
+ super.checkVisibility_imeLayerBecomesInvisible()
+ }
+
+ @FlakyTest(bugId = 141458352)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeAppLayerIsAlwaysVisible() {
+ super.checkVisibility_imeAppLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 141458352)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeAppWindowIsAlwaysVisible() {
+ super.checkVisibility_imeAppWindowIsAlwaysVisible()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
new file mode 100644
index 000000000000..a1030d8248b7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseImeAutoOpenWindowToHomeTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : CloseImeWindowToHomeTest(beginRotationName, beginRotation) {
+ init {
+ testApp = ImeAppAutoFocusHelper(instrumentation)
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppAutoFocusHelper,
+ instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @FlakyTest(bugId = 141458352)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeWindowBecomesInvisible() {
+ super.checkVisibility_imeWindowBecomesInvisible()
+ }
+
+ @FlakyTest(bugId = 141458352)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeLayerBecomesInvisible() {
+ super.checkVisibility_imeLayerBecomesInvisible()
+ }
+
+ @FlakyTest(bugId = 157449248)
+ @Ignore("Waiting bug feedback")
+ @Test
+ override fun checkVisibility_imeAppWindowBecomesInvisible() {
+ super.checkVisibility_imeAppWindowBecomesInvisible()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
new file mode 100644
index 000000000000..6e7c92b97bfb
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class CloseImeWindowToAppTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = ImeAppHelper(instrumentation)
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppHelper,
+ instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Ignore("Flaky. Pending debug")
+ @Test
+ open fun checkVisibility_imeLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(IME_WINDOW_TITLE)
+ .then()
+ .hidesLayer(IME_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ open fun checkVisibility_imeAppLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ open fun checkVisibility_imeAppWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindowOnTop(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ companion object {
+ const val IME_WINDOW_TITLE = "InputMethod"
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
new file mode 100644
index 000000000000..7b155ebd93e1
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing to home transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class CloseImeWindowToHomeTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = ImeAppHelper(instrumentation)
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppHelper,
+ instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ open fun checkVisibility_imeWindowBecomesInvisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsImeWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesImeWindow(IME_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 153739621)
+ @Ignore
+ @Test
+ open fun checkVisibility_imeLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .showsLayer(IME_WINDOW_TITLE)
+ .then()
+ .hidesLayer(IME_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 153739621)
+ @Ignore
+ @Test
+ fun checkVisibility_imeAppLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ open fun checkVisibility_imeAppWindowBecomesInvisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .hidesAppWindowOnTop(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ companion object {
+ const val IME_WINDOW_TITLE: String = "InputMethod"
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
new file mode 100644
index 000000000000..9885359a0fb7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTests:OpenImeWindowTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenImeWindowTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = ImeAppHelper(instrumentation)
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.editTextSetFocus(testApp as ImeAppHelper,
+ instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ fun checkVisibility_imeWindowBecomesVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .hidesImeWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsImeWindow(IME_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_imeLayerBecomesVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hidesLayer(IME_WINDOW_TITLE)
+ .then()
+ .showsLayer(IME_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ companion object {
+ private const val IME_WINDOW_TITLE = "InputMethod"
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
new file mode 100644
index 000000000000..943a52592910
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launch app from launcher.
+ * To run this test: `atest FlickerTests:OpenAppColdTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenAppColdTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ fun checkVisibility_wallpaperWindowBecomesInvisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ .forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindowOnTop(
+ "com.android.launcher3/.Launcher")
+ .then()
+ .showsAppWindowOnTop(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_wallpaperLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
new file mode 100644
index 000000000000..7964d949e737
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test warm launch app.
+ * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenAppWarmTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ fun checkVisibility_wallpaperBecomesInvisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ .forAllEntries()
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Ignore("Waiting bug feedback")
+ @Test
+ fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindowOnTop(
+ "com.android.launcher3/.Launcher")
+ .then()
+ .showsAppWindowOnTop(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_wallpaperLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
new file mode 100644
index 000000000000..79321f9488ad
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.pip
+
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import org.junit.AfterClass
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+abstract class PipTestBase(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = PipAppHelper(instrumentation)
+ }
+
+ @Test
+ fun checkVisibility_pipWindowBecomesVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .showsAppWindowOnTop(sPipWindowTitle)
+ .then()
+ .hidesAppWindow(sPipWindowTitle)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_pipLayerBecomesVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .showsLayer(sPipWindowTitle)
+ .then()
+ .hidesLayer(sPipWindowTitle)
+ .forAllEntries()
+ }
+ }
+
+ companion object {
+ const val sPipWindowTitle = "PipMenuActivity"
+
+ @AfterClass
+ @JvmStatic
+ fun teardown() {
+ val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ if (AutomationUtils.hasPipWindow(device)) {
+ AutomationUtils.closePipWindow(device)
+ }
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
new file mode 100644
index 000000000000..bfececa72d4e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.pip
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 152738416)
+@Ignore("Waiting bug feedback")
+class PipToAppTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : PipTestBase(beginRotationName, beginRotation) {
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.exitPipModeToApp(testApp as PipAppHelper, instrumentation,
+ uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .skipUntilFirstAssertion()
+ .showsAppWindowOnTop(sPipWindowTitle)
+ .then()
+ .showsBelowAppWindow("Wallpaper")
+ .then()
+ .showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .hidesAppWindowOnTop(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
new file mode 100644
index 000000000000..ecfcd8298c3f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.pip
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest FlickerTests:PipToHomeTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 152738416)
+@Ignore("Waiting bug feedback")
+class PipToHomeTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : PipTestBase(beginRotationName, beginRotation) {
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.exitPipModeToHome(testApp as PipAppHelper, instrumentation,
+ uiDevice, beginRotation)
+ .includeJankyRuns().build()
+
+ @Ignore
+ @Test
+ fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindowOnTop(sPipWindowTitle)
+ .then()
+ .showsBelowAppWindow("Wallpaper")
+ .then()
+ .showsAppWindowOnTop("Wallpaper")
+ .forAllEntries()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
new file mode 100644
index 000000000000..7a581d066c2b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.util.Log
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.RotationTestBase
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WindowUtils
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations.
+ * To run this test: `atest FlickerTest:ChangeAppRotationTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ChangeAppRotationTest(
+ beginRotationName: String,
+ endRotationName: String,
+ beginRotation: Int,
+ endRotation: Int
+) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
+ init {
+ testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice,
+ beginRotation, endRotation)
+ .includeJankyRuns().build()
+
+ @Test
+ fun checkPosition_appLayerRotates() {
+ val startingPos = WindowUtils.getAppPosition(beginRotation)
+ val endingPos = WindowUtils.getAppPosition(endRotation)
+ Log.e(TAG, "startingPos=$startingPos endingPos=$endingPos")
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(testApp.getPackage(), startingPos).inTheBeginning()
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(testApp.getPackage(), endingPos).atTheEnd()
+ }
+ }
+
+ @Ignore("Flaky. Pending debug")
+ @Test
+ fun checkVisibility_screenshotLayerBecomesInvisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(testApp.getPackage())
+ .then()
+ .replaceVisibleLayer(testApp.getPackage(), SCREENSHOT_LAYER)
+ .then()
+ .showsLayer(testApp.getPackage()).and().showsLayer(SCREENSHOT_LAYER)
+ .then()
+ .replaceVisibleLayer(SCREENSHOT_LAYER, testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
new file mode 100644
index 000000000000..d53af6f53bf2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.content.Intent
+import android.view.Surface
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.RotationTestBase
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations using seamless rotations.
+ * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 147659548)
+@Ignore("Waiting bug feedback")
+class SeamlessAppRotationTest(
+ private val intent: Intent,
+ beginRotationName: String,
+ endRotationName: String,
+ beginRotation: Int,
+ endRotation: Int
+) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
+ override val transitionToRun: TransitionRunner
+ get() {
+ var intentId = ""
+ if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
+ intentId = "BUSY_UI_THREAD"
+ }
+ return CommonTransitions.changeAppRotation(intent, intentId,
+ InstrumentationRegistry.getContext(), instrumentation, uiDevice,
+ beginRotation, endRotation).build()
+ }
+
+ @Test
+ fun checkPosition_appLayerRotates() {
+ val startingPos = WindowUtils.getAppPosition(beginRotation)
+ val endingPos = WindowUtils.getAppPosition(endRotation)
+ if (startingPos == endingPos) {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
+ .forAllEntries()
+ }
+ } else {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
+ .then()
+ .hasVisibleRegion(intent.component?.packageName ?: "", endingPos)
+ .forAllEntries()
+ }
+ }
+ }
+
+ @Test
+ fun checkCoveredRegion_noUncoveredRegions() {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (startingBounds == endingBounds) {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .coversRegion(startingBounds)
+ .forAllEntries()
+ }
+ } else {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .coversRegion(startingBounds)
+ .then()
+ .coversRegion(endingBounds)
+ .forAllEntries()
+ }
+ }
+ }
+
+ companion object {
+ // launch test activity that supports seamless rotation
+
+ // launch test activity that supports seamless rotation with a busy UI thread to miss frames
+ // when the app is asked to redraw
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ val params: MutableCollection<Array<Any>> = ArrayList()
+ val testIntents = ArrayList<Intent>()
+
+ // launch test activity that supports seamless rotation
+ var intent = Intent(Intent.ACTION_MAIN)
+ intent.component = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME
+ testIntents.add(intent)
+
+ // launch test activity that supports seamless rotation with a busy UI thread to miss frames
+ // when the app is asked to redraw
+ intent = Intent(intent)
+ intent.putExtra(ActivityOptions.EXTRA_STARVE_UI_THREAD, true)
+ testIntents.add(intent)
+ for (testIntent in testIntents) {
+ for (begin in supportedRotations) {
+ for (end in supportedRotations) {
+ if (begin != end) {
+ var testId: String = Surface.rotationToString(begin) +
+ "_" + Surface.rotationToString(end)
+ if (testIntent.extras?.getBoolean(
+ ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
+ testId += "_" + "BUSY_UI_THREAD"
+ }
+ params.add(arrayOf(testId, testIntent, begin, end))
+ }
+ }
+ }
+ }
+ return params
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
new file mode 100644
index 000000000000..b5611a45a2e7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.splitscreen
+
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WmTraceSubject
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenAppToSplitScreenTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
+ beginRotation).includeJankyRuns().build()
+
+ @Test
+ fun checkVisibility_navBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_statusBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_dividerLayerBecomesVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ .forAllEntries()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
new file mode 100644
index 000000000000..b6cce266ab88
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.splitscreen
+
+import android.graphics.Region
+import android.util.Rational
+import android.view.Surface
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.FlickerTestBase
+import com.android.server.wm.flicker.LayersTrace
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.TransitionResult
+import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.google.common.truth.Truth
+import org.junit.AfterClass
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+
+/**
+ * Test split screen resizing window transitions.
+ * To run this test: `atest FlickerTests:ResizeSplitScreenTest`
+ *
+ * Currently it runs only in 0 degrees because of b/156100803
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 159096424)
+@Ignore("Waiting bug feedback")
+class ResizeSplitScreenTest : FlickerTestBase() {
+ init {
+ testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() {
+ val bottomApp = ImeAppHelper(instrumentation)
+ return CommonTransitions.resizeSplitScreen(testApp, bottomApp, instrumentation,
+ uiDevice, Surface.ROTATION_0,
+ Rational(1, 3), Rational(2, 3))
+ .includeJankyRuns().build()
+ }
+
+ @Test
+ fun checkVisibility_topAppLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(sSimpleActivity)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_bottomAppLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(sImeActivity)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_dividerLayerIsAlwaysVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ @Ignore("Waiting feedback")
+ fun checkPosition_appsStartingBounds() {
+ val displayBounds = WindowUtils.getDisplayBounds()
+ checkResults { result: TransitionResult ->
+ val entries = LayersTrace.parseFrom(result.layersTrace,
+ result.layersTracePath, result.layersTraceChecksum)
+ Truth.assertThat(entries.entries).isNotEmpty()
+ val startingDividerBounds = entries.entries[0].getVisibleBounds(
+ DOCKED_STACK_DIVIDER).bounds
+ val startingTopAppBounds = Region(0, 0, startingDividerBounds.right,
+ startingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
+ val startingBottomAppBounds = Region(0,
+ startingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.getNavigationBarHeight())
+ LayersTraceSubject.assertThat(result)
+ .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
+ .inTheBeginning()
+ LayersTraceSubject.assertThat(result)
+ .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
+ .inTheBeginning()
+ }
+ }
+
+ @Test
+ @Ignore("Waiting feedback")
+ fun checkPosition_appsEndingBounds() {
+ val displayBounds = WindowUtils.getDisplayBounds()
+ checkResults { result: TransitionResult ->
+ val entries = LayersTrace.parseFrom(result.layersTrace,
+ result.layersTracePath, result.layersTraceChecksum)
+ Truth.assertThat(entries.entries).isNotEmpty()
+ val endingDividerBounds = entries.entries[entries.entries.size - 1].getVisibleBounds(
+ DOCKED_STACK_DIVIDER).bounds
+ val startingTopAppBounds = Region(0, 0, endingDividerBounds.right,
+ endingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
+ val startingBottomAppBounds = Region(0,
+ endingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.getNavigationBarHeight())
+ LayersTraceSubject.assertThat(result)
+ .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
+ .atTheEnd()
+ LayersTraceSubject.assertThat(result)
+ .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
+ .atTheEnd()
+ }
+ }
+
+ @Test
+ fun checkVisibility_navBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_statusBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ @FlakyTest(bugId = 156223549)
+ @Ignore("Waiting bug feedback")
+ fun checkVisibility_topAppWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindow(sSimpleActivity)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ @FlakyTest(bugId = 156223549)
+ @Ignore("Waiting bug feedback")
+ fun checkVisibility_bottomAppWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindow(sImeActivity)
+ .forAllEntries()
+ }
+ }
+
+ companion object {
+ private const val sSimpleActivity = "SimpleActivity"
+ private const val sImeActivity = "ImeActivity"
+
+ @AfterClass
+ @JvmStatic
+ fun teardown() {
+ val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ if (AutomationUtils.isInSplitScreen(device)) {
+ AutomationUtils.exitSplitScreen(device)
+ }
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
new file mode 100644
index 000000000000..fdcafdb12a78
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.splitscreen
+
+import android.view.Surface
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.CommonTransitions
+import com.android.server.wm.flicker.FlickerTestBase
+import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.helpers.AutomationUtils
+import org.junit.AfterClass
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class SplitScreenToLauncherTest : FlickerTestBase() {
+ init {
+ testApp = StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ }
+
+ override val transitionToRun: TransitionRunner
+ get() = CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
+ Surface.ROTATION_0).includeJankyRuns().build()
+
+ @Test
+ fun checkCoveredRegion_noUncoveredRegions() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .coversRegion(WindowUtils.getDisplayBounds()).forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_dividerLayerBecomesInVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_appLayerBecomesInVisible() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ .forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_navBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ @Test
+ fun checkVisibility_statusBarWindowIsAlwaysVisible() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ }
+ }
+
+ companion object {
+ @AfterClass
+ @JvmStatic
+ fun teardown() {
+ val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ if (AutomationUtils.isInSplitScreen(device)) {
+ AutomationUtils.exitSplitScreen(device)
+ }
+ }
+ }
+}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 55bbe22c4d86..c2fd0c39221e 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -453,6 +453,32 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
+ @Test
+ public void testExpireApexRollback() throws Exception {
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ pushTestApex();
+
+ // Push files to apex data directory
+ String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 =
+ apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
+ assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+
+ // Install new version of the APEX with rollback enabled
+ runPhase("testRollbackApexDataDirectories_Phase1");
+ getDevice().reboot();
+
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // Expire all rollbacks and check CE snapshot directories are deleted
+ runPhase("testCleanUp");
+ for (String dir : after) {
+ assertNull(getDevice().getFileEntry(dir));
+ }
+ }
+
private void pushTestApex() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index a230de46dcf3..4c741c49cfdb 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -25,6 +25,7 @@
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::OneofDescriptor;
using google::protobuf::EnumDescriptor;
using google::protobuf::FieldDescriptor;
using google::protobuf::FileDescriptor;
@@ -396,16 +397,14 @@ int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>
collate_enums(*field->enum_type(), &atField);
}
- // Generate signature for pushed atoms
- if (atomDecl->code < PULL_ATOM_START_ID) {
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature->push_back(JAVA_TYPE_INT);
- } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
- signature->push_back(JAVA_TYPE_BYTE_ARRAY);
- } else {
- signature->push_back(javaType);
- }
+ // Generate signature for atom.
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ signature->push_back(JAVA_TYPE_INT);
+ } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+ signature->push_back(JAVA_TYPE_BYTE_ARRAY);
+ } else {
+ signature->push_back(javaType);
}
atomDecl->fields.push_back(atField);
@@ -518,8 +517,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
shared_ptr<AtomDecl> atomDecl =
make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
- if (atomDecl->code < PULL_ATOM_START_ID &&
- atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
+ if (atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
AnnotationValue(true));
@@ -537,7 +535,24 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
continue;
}
- FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = atoms->signatureInfoMap[signature];
+ const OneofDescriptor* oneofAtom = atomField->containing_oneof();
+ if (oneofAtom == nullptr) {
+ print_error(atomField, "Atom is not declared in a `oneof` field: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
+ else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
+ (oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
+ print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
+
+ FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = oneofAtom->name() ==
+ ONEOF_PUSHED_ATOM_NAME ? atoms->signatureInfoMap[signature] :
+ atoms->pulledAtomsSignatureInfoMap[signature];
populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
atoms->decls.insert(atomDecl);
@@ -556,6 +571,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
}
if (dbg) {
+ // Signatures for pushed atoms.
printf("signatures = [\n");
for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
it != atoms->signatureInfoMap.end(); it++) {
@@ -566,6 +582,17 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
}
printf("\n");
}
+
+ // Signatures for pull atoms.
+ for (SignatureInfoMap::const_iterator it = atoms->pulledAtomsSignatureInfoMap.begin();
+ it != atoms->pulledAtomsSignatureInfoMap.end(); it++) {
+ printf(" ");
+ for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
+ jt++) {
+ printf(" %d", (int)*jt);
+ }
+ printf("\n");
+ }
printf("]\n");
}
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 10b34ecf5f54..e637ed945a08 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -29,6 +29,7 @@
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::OneofDescriptor;
using google::protobuf::Descriptor;
using google::protobuf::FieldDescriptor;
using std::map;
@@ -41,6 +42,14 @@ const int PULL_ATOM_START_ID = 10000;
const int FIRST_UID_IN_CHAIN_ID = 0;
+/**
+ * The types of oneof atoms.
+ *
+ * `OneofDescriptor::name()` returns the name of the oneof.
+ */
+const string ONEOF_PUSHED_ATOM_NAME = "pushed";
+const string ONEOF_PULLED_ATOM_NAME = "pulled";
+
enum AnnotationId : uint8_t {
ANNOTATION_ID_IS_UID = 1,
ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2,
@@ -184,6 +193,7 @@ using SignatureInfoMap = map<vector<java_type_t>, FieldNumberToAtomDeclSet>;
struct Atoms {
SignatureInfoMap signatureInfoMap;
+ SignatureInfoMap pulledAtomsSignatureInfoMap;
AtomDeclSet decls;
AtomDeclSet non_chained_decls;
SignatureInfoMap nonChainedSignatureInfoMap;
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index f4c937c3f599..ffbe9f800736 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -96,29 +96,160 @@ static void write_annotations(FILE* out, int argIndex,
}
}
+static void write_method_signature(FILE* out, const vector<java_type_t>& signature,
+ const AtomDecl& attributionDecl) {
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+ chainField.name.c_str());
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", android.util.SparseArray<Object> valueMap");
+ } else {
+ fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ }
+ argIndex++;
+ }
+}
+
+static int write_method_body(FILE* out, const vector<java_type_t>& signature,
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
+ const AtomDecl& attributionDecl, const string& indent) {
+ // Start StatsEvent.Builder.
+ fprintf(out,
+ "%s final StatsEvent.Builder builder = "
+ "StatsEvent.newBuilder();\n",
+ indent.c_str());
+
+ // Write atom code.
+ fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
+
+ // Write the args.
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
+ "arg%d);\n",
+ indent.c_str(), argIndex, argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+
+ fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
+ fprintf(out, "%s null == %s ? new int[0] : %s,\n",
+ indent.c_str(), uidName, uidName);
+ fprintf(out, "%s null == %s ? new String[0] : %s);\n",
+ indent.c_str(), tagName, tagName);
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ fprintf(out, "\n");
+ fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
+ fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
+ fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
+ fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
+ fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s intMap = new "
+ "android.util.SparseIntArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s intMap.put(key, (Integer) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Long) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s longMap = new "
+ "android.util.SparseLongArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s longMap.put(key, (Long) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof String) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s stringMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s stringMap.put(key, (String) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Float) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s floatMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s floatMap.put(key, (Float) value);\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out,
+ "%s builder.writeKeyValuePairs("
+ "intMap, longMap, stringMap, floatMap);\n",
+ indent.c_str());
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
+ argIndex++;
+ }
+ return 0;
+}
+
static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write(int code");
- const vector<java_type_t>& signature = signatureInfoMapIt->first;
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
- chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> valueMap");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
+ write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
@@ -128,130 +259,13 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
indent = " ";
}
- // Start StatsEvent.Builder.
- fprintf(out,
- "%s final StatsEvent.Builder builder = "
- "StatsEvent.newBuilder();\n",
- indent.c_str());
-
- // Write atom code.
- fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
-
- // Write the args.
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
- "arg%d);\n",
- indent.c_str(), argIndex, argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
- fprintf(out, "%s null == %s ? new int[0] : %s,\n",
- indent.c_str(), uidName, uidName);
- fprintf(out, "%s null == %s ? new String[0] : %s);\n",
- indent.c_str(), tagName, tagName);
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- fprintf(out, "\n");
- fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
- fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
- indent.c_str());
- fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out,
- "%s intMap = new "
- "android.util.SparseIntArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s intMap.put(key, (Integer) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Long) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new "
- "android.util.SparseLongArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s longMap.put(key, (Long) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof String) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s stringMap.put(key, (String) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Float) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s floatMap.put(key, (Float) value);\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out,
- "%s builder.writeKeyValuePairs("
- "intMap, longMap, stringMap, floatMap);\n",
- indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
- argIndex++;
+ int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ attributionDecl, indent);
+ if (ret != 0) {
+ return ret;
}
-
fprintf(out, "\n");
+
fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
@@ -259,9 +273,9 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
if (supportQ) {
fprintf(out, " } else {\n");
fprintf(out, " QLogger.write(code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signatureInfoMapIt->first.begin();
+ arg != signatureInfoMapIt->first.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -285,6 +299,32 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
return 0;
}
+static int write_java_build_stats_event_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ // Print method signature.
+ fprintf(out, " public static StatsEvent buildStatsEvent(int code");
+ write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ fprintf(out, ") {\n");
+
+ // Print method body.
+ string indent("");
+ int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ attributionDecl, indent);
+ if (ret != 0) {
+ return ret;
+ }
+ fprintf(out, "\n");
+
+ fprintf(out, "%s return builder.build();\n", indent.c_str());
+
+ fprintf(out, " }\n"); // method
+ fprintf(out, "\n");
+ }
+ return 0;
+}
+
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaPackage, const bool supportQ,
const bool supportWorkSource) {
@@ -319,6 +359,8 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attribut
fprintf(out, " // Write methods\n");
errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
+ errors += write_java_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ attributionDecl);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
}
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index aaa488e44fee..e658b62b8daa 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -58,7 +58,7 @@ message AllTypesAtom {
}
message Event {
- oneof event {
+ oneof pushed {
OutOfOrderAtom out_of_order_atom = 2;
IntAtom int_atom = 1;
AnotherIntAtom another_int_atom = 3;
@@ -74,7 +74,7 @@ message BadTypesAtom {
}
message BadTypesEvent {
- oneof event {
+ oneof pushed {
BadTypesAtom bad_types_atom = 1;
}
}
@@ -84,7 +84,7 @@ message BadSkippedFieldSingleAtom {
}
message BadSkippedFieldSingle {
- oneof event {
+ oneof pushed {
BadSkippedFieldSingleAtom bad = 1;
}
}
@@ -96,7 +96,7 @@ message BadSkippedFieldMultipleAtom {
}
message BadSkippedFieldMultiple {
- oneof event {
+ oneof pushed {
BadSkippedFieldMultipleAtom bad = 1;
}
}
@@ -107,11 +107,11 @@ message BadAttributionNodePositionAtom {
}
message BadAttributionNodePosition {
- oneof event { BadAttributionNodePositionAtom bad = 1; }
+ oneof pushed { BadAttributionNodePositionAtom bad = 1; }
}
message GoodEventWithBinaryFieldAtom {
- oneof event { GoodBinaryFieldAtom field1 = 1; }
+ oneof pushed { GoodBinaryFieldAtom field1 = 1; }
}
message ComplexField {
@@ -124,7 +124,7 @@ message GoodBinaryFieldAtom {
}
message BadEventWithBinaryFieldAtom {
- oneof event { BadBinaryFieldAtom field1 = 1; }
+ oneof pushed { BadBinaryFieldAtom field1 = 1; }
}
message BadBinaryFieldAtom {
@@ -133,7 +133,7 @@ message BadBinaryFieldAtom {
}
message BadStateAtoms {
- oneof event {
+ oneof pushed {
BadStateAtom1 bad1 = 1;
BadStateAtom2 bad2 = 2;
BadStateAtom3 bad3 = 3;
@@ -141,7 +141,7 @@ message BadStateAtoms {
}
message GoodStateAtoms {
- oneof event {
+ oneof pushed {
GoodStateAtom1 good1 = 1;
GoodStateAtom2 good2 = 2;
}
@@ -204,7 +204,7 @@ message NoModuleAtom {
}
message ModuleAtoms {
- oneof event {
+ oneof pushed {
ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
@@ -213,3 +213,24 @@ message ModuleAtoms {
NoModuleAtom no_module_atom = 4;
}
}
+
+message NotAPushNorPullAtom {
+ oneof event {
+ IntAtom int_atom = 1;
+ }
+}
+
+message AtomNotInAOneof {
+ optional IntAtom int_atom = 1;
+}
+
+message PushedAndPulledAtoms {
+ oneof pushed {
+ IntAtom int_atom_1 = 1;
+ }
+
+ oneof pulled {
+ OutOfOrderAtom out_of_order_atom = 11;
+ AnotherIntAtom another_int_atom = 10;
+ }
+}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index dbae58889333..5fd728a29c07 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -365,5 +365,69 @@ TEST(CollationTest, RecognizeModule1Atom) {
EXPECT_TRUE(annotation->value.boolValue);
}
+/**
+ * Test that an atom is not a pushed nor pulled atom.
+ */
+TEST(CollationTest, InvalidAtomType) {
+ Atoms atoms;
+ int errorCount = collate_atoms(NotAPushNorPullAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test that an atom was not declared in a `oneof` field.
+ */
+TEST(CollationTest, AtomNotDeclaredInAOneof) {
+ Atoms atoms;
+ int errorCount = collate_atoms(AtomNotInAOneof::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test a correct collation with pushed and pulled atoms.
+ */
+TEST(CollationTest, CollatePushedAndPulledAtoms) {
+ Atoms atoms;
+ int errorCount = collate_atoms(PushedAndPulledAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(0, errorCount);
+ EXPECT_EQ(1ul, atoms.signatureInfoMap.size());
+ EXPECT_EQ(2ul, atoms.pulledAtomsSignatureInfoMap.size());
+
+ // IntAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
+
+ // AnotherIntAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT);
+
+ // OutOfOrderAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
+
+ EXPECT_EQ(3ul, atoms.decls.size());
+
+ AtomDeclSet::const_iterator atomIt = atoms.decls.begin();
+ EXPECT_EQ(1, (*atomIt)->code);
+ EXPECT_EQ("int_atom_1", (*atomIt)->name);
+ EXPECT_EQ("IntAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(10, (*atomIt)->code);
+ EXPECT_EQ("another_int_atom", (*atomIt)->name);
+ EXPECT_EQ("AnotherIntAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(11, (*atomIt)->code);
+ EXPECT_EQ("out_of_order_atom", (*atomIt)->name);
+ EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(atoms.decls.end(), atomIt);
+}
+
} // namespace stats_log_api_gen
} // namespace android