summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--StubLibraries.bp50
-rw-r--r--apct-tests/perftests/multiuser/AndroidTest.xml3
-rw-r--r--api/module-lib-current.txt7
-rwxr-xr-xapi/system-current.txt1
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/statsd/src/atoms.proto51
-rw-r--r--core/java/android/app/ActivityView.java15
-rw-r--r--core/java/android/content/res/ApkAssets.java19
-rw-r--r--core/java/android/hardware/display/DisplayManager.java2
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/view/InsetsController.java11
-rw-r--r--core/java/android/view/InsetsState.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java4
-rw-r--r--core/java/android/window/VirtualDisplayTaskEmbedder.java9
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java2
-rw-r--r--core/proto/android/providers/settings/secure.proto3
-rw-r--r--core/res/Android.bp7
-rw-r--r--core/tests/coretests/AndroidManifest.xml1
-rw-r--r--core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java19
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java14
-rw-r--r--data/etc/car/Android.bp7
-rw-r--r--data/etc/car/com.android.car.floatingcardslauncher.xml25
-rw-r--r--graphics/java/android/graphics/Paint.java2
-rw-r--r--libs/androidfw/ResourceTypes.cpp1
-rw-r--r--libs/hwui/Android.bp7
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp98
-rw-r--r--libs/hwui/SkiaCanvas.cpp7
-rw-r--r--libs/hwui/VectorDrawable.cpp7
-rw-r--r--libs/hwui/VectorDrawable.h14
-rw-r--r--libs/hwui/hwui/Canvas.cpp2
-rw-r--r--libs/hwui/hwui/Paint.h9
-rw-r--r--libs/hwui/hwui/PaintImpl.cpp27
-rw-r--r--libs/hwui/jni/Paint.cpp14
-rw-r--r--libs/hwui/jni/Shader.cpp137
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp4
-rw-r--r--libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp4
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp21
-rw-r--r--libs/hwui/renderthread/RenderThread.h4
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp29
-rw-r--r--libs/hwui/renderthread/VulkanManager.h23
-rw-r--r--libs/hwui/shader/BitmapShader.cpp31
-rw-r--r--libs/hwui/shader/BitmapShader.h39
-rw-r--r--libs/hwui/shader/ComposeShader.cpp51
-rw-r--r--libs/hwui/shader/ComposeShader.h43
-rw-r--r--libs/hwui/shader/LinearGradientShader.cpp39
-rw-r--r--libs/hwui/shader/LinearGradientShader.h42
-rw-r--r--libs/hwui/shader/RadialGradientShader.cpp38
-rw-r--r--libs/hwui/shader/RadialGradientShader.h42
-rw-r--r--libs/hwui/shader/RuntimeShader.cpp36
-rw-r--r--libs/hwui/shader/RuntimeShader.h40
-rw-r--r--libs/hwui/shader/Shader.cpp87
-rw-r--r--libs/hwui/shader/Shader.h82
-rw-r--r--libs/hwui/shader/SweepGradientShader.cpp38
-rw-r--r--libs/hwui/shader/SweepGradientShader.h41
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp22
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp47
-rw-r--r--libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp24
-rw-r--r--libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp11
-rw-r--r--libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp22
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp21
-rw-r--r--media/java/android/media/session/ISession.aidl3
-rw-r--r--media/java/android/media/session/MediaSession.java9
-rw-r--r--media/java/android/media/session/MediaSessionManager.java12
-rw-r--r--media/java/android/media/session/ParcelableListBinder.java131
-rw-r--r--non-updatable-api/module-lib-current.txt7
-rw-r--r--non-updatable-api/system-current.txt1
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/proguard.flags3
-rw-r--r--packages/SystemUI/res/layout/bubble_stack_user_education.xml15
-rw-r--r--packages/SystemUI/res/layout/bubbles_manage_button_education.xml124
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml4
-rw-r--r--packages/SystemUI/res/values/attrs.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java283
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt134
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java355
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java165
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java128
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java105
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java183
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java100
-rw-r--r--packages/Tethering/AndroidManifestBase.xml3
-rw-r--r--services/Android.bp4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java50
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java48
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java52
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java83
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java12
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java15
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java85
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java16
-rw-r--r--services/core/java/com/android/server/pm/Settings.java108
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java110
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java362
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java47
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java28
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java8
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/UnknownAppVisibilityController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java12
-rw-r--r--telephony/api/system-current.txt1
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java13
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt4
163 files changed, 3434 insertions, 1675 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 2bd5aee0cd24..bb6538739c49 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -299,6 +299,7 @@ java_defaults {
static_libs: [
// License notices from art module
"art-notices-for-framework-stubs-jar",
+ "framework-res-package-jar", // Export package of framework-res
],
errorprone: {
javacflags: [
@@ -311,6 +312,15 @@ java_defaults {
compile_dex: true,
}
+java_defaults {
+ name: "android_stubs_dists_default",
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android.jar",
+ },
+}
+
java_library_static {
name: "android_monolith_stubs_current",
srcs: [ ":api-stubs-docs" ],
@@ -346,7 +356,21 @@ java_library_static {
name: "android_system_monolith_stubs_current",
srcs: [ ":system-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/system",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_system.jar",
+ },
+ ],
}
java_library_static {
@@ -378,14 +402,34 @@ java_library_static {
name: "android_test_stubs_current",
srcs: [ ":test-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/test",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_test.jar",
+ },
+ ],
}
java_library_static {
name: "android_module_lib_stubs_current",
srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
libs: ["sdk_system_29_android"],
+ dist: {
+ dir: "apistubs/android/module-lib",
+ },
}
java_library_static {
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index c7929af6077f..fbe589248338 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -27,6 +27,9 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
</target_preparer>
<!-- Needed for pulling the collected trace config on to the host -->
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 7cd8a628c9fc..17545a469cb8 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -46,6 +46,13 @@ package android.media.session {
field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
}
+ public final class MediaSessionManager {
+ method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ }
+
}
package android.net {
diff --git a/api/system-current.txt b/api/system-current.txt
index ea16238316ac..3ab164554da6 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12171,6 +12171,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index a1d1fa781096..342bd81ac69b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1305,6 +1305,8 @@ package android.hardware.display {
method public android.graphics.Point getStableDisplaySize();
method public boolean isMinimalPostProcessingRequested(int);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+ field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
+ field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
}
@@ -4618,6 +4620,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6b335ee1b923..8b2c2da9396d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -485,6 +485,9 @@ message Atom {
NetworkTetheringReported network_tethering_reported =
303 [(module) = "network_tethering"];
ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"];
+ UIInteractionFrameInfoReported ui_interaction_frame_info_reported =
+ 305 [(module) = "framework"];
+ UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -5054,6 +5057,54 @@ message BlobOpened{
optional Result result = 4;
}
+/**
+ * Event to track Jank for various system interactions.
+ *
+ * Logged from:
+ * frameworks/base/core/java/android/os/aot/FrameTracker.java
+ */
+message UIInteractionFrameInfoReported {
+ enum InteractionType {
+ UNKNOWN = 0;
+ NOTIFICATION_SHADE_SWIPE = 1;
+ }
+
+ optional InteractionType interaction_type = 1;
+
+ // Number of frames rendered during the interaction.
+ optional int64 total_frames = 2;
+
+ // Number of frames that were skipped in rendering during the interaction.
+ optional int64 missed_frames = 3;
+
+ // Maximum time it took to render a single frame during the interaction.
+ optional int64 max_frame_time_nanos = 4;
+}
+
+/**
+ * Event to track various latencies in SystemUI.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/util/LatencyTracker.java
+ */
+message UIActionLatencyReported {
+ enum ActionType {
+ UNKNOWN = 0;
+ ACTION_EXPAND_PANEL = 1;
+ ACTION_TOGGLE_RECENTS = 2;
+ ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 3;
+ ACTION_CHECK_CREDENTIAL = 4;
+ ACTION_CHECK_CREDENTIAL_UNLOCKED = 5;
+ ACTION_TURN_ON_SCREEN = 6;
+ ACTION_ROTATE_SCREEN = 7;
+ ACTION_FACE_WAKE_AND_UNLOCK = 8;
+ }
+
+ optional ActionType action = 1;
+
+ optional int64 latency_millis = 2;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 98a23f2b0075..3cb6293f0706 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -105,7 +105,8 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd
public ActivityView(
@NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
boolean singleTaskInstance, boolean usePublicVirtualDisplay) {
- this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false);
+ this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay,
+ false /* disableSurfaceViewBackgroundLayer */);
}
/** @hide */
@@ -113,12 +114,22 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd
@NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
boolean singleTaskInstance, boolean usePublicVirtualDisplay,
boolean disableSurfaceViewBackgroundLayer) {
+ this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay,
+ disableSurfaceViewBackgroundLayer, false /* useTrustedDisplay */);
+ }
+
+ // TODO(b/162901735): Refactor ActivityView with Builder
+ /** @hide */
+ public ActivityView(
+ @NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
+ boolean singleTaskInstance, boolean usePublicVirtualDisplay,
+ boolean disableSurfaceViewBackgroundLayer, boolean useTrustedDisplay) {
super(context, attrs, defStyle);
if (useTaskOrganizer()) {
mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this);
} else {
mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance,
- usePublicVirtualDisplay);
+ usePublicVirtualDisplay, useTrustedDisplay);
}
mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer);
// Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index bc418061e1d1..b0437ac7284e 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -101,14 +101,11 @@ public final class ApkAssets {
public @interface FormatType {}
@GuardedBy("this")
- private final long mNativePtr;
+ private long mNativePtr; // final, except cleared in finalizer.
@Nullable
@GuardedBy("this")
- private final StringBlock mStringBlock;
-
- @GuardedBy("this")
- private boolean mOpen = true;
+ private final StringBlock mStringBlock; // null or closed if mNativePtr = 0.
@PropertyFlags
private final int mFlags;
@@ -380,12 +377,16 @@ public final class ApkAssets {
/** @hide */
@Nullable
public OverlayableInfo getOverlayableInfo(String overlayableName) throws IOException {
- return nativeGetOverlayableInfo(mNativePtr, overlayableName);
+ synchronized (this) {
+ return nativeGetOverlayableInfo(mNativePtr, overlayableName);
+ }
}
/** @hide */
public boolean definesOverlayable() throws IOException {
- return nativeDefinesOverlayable(mNativePtr);
+ synchronized (this) {
+ return nativeDefinesOverlayable(mNativePtr);
+ }
}
/**
@@ -412,12 +413,12 @@ public final class ApkAssets {
*/
public void close() {
synchronized (this) {
- if (mOpen) {
- mOpen = false;
+ if (mNativePtr != 0) {
if (mStringBlock != null) {
mStringBlock.close();
}
nativeDestroy(mNativePtr);
+ mNativePtr = 0;
}
}
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index c1ba2094d3cf..392f56212058 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -310,6 +310,7 @@ public final class DisplayManager {
* @hide
*/
// TODO (b/114338689): Remove the flag and use IWindowManager#setShouldShowSystemDecors
+ @TestApi
public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
/**
@@ -320,6 +321,7 @@ public final class DisplayManager {
* @see #VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
* @hide
*/
+ @TestApi
public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
/** @hide */
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 50cc764dd536..58c8efa3a972 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -102,6 +102,8 @@ public final class Trace {
/** @hide */
public static final long TRACE_TAG_RRO = 1L << 26;
/** @hide */
+ public static final long TRACE_TAG_SYSPROP = 1L << 27;
+ /** @hide */
public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 73b33c20d296..6903a995bf7b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9037,6 +9037,13 @@ public final class Settings {
"accessibility_magnification_capability";
/**
+ * Whether the Adaptive connectivity option is enabled.
+ *
+ * @hide
+ */
+ public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled";
+
+ /**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7f45c044408a..403ac3ab29c0 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -629,7 +629,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
}
- if (!mState.equals(state, true /* excludingCaptionInsets */,
+ if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */,
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState);
updateRequestedState();
@@ -1138,15 +1138,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (invokeCallback) {
control.cancel();
}
+ boolean stateChanged = false;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
ArraySet<Integer> types = toInternalType(control.getTypes());
for (int j = types.size() - 1; j >= 0; j--) {
- if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
- mHost.notifyInsetsChanged();
- }
+ stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
if (invokeCallback && runningAnimation.startDispatched) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
@@ -1154,6 +1153,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
break;
}
}
+ if (stateChanged) {
+ mHost.notifyInsetsChanged();
+ updateRequestedState();
+ }
}
private void applyLocalVisibilityOverride() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b0b509932a8..593b37af26ad 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -60,6 +60,8 @@ import java.util.StringJoiner;
*/
public class InsetsState implements Parcelable {
+ public static final InsetsState EMPTY = new InsetsState();
+
/**
* Internal representation of inset source types. This is different from the public API in
* {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 28644858377a..7cc347d25458 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -294,7 +294,7 @@ public final class InputMethodInfo implements Parcelable {
*/
public InputMethodInfo(String packageName, String className,
CharSequence label, String settingsActivity) {
- this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
+ this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
@@ -344,7 +344,7 @@ public final class InputMethodInfo implements Parcelable {
mIsVrOnly = isVrOnly;
}
- private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
+ private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
CharSequence label) {
ResolveInfo ri = new ResolveInfo();
ServiceInfo si = new ServiceInfo();
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index 9ccb4c172158..9013da36007e 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -19,6 +19,7 @@ package android.window;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static android.view.Display.INVALID_DISPLAY;
import android.app.ActivityManager;
@@ -63,6 +64,7 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder {
private int mDisplayDensityDpi;
private final boolean mSingleTaskInstance;
private final boolean mUsePublicVirtualDisplay;
+ private final boolean mUseTrustedDisplay;
private VirtualDisplay mVirtualDisplay;
private Insets mForwardedInsets;
private DisplayMetrics mTmpDisplayMetrics;
@@ -77,10 +79,12 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder {
* only applicable if virtual displays are used
*/
public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host,
- boolean singleTaskInstance, boolean usePublicVirtualDisplay) {
+ boolean singleTaskInstance, boolean usePublicVirtualDisplay,
+ boolean useTrustedDisplay) {
super(context, host);
mSingleTaskInstance = singleTaskInstance;
mUsePublicVirtualDisplay = usePublicVirtualDisplay;
+ mUseTrustedDisplay = useTrustedDisplay;
}
/**
@@ -103,6 +107,9 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder {
if (mUsePublicVirtualDisplay) {
virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_PUBLIC;
}
+ if (mUseTrustedDisplay) {
+ virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ }
mVirtualDisplay = displayManager.createVirtualDisplay(
DISPLAY_NAME + "@" + System.identityHashCode(this), mHost.getWidth(),
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 053b06f3d407..2f8c45770eb5 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -347,7 +347,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
super(context);
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
/**
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 541e018d079b..3d12d072eb80 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -181,6 +181,7 @@ message SecureSettingsProto {
optional SettingProto cmas_additional_broadcast_pkg = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
repeated SettingProto completed_categories = 15;
optional SettingProto connectivity_release_pending_intent_delay_ms = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto adaptive_connectivity_enabled = 84 [ (android.privacy).dest = DEST_AUTOMATIC ];
message Controls {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -614,5 +615,5 @@ message SecureSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 84;
+ // Next tag = 85;
}
diff --git a/core/res/Android.bp b/core/res/Android.bp
index b365de4f4630..f94a2b08e6c3 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -46,6 +46,13 @@ android_app {
},
}
+java_genrule {
+ name: "framework-res-package-jar",
+ srcs: [":framework-res{.export-package.apk}"],
+ out: ["framework-res-package.jar"],
+ cmd: "cp $(in) $(out)",
+}
+
// This logic can be removed once robolectric's transition to binary resources is complete
filegroup {
name: "robolectric_framework_raw_res_files",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3c5d951f685e..e17c312dbffc 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -129,6 +129,7 @@
<!-- virtual display test permissions -->
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
+ <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
<!-- color extraction test permissions -->
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index daf613976358..0f6284d22d10 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -247,6 +247,25 @@ public class VirtualDisplayTest extends AndroidTestCase {
assertDisplayUnregistered(display);
}
+ /**
+ * Ensures that an application can create a trusted virtual display with the permission
+ * {@code ADD_TRUSTED_DISPLAY}.
+ */
+ public void testTrustedVirtualDisplay() throws Exception {
+ VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+ WIDTH, HEIGHT, DENSITY, mSurface,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED);
+ assertNotNull("virtual display must not be null", virtualDisplay);
+
+ Display display = virtualDisplay.getDisplay();
+ try {
+ assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_TRUSTED);
+ } finally {
+ virtualDisplay.release();
+ }
+ assertDisplayUnregistered(display);
+ }
+
private void assertDisplayRegistered(Display display, int flags) {
assertNotNull("display object must not be null", display);
assertTrue("display must be valid", display.isValid());
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index af02b7bdbd90..de128ad6d78e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -746,6 +746,20 @@ public class InsetsControllerTest {
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(newState.getSource(ITYPE_IME),
mTestHost.getModifiedState().peekSource(ITYPE_IME));
+
+ // The modified frames cannot be updated if there is an animation.
+ mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR));
+ mController.hide(navigationBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--;
+ mController.onStateChanged(newState);
+ assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
+
+ // The modified frames can be updated while the animation is done.
+ mController.cancelExistingAnimations();
+ assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
});
}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index d0e688d3efc1..e122e0026aac 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -144,13 +144,6 @@ prebuilt_etc {
}
prebuilt_etc {
- name: "allowed_privapp_com.android.car.floatingcardslauncher",
- sub_dir: "permissions",
- src: "com.android.car.floatingcardslauncher.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "allowed_privapp_com.android.car.ui.paintbooth",
sub_dir: "permissions",
src: "com.android.car.ui.paintbooth.xml",
diff --git a/data/etc/car/com.android.car.floatingcardslauncher.xml b/data/etc/car/com.android.car.floatingcardslauncher.xml
deleted file mode 100644
index 2755fee4eb55..000000000000
--- a/data/etc/car/com.android.car.floatingcardslauncher.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<permissions>
- <privapp-permissions package="com.android.car.floatingcardslauncher">
- <permission name="android.permission.ACTIVITY_EMBEDDING"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- </privapp-permissions>
-</permissions>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 28d7911c771f..964640b106b9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -3111,7 +3111,7 @@ public class Paint {
@CriticalNative
private static native boolean nGetFillPath(long paintPtr, long src, long dst);
@CriticalNative
- private static native long nSetShader(long paintPtr, long shader);
+ private static native void nSetShader(long paintPtr, long shader);
@CriticalNative
private static native long nSetColorFilter(long paintPtr, long filter);
@CriticalNative
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4d7e5dfea4f7..dfb4009b07e2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -37,7 +37,6 @@
#include <androidfw/TypeWrappers.h>
#include <cutils/atomic.h>
#include <utils/ByteOrder.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 9ae5ad97ed36..0b13754271b9 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -462,6 +462,13 @@ cc_defaults {
"RenderNode.cpp",
"RenderProperties.cpp",
"RootRenderNode.cpp",
+ "shader/Shader.cpp",
+ "shader/BitmapShader.cpp",
+ "shader/ComposeShader.cpp",
+ "shader/LinearGradientShader.cpp",
+ "shader/RadialGradientShader.cpp",
+ "shader/RuntimeShader.cpp",
+ "shader/SweepGradientShader.cpp",
"SkiaCanvas.cpp",
"VectorDrawable.cpp",
],
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 87244427a719..ab9b8b55a4cb 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -56,12 +56,6 @@ class AHBUploader : public RefBase {
public:
virtual ~AHBUploader() {}
- // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
- // need to do an upload.
- void initialize() {
- onInitialize();
- }
-
void destroy() {
std::lock_guard _lock{mLock};
LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
@@ -91,7 +85,6 @@ protected:
sp<ThreadBase> mUploadThread = nullptr;
private:
- virtual void onInitialize() = 0;
virtual void onIdle() = 0;
virtual void onDestroy() = 0;
@@ -141,7 +134,6 @@ private:
class EGLUploader : public AHBUploader {
private:
- void onInitialize() override {}
void onDestroy() override {
mEglManager.destroy();
}
@@ -231,62 +223,67 @@ private:
class VkUploader : public AHBUploader {
private:
- void onInitialize() override {
- std::lock_guard _lock{mLock};
- if (!mUploadThread) {
- mUploadThread = new ThreadBase{};
- }
- if (!mUploadThread->isRunning()) {
- mUploadThread->start("GrallocUploadThread");
- }
-
- mUploadThread->queue().post([this]() {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- mVulkanManager.initialize();
- }
- });
- }
void onDestroy() override {
+ std::lock_guard _lock{mVkLock};
mGrContext.reset();
- mVulkanManager.destroy();
+ mVulkanManagerStrong.clear();
}
void onIdle() override {
- mGrContext.reset();
+ onDestroy();
}
- void onBeginUpload() override {
- {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- LOG_ALWAYS_FATAL_IF(mGrContext,
- "GrContext exists with no VulkanManager for vulkan uploads");
- mUploadThread->queue().runSync([this]() {
- mVulkanManager.initialize();
- });
- }
- }
- if (!mGrContext) {
- GrContextOptions options;
- mGrContext = mVulkanManager.createContext(options);
- LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
- this->postIdleTimeoutCheck();
- }
- }
+ void onBeginUpload() override {}
bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
AHardwareBuffer* ahb) override {
- ATRACE_CALL();
+ bool uploadSucceeded = false;
+ mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
+ ATRACE_CALL();
+ std::lock_guard _lock{mVkLock};
+
+ renderthread::VulkanManager* vkManager = getVulkanManager();
+ if (!vkManager->hasVkContext()) {
+ LOG_ALWAYS_FATAL_IF(mGrContext,
+ "GrContext exists with no VulkanManager for vulkan uploads");
+ vkManager->initialize();
+ }
+
+ if (!mGrContext) {
+ GrContextOptions options;
+ mGrContext = vkManager->createContext(options,
+ renderthread::VulkanManager::ContextType::kUploadThread);
+ LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+ this->postIdleTimeoutCheck();
+ }
+
+ sk_sp<SkImage> image =
+ SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
+ mGrContext->submit(true);
+
+ uploadSucceeded = (image.get() != nullptr);
+ });
+ return uploadSucceeded;
+ }
- std::lock_guard _lock{mLock};
+ /* must be called on the upload thread after the vkLock has been acquired */
+ renderthread::VulkanManager* getVulkanManager() {
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = mVulkanManagerWeak.promote();
+
+ // create a new manager if we couldn't promote the weak ref
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
+ mGrContext.reset();
+ mVulkanManagerWeak = mVulkanManagerStrong;
+ }
+ }
- sk_sp<SkImage> image =
- SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
- return (image.get() != nullptr);
+ return mVulkanManagerStrong.get();
}
sk_sp<GrDirectContext> mGrContext;
- renderthread::VulkanManager mVulkanManager;
+ sp<renderthread::VulkanManager> mVulkanManagerStrong;
+ wp<renderthread::VulkanManager> mVulkanManagerWeak;
std::mutex mVkLock;
};
@@ -428,7 +425,6 @@ void HardwareBitmapUploader::initialize() {
bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
uirenderer::RenderPipelineType::SkiaGL;
createUploader(usingGL);
- sUploader->initialize();
}
void HardwareBitmapUploader::terminate() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 242b8b0d139e..cfba5d4f6aa2 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -42,6 +42,8 @@
#include <SkTextBlob.h>
#include <SkVertices.h>
+#include <shader/BitmapShader.h>
+
#include <memory>
#include <optional>
#include <utility>
@@ -49,6 +51,7 @@
namespace android {
using uirenderer::PaintUtils;
+using uirenderer::BitmapShader;
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
@@ -681,7 +684,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
if (paint) {
pnt = *paint;
}
- pnt.setShader(bitmap.makeImage()->makeShader());
+
+ pnt.setShader(sk_ref_sp(new BitmapShader(
+ bitmap.makeImage(), SkTileMode::kClamp, SkTileMode::kClamp, nullptr)));
auto v = builder.detach();
apply_looper(&pnt, [&](const SkPaint& p) {
mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index cd908354aea5..0f566e4b494a 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -23,7 +23,6 @@
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
-#include "SkShader.h"
#include "hwui/Paint.h"
#ifdef __ANDROID__
@@ -159,10 +158,10 @@ void FullPath::draw(SkCanvas* outCanvas, bool useStagingData) {
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
- SkPaint paint;
+ Paint paint;
if (properties.getFillGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
- paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getFillGradient())));
+ paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getFillGradient())));
needsFill = true;
} else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
@@ -179,7 +178,7 @@ void FullPath::draw(SkCanvas* outCanvas, bool useStagingData) {
bool needsStroke = false;
if (properties.getStrokeGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
- paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getStrokeGradient())));
+ paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getStrokeGradient())));
needsStroke = true;
} else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index ac7d41e0d600..d4086f1aa622 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,8 +31,8 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
-#include <SkShader.h>
#include <SkSurface.h>
+#include <shader/Shader.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -227,20 +227,20 @@ public:
strokeGradient = prop.strokeGradient;
onPropertyChanged();
}
- void setFillGradient(SkShader* gradient) {
+ void setFillGradient(Shader* gradient) {
if (fillGradient.get() != gradient) {
fillGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- void setStrokeGradient(SkShader* gradient) {
+ void setStrokeGradient(Shader* gradient) {
if (strokeGradient.get() != gradient) {
strokeGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- SkShader* getFillGradient() const { return fillGradient.get(); }
- SkShader* getStrokeGradient() const { return strokeGradient.get(); }
+ Shader* getFillGradient() const { return fillGradient.get(); }
+ Shader* getStrokeGradient() const { return strokeGradient.get(); }
float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
@@ -320,8 +320,8 @@ public:
count,
};
PrimitiveFields mPrimitiveFields;
- sk_sp<SkShader> fillGradient;
- sk_sp<SkShader> strokeGradient;
+ sk_sp<Shader> fillGradient;
+ sk_sp<Shader> strokeGradient;
};
// Called from UI thread
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index c138a32eacc2..2a377bbb83f2 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -73,7 +73,7 @@ void Canvas::drawTextDecorations(float x, float y, float length, const Paint& pa
static void simplifyPaint(int color, Paint* paint) {
paint->setColor(color);
- paint->setShader(nullptr);
+ paint->setShader((sk_sp<uirenderer::Shader>)nullptr);
paint->setColorFilter(nullptr);
paint->setLooper(nullptr);
paint->setStrokeWidth(4 + 0.04 * paint->getSkFont().getSize());
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index e75e9e7c6933..0bb689c19079 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -30,6 +30,8 @@
#include <minikin/FamilyVariant.h>
#include <minikin/Hyphenator.h>
+#include <shader/Shader.h>
+
namespace android {
class Paint : public SkPaint {
@@ -149,8 +151,14 @@ public:
// The only respected flags are : [ antialias, dither, filterBitmap ]
static uint32_t GetSkPaintJavaFlags(const SkPaint&);
static void SetSkPaintJavaFlags(SkPaint*, uint32_t flags);
+
+ void setShader(sk_sp<uirenderer::Shader> shader);
private:
+
+ using SkPaint::setShader;
+ using SkPaint::setImageFilter;
+
SkFont mFont;
sk_sp<SkDrawLooper> mLooper;
@@ -169,6 +177,7 @@ private:
bool mStrikeThru = false;
bool mUnderline = false;
bool mDevKern = false;
+ sk_sp<uirenderer::Shader> mShader;
};
} // namespace android
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index fa2674fc2f5e..21f60fd7b671 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -24,7 +24,8 @@ Paint::Paint()
, mWordSpacing(0)
, mFontFeatureSettings()
, mMinikinLocaleListId(0)
- , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {
+ , mFamilyVariant(minikin::FamilyVariant::DEFAULT)
+ , mShader(nullptr) {
// SkPaint::antialiasing defaults to false, but
// SkFont::edging defaults to kAntiAlias. To keep them
// insync, we manually set the font to kAilas.
@@ -45,7 +46,8 @@ Paint::Paint(const Paint& paint)
, mAlign(paint.mAlign)
, mStrikeThru(paint.mStrikeThru)
, mUnderline(paint.mUnderline)
- , mDevKern(paint.mDevKern) {}
+ , mDevKern(paint.mDevKern)
+ , mShader(paint.mShader){}
Paint::~Paint() {}
@@ -65,9 +67,30 @@ Paint& Paint::operator=(const Paint& other) {
mStrikeThru = other.mStrikeThru;
mUnderline = other.mUnderline;
mDevKern = other.mDevKern;
+ mShader = other.mShader;
return *this;
}
+void Paint::setShader(sk_sp<uirenderer::Shader> shader) {
+ if (shader) {
+ // If there is an SkShader compatible shader, apply it
+ sk_sp<SkShader> skShader = shader->asSkShader();
+ if (skShader.get()) {
+ SkPaint::setShader(skShader);
+ SkPaint::setImageFilter(nullptr);
+ } else {
+ // ... otherwise the specified shader can only be represented as an ImageFilter
+ SkPaint::setShader(nullptr);
+ SkPaint::setImageFilter(shader->asSkImageFilter());
+ }
+ } else {
+ // No shader is provided at all, clear out both the SkShader and SkImageFilter slots
+ SkPaint::setShader(nullptr);
+ SkPaint::setImageFilter(nullptr);
+ }
+ mShader = shader;
+}
+
bool operator==(const Paint& a, const Paint& b) {
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
a.mFont == b.mFont &&
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index df8635a8fe5a..554674a331cd 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -47,6 +47,7 @@
#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <minikin/MinikinPaint.h>
+#include <shader/Shader.h>
#include <unicode/utf16.h>
#include <cassert>
@@ -54,6 +55,8 @@
#include <memory>
#include <vector>
+using namespace android::uirenderer;
+
namespace android {
struct JMetricsID {
@@ -782,11 +785,10 @@ namespace PaintGlue {
return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
}
- static jlong setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
- obj->setShader(sk_ref_sp(shader));
- return reinterpret_cast<jlong>(obj->getShader());
+ static void setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
+ auto* paint = reinterpret_cast<Paint*>(objHandle);
+ auto* shader = reinterpret_cast<Shader*>(shaderHandle);
+ paint->setShader(sk_ref_sp(shader));
}
static jlong setColorFilter(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong filterHandle) {
@@ -1097,7 +1099,7 @@ static const JNINativeMethod methods[] = {
{"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
{"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
{"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
- {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
+ {"nSetShader","(JJ)V", (void*) PaintGlue::setShader},
{"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
{"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
{"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index e76aace601be..9b1972ed664f 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -5,6 +5,13 @@
#include "SkShader.h"
#include "SkBlendMode.h"
#include "include/effects/SkRuntimeEffect.h"
+#include "shader/Shader.h"
+#include "shader/BitmapShader.h"
+#include "shader/ComposeShader.h"
+#include "shader/LinearGradientShader.h"
+#include "shader/RadialGradientShader.h"
+#include "shader/RuntimeShader.h"
+#include "shader/SweepGradientShader.h"
#include <vector>
@@ -50,7 +57,7 @@ static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvAr
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Shader_safeUnref(SkShader* shader) {
+static void Shader_safeUnref(Shader* shader) {
SkSafeUnref(shader);
}
@@ -74,15 +81,15 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j
SkBitmap bitmap;
image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
}
- sk_sp<SkShader> shader = image->makeShader(
- (SkTileMode)tileModeX, (SkTileMode)tileModeY);
- ThrowIAE_IfNull(env, shader.get());
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new BitmapShader(
+ image,
+ static_cast<SkTileMode>(tileModeX),
+ static_cast<SkTileMode>(tileModeY),
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,17 +125,18 @@ static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
- ThrowIAE_IfNull(env, shader);
-
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* shader = new LinearGradientShader(
+ pts,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ static_cast<SkTileMode>(tileMode),
+ sGradientShaderFlags,
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -148,17 +156,20 @@ static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
- ThrowIAE_IfNull(env, shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new RadialGradientShader(
+ center,
+ radius,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ static_cast<SkTileMode>(tileMode),
+ sGradientShaderFlags,
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////
@@ -174,54 +185,58 @@ static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- sGradientShaderFlags, nullptr);
- ThrowIAE_IfNull(env, shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new SweepGradientShader(
+ x,
+ y,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ sGradientShaderFlags,
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
- SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
- SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
- sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
- sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
-
- SkShader* shader;
-
- if (matrix) {
- shader = baseShader->makeWithLocalMatrix(*matrix).release();
- } else {
- shader = baseShader.release();
- }
- return reinterpret_cast<jlong>(shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* shaderA = reinterpret_cast<Shader*>(shaderAHandle);
+ auto* shaderB = reinterpret_cast<Shader*>(shaderBHandle);
+
+ auto mode = static_cast<SkBlendMode>(xfermodeHandle);
+
+ auto* composeShader = new ComposeShader(
+ *shaderA,
+ *shaderB,
+ mode,
+ matrix
+ );
+
+ return reinterpret_cast<jlong>(composeShader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
- SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
+ auto* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
AutoJavaByteArray arInputs(env, inputs);
- sk_sp<SkData> fData;
- fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
- ThrowIAE_IfNull(env, shader);
+ auto data = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- return reinterpret_cast<jlong>(shader.release());
+ auto* shader = new RuntimeShader(
+ *effect,
+ std::move(data),
+ isOpaque == JNI_TRUE,
+ matrix
+ );
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -239,12 +254,8 @@ static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sks
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Effect_safeUnref(SkRuntimeEffect* effect) {
- SkSafeUnref(effect);
-}
-
static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index fc594da19708..e817ca744c58 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -184,7 +184,9 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
}
proxy->setSurface(window, enableTimeout);
- ANativeWindow_release(window);
+ if (window) {
+ ANativeWindow_release(window);
+ }
}
static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
index 9cffceb308c8..a1adcb30e80d 100644
--- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -143,13 +143,13 @@ static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong full
static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ auto* fillShader = reinterpret_cast<Shader*>(fillGradientPtr);
path->mutateStagingProperties()->setFillGradient(fillShader);
}
static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ auto* strokeShader = reinterpret_cast<Shader*>(strokeGradientPtr);
path->mutateStagingProperties()->setStrokeGradient(strokeShader);
}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aad0cca80cdc..b51f6dcfc66f 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -77,10 +77,10 @@ void RenderProxy::setName(const char* name) {
}
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
- ANativeWindow_acquire(window);
+ if (window) { ANativeWindow_acquire(window); }
mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
mContext->setSurface(win, enableTimeout);
- ANativeWindow_release(win);
+ if (win) { ANativeWindow_release(win); }
});
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 565fb61c8994..4dcbc4458e97 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -131,8 +131,7 @@ RenderThread::RenderThread()
, mFrameCallbackTaskPending(false)
, mRenderState(nullptr)
, mEglManager(nullptr)
- , mFunctorManager(WebViewFunctorManager::instance())
- , mVkManager(nullptr) {
+ , mFunctorManager(WebViewFunctorManager::instance()) {
Properties::load();
start("RenderThread");
}
@@ -166,7 +165,7 @@ void RenderThread::initThreadLocals() {
initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
- mVkManager = new VulkanManager();
+ mVkManager = VulkanManager::getInstance();
mCacheManager = new CacheManager();
}
@@ -196,7 +195,8 @@ void RenderThread::requireGlContext() {
}
void RenderThread::requireVkContext() {
- if (mVkManager->hasVkContext()) {
+ // the getter creates the context in the event it had been destroyed by destroyRenderingContext
+ if (vulkanManager().hasVkContext()) {
return;
}
mVkManager->initialize();
@@ -222,11 +222,16 @@ void RenderThread::destroyRenderingContext() {
mEglManager->destroy();
}
} else {
- if (vulkanManager().hasVkContext()) {
- setGrContext(nullptr);
- vulkanManager().destroy();
- }
+ setGrContext(nullptr);
+ mVkManager.clear();
+ }
+}
+
+VulkanManager& RenderThread::vulkanManager() {
+ if (!mVkManager.get()) {
+ mVkManager = VulkanManager::getInstance();
}
+ return *mVkManager.get();
}
void RenderThread::dumpGraphicsMemory(int fd) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b8ce55650516..d7dc00b8a5c1 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -110,7 +110,7 @@ public:
void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
- VulkanManager& vulkanManager() { return *mVkManager; }
+ VulkanManager& vulkanManager();
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
void dumpGraphicsMemory(int fd);
@@ -188,7 +188,7 @@ private:
sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
- VulkanManager* mVkManager;
+ sp<VulkanManager> mVkManager;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 249936eb485e..0c5cf682e566 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -57,12 +57,22 @@ static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& fe
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-void VulkanManager::destroy() {
- if (VK_NULL_HANDLE != mCommandPool) {
- mDestroyCommandPool(mDevice, mCommandPool, nullptr);
- mCommandPool = VK_NULL_HANDLE;
+sp<VulkanManager> VulkanManager::getInstance() {
+ // cache a weakptr to the context to enable a second thread to share the same vulkan state
+ static wp<VulkanManager> sWeakInstance = nullptr;
+ static std::mutex sLock;
+
+ std::lock_guard _lock{sLock};
+ sp<VulkanManager> vulkanManager = sWeakInstance.promote();
+ if (!vulkanManager.get()) {
+ vulkanManager = new VulkanManager();
+ sWeakInstance = vulkanManager;
}
+ return vulkanManager;
+}
+
+VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
mDestroyDevice(mDevice, nullptr);
@@ -73,6 +83,7 @@ void VulkanManager::destroy() {
}
mGraphicsQueue = VK_NULL_HANDLE;
+ mAHBUploadQueue = VK_NULL_HANDLE;
mPresentQueue = VK_NULL_HANDLE;
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
@@ -175,6 +186,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
for (uint32_t i = 0; i < queueCount; i++) {
if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
mGraphicsQueueIndex = i;
+ LOG_ALWAYS_FATAL_IF(queueProps[i].queueCount < 2);
break;
}
}
@@ -283,7 +295,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
queueNextPtr, // pNext
0, // VkDeviceQueueCreateFlags
mGraphicsQueueIndex, // queueFamilyIndex
- 1, // queueCount
+ 2, // queueCount
queuePriorities, // pQueuePriorities
},
{
@@ -347,6 +359,7 @@ void VulkanManager::initialize() {
this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
+ mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
// create the command pool for the command buffers
if (VK_NULL_HANDLE == mCommandPool) {
@@ -369,7 +382,8 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
+ ContextType contextType) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -381,7 +395,8 @@ sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& opti
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
backendContext.fDevice = mDevice;
- backendContext.fQueue = mGraphicsQueue;
+ backendContext.fQueue = (contextType == ContextType::kRenderThread) ? mGraphicsQueue
+ : mAHBUploadQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
backendContext.fMaxAPIVersion = mAPIVersion;
backendContext.fVkExtensions = &mExtensions;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 3f2df8d75d89..13335f32ef06 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -43,10 +43,9 @@ class RenderThread;
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
// windowing contexts. The VulkanManager must be initialized before use.
-class VulkanManager {
+class VulkanManager final : public RefBase {
public:
- explicit VulkanManager() {}
- ~VulkanManager() { destroy(); }
+ static sp<VulkanManager> getInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -68,9 +67,6 @@ public:
Frame dequeueNextBuffer(VulkanSurface* surface);
void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
- // Cleans up all the global state in the VulkanManger.
- void destroy();
-
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(int fence, GrDirectContext* grContext);
@@ -83,12 +79,24 @@ public:
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
+
+ enum class ContextType {
+ kRenderThread,
+ kUploadThread
+ };
+
+ // returns a Skia graphic context used to draw content on the specified thread
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
private:
friend class VulkanSurface;
+
+ explicit VulkanManager() {}
+ ~VulkanManager();
+
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
@@ -154,6 +162,7 @@ private:
uint32_t mGraphicsQueueIndex;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
+ VkQueue mAHBUploadQueue = VK_NULL_HANDLE;
uint32_t mPresentQueueIndex;
VkQueue mPresentQueue = VK_NULL_HANDLE;
VkCommandPool mCommandPool = VK_NULL_HANDLE;
diff --git a/libs/hwui/shader/BitmapShader.cpp b/libs/hwui/shader/BitmapShader.cpp
new file mode 100644
index 000000000000..fe653e85a021
--- /dev/null
+++ b/libs/hwui/shader/BitmapShader.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#include "BitmapShader.h"
+
+#include "SkImagePriv.h"
+
+namespace android::uirenderer {
+BitmapShader::BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
+ const SkTileMode tileModeY, const SkMatrix* matrix)
+ : Shader(matrix), skShader(image->makeShader(tileModeX, tileModeY)) {}
+
+sk_sp<SkShader> BitmapShader::makeSkShader() {
+ return skShader;
+}
+
+BitmapShader::~BitmapShader() {}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/BitmapShader.h b/libs/hwui/shader/BitmapShader.h
new file mode 100644
index 000000000000..ed6a6e6802d1
--- /dev/null
+++ b/libs/hwui/shader/BitmapShader.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a Bitmap as either a SkShader or SkImageFilter
+ */
+class BitmapShader : public Shader {
+public:
+ BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
+ const SkTileMode tileModeY, const SkMatrix* matrix);
+ ~BitmapShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/ComposeShader.cpp b/libs/hwui/shader/ComposeShader.cpp
new file mode 100644
index 000000000000..3765489e7431
--- /dev/null
+++ b/libs/hwui/shader/ComposeShader.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include "ComposeShader.h"
+
+#include "SkImageFilters.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+ComposeShader::ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
+ const SkMatrix* matrix)
+ : Shader(matrix) {
+ // If both Shaders can be represented as SkShaders then use those, if not
+ // create an SkImageFilter from both Shaders and create the equivalent SkImageFilter
+ sk_sp<SkShader> skShaderA = shaderA.asSkShader();
+ sk_sp<SkShader> skShaderB = shaderB.asSkShader();
+ if (skShaderA.get() && skShaderB.get()) {
+ skShader = SkShaders::Blend(blendMode, skShaderA, skShaderB);
+ skImageFilter = nullptr;
+ } else {
+ sk_sp<SkImageFilter> skImageFilterA = shaderA.asSkImageFilter();
+ sk_sp<SkImageFilter> skImageFilterB = shaderB.asSkImageFilter();
+ skShader = nullptr;
+ skImageFilter = SkImageFilters::Xfermode(blendMode, skImageFilterA, skImageFilterB);
+ }
+}
+
+sk_sp<SkShader> ComposeShader::makeSkShader() {
+ return skShader;
+}
+
+sk_sp<SkImageFilter> ComposeShader::makeSkImageFilter() {
+ return skImageFilter;
+}
+
+ComposeShader::~ComposeShader() {}
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/ComposeShader.h b/libs/hwui/shader/ComposeShader.h
new file mode 100644
index 000000000000..a246b520d46a
--- /dev/null
+++ b/libs/hwui/shader/ComposeShader.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that can composite 2 Shaders together with the specified blend mode.
+ * This implementation can appropriately convert the composed result to either an SkShader or
+ * SkImageFilter depending on the inputs
+ */
+class ComposeShader : public Shader {
+public:
+ ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
+ const SkMatrix* matrix);
+ ~ComposeShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+ sk_sp<SkImageFilter> makeSkImageFilter() override;
+
+private:
+ sk_sp<SkShader> skShader;
+ sk_sp<SkImageFilter> skImageFilter;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/LinearGradientShader.cpp b/libs/hwui/shader/LinearGradientShader.cpp
new file mode 100644
index 000000000000..868fa44fb4b7
--- /dev/null
+++ b/libs/hwui/shader/LinearGradientShader.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include "LinearGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+
+namespace android::uirenderer {
+
+LinearGradientShader::LinearGradientShader(const SkPoint pts[2],
+ const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeLinear(pts, colors.data(), colorspace, pos, colors.size(),
+ tileMode, shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> LinearGradientShader::makeSkShader() {
+ return skShader;
+}
+
+LinearGradientShader::~LinearGradientShader() {}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/LinearGradientShader.h b/libs/hwui/shader/LinearGradientShader.h
new file mode 100644
index 000000000000..596f4e009448
--- /dev/null
+++ b/libs/hwui/shader/LinearGradientShader.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp of colors to either as either SkShader or
+ * SkImageFilter
+ */
+class LinearGradientShader : public Shader {
+public:
+ LinearGradientShader(const SkPoint pts[2], const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix);
+ ~LinearGradientShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/RadialGradientShader.cpp b/libs/hwui/shader/RadialGradientShader.cpp
new file mode 100644
index 000000000000..21ff56fee2f8
--- /dev/null
+++ b/libs/hwui/shader/RadialGradientShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#include "RadialGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+
+namespace android::uirenderer {
+
+RadialGradientShader::RadialGradientShader(const SkPoint& center, const float radius,
+ const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeRadial(center, radius, colors.data(), colorspace, pos,
+ colors.size(), tileMode, shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> RadialGradientShader::makeSkShader() {
+ return skShader;
+}
+
+RadialGradientShader::~RadialGradientShader() {}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/RadialGradientShader.h b/libs/hwui/shader/RadialGradientShader.h
new file mode 100644
index 000000000000..9a2ff139aedb
--- /dev/null
+++ b/libs/hwui/shader/RadialGradientShader.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp from the center outward to either as either
+ * a SkShader or SkImageFilter
+ */
+class RadialGradientShader : public Shader {
+public:
+ RadialGradientShader(const SkPoint& center, const float radius,
+ const std::vector<SkColor4f>& colors, sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix);
+ ~RadialGradientShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.cpp b/libs/hwui/shader/RuntimeShader.cpp
new file mode 100644
index 000000000000..dd0b6980841a
--- /dev/null
+++ b/libs/hwui/shader/RuntimeShader.cpp
@@ -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.
+ */
+
+#include "RuntimeShader.h"
+
+#include "SkShader.h"
+#include "include/effects/SkRuntimeEffect.h"
+
+namespace android::uirenderer {
+
+RuntimeShader::RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
+ const SkMatrix* matrix)
+ : Shader(nullptr)
+ , // Explicitly passing null as RuntimeShader is created with the
+ // matrix directly
+ skShader(effect.makeShader(std::move(data), nullptr, 0, matrix, isOpaque)) {}
+
+sk_sp<SkShader> RuntimeShader::makeSkShader() {
+ return skShader;
+}
+
+RuntimeShader::~RuntimeShader() {}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.h b/libs/hwui/shader/RuntimeShader.h
new file mode 100644
index 000000000000..7fe0b0206467
--- /dev/null
+++ b/libs/hwui/shader/RuntimeShader.h
@@ -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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+#include "include/effects/SkRuntimeEffect.h"
+
+namespace android::uirenderer {
+
+/**
+ * RuntimeShader implementation that can map to either a SkShader or SkImageFilter
+ */
+class RuntimeShader : public Shader {
+public:
+ RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
+ const SkMatrix* matrix);
+ ~RuntimeShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/Shader.cpp b/libs/hwui/shader/Shader.cpp
new file mode 100644
index 000000000000..45123dd55002
--- /dev/null
+++ b/libs/hwui/shader/Shader.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include "Shader.h"
+
+#include "SkImageFilters.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+
+namespace android::uirenderer {
+
+Shader::Shader(const SkMatrix* matrix)
+ : localMatrix(matrix ? *matrix : SkMatrix::I())
+ , skShader(nullptr)
+ , skImageFilter(nullptr) {}
+
+Shader::~Shader() {}
+
+sk_sp<SkShader> Shader::asSkShader() {
+ // If we already have created a shader with these parameters just return the existing
+ // shader we have already created
+ if (!this->skShader.get()) {
+ this->skShader = makeSkShader();
+ if (this->skShader.get()) {
+ if (!localMatrix.isIdentity()) {
+ this->skShader = this->skShader->makeWithLocalMatrix(localMatrix);
+ }
+ }
+ }
+ return this->skShader;
+}
+
+/**
+ * By default return null as we cannot convert all visual effects to SkShader instances
+ */
+sk_sp<SkShader> Shader::makeSkShader() {
+ return nullptr;
+}
+
+sk_sp<SkImageFilter> Shader::asSkImageFilter() {
+ // If we already have created an ImageFilter with these parameters just return the existing
+ // ImageFilter we have already created
+ if (!this->skImageFilter.get()) {
+ // Attempt to create an SkImageFilter from the current Shader implementation
+ this->skImageFilter = makeSkImageFilter();
+ if (this->skImageFilter) {
+ if (!localMatrix.isIdentity()) {
+ // If we have created an SkImageFilter and we have a transformation, wrap
+ // the created SkImageFilter to apply the given matrix
+ this->skImageFilter = SkImageFilters::MatrixTransform(
+ localMatrix, kMedium_SkFilterQuality, this->skImageFilter);
+ }
+ } else {
+ // Otherwise if no SkImageFilter implementation is provided, create one from
+ // the result of asSkShader. Note the matrix is already applied to the shader in
+ // this case so just convert it to an SkImageFilter using SkImageFilters::Paint
+ SkPaint paint;
+ paint.setShader(asSkShader());
+ sk_sp<SkImageFilter> paintFilter = SkImageFilters::Paint(paint);
+ this->skImageFilter = SkImageFilters::Xfermode(SkBlendMode::kDstIn,
+ std::move(paintFilter));
+ }
+ }
+ return this->skImageFilter;
+}
+
+/**
+ * By default return null for subclasses to implement. If there is not a direct SkImageFilter
+ * conversion
+ */
+sk_sp<SkImageFilter> Shader::makeSkImageFilter() {
+ return nullptr;
+}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/Shader.h b/libs/hwui/shader/Shader.h
new file mode 100644
index 000000000000..3c0cdaae8253
--- /dev/null
+++ b/libs/hwui/shader/Shader.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "SkImageFilter.h"
+#include "SkShader.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+
+class SkMatrix;
+
+namespace android::uirenderer {
+
+/**
+ * Shader class that can optionally wrap an SkShader or SkImageFilter depending
+ * on the implementation
+ */
+class Shader: public SkRefCnt {
+public:
+ /**
+ * Creates a Shader instance with an optional transformation matrix
+ * @param matrix Optional matrix to transform the underlying SkShader or SkImageFilter
+ */
+ Shader(const SkMatrix* matrix);
+ virtual ~Shader();
+
+ /**
+ * Create an SkShader from the current Shader instance or return a previously
+ * created instance. This can be null if no SkShader could be created from this
+ * Shader instance.
+ */
+ sk_sp<SkShader> asSkShader();
+
+ /**
+ * Create an SkImageFilter from the current Shader instance or return a previously
+ * created instance. Unlike asSkShader, this method cannot return null.
+ */
+ sk_sp<SkImageFilter> asSkImageFilter();
+
+protected:
+ /**
+ * Create a new SkShader instance based on this Shader instance
+ */
+ virtual sk_sp<SkShader> makeSkShader();
+
+ /**
+ * Create a new SkImageFilter instance based on this Shader instance. If no SkImageFilter
+ * can be created then return nullptr
+ */
+ virtual sk_sp<SkImageFilter> makeSkImageFilter();
+
+private:
+ /**
+ * Optional matrix transform
+ */
+ const SkMatrix localMatrix;
+
+ /**
+ * Cached SkShader instance to be returned on subsequent queries
+ */
+ sk_sp<SkShader> skShader;
+
+ /**
+ * Cached SkImageFilter instance to be returned on subsequent queries
+ */
+ sk_sp<SkImageFilter> skImageFilter;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/SweepGradientShader.cpp b/libs/hwui/shader/SweepGradientShader.cpp
new file mode 100644
index 000000000000..3b1f37f8b051
--- /dev/null
+++ b/libs/hwui/shader/SweepGradientShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "SweepGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+#include "SkImageFilters.h"
+
+namespace android::uirenderer {
+
+SweepGradientShader::SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
+ const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
+ const uint32_t shaderFlags, const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeSweep(x, y, colors.data(), colorspace, pos, colors.size(),
+ shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> SweepGradientShader::makeSkShader() {
+ return skShader;
+}
+
+SweepGradientShader::~SweepGradientShader() {}
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/SweepGradientShader.h b/libs/hwui/shader/SweepGradientShader.h
new file mode 100644
index 000000000000..dad3ef0ffad4
--- /dev/null
+++ b/libs/hwui/shader/SweepGradientShader.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp clockwise such that the start and end colors
+ * are visible at 3 o'clock. This handles converting to either an SkShader or SkImageFilter
+ */
+class SweepGradientShader : public Shader {
+public:
+ SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
+ const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
+ const uint32_t shaderFlags, const SkMatrix* matrix);
+ virtual ~SweepGradientShader() override;
+
+protected:
+ virtual sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index c4067af388e3..e2c1651d823a 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -18,6 +18,7 @@
#include "hwui/Paint.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
+#include <shader/BitmapShader.h>
#include "utils/Color.h"
class BitmapShaders;
@@ -45,15 +46,24 @@ public:
});
Paint paint;
+ sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
+ hwuiBitmap->makeImage(),
+ SkTileMode::kRepeat,
+ SkTileMode::kRepeat,
+ nullptr
+ );
+
sk_sp<SkImage> image = hwuiBitmap->makeImage();
- sk_sp<SkShader> repeatShader =
- image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
- paint.setShader(std::move(repeatShader));
+ paint.setShader(std::move(bitmapShader));
canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
- sk_sp<SkShader> mirrorShader =
- image->makeShader(SkTileMode::kMirror, SkTileMode::kMirror);
- paint.setShader(std::move(mirrorShader));
+ sk_sp<BitmapShader> mirrorBitmapShader = sk_make_sp<BitmapShader>(
+ image,
+ SkTileMode::kMirror,
+ SkTileMode::kMirror,
+ nullptr
+ );
+ paint.setShader(std::move(mirrorBitmapShader));
canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
}
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 5886ea39acce..d37bc3c7d37c 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -20,6 +20,10 @@
#include <SkGradientShader.h>
#include <SkImagePriv.h>
#include <ui/PixelFormat.h>
+#include <shader/BitmapShader.h>
+#include <shader/LinearGradientShader.h>
+#include <shader/RadialGradientShader.h>
+#include <shader/ComposeShader.h>
class HwBitmapInCompositeShader;
@@ -50,20 +54,41 @@ public:
pixels[4000 + 4 * i + 3] = 255;
}
buffer->unlock();
- sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer->toAHardwareBuffer(),
- SkColorSpace::MakeSRGB()));
- sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
+
+ sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
+ Bitmap::createFrom(
+ buffer->toAHardwareBuffer(),
+ SkColorSpace::MakeSRGB()
+ )->makeImage(),
+ SkTileMode::kClamp,
+ SkTileMode::kClamp,
+ nullptr
+ );
SkPoint center;
center.set(50, 50);
- SkColor colors[2];
- colors[0] = Color::Black;
- colors[1] = Color::White;
- sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(
- center, 50, colors, nullptr, 2, SkTileMode::kRepeat);
-
- sk_sp<SkShader> compositeShader(
- SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
+
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = SkColors::kBlack;
+ vColors[1] = SkColors::kWhite;
+
+ sk_sp<RadialGradientShader> radialShader = sk_make_sp<RadialGradientShader>(
+ center,
+ 50,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kRepeat,
+ 0,
+ nullptr
+ );
+
+ sk_sp<ComposeShader> compositeShader = sk_make_sp<ComposeShader>(
+ *bitmapShader.get(),
+ *radialShader.get(),
+ SkBlendMode::kDstATop,
+ nullptr
+ );
Paint paint;
paint.setShader(std::move(compositeShader));
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index a9449b62a1f8..76e39deedd9a 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -17,7 +17,8 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
#include "hwui/Paint.h"
-#include <SkGradientShader.h>
+#include "SkColor.h"
+#include <shader/LinearGradientShader.h>
class ListOfFadedTextAnimation;
@@ -42,15 +43,26 @@ class ListOfFadedTextAnimation : public TestListViewSceneBase {
pts[0].set(0, 0);
pts[1].set(0, 1);
- SkColor colors[2] = {Color::Black, Color::Transparent};
- sk_sp<SkShader> s(
- SkGradientShader::MakeLinear(pts, colors, NULL, 2, SkTileMode::kClamp));
-
SkMatrix matrix;
matrix.setScale(1, length);
matrix.postRotate(-90);
+
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = SkColors::kBlack;
+ vColors[1] = SkColors::kTransparent;
+
+ sk_sp<LinearGradientShader> linearGradientShader = sk_make_sp<LinearGradientShader>(
+ pts,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kClamp,
+ 0,
+ &matrix
+ );
+
Paint fadingPaint;
- fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
+ fadingPaint.setShader(linearGradientShader);
fadingPaint.setBlendMode(SkBlendMode::kDstOut);
canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
canvas.restore();
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index a0bc5aa245d5..bdc157f85264 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -17,7 +17,7 @@
#include "TestSceneBase.h"
#include <SkColorMatrixFilter.h>
-#include <SkGradientShader.h>
+#include <shader/LinearGradientShader.h>
class SimpleColorMatrixAnimation;
@@ -65,9 +65,12 @@ private:
// enough renderer might apply it directly to the paint color)
float pos[] = {0, 1};
SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
- SkColor colors[2] = {Color::DeepPurple_500, Color::DeepOrange_500};
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
- SkTileMode::kClamp));
+ std::vector<SkColor4f> colors(2);
+ colors[0] = SkColor4f::FromColor(Color::DeepPurple_500);
+ colors[1] = SkColor4f::FromColor(Color::DeepOrange_500);
+ paint.setShader(sk_make_sp<LinearGradientShader>(
+ pts, colors, SkColorSpace::MakeSRGB(), pos, SkTileMode::kClamp,
+ 0, nullptr));
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 57a260c8d234..9a15c9d370a4 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -17,6 +17,7 @@
#include "TestSceneBase.h"
#include <SkGradientShader.h>
+#include <shader/LinearGradientShader.h>
class SimpleGradientAnimation;
@@ -55,9 +56,24 @@ private:
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
// use i%2 start position to pick 2 color combo with black in it
- SkColor colors[3] = {Color::Transparent, Color::Black, Color::Cyan_500};
- paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
- SkTileMode::kClamp));
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = ((i % 2) == 0) ?
+ SkColor4f::FromColor(Color::Transparent) :
+ SkColor4f::FromColor(Color::Black);
+ vColors[1] = (((i + 1) % 2) == 0) ?
+ SkColor4f::FromColor(Color::Black) :
+ SkColor4f::FromColor(Color::Cyan_500);
+
+ sk_sp<LinearGradientShader> gradient = sk_make_sp<LinearGradientShader>(
+ pts,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ pos,
+ SkTileMode::kClamp,
+ 0,
+ nullptr
+ );
+ paint.setShader(gradient);
canvas.drawRect(i, i, width, height, paint);
}
});
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 6d4c57413f00..5e56b26f46f0 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,9 +17,14 @@
#include <gtest/gtest.h>
#include "PathParser.h"
+#include "GraphicsJNI.h"
+#include "SkGradientShader.h"
+#include "SkShader.h"
#include "VectorDrawable.h"
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
+#include <shader/Shader.h>
+#include <shader/LinearGradientShader.h>
#include <functional>
@@ -395,7 +400,21 @@ TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
bitmap.allocN32Pixels(5, 5, false);
SkCanvas canvas(bitmap);
- sk_sp<SkShader> shader = SkShaders::Color(SK_ColorBLACK);
+ SkPoint pts[2];
+ pts[0].set(0, 0);
+ pts[1].set(0, 0);
+
+ std::vector<SkColor4f> colors(2);
+ colors[0] = SkColors::kBlack;
+ colors[1] = SkColors::kBlack;
+
+ sk_sp<LinearGradientShader> shader = sk_sp(new LinearGradientShader(pts,
+ colors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kClamp,
+ SkGradientShader::kInterpolateColorsInPremul_Flag,
+ nullptr));
// Initial ref count is 1
EXPECT_TRUE(shader->unique());
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 21378c80fd56..77f7b54368f8 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -41,7 +41,8 @@ interface ISession {
// These commands are for the TransportPerformer
void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
void setPlaybackState(in PlaybackState state);
- void setQueue(in ParceledListSlice queue);
+ void resetQueue();
+ IBinder getBinderForSetQueue();
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 70bd1609ddbd..6c41f7bcd0bc 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -25,7 +25,6 @@ import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
@@ -36,6 +35,7 @@ import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -491,7 +491,12 @@ public final class MediaSession {
*/
public void setQueue(@Nullable List<QueueItem> queue) {
try {
- mBinder.setQueue(queue == null ? null : new ParceledListSlice(queue));
+ if (queue == null) {
+ mBinder.resetQueue();
+ } else {
+ IBinder binder = mBinder.getBinderForSetQueue();
+ ParcelableListBinder.send(binder, queue);
+ }
} catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6976a3569655..20006934ee46 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -523,7 +523,8 @@ public final class MediaSessionManager {
* @param keyEvent The KeyEvent to send.
* @hide
*/
- public void dispatchMediaKeyEventAsSystemService(KeyEvent keyEvent) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void dispatchMediaKeyEventAsSystemService(@NonNull KeyEvent keyEvent) {
dispatchMediaKeyEventInternal(true, keyEvent, false);
}
@@ -548,6 +549,7 @@ public final class MediaSessionManager {
* @return {@code true} if the event was sent to the session, {@code false} otherwise
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean dispatchMediaKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
@NonNull KeyEvent keyEvent) {
if (sessionToken == null) {
@@ -586,10 +588,15 @@ public final class MediaSessionManager {
* Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
* {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
* from the hardware devices.
+ * <p>
+ * Valid stream types include {@link AudioManager.PublicStreamTypes} and
+ * {@link AudioManager#USE_DEFAULT_STREAM_TYPE}.
*
- * @param keyEvent The KeyEvent to send.
+ * @param keyEvent volume key event
+ * @param streamType type of stream
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEventAsSystemService(@NonNull KeyEvent keyEvent, int streamType) {
dispatchVolumeKeyEventInternal(true, keyEvent, streamType, false);
}
@@ -614,6 +621,7 @@ public final class MediaSessionManager {
* @param keyEvent volume key event
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
@NonNull KeyEvent keyEvent) {
if (sessionToken == null) {
diff --git a/media/java/android/media/session/ParcelableListBinder.java b/media/java/android/media/session/ParcelableListBinder.java
new file mode 100644
index 000000000000..a7aacf2d8fca
--- /dev/null
+++ b/media/java/android/media/session/ParcelableListBinder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 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 android.media.session;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Binder to receive a list that has a large number of {@link Parcelable} items.
+ *
+ * It's similar to {@link android.content.pm.ParceledListSlice}, but transactions are performed in
+ * the opposite direction.
+ *
+ * @param <T> the type of {@link Parcelable}
+ * @hide
+ */
+public class ParcelableListBinder<T extends Parcelable> extends Binder {
+
+ private static final int SUGGESTED_MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
+
+ private static final int END_OF_PARCEL = 0;
+ private static final int ITEM_CONTINUED = 1;
+
+ private final Consumer<List<T>> mConsumer;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final List<T> mList = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private int mCount;
+
+ @GuardedBy("mLock")
+ private boolean mConsumed;
+
+ /**
+ * Creates an instance.
+ *
+ * @param consumer a consumer that consumes the list received
+ */
+ public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) {
+ mConsumer = consumer;
+ }
+
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code != FIRST_CALL_TRANSACTION) {
+ return super.onTransact(code, data, reply, flags);
+ }
+ List<T> listToBeConsumed;
+ synchronized (mLock) {
+ if (mConsumed) {
+ return false;
+ }
+ int i = mList.size();
+ if (i == 0) {
+ mCount = data.readInt();
+ }
+ while (i < mCount && data.readInt() != END_OF_PARCEL) {
+ mList.add(data.readParcelable(null));
+ i++;
+ }
+ if (i >= mCount) {
+ listToBeConsumed = mList;
+ mConsumed = true;
+ } else {
+ listToBeConsumed = null;
+ }
+ }
+ if (listToBeConsumed != null) {
+ mConsumer.accept(listToBeConsumed);
+ }
+ return true;
+ }
+
+ /**
+ * Sends a list of {@link Parcelable} to a binder.
+ *
+ * @param binder a binder interface backed by {@link ParcelableListBinder}
+ * @param list a list to send
+ */
+ public static <T extends Parcelable> void send(@NonNull IBinder binder, @NonNull List<T> list)
+ throws RemoteException {
+ int count = list.size();
+ int i = 0;
+ while (i < count) {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ if (i == 0) {
+ data.writeInt(count);
+ }
+ while (i < count && data.dataSize() < SUGGESTED_MAX_IPC_SIZE) {
+ data.writeInt(ITEM_CONTINUED);
+ data.writeParcelable(list.get(i), 0);
+ i++;
+ }
+ if (i < count) {
+ data.writeInt(END_OF_PARCEL);
+ }
+ binder.transact(FIRST_CALL_TRANSACTION, data, reply, 0);
+ reply.recycle();
+ data.recycle();
+ }
+ }
+}
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 617a83f05791..8892a2954afb 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -46,6 +46,13 @@ package android.media.session {
field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
}
+ public final class MediaSessionManager {
+ method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ }
+
}
package android.os {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index dbf9e9fb4ae5..3fd0ee1c8011 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -11037,6 +11037,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
index b8e1edc46da7..20aa5f79c5cc 100644
--- a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
+++ b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
@@ -22,7 +22,8 @@
<item target="attr/icon" value="@attr/icon"/>
<item target="attr/selectedIcon" value="@attr/selectedIcon"/>
- <item target="attr/intent" value="@attr/longIntent"/>
+ <item target="attr/intent" value="@attr/intent"/>
+ <item target="attr/longIntent" value="@attr/longIntent"/>
<item target="attr/componentNames" value="@attr/componentNames"/>
<item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
<item target="attr/categories" value="@attr/categories"/>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 9d06c8467e41..72a6074ff89c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -465,7 +465,16 @@ public class LocalMediaManager implements BluetoothCallback {
synchronized (mMediaDevicesLock) {
mMediaDevices.clear();
mMediaDevices.addAll(devices);
- mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ // Add disconnected bluetooth devices only when phone output device is available.
+ for (MediaDevice device : devices) {
+ final int type = device.getDeviceType();
+ if (type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE
+ || type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
+ || type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE) {
+ mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ break;
+ }
+ }
}
final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index a654fd47ea12..8e850b25159c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -585,6 +585,7 @@ public class LocalMediaManagerTest {
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
@@ -683,6 +684,7 @@ public class LocalMediaManagerTest {
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index bdf00e38ce94..bcd2ff71b57f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -175,5 +175,6 @@ public class SecureSettings {
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
Settings.Secure.PANIC_GESTURE_ENABLED,
Settings.Secure.PANIC_SOUND_ENABLED,
+ Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4ea7f3a23c10..3630f257f583 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -263,5 +263,6 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.PANIC_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.PANIC_SOUND_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ADAPTIVE_CONNECTIVITY_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 47cc6d0fd752..66be8dd68283 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1976,6 +1976,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
SecureSettingsProto.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS);
+ dumpSetting(s, p,
+ Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED,
+ SecureSettingsProto.ADAPTIVE_CONNECTIVITY_ENABLED);
final long controlsToken = p.start(SecureSettingsProto.CONTROLS);
dumpSetting(s, p,
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index b42d71abaa6d..df66bf5a1051 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -45,4 +45,5 @@
-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
-keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; }
--keep class com.android.systemui.dagger.Dagger** { *; } \ No newline at end of file
+-keep class com.android.systemui.dagger.Dagger** { *; }
+-keep class com.android.systemui.tv.Dagger** { *; } \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
index 616403219bc6..fe1ed4b6f726 100644
--- a/packages/SystemUI/res/layout/bubble_stack_user_education.xml
+++ b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
@@ -15,8 +15,8 @@
~ limitations under the License.
-->
<LinearLayout
+ android:id="@+id/stack_education_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/user_education_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingTop="48dp"
@@ -25,26 +25,29 @@
android:paddingEnd="16dp"
android:layout_marginEnd="24dp"
android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg">
-
+ android:background="@drawable/bubble_stack_user_education_bg"
+ >
<TextView
- android:id="@+id/user_education_title"
+ android:id="@+id/stack_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
android:maxLines="2"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_title"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
<TextView
- android:id="@+id/user_education_description"
+ android:id="@+id/stack_education_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_description"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 213bb923db65..b51dc93dc373 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -14,77 +14,77 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.bubbles.ManageEducationView
+
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:id="@+id/manage_education_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:paddingTop="28dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="@dimen/bubble_expanded_view_padding"
+ android:paddingEnd="48dp"
+ android:layout_marginEnd="24dp"
+ android:orientation="vertical"
+ android:background="@drawable/bubble_stack_user_education_bg"
>
- <LinearLayout
+
+ <TextView
+ android:id="@+id/user_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/manage_education_view"
- android:clickable="true"
- android:paddingTop="28dp"
+ android:paddingStart="16dp"
android:paddingBottom="16dp"
- android:paddingStart="@dimen/bubble_expanded_view_padding"
- android:paddingEnd="48dp"
- android:layout_marginEnd="24dp"
- android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg"
- >
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:text="@string/bubbles_user_education_manage_title"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
- <TextView
- android:id="@+id/user_education_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="16dp"
- android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
- android:maxLines="2"
- android:ellipsize="end"
- android:text="@string/bubbles_user_education_manage_title"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
+ <TextView
+ android:id="@+id/user_education_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingBottom="24dp"
+ android:text="@string/bubbles_user_education_manage"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
- <TextView
- android:id="@+id/user_education_description"
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/button_layout"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/manage"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="24dp"
- android:text="@string/bubbles_user_education_manage"
- android:maxLines="2"
- android:ellipsize="end"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+ android:focusable="true"
+ android:clickable="false"
+ android:text="@string/manage_bubbles_text"
+ android:textColor="?attr/wallpaperTextColor"
+ />
- <LinearLayout
- android:layout_height="wrap_content"
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/got_it"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
- android:id="@+id/button_layout"
- android:orientation="horizontal" >
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/manage"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:clickable="false"
- android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/got_it"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:text="@string/bubbles_user_education_got_it"
- android:textColor="?attr/wallpaperTextColor"
- />
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:text="@string/bubbles_user_education_got_it"
+ android:textColor="?attr/wallpaperTextColor"
+ />
</LinearLayout>
-</com.android.systemui.bubbles.ManageEducationView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 732758a2ded2..31a33fbfc308 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -5,6 +5,6 @@
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- systemui:sensorRadius="140px"
- systemui:sensorMarginBottom="630px"
+ systemui:sensorRadius="130px"
+ systemui:sensorCenterY="1636px"
systemui:sensorTouchAreaCoefficient="0.5"/>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 84dbd60b799d..a62502965dd2 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -159,7 +159,7 @@
<declare-styleable name="UdfpsView">
<attr name="sensorRadius" format="dimension"/>
- <attr name="sensorMarginBottom" format="dimension"/>
+ <attr name="sensorCenterY" format="dimension"/>
<attr name="sensorPressureCoefficient" format="float"/>
<attr name="sensorTouchAreaCoefficient" format="float"/>
</declare-styleable>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 765a9422585a..d12f0103238d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1342,7 +1342,7 @@
<dimen name="controls_app_divider_height">2dp</dimen>
<dimen name="controls_app_divider_side_margin">32dp</dimen>
- <dimen name="controls_card_margin">2dp</dimen>
+ <dimen name="controls_card_margin">@dimen/control_base_item_margin</dimen>
<item name="control_card_elevation" type="dimen" format="float">15</item>
<dimen name="controls_dialog_padding">32dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 59af458e2402..17b840cc7a20 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -162,8 +162,8 @@ public class ExpandHelper implements Gefingerpoken {
*
* @param context application context
* @param callback the container that holds the items to be manipulated
- * @param small the smallest allowable size for the manuipulated items.
- * @param large the largest allowable size for the manuipulated items.
+ * @param small the smallest allowable size for the manipulated items.
+ * @param large the largest allowable size for the manipulated items.
*/
public ExpandHelper(Context context, Callback callback, int small, int large) {
mSmallSize = small;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 36353fa96956..d7e91384f049 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -53,12 +53,10 @@ public class UdfpsView extends View implements DozeReceiver,
private final Paint mScrimPaint;
private final Paint mDebugTextPaint;
- private float mSensorX;
- private float mSensorY;
private final RectF mSensorRect;
private final Paint mSensorPaint;
private final float mSensorRadius;
- private final float mSensorMarginBottom;
+ private final float mSensorCenterY;
private final float mSensorTouchAreaCoefficient;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
@@ -66,6 +64,10 @@ public class UdfpsView extends View implements DozeReceiver,
private final Rect mTouchableRegion;
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;
+ // This is calculated from the screen's dimensions at runtime, as opposed to mSensorCenterY,
+ // which is defined in layout.xml
+ private float mSensorCenterX;
+
// AOD anti-burn-in offsets
private float mInterpolatedDarkAmount;
private float mBurnInOffsetX;
@@ -84,7 +86,7 @@ public class UdfpsView extends View implements DozeReceiver,
if (!a.hasValue(R.styleable.UdfpsView_sensorRadius)) {
throw new IllegalArgumentException("UdfpsView must contain sensorRadius");
}
- if (!a.hasValue(R.styleable.UdfpsView_sensorMarginBottom)) {
+ if (!a.hasValue(R.styleable.UdfpsView_sensorCenterY)) {
throw new IllegalArgumentException("UdfpsView must contain sensorMarginBottom");
}
if (!a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
@@ -92,7 +94,7 @@ public class UdfpsView extends View implements DozeReceiver,
"UdfpsView must contain sensorTouchAreaCoefficient");
}
mSensorRadius = a.getDimension(R.styleable.UdfpsView_sensorRadius, 0f);
- mSensorMarginBottom = a.getDimension(R.styleable.UdfpsView_sensorMarginBottom, 0f);
+ mSensorCenterY = a.getDimension(R.styleable.UdfpsView_sensorCenterY, 0f);
mSensorTouchAreaCoefficient = a.getFloat(
R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f);
} finally {
@@ -163,10 +165,9 @@ public class UdfpsView extends View implements DozeReceiver,
final int h = getLayoutParams().height;
final int w = getLayoutParams().width;
mScrimRect.set(0 /* left */, 0 /* top */, w, h);
- mSensorX = w / 2f;
- mSensorY = h - mSensorMarginBottom - mSensorRadius;
- mSensorRect.set(mSensorX - mSensorRadius, mSensorY - mSensorRadius,
- mSensorX + mSensorRadius, mSensorY + mSensorRadius);
+ mSensorCenterX = w / 2f;
+ mSensorRect.set(mSensorCenterX - mSensorRadius, mSensorCenterY - mSensorRadius,
+ mSensorCenterX + mSensorRadius, mSensorCenterY + mSensorRadius);
// Sets mTouchableRegion with rounded up values from mSensorRect.
mSensorRect.roundOut(mTouchableRegion);
@@ -210,10 +211,10 @@ public class UdfpsView extends View implements DozeReceiver,
}
boolean isValidTouch(float x, float y, float pressure) {
- return x > (mSensorX - mSensorRadius * mSensorTouchAreaCoefficient)
- && x < (mSensorX + mSensorRadius * mSensorTouchAreaCoefficient)
- && y > (mSensorY - mSensorRadius * mSensorTouchAreaCoefficient)
- && y < (mSensorY + mSensorRadius * mSensorTouchAreaCoefficient);
+ return x > (mSensorCenterX - mSensorRadius * mSensorTouchAreaCoefficient)
+ && x < (mSensorCenterX + mSensorRadius * mSensorTouchAreaCoefficient)
+ && y > (mSensorCenterY - mSensorRadius * mSensorTouchAreaCoefficient)
+ && y < (mSensorCenterY + mSensorRadius * mSensorTouchAreaCoefficient);
}
void setScrimAlpha(int alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index fa0d2ba84b4e..80150c9b7e32 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -305,7 +305,7 @@ public class BubbleExpandedView extends LinearLayout {
mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/,
- true /* disableSurfaceViewBackgroundLayer */);
+ true /* disableSurfaceViewBackgroundLayer */, true /* useTrustedDisplay */);
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ec9644af7013..64df2b99ee22 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,11 +19,7 @@ package com.android.systemui.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -38,7 +34,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Outline;
@@ -54,7 +49,6 @@ import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -70,10 +64,8 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -82,7 +74,6 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -115,10 +106,6 @@ public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
- /** Animation durations for bubble stack user education views. **/
- static final int ANIMATE_STACK_USER_EDUCATION_DURATION = 200;
- private static final int ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT = 40;
-
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
static final float FLYOUT_DRAG_PERCENT_DISMISS = 0.25f;
@@ -556,7 +543,7 @@ public class BubbleStackView extends FrameLayout
// Otherwise, we either tapped the stack (which means we're collapsed
// and should expand) or the currently selected bubble (we're expanded
// and should collapse).
- if (!maybeShowStackUserEducation()) {
+ if (!maybeShowStackEdu()) {
mBubbleData.setExpanded(!mBubbleData.isExpanded());
}
}
@@ -582,7 +569,9 @@ public class BubbleStackView extends FrameLayout
}
if (mBubbleData.isExpanded()) {
- maybeShowManageEducation(false /* show */);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* show */);
+ }
// If we're expanded, tell the animation controller to prepare to drag this bubble,
// dispatching to the individual bubble magnet listener.
@@ -637,7 +626,9 @@ public class BubbleStackView extends FrameLayout
mExpandedAnimationController.dragBubbleOut(
v, viewInitialX + dx, viewInitialY + dy);
} else {
- hideStackUserEducation(false /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(false /* fromExpansion */);
+ }
mStackAnimationController.moveStackFromTouch(
viewInitialX + dx, viewInitialY + dy);
}
@@ -684,7 +675,7 @@ public class BubbleStackView extends FrameLayout
private OnClickListener mFlyoutClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
- if (maybeShowStackUserEducation()) {
+ if (maybeShowStackEdu()) {
// If we're showing user education, don't open the bubble show the education first
mBubbleToExpandAfterFlyoutCollapse = null;
} else {
@@ -728,7 +719,7 @@ public class BubbleStackView extends FrameLayout
mFlyout.removeCallbacks(mHideFlyout);
animateFlyoutCollapsed(shouldDismiss, velX);
- maybeShowStackUserEducation();
+ maybeShowStackEdu();
}
};
@@ -737,14 +728,8 @@ public class BubbleStackView extends FrameLayout
@Nullable
private BubbleOverflow mBubbleOverflow;
-
- private boolean mShouldShowUserEducation;
- private boolean mAnimatingEducationAway;
- private View mUserEducationView;
-
- private boolean mShouldShowManageEducation;
- private ManageEducationView mManageEducationView;
- private boolean mAnimatingManageEducationAway;
+ private StackEducationView mStackEduView;
+ private ManageEducationView mManageEduView;
private ViewGroup mManageMenu;
private ImageView mManageSettingsIcon;
@@ -805,8 +790,6 @@ public class BubbleStackView extends FrameLayout
onBubbleAnimatedOut);
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
- setUpUserEducation();
-
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
// is centered. It greatly simplifies translation positioning/animations. Views that will
// actually lay out differently in RTL, such as the flyout and expanded view, will set their
@@ -819,6 +802,8 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ updateUserEdu();
+
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setClipChildren(false);
@@ -1092,48 +1077,66 @@ public class BubbleStackView extends FrameLayout
addView(mManageMenu);
}
- private void setUpUserEducation() {
- if (mUserEducationView != null) {
- removeView(mUserEducationView);
- }
- mShouldShowUserEducation = shouldShowBubblesEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowUserEducation: " + mShouldShowUserEducation);
+ /**
+ * Whether the educational view should show for the expanded view "manage" menu.
+ */
+ private boolean shouldShowManageEdu() {
+ final boolean seen = Prefs.getBoolean(mContext,
+ Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false /* default */);
+ final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
+ && mExpandedBubble != null;
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show manage edu: " + shouldShow);
}
- if (mShouldShowUserEducation) {
- mUserEducationView = mInflater.inflate(R.layout.bubble_stack_user_education, this,
- false /* attachToRoot */);
- mUserEducationView.setVisibility(GONE);
-
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.colorAccent,
- android.R.attr.textColorPrimaryInverse});
- final int bgColor = ta.getColor(0, Color.BLACK);
- int textColor = ta.getColor(1, Color.WHITE);
- ta.recycle();
- textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
+ return shouldShow;
+ }
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- title.setTextColor(textColor);
- description.setTextColor(textColor);
+ private void maybeShowManageEdu() {
+ if (!shouldShowManageEdu()) {
+ return;
+ }
+ if (mManageEduView == null) {
+ mManageEduView = new ManageEducationView(mContext);
+ addView(mManageEduView);
+ }
+ mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
+ }
- updateUserEducationForLayoutDirection();
- addView(mUserEducationView);
+ /**
+ * Whether education view should show for the collapsed stack.
+ */
+ private boolean shouldShowStackEdu() {
+ final boolean seen = Prefs.getBoolean(getContext(),
+ Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION, false /* default */);
+ final boolean shouldShow = !seen || BubbleDebugConfig.forceShowUserEducation(mContext);
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show stack edu: " + shouldShow);
}
+ return shouldShow;
+ }
- if (mManageEducationView != null) {
- removeView(mManageEducationView);
+ /**
+ * @return true if education view for collapsed stack should show and was not showing before.
+ */
+ private boolean maybeShowStackEdu() {
+ if (!shouldShowStackEdu()) {
+ return false;
+ }
+ if (mStackEduView == null) {
+ mStackEduView = new StackEducationView(mContext);
+ addView(mStackEduView);
}
- mShouldShowManageEducation = shouldShowManageEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowManageEducation: " + mShouldShowManageEducation);
+ return mStackEduView.show(mStackAnimationController.getStartPosition());
+ }
+
+ private void updateUserEdu() {
+ maybeShowStackEdu();
+ if (mManageEduView != null) {
+ mManageEduView.invalidate();
}
- if (mShouldShowManageEducation) {
- mManageEducationView = (ManageEducationView)
- mInflater.inflate(R.layout.bubbles_manage_button_education, this /* root */,
- false /* attachToRoot */);
- addView(mManageEducationView);
+ maybeShowManageEdu();
+ if (mStackEduView != null) {
+ mStackEduView.invalidate();
}
}
@@ -1164,9 +1167,9 @@ public class BubbleStackView extends FrameLayout
*/
public void onThemeChanged() {
setUpFlyout();
- setUpUserEducation();
setUpManageMenu();
updateOverflow();
+ updateUserEdu();
updateExpandedViewTheme();
}
@@ -1197,12 +1200,11 @@ public class BubbleStackView extends FrameLayout
public void onLayoutDirectionChanged(int direction) {
mManageMenu.setLayoutDirection(direction);
mFlyout.setLayoutDirection(direction);
- if (mUserEducationView != null) {
- mUserEducationView.setLayoutDirection(direction);
- updateUserEducationForLayoutDirection();
+ if (mStackEduView != null) {
+ mStackEduView.setLayoutDirection(direction);
}
- if (mManageEducationView != null) {
- mManageEducationView.setLayoutDirection(direction);
+ if (mManageEduView != null) {
+ mManageEduView.setLayoutDirection(direction);
}
updateExpandedViewDirection(direction);
}
@@ -1446,7 +1448,7 @@ public class BubbleStackView extends FrameLayout
Log.d(TAG, "addBubble: " + bubble);
}
- if (getBubbleCount() == 0 && mShouldShowUserEducation) {
+ if (getBubbleCount() == 0 && shouldShowStackEdu()) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
mStackAnimationController.getStartPosition());
@@ -1649,115 +1651,6 @@ public class BubbleStackView extends FrameLayout
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
- /**
- * If necessary, shows the user education view for the bubble stack. This appears the first
- * time a user taps on a bubble.
- *
- * @return true if user education was shown, false otherwise.
- */
- private boolean maybeShowStackUserEducation() {
- if (mShouldShowUserEducation && mUserEducationView.getVisibility() != VISIBLE) {
- mUserEducationView.setAlpha(0);
- mUserEducationView.setVisibility(VISIBLE);
- updateUserEducationForLayoutDirection();
-
- // Post so we have height of mUserEducationView
- mUserEducationView.post(() -> {
- final int viewHeight = mUserEducationView.getHeight();
- PointF stackPosition = mStackAnimationController.getStartPosition();
- final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
- mUserEducationView.setTranslationY(translationY);
- mUserEducationView.animate()
- .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION)
- .setInterpolator(FAST_OUT_SLOW_IN)
- .alpha(1);
- });
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, true);
- return true;
- }
- return false;
- }
-
- private void updateUserEducationForLayoutDirection() {
- if (mUserEducationView == null) {
- return;
- }
- LinearLayout textLayout = mUserEducationView.findViewById(R.id.user_education_view);
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- boolean isLtr =
- getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
- if (isLtr) {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_LTR);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg);
- title.setGravity(Gravity.LEFT);
- description.setGravity(Gravity.LEFT);
- } else {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_RTL);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg_rtl);
- title.setGravity(Gravity.RIGHT);
- description.setGravity(Gravity.RIGHT);
- }
- }
-
- /**
- * If necessary, hides the user education view for the bubble stack.
- *
- * @param fromExpansion if true this indicates the hide is happening due to the bubble being
- * expanded, false if due to a touch outside of the bubble stack.
- */
- void hideStackUserEducation(boolean fromExpansion) {
- if (mShouldShowUserEducation
- && mUserEducationView.getVisibility() == VISIBLE
- && !mAnimatingEducationAway) {
- mAnimatingEducationAway = true;
- mUserEducationView.animate()
- .alpha(0)
- .setDuration(fromExpansion
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingEducationAway = false;
- mShouldShowUserEducation = shouldShowBubblesEducation();
- mUserEducationView.setVisibility(GONE);
- });
- }
- }
-
- /**
- * If necessary, toggles the user education view for the manage button. This is shown when the
- * bubble stack is expanded for the first time.
- *
- * @param show whether the user education view should show or not.
- */
- void maybeShowManageEducation(boolean show) {
- if (mManageEducationView == null) {
- return;
- }
- if (show
- && mShouldShowManageEducation
- && mManageEducationView.getVisibility() != VISIBLE
- && mIsExpanded
- && mExpandedBubble.getExpandedView() != null) {
- mManageEducationView.show(mExpandedBubble.getExpandedView(), mTempRect,
- () -> maybeShowManageEducation(false) /* run on click */);
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true);
- } else if (!show
- && mManageEducationView.getVisibility() == VISIBLE
- && !mAnimatingManageEducationAway) {
- mManageEducationView.animate()
- .alpha(0)
- .setDuration(mIsExpansionAnimating
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingManageEducationAway = false;
- mShouldShowManageEducation = shouldShowManageEducation();
- mManageEducationView.setVisibility(GONE);
- });
- }
- }
-
void showExpandedViewContents(int displayId) {
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null
@@ -1791,7 +1684,9 @@ public class BubbleStackView extends FrameLayout
cancelDelayedExpandCollapseSwitchAnimations();
mIsExpanded = true;
- hideStackUserEducation(true /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(true /* fromExpansion */);
+ }
beforeExpandedViewAnimation();
mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -1799,7 +1694,9 @@ public class BubbleStackView extends FrameLayout
updatePointerPosition();
mExpandedAnimationController.expandFromStack(() -> {
afterExpandedViewAnimation();
- maybeShowManageEducation(true);
+ if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
+ maybeShowManageEdu();
+ }
} /* after */);
mExpandedViewContainer.setTranslationX(0);
@@ -1936,7 +1833,9 @@ public class BubbleStackView extends FrameLayout
.withEndActions(() -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
beforeExpandedViewAnimation();
- maybeShowManageEducation(false);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* fromExpansion */);
+ }
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "animateCollapse");
@@ -2104,8 +2003,8 @@ public class BubbleStackView extends FrameLayout
// from any location.
if (!mIsExpanded
|| mShowingManage
- || (mManageEducationView != null
- && mManageEducationView.getVisibility() == VISIBLE)) {
+ || (mManageEduView != null
+ && mManageEduView.getVisibility() == VISIBLE)) {
touchableRegion.setEmpty();
}
}
@@ -2289,7 +2188,7 @@ public class BubbleStackView extends FrameLayout
if (flyoutMessage == null
|| flyoutMessage.message == null
|| !bubble.showFlyout()
- || (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE)
+ || (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE)
|| isExpanded()
|| mIsExpansionAnimating
|| mIsGestureInProgress
@@ -2398,7 +2297,7 @@ public class BubbleStackView extends FrameLayout
* them.
*/
public void getTouchableRegion(Rect outRect) {
- if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
+ if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
// When user education shows then capture all touches
outRect.set(0, 0, getWidth(), getHeight());
return;
@@ -2770,18 +2669,6 @@ public class BubbleStackView extends FrameLayout
return mExpandedBubble.getExpandedView().performBackPressIfNeeded();
}
- /** Whether the educational view should appear for bubbles. **/
- private boolean shouldShowBubblesEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, false);
- }
-
- /** Whether the educational view should appear for the expanded view "manage" button. **/
- private boolean shouldShowManageEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false);
- }
-
/** For debugging only */
List<Bubble> getBubblesOnScreen() {
List<Bubble> bubbles = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
index c58ab31c4561..26a9773f9bb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
@@ -18,52 +18,56 @@ package com.android.systemui.bubbles
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
-import android.util.AttributeSet
-import android.view.Gravity
+import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
import com.android.systemui.R
/**
- * Educational view to highlight the manage button that allows a user to configure the settings
+ * User education view to highlight the manage button that allows a user to configure the settings
* for the bubble. Shown only the first time a user expands a bubble.
*/
-class ManageEducationView @JvmOverloads constructor(
- context: Context?,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
- defStyleRes: Int = 0
-) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+class ManageEducationView constructor(context: Context) : LinearLayout(context) {
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage) }
private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
- private var isInflated = false
+
+ private var isHiding = false
init {
- this.visibility = View.GONE
- this.elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
- this.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this);
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
}
- override fun setLayoutDirection(direction: Int) {
- super.setLayoutDirection(direction)
- // setLayoutDirection runs before onFinishInflate
- // so skip if views haven't inflated; otherwise we'll get NPEs
- if (!isInflated) return
- setDirection()
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
}
override fun onFinishInflate() {
super.onFinishInflate()
- isInflated = true
- setDirection()
+ layoutDirection = resources.configuration.layoutDirection
setTextColor()
}
@@ -78,29 +82,35 @@ class ManageEducationView @JvmOverloads constructor(
descTextView.setTextColor(textColor)
}
- fun setDirection() {
+ private fun setDrawableDirection() {
manageView.setBackgroundResource(
if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL)
R.drawable.bubble_stack_user_education_bg_rtl
else R.drawable.bubble_stack_user_education_bg)
- titleTextView.gravity = Gravity.START
- descTextView.gravity = Gravity.START
}
- fun show(expandedView: BubbleExpandedView, rect : Rect, hideMenu: Runnable) {
+ /**
+ * If necessary, toggles the user education view for the manage button. This is shown when the
+ * bubble stack is expanded for the first time.
+ *
+ * @param show whether the user education view should show or not.
+ */
+ fun show(expandedView: BubbleExpandedView, rect : Rect) {
+ if (visibility == VISIBLE) return
+
alpha = 0f
visibility = View.VISIBLE
post {
expandedView.getManageButtonBoundsOnScreen(rect)
- with(hideMenu) {
- manageButton
- .setOnClickListener {
- expandedView.findViewById<View>(R.id.settings_button).performClick()
- this.run()
- }
- gotItButton.setOnClickListener { this.run() }
- setOnClickListener { this.run() }
- }
+
+ manageButton
+ .setOnClickListener {
+ expandedView.findViewById<View>(R.id.settings_button).performClick()
+ hide(true /* isStackExpanding */)
+ }
+ gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
+ setOnClickListener { hide(true /* isStackExpanding */) }
+
with(manageView) {
translationX = 0f
val inset = resources.getDimensionPixelSize(
@@ -109,9 +119,27 @@ class ManageEducationView @JvmOverloads constructor(
}
bringToFront()
animate()
- .setDuration(BubbleStackView.ANIMATE_STACK_USER_EDUCATION_DURATION.toLong())
+ .setDuration(ANIMATE_DURATION)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1f)
}
+ setShouldShow(false)
+ }
+
+ fun hide(isStackExpanding: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .withStartAction { isHiding = true }
+ .alpha(0f)
+ .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction {
+ isHiding = false
+ visibility = GONE
+ };
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_MANAGE_EDUCATION, !shouldShow)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
new file mode 100644
index 000000000000..3e4c729d8315
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.bubbles
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.PointF
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.internal.util.ContrastColorUtil
+import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION
+import com.android.systemui.R
+
+/**
+ * User education view to highlight the collapsed stack of bubbles.
+ * Shown only the first time a user taps the stack.
+ */
+class StackEducationView constructor(context: Context) : LinearLayout(context){
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
+
+ private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
+ private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
+ private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
+
+ private var isHiding = false
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this);
+
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ }
+
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ layoutDirection = resources.configuration.layoutDirection
+ setTextColor()
+ }
+
+ private fun setTextColor() {
+ val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
+ android.R.attr.textColorPrimaryInverse))
+ val bgColor = ta.getColor(0 /* index */, Color.BLACK)
+ var textColor = ta.getColor(1 /* index */, Color.WHITE)
+ ta.recycle()
+ textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
+ titleTextView.setTextColor(textColor)
+ descTextView.setTextColor(textColor)
+ }
+
+ private fun setDrawableDirection() {
+ view.setBackgroundResource(
+ if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR)
+ R.drawable.bubble_stack_user_education_bg
+ else R.drawable.bubble_stack_user_education_bg_rtl)
+ }
+
+ /**
+ * If necessary, shows the user education view for the bubble stack. This appears the first
+ * time a user taps on a bubble.
+ *
+ * @return true if user education was shown, false otherwise.
+ */
+ fun show(stackPosition: PointF) : Boolean{
+ if (visibility == VISIBLE) return false
+
+ setAlpha(0f)
+ setVisibility(View.VISIBLE)
+ post {
+ with(view) {
+ val bubbleSize = context.resources.getDimensionPixelSize(
+ R.dimen.individual_bubble_size)
+ translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
+ }
+ animate()
+ .setDuration(ANIMATE_DURATION)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ }
+ setShouldShow(false)
+ return true
+ }
+
+ /**
+ * If necessary, hides the stack education view.
+ *
+ * @param fromExpansion if true this indicates the hide is happening due to the bubble being
+ * expanded, false if due to a touch outside of the bubble stack.
+ */
+ fun hide(fromExpansion: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .alpha(0f)
+ .setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction { visibility = GONE }
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_EDUCATION, !shouldShow)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index c683a87d6282..31830b94e8e4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -72,8 +72,13 @@ class ControlAdapter(
TYPE_CONTROL -> {
ControlHolder(
layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
- layoutParams.apply {
+ (layoutParams as ViewGroup.MarginLayoutParams).apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
+ // Reset margins as they will be set through the decoration
+ topMargin = 0
+ bottomMargin = 0
+ leftMargin = 0
+ rightMargin = 0
}
elevation = this@ControlAdapter.elevation
background = parent.context.getDrawable(
@@ -386,7 +391,7 @@ class MarginItemDecorator(
val type = parent.adapter?.getItemViewType(position)
if (type == ControlAdapter.TYPE_CONTROL) {
outRect.apply {
- top = topMargin
+ top = topMargin * 2 // Use double margin, as we are not setting bottom
left = sideMargins
right = sideMargins
bottom = 0
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 1a1cc072c6bf..19b0ea1db04e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -33,9 +33,6 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-import dagger.Reusable;
-
-@Reusable // Don't create multiple DozeServices.
public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
@@ -60,7 +57,7 @@ public class DozeService extends DreamService
setWindowless(true);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- DozeComponent dozeComponent = mDozeComponentBuilder.build();
+ DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
mDozeMachine = dozeComponent.getDozeMachine();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
index 247285434df9..05050f905e60 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
@@ -19,6 +19,7 @@ package com.android.systemui.doze.dagger;
import com.android.systemui.doze.DozeMachine;
import com.android.systemui.doze.DozeService;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -30,7 +31,7 @@ public interface DozeComponent {
/** Simple Builder for {@link DozeComponent}. */
@Subcomponent.Factory
interface Builder {
- DozeComponent build();
+ DozeComponent build(@BindsInstance DozeMachine.Service dozeMachineService);
}
/** Supply a {@link DozeMachine}. */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
index a12e280fcca6..04f7c368fdc4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -33,7 +33,6 @@ 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;
@@ -52,9 +51,9 @@ public abstract class DozeModule {
@Provides
@DozeScope
@WrappedService
- static DozeMachine.Service providesWrappedService(DozeService dozeService, DozeHost dozeHost,
- DozeParameters dozeParameters) {
- DozeMachine.Service wrappedService = dozeService;
+ static DozeMachine.Service providesWrappedService(DozeMachine.Service dozeMachineService,
+ DozeHost dozeHost, DozeParameters dozeParameters) {
+ DozeMachine.Service wrappedService = dozeMachineService;
wrappedService = new DozeBrightnessHostForwarder(wrappedService, dozeHost);
wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
wrappedService, dozeParameters);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
index 17e62890aadd..3bfdf5caa9b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
/**
* Stores the state that [ShadeListBuilder] assigns to this [ListEntry]
@@ -35,7 +35,6 @@ data class ListAttachState private constructor(
* parent's section. Null if not attached to the list.
*/
var section: NotifSection?,
- var sectionIndex: Int,
/**
* If a [NotifFilter] is excluding this entry from the list, then that filter. Always null for
@@ -60,7 +59,6 @@ data class ListAttachState private constructor(
fun clone(other: ListAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
excludingFilter = other.excludingFilter
promoter = other.promoter
suppressedChanges.clone(other.suppressedChanges)
@@ -70,7 +68,6 @@ data class ListAttachState private constructor(
fun reset() {
parent = null
section = null
- sectionIndex = -1
excludingFilter = null
promoter = null
suppressedChanges.reset()
@@ -82,7 +79,6 @@ data class ListAttachState private constructor(
return ListAttachState(
null,
null,
- -1,
null,
null,
SuppressedAttachState.create())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 786c97d03712..52c5c3e08118 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -112,11 +112,9 @@ public class ListDumper {
.append(")");
}
- if (entry.getNotifSection() != null) {
- sb.append(" sectionIndex=")
- .append(entry.getSection())
- .append(" sectionName=")
- .append(entry.getNotifSection().getName());
+ if (entry.getSection() != null) {
+ sb.append(" section=")
+ .append(entry.getSection().getLabel());
}
if (includeRecordKeeping) {
@@ -175,12 +173,9 @@ public class ListDumper {
}
if (notifEntry.getAttachState().getSuppressedChanges().getSection() != null) {
- rksb.append("suppressedSectionIndex=")
+ rksb.append("suppressedSection=")
.append(notifEntry.getAttachState().getSuppressedChanges()
- .getSectionIndex())
- .append(" sectionName=")
- .append(notifEntry.getAttachState().getSuppressedChanges()
- .getSection().getName())
+ .getSection())
.append(" ");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 65f5dc4e5f7c..82c1f243dcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -21,7 +21,7 @@ import android.annotation.UptimeMillisLong;
import androidx.annotation.Nullable;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
/**
* Abstract superclass for top-level entries, i.e. things that can appear in the final notification
@@ -78,13 +78,12 @@ public abstract class ListEntry {
return mPreviousAttachState.getParent();
}
- /** The section this notification was assigned to (0 to N-1, where N is number of sections). */
- public int getSection() {
- return mAttachState.getSectionIndex();
+ @Nullable public NotifSection getSection() {
+ return mAttachState.getSection();
}
- @Nullable public NotifSection getNotifSection() {
- return mAttachState.getSection();
+ public int getSectionIndex() {
+ return mAttachState.getSection() != null ? mAttachState.getSection().getIndex() : -1;
}
ListAttachState getAttachState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 05dd4df1f2ce..a1844ff5d221 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -24,7 +24,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -155,10 +155,10 @@ public class NotifPipeline implements CommonNotifCollection {
* Sections that are used to sort top-level entries. If two entries have the same section,
* NotifComparators are consulted. Sections from this list are called in order for each
* notification passed through the pipeline. The first NotifSection to return true for
- * {@link NotifSection#isInSection(ListEntry)} sets the entry as part of its Section.
+ * {@link NotifSectioner#isInSection(ListEntry)} sets the entry as part of its Section.
*/
- public void setSections(List<NotifSection> sections) {
- mShadeListBuilder.setSections(sections);
+ public void setSections(List<NotifSectioner> sections) {
+ mShadeListBuilder.setSectioners(sections);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 6cbebf803511..2b545c56c8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -28,10 +28,11 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
-import android.util.Pair;
import androidx.annotation.NonNull;
@@ -39,6 +40,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -48,7 +50,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeL
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
@@ -119,6 +121,8 @@ public class ShadeListBuilder implements Dumpable {
mLogger = logger;
mInteractionTracker = interactionTracker;
dumpManager.registerDumpable(TAG, this);
+
+ setSectioners(Collections.emptyList());
}
/**
@@ -193,15 +197,17 @@ public class ShadeListBuilder implements Dumpable {
promoter.setInvalidationListener(this::onPromoterInvalidated);
}
- void setSections(List<NotifSection> sections) {
+ void setSectioners(List<NotifSectioner> sectioners) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
- for (NotifSection section : sections) {
- mNotifSections.add(section);
- section.setInvalidationListener(this::onNotifSectionInvalidated);
+ for (NotifSectioner sectioner : sectioners) {
+ mNotifSections.add(new NotifSection(sectioner, mNotifSections.size()));
+ sectioner.setInvalidationListener(this::onNotifSectionInvalidated);
}
+
+ mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
}
void setNotifStabilityManager(NotifStabilityManager notifStabilityManager) {
@@ -275,7 +281,7 @@ public class ShadeListBuilder implements Dumpable {
rebuildListIfBefore(STATE_TRANSFORMING);
}
- private void onNotifSectionInvalidated(NotifSection section) {
+ private void onNotifSectionInvalidated(NotifSectioner section) {
Assert.isMainThread();
mLogger.logNotifSectionInvalidated(section.getName(), mPipelineState.getState());
@@ -652,7 +658,6 @@ public class ShadeListBuilder implements Dumpable {
*/
private void annulAddition(ListEntry entry) {
entry.setParent(null);
- entry.getAttachState().setSectionIndex(-1);
entry.getAttachState().setSection(null);
entry.getAttachState().setPromoter(null);
if (entry.mFirstAddedIteration == mIterationCount) {
@@ -663,12 +668,12 @@ public class ShadeListBuilder implements Dumpable {
private void sortList() {
// Assign sections to top-level elements and sort their children
for (ListEntry entry : mNotifList) {
- Pair<NotifSection, Integer> sectionWithIndex = applySections(entry);
+ NotifSection section = applySections(entry);
if (entry instanceof GroupEntry) {
GroupEntry parent = (GroupEntry) entry;
for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setSection(sectionWithIndex.first);
- child.getAttachState().setSectionIndex(sectionWithIndex.second);
+ child.getAttachState().setSection(section);
+ child.getAttachState().setSection(section);
}
parent.sortChildren(sChildComparator);
}
@@ -736,16 +741,13 @@ public class ShadeListBuilder implements Dumpable {
mLogger.logSectionChanged(
mIterationCount,
prev.getSection(),
- prev.getSectionIndex(),
- curr.getSection(),
- curr.getSectionIndex());
+ curr.getSection());
}
if (curr.getSuppressedChanges().getSection() != null) {
mLogger.logSectionChangeSuppressed(
mIterationCount,
curr.getSuppressedChanges().getSection(),
- curr.getSuppressedChanges().getSectionIndex(),
curr.getSection());
}
}
@@ -762,7 +764,10 @@ public class ShadeListBuilder implements Dumpable {
callOnCleanup(mNotifPromoters);
callOnCleanup(mNotifFinalizeFilters);
callOnCleanup(mNotifComparators);
- callOnCleanup(mNotifSections);
+
+ for (int i = 0; i < mNotifSections.size(); i++) {
+ mNotifSections.get(i).getSectioner().onCleanup();
+ }
if (mNotifStabilityManager != null) {
callOnCleanup(List.of(mNotifStabilityManager));
@@ -777,7 +782,9 @@ public class ShadeListBuilder implements Dumpable {
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
- int cmp = Integer.compare(o1.getSection(), o2.getSection());
+ int cmp = Integer.compare(
+ requireNonNull(o1.getSection()).getIndex(),
+ requireNonNull(o2.getSection()).getIndex());
if (cmp == 0) {
for (int i = 0; i < mNotifComparators.size(); i++) {
@@ -855,45 +862,41 @@ public class ShadeListBuilder implements Dumpable {
return null;
}
- private Pair<NotifSection, Integer> applySections(ListEntry entry) {
- Pair<NotifSection, Integer> sectionWithIndex = findSection(entry);
+ private NotifSection applySections(ListEntry entry) {
+ final NotifSection newSection = findSection(entry);
final ListAttachState prevAttachState = entry.getPreviousAttachState();
+ NotifSection finalSection = newSection;
+
// are we changing sections of this entry?
if (mNotifStabilityManager != null
&& prevAttachState.getParent() != null
- && (sectionWithIndex.first != prevAttachState.getSection()
- || sectionWithIndex.second != prevAttachState.getSectionIndex())) {
+ && newSection != prevAttachState.getSection()) {
// are section changes allowed?
- if (!mNotifStabilityManager.isSectionChangeAllowed(
- entry.getRepresentativeEntry())) {
- entry.getAttachState().getSuppressedChanges().setSection(
- sectionWithIndex.first);
- entry.getAttachState().getSuppressedChanges().setSectionIndex(
- sectionWithIndex.second);
+ if (!mNotifStabilityManager.isSectionChangeAllowed(entry.getRepresentativeEntry())) {
+ // record the section that we wanted to change to
+ entry.getAttachState().getSuppressedChanges().setSection(newSection);
// keep the previous section
- sectionWithIndex = new Pair(
- prevAttachState.getSection(),
- prevAttachState.getSectionIndex());
+ finalSection = prevAttachState.getSection();
}
}
- entry.getAttachState().setSection(sectionWithIndex.first);
- entry.getAttachState().setSectionIndex(sectionWithIndex.second);
+ entry.getAttachState().setSection(finalSection);
- return sectionWithIndex;
+ return finalSection;
}
- private Pair<NotifSection, Integer> findSection(ListEntry entry) {
+ @NonNull
+ private NotifSection findSection(ListEntry entry) {
for (int i = 0; i < mNotifSections.size(); i++) {
- NotifSection sectioner = mNotifSections.get(i);
- if (sectioner.isInSection(entry)) {
- return new Pair<>(sectioner, i);
+ NotifSection section = mNotifSections.get(i);
+ if (section.getSectioner().isInSection(entry)) {
+ return section;
}
}
- return new Pair<>(sDefaultSection, mNotifSections.size());
+ throw new RuntimeException("Missing default sectioner!");
}
private void rebuildListIfBefore(@PipelineState.StateName int state) {
@@ -963,15 +966,15 @@ public class ShadeListBuilder implements Dumpable {
void onRenderList(@NonNull List<ListEntry> entries);
}
- private static final NotifSection sDefaultSection =
- new NotifSection("UnknownSection") {
+ private static final NotifSectioner DEFAULT_SECTIONER =
+ new NotifSectioner("UnknownSection") {
@Override
public boolean isInSection(ListEntry entry) {
return true;
}
};
- private static final String TAG = "ShadeListBuilder";
-
private static final int MIN_CHILDREN_FOR_GROUP = 2;
+
+ private static final String TAG = "ShadeListBuilder";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
index 52612365712e..3eb2e610f329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.collection
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
/**
* Stores the suppressed state that [ShadeListBuilder] assigned to this [ListEntry] before the
@@ -33,22 +33,19 @@ data class SuppressedAttachState private constructor(
* The assigned section for this ListEntry. If the child of the group, this will be the
* parent's section. Null if not attached to the list.
*/
- var section: NotifSection?,
- var sectionIndex: Int
+ var section: NotifSection?
) {
/** Copies the state of another instance. */
fun clone(other: SuppressedAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
}
/** Resets back to a "clean" state (the same as created by the factory method) */
fun reset() {
parent = null
section = null
- sectionIndex = -1
}
companion object {
@@ -56,8 +53,7 @@ data class SuppressedAttachState private constructor(
fun create(): SuppressedAttachState {
return SuppressedAttachState(
null,
- null,
- -1)
+ null)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 0b9bded5ef58..c7ac40346ce1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -29,7 +29,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -83,8 +83,8 @@ public class AppOpsCoordinator implements Coordinator {
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
/**
@@ -179,7 +179,7 @@ public class AppOpsCoordinator implements Coordinator {
/**
* Puts foreground service notifications into its own section.
*/
- private final NotifSection mNotifSection = new NotifSection("ForegroundService") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index c8e859f27a5c..dea11626a3f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -21,7 +21,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import javax.inject.Inject
@@ -42,7 +42,7 @@ class ConversationCoordinator @Inject constructor(
}
}
- private val mNotifSection: NotifSection = object : NotifSection("People") {
+ val sectioner = object : NotifSectioner("People") {
override fun isInSection(entry: ListEntry): Boolean {
return isConversation(entry.representativeEntry!!)
}
@@ -52,10 +52,6 @@ class ConversationCoordinator @Inject constructor(
pipeline.addPromoter(notificationPromoter)
}
- fun getSection(): NotifSection {
- return mNotifSection
- }
-
private fun isConversation(entry: NotificationEntry): Boolean =
peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) !=
TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 6e6cecaf62fa..c023400ca9ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -27,7 +27,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -88,8 +88,8 @@ public class HeadsUpCoordinator implements Coordinator {
pipeline.addNotificationLifetimeExtender(mLifetimeExtender);
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
private void onHeadsUpViewBound(NotificationEntry entry) {
@@ -191,7 +191,7 @@ public class HeadsUpCoordinator implements Coordinator {
}
};
- private final NotifSection mNotifSection = new NotifSection("HeadsUp") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp") {
@Override
public boolean isInSection(ListEntry entry) {
return isCurrentlyShowingHun(entry);
@@ -207,7 +207,7 @@ public class HeadsUpCoordinator implements Coordinator {
endNotifLifetimeExtension();
mCurrentHun = newHUN;
mNotifPromoter.invalidateList();
- mNotifSection.invalidateList();
+ mNotifSectioner.invalidateList();
}
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 87ca717982f5..ded5e46593f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
@@ -41,7 +41,7 @@ import javax.inject.Inject;
public class NotifCoordinators implements Dumpable {
private static final String TAG = "NotifCoordinators";
private final List<Coordinator> mCoordinators = new ArrayList<>();
- private final List<NotifSection> mOrderedSections = new ArrayList<>();
+ private final List<NotifSectioner> mOrderedSections = new ArrayList<>();
/**
* Creates all the coordinators.
@@ -81,12 +81,12 @@ public class NotifCoordinators implements Dumpable {
// Manually add Ordered Sections
// HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mOrderedSections.add(headsUpCoordinator.getSection()); // HeadsUp
+ mOrderedSections.add(headsUpCoordinator.getSectioner()); // HeadsUp
}
- mOrderedSections.add(appOpsCoordinator.getSection()); // ForegroundService
- mOrderedSections.add(conversationCoordinator.getSection()); // People
- mOrderedSections.add(rankingCoordinator.getAlertingSection()); // Alerting
- mOrderedSections.add(rankingCoordinator.getSilentSection()); // Silent
+ mOrderedSections.add(appOpsCoordinator.getSectioner()); // ForegroundService
+ mOrderedSections.add(conversationCoordinator.getSectioner()); // People
+ mOrderedSections.add(rankingCoordinator.getAlertingSectioner()); // Alerting
+ mOrderedSections.add(rankingCoordinator.getSilentSectioner()); // Silent
}
/**
@@ -109,7 +109,7 @@ public class NotifCoordinators implements Dumpable {
pw.println("\t" + c.getClass());
}
- for (NotifSection s : mOrderedSections) {
+ for (NotifSectioner s : mOrderedSections) {
pw.println("\t" + s.getName());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index a32b1636057b..0f08e0ff491c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -22,7 +22,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import javax.inject.Inject;
@@ -57,22 +57,22 @@ public class RankingCoordinator implements Coordinator {
pipeline.addPreGroupFilter(mDozingFilter);
}
- public NotifSection getAlertingSection() {
- return mAlertingNotifSection;
+ public NotifSectioner getAlertingSectioner() {
+ return mAlertingNotifSectioner;
}
- public NotifSection getSilentSection() {
- return mSilentNotifSection;
+ public NotifSectioner getSilentSectioner() {
+ return mSilentNotifSectioner;
}
- private final NotifSection mAlertingNotifSection = new NotifSection("Alerting") {
+ private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting") {
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
}
};
- private final NotifSection mSilentNotifSection = new NotifSection("Silent") {
+ private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent") {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
new file mode 100644
index 000000000000..c09122ea3c26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.statusbar.notification.collection.listbuilder
+
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+
+data class NotifSection(
+ val sectioner: NotifSectioner,
+ val index: Int
+) {
+ val label: String
+ get() = "Section($index, \"${sectioner.name}\")"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index f7bfeb7234f0..9ee7db738c20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
import javax.inject.Inject
class ShadeListBuilderLogger @Inject constructor(
@@ -211,21 +210,17 @@ class ShadeListBuilderLogger @Inject constructor(
fun logSectionChanged(
buildId: Int,
prevSection: NotifSection?,
- prevIndex: Int,
- newSection: NotifSection?,
- newIndex: Int
+ newSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = prevSection?.name
- int1 = prevIndex
- str2 = newSection?.name
- int2 = newIndex
+ str1 = prevSection?.label
+ str2 = newSection?.label
}, {
if (str1 == null) {
- "(Build $long1) Section assigned: '$str2' (#$int2)"
+ "(Build $long1) Section assigned: $str2"
} else {
- "(Build $long1) Section changed: '$str1' (#$int1) -> '$str2' (#$int2)"
+ "(Build $long1) Section changed: $str1 -> $str2"
}
})
}
@@ -233,17 +228,14 @@ class ShadeListBuilderLogger @Inject constructor(
fun logSectionChangeSuppressed(
buildId: Int,
suppressedSection: NotifSection?,
- suppressedSectionIndex: Int,
assignedSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = suppressedSection?.name
- int1 = suppressedSectionIndex
- str2 = assignedSection?.name
+ str1 = suppressedSection?.label
+ str2 = assignedSection?.label
}, {
- "(Build $long1) Section change suppressed: '$str1' (#$int1). " +
- "Keeping section: '$str2'"
+ "(Build $long1) Suppressing section change to $str1 (staying at $str2)"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index fe5ba3c8e6fc..b57f504189f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -22,8 +22,8 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
/**
* Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSections}.
*/
-public abstract class NotifSection extends Pluggable<NotifSection> {
- protected NotifSection(String name) {
+public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
+ protected NotifSectioner(String name) {
super(name);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
index e8124944bcb0..a1800ed12125 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
@@ -25,10 +25,10 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
* we should just modify NLC to implement the NodeController interface.
*/
class RootNodeController(
- private val listContainer: NotificationListContainer
+ private val listContainer: NotificationListContainer,
+ override val view: View
) : NodeController {
override val nodeLabel: String = "<root>"
- override val view: View = listContainer as View
override fun getChildAt(index: Int): View? {
return listContainer.getContainerChildAt(index)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index 118ff4a9fbb7..3c35b7bd8472 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.render
+import android.content.Context
+import android.view.View
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -30,12 +32,15 @@ import javax.inject.Inject
* currently populate the notification shade.
*/
class ShadeViewManager constructor(
+ context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
- private val rootController = RootNodeController(listContainer)
+ // We pass a shim view here because the listContainer may not actually have a view associated
+ // with it and the differ never actually cares about the root node's view.
+ private val rootController = RootNodeController(listContainer, View(context))
private val viewDiffer = ShadeViewDiffer(rootController, logger)
fun attach(listBuilder: ShadeListBuilder) {
@@ -82,11 +87,17 @@ class ShadeViewManager constructor(
}
class ShadeViewManagerFactory @Inject constructor(
+ private val context: Context,
private val logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
fun create(listContainer: NotificationListContainer): ShadeViewManager {
- return ShadeViewManager(listContainer, logger, viewBarn, notificationIconAreaController)
+ return ShadeViewManager(
+ context,
+ listContainer,
+ logger,
+ viewBarn,
+ notificationIconAreaController)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d4c270f45ceb..e061472b3939 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -95,21 +95,15 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -145,7 +139,6 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -154,11 +147,8 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Assert;
@@ -178,7 +168,7 @@ import javax.inject.Named;
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
-public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter, Dumpable {
+public class NotificationStackScrollLayout extends ViewGroup implements Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -195,10 +185,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
- private final KeyguardBypassController mKeyguardBypassController;
+ private OnMenuEventListener mMenuEventListener;
+ private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
private final DynamicPrivacyController mDynamicPrivacyController;
private final SysuiStatusBarStateController mStatusbarStateController;
- private final KeyguardMediaController mKeyguardMediaController;
private ExpandHelper mExpandHelper;
private final NotificationSwipeHelper mSwipeHelper;
@@ -249,6 +239,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private int mBottomMargin;
private int mBottomInset = 0;
private float mQsExpansionFraction;
+ private int mCurrentUserId;
/**
* The algorithm which calculates the properties for our children
@@ -326,7 +317,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* motion.
*/
private int mMaxScrollAfterExpand;
- private ExpandableNotificationRow.LongPressListener mLongPressListener;
boolean mCheckForLeavebehind;
/**
@@ -348,12 +338,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return true;
}
};
- private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
- @Override
- public void onUserChanged(int userId) {
- updateSensitiveness(false /* animated */);
- }
- };
+
private StatusBar mStatusBar;
private int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
@@ -368,7 +353,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private boolean mForceNoOverlappingRendering;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
private FalsingManager mFalsingManager;
- private final ZenModeController mZenController;
private boolean mAnimationRunning;
private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -498,7 +482,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final Rect mTmpRect = new Rect();
private final FeatureFlags mFeatureFlags;
private final NotifPipeline mNotifPipeline;
@@ -511,7 +494,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
protected final UiEventLogger mUiEventLogger;
private final NotificationRemoteInputManager mRemoteInputManager =
Dependency.get(NotificationRemoteInputManager.class);
- private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
private final LockscreenGestureLogger mLockscreenGestureLogger =
@@ -536,11 +518,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private int mWaterfallTopInset;
private NotificationStackScrollLayoutController mController;
- private SysuiColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
- (colorExtractor, which) -> {
- final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
- updateDecorViews(useDarkText);
- };
+ private boolean mKeyguardMediaControllorVisible;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -555,20 +533,44 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
};
+ private final ScrollAdapter mScrollAdapter = new ScrollAdapter() {
+ @Override
+ public boolean isScrolledToTop() {
+ if (ANCHOR_SCROLLING) {
+ updateScrollAnchor();
+ // TODO: once we're recycling this will need to check the adapter position of the
+ // child
+ return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
+ } else {
+ return mOwnScrollY == 0;
+ }
+ }
+
+ @Override
+ public boolean isScrolledToBottom() {
+ if (ANCHOR_SCROLLING) {
+ return getMaxPositiveScrollAmount() <= 0;
+ } else {
+ return mOwnScrollY >= getScrollRange();
+ }
+ }
+
+ @Override
+ public View getHostView() {
+ return NotificationStackScrollLayout.this;
+ }
+ };
+
@Inject
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
- SysuiStatusBarStateController statusBarStateController,
+ SysuiStatusBarStateController statusbarStateController,
HeadsUpManagerPhone headsUpManager,
- KeyguardBypassController keyguardBypassController,
- KeyguardMediaController keyguardMediaController,
FalsingManager falsingManager,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGutsManager notificationGutsManager,
- ZenModeController zenController,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
@@ -583,13 +585,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mRoundnessManager = notificationRoundnessManager;
- mLockscreenUserManager = notificationLockscreenUserManager;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mKeyguardBypassController = keyguardBypassController;
mFalsingManager = falsingManager;
- mZenController = zenController;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -608,16 +607,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
- mExpandHelper.setScrollAdapter(this);
+ mExpandHelper.setScrollAdapter(mScrollAdapter);
+
+ // TODO: move swipe helper into controller.
+ // The anonymous proxy through to mMenuEventListener is temporary until more can be moved
+ // into the controller.
mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
- getContext(), mMenuEventListener, mFalsingManager);
+ getContext(), new OnMenuEventListener() {
+ @Override
+ public void onMenuClicked(View row, int x, int y, MenuItem menu) {
+ mMenuEventListener.onMenuClicked(row, x, y, menu);
+ }
+
+ @Override
+ public void onMenuReset(View row) {
+ mMenuEventListener.onMenuReset(row);
+ }
+
+ @Override
+ public void onMenuShown(View row) {
+ mMenuEventListener.onMenuShown(row);
+ }
+ }, mFalsingManager);
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
- initView(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
mFadeNotificationsOnDismiss =
res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
- mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
setOutlineProvider(mOutlineProvider);
// Blocking helper manager wants to know the expanded state, update as well.
@@ -667,20 +683,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
mDynamicPrivacyController = dynamicPrivacyController;
- mStatusbarStateController = statusBarStateController;
+ mStatusbarStateController = statusbarStateController;
initializeForegroundServiceSection(fgsFeatureController);
mUiEventLogger = uiEventLogger;
- mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
- mKeyguardMediaController = keyguardMediaController;
- keyguardMediaController.setVisibilityChangedListener((visible) -> {
- if (visible) {
- generateAddAnimation(keyguardMediaController.getView(), false /*fromMoreCard */);
- } else {
- generateRemoveAnimation(keyguardMediaController.getView());
- }
- requestChildrenUpdate();
- return null;
- });
}
private void initializeForegroundServiceSection(
@@ -719,7 +724,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public float getWakeUpHeight() {
ExpandableView firstChild = getFirstChildWithBackground();
if (firstChild != null) {
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
return firstChild.getHeadsUpHeightWithoutHeader();
} else {
return firstChild.getCollapsedHeight();
@@ -794,21 +799,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
};
}
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
- .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
@@ -898,7 +888,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
boolean shouldDrawBackground;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
shouldDrawBackground = isPulseExpanding();
} else {
shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
@@ -1013,9 +1003,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
+ private void reinitView() {
+ initView(getContext(), mKeyguardBypassEnabledProvider);
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void initView(Context context) {
+ void initView(Context context,
+ KeyguardBypassEnabledProvider keyguardBypassEnabledProvider) {
mScroller = new OverScroller(getContext());
+ mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider;
+
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
@@ -1227,7 +1224,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
float end = start + child.getActualHeight();
boolean clip = clipStart > start && clipStart < end
|| clipEnd >= start && clipEnd <= end;
- clip &= !(first && isScrolledToTop());
+ clip &= !(first && mScrollAdapter.isScrolledToTop());
child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
: ExpandableView.NO_ROUNDNESS);
first = false;
@@ -1287,7 +1284,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestChildrenUpdate() {
+ void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
mChildrenUpdateRequested = true;
@@ -1417,7 +1414,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private void notifyAppearChangedListeners() {
float appear;
float expandAmount;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
appear = calculateAppearFractionBypass();
expandAmount = getPulseHeight();
} else {
@@ -1819,7 +1816,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
- initView(getContext());
+ reinitView();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -2220,7 +2217,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
springBack();
} else {
float overScrollTop = getCurrentOverScrollAmount(true /* top */);
- if (isScrolledToTop() && mScrollAnchorViewY > 0) {
+ if (mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0) {
notifyOverscrollTopListener(mScrollAnchorViewY,
isRubberbanded(true /* onTop */));
} else {
@@ -2268,7 +2265,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void springBack() {
if (ANCHOR_SCROLLING) {
- boolean overScrolledTop = isScrolledToTop() && mScrollAnchorViewY > 0;
+ boolean overScrolledTop = mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0;
int maxPositiveScrollAmount = getMaxPositiveScrollAmount();
boolean overscrolledBottom = maxPositiveScrollAmount < 0;
if (overScrolledTop || overscrolledBottom) {
@@ -2545,8 +2542,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForwardAndBackwardScrollability() {
- boolean forwardScrollable = mScrollable && !isScrolledToBottom();
- boolean backwardsScrollable = mScrollable && !isScrolledToTop();
+ boolean forwardScrollable = mScrollable && !mScrollAdapter.isScrolledToBottom();
+ boolean backwardsScrollable = mScrollable && !mScrollAdapter.isScrolledToTop();
boolean changed = forwardScrollable != mForwardScrollable
|| backwardsScrollable != mBackwardScrollable;
mForwardScrollable = forwardScrollable;
@@ -2667,7 +2664,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
&& (mAmbientState.isDozing()
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard));
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
for (NotificationSection section : mSections) {
int minBottomPosition = minTopPosition;
if (section == lastSection) {
@@ -2830,7 +2827,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mLastScrollerY = 0;
// x velocity is set to 1 to avoid overscroller bug
mScroller.fling(0, 0, 1, velocityY, 0, 0, minY, maxY, 0,
- mExpandedInThisMotion && !isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
+ mExpandedInThisMotion
+ && !mScrollAdapter.isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
}
}
@@ -2937,7 +2935,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
} else {
mTopPaddingOverflow = 0;
}
- setTopPadding(topPadding, animate && !mKeyguardBypassController.getBypassEnabled());
+ setTopPadding(topPadding, animate && !mKeyguardBypassEnabledProvider.getBypassEnabled());
setExpandedHeight(mExpandedHeight);
}
@@ -3095,7 +3093,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* @return Whether an animation was generated.
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private boolean generateRemoveAnimation(ExpandableView child) {
+ boolean generateRemoveAnimation(ExpandableView child) {
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
return false;
@@ -3332,7 +3330,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- void onViewAddedInternal(ExpandableView child) {
+ private void onViewAddedInternal(ExpandableView child) {
updateHideSensitiveForChild(child);
child.setOnHeightChangedListener(mOnChildHeightChangedListener);
generateAddAnimation(child, false /* fromMoreCard */);
@@ -3343,7 +3341,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
if (ANCHOR_SCROLLING) {
// TODO: once we're recycling this will need to check the adapter position of the child
- if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
+ if (child == getFirstChildNotGone()
+ && (mScrollAdapter.isScrolledToTop() || !mIsExpanded)) {
// New child was added at the top while we're scrolled to the top;
// make it the new anchor view so that we stay at the top.
mScrollAnchorView = child;
@@ -3361,6 +3360,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
onViewRemovedInternal(row, childrenContainer);
}
+ public void notifyGroupChildAdded(ExpandableView row) {
+ onViewAddedInternal(row);
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
@@ -3533,7 +3536,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
boolean performDisappearAnimation = !mIsExpanded
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard()
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
&& mHeadsUpManager.hasPinnedHeadsUp());
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
@@ -3769,11 +3772,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return y < getHeight() - getEmptyBottomMargin();
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
- mLongPressListener = listener;
- }
-
private float getTouchSlop(MotionEvent event) {
// Adjust the touch slop if another gesture may be being performed.
return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
@@ -4227,7 +4225,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
- mScrolledToTopOnFirstDown = isScrolledToTop();
+ mScrolledToTopOnFirstDown = mScrollAdapter.isScrolledToTop();
final ExpandableView childAtTouchPos = getChildAtPosition(
ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */);
if (childAtTouchPos == null) {
@@ -4411,32 +4409,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToTop() {
- if (ANCHOR_SCROLLING) {
- updateScrollAnchor();
- // TODO: once we're recycling this will need to check the adapter position of the child
- return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
- } else {
- return mOwnScrollY == 0;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToBottom() {
- if (ANCHOR_SCROLLING) {
- return getMaxPositiveScrollAmount() <= 0;
- } else {
- return mOwnScrollY >= getScrollRange();
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public View getHostView() {
- return this;
+ boolean isScrolledToBottom() {
+ return mScrollAdapter.isScrolledToBottom();
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
@@ -4734,8 +4708,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateSensitiveness(boolean animate) {
- boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode();
+ void updateSensitiveness(boolean animate, boolean hideSensitive) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -4927,7 +4900,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
// Since we are clipping to the outline we need to make sure that the shadows aren't
// clipped when pulsing
float ownTranslationZ = 0;
- if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
ExpandableView firstChildNotGone = getFirstChildNotGone();
if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
ownTranslationZ = firstChildNotGone.getTranslationZ();
@@ -4992,11 +4965,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void updateEmptyShadeView(boolean visible) {
+ void updateEmptyShadeView(boolean visible, boolean notifVisibleInShade) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
int oldTextRes = mEmptyShadeView.getTextResource();
- int newTextRes = mZenController.areNotificationsHiddenInShade()
+ int newTextRes = notifVisibleInShade
? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
if (oldTextRes != newTextRes) {
mEmptyShadeView.setText(newTextRes);
@@ -5093,7 +5066,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestAnimateEverything() {
+ void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
mEverythingNeedsAnimation = true;
mNeedsAnimation = true;
@@ -5431,17 +5404,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mAmbientState.setStatusBarState(statusBarState);
}
- private void onStatePostChange() {
+ void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
+ mAmbientState.setActivatedChild(null);
+ mAmbientState.setDimmed(onKeyguard);
+
if (mHeadsUpAppearanceController != null) {
mHeadsUpAppearanceController.onStateChanged();
}
- SysuiStatusBarStateController state = (SysuiStatusBarStateController)
- Dependency.get(StatusBarStateController.class);
- updateSensitiveness(state.goingToFullShade() /* animate */);
- setDimmed(onKeyguard, state.fromShadeLocked() /* animate */);
+ setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = getActivatedChild();
setActivatedChild(null);
@@ -5771,7 +5744,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
*/
public float setPulseHeight(float height) {
mAmbientState.setPulseHeight(height);
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
notifyAppearChangedListeners();
}
requestChildrenUpdate();
@@ -5849,6 +5822,31 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return mController;
}
+ void setCurrentUserid(int userId) {
+ mCurrentUserId = userId;
+ }
+
+ void onMenuShown(View row) {
+ mSwipeHelper.onMenuShown(row);
+ }
+
+ void onMenuReset(View row) {
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ if (row instanceof ExpandableNotificationRow) {
+ mHeadsUpManager.setMenuShown(
+ ((ExpandableNotificationRow) row).getEntry(), false);
+
+ }
+ }
+ }
+
+ void setMenuEventListener(OnMenuEventListener menuEventListener) {
+ mMenuEventListener = menuEventListener;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -6204,89 +6202,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private final StateListener mStateListener = new StateListener() {
- @Override
- public void onStatePreChange(int oldState, int newState) {
- if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
- requestAnimateEverything();
- }
- }
- @Override
- public void onStateChanged(int newState) {
- setStatusBarState(newState);
- }
-
- @Override
- public void onStatePostChange() {
- NotificationStackScrollLayout.this.onStatePostChange();
- }
- };
-
- @VisibleForTesting
- @ShadeViewRefactor(RefactorComponent.INPUT)
- protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
- @Override
- public void onMenuClicked(View view, int x, int y, MenuItem item) {
- if (mLongPressListener == null) {
- return;
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
- .setType(MetricsEvent.TYPE_ACTION)
- );
- }
- mLongPressListener.onLongPress(view, x, y, item);
- }
-
- @Override
- public void onMenuReset(View row) {
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- if (translatingParentView != null && row == translatingParentView) {
- mSwipeHelper.clearExposedMenuView();
- mSwipeHelper.clearTranslatingParentView();
- if (row instanceof ExpandableNotificationRow) {
- mHeadsUpManager.setMenuShown(
- ((ExpandableNotificationRow) row).getEntry(), false);
-
- }
- }
- }
-
- @Override
- public void onMenuShown(View row) {
- if (row instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
- mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
- .setType(MetricsEvent.TYPE_ACTION));
- mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
- mSwipeHelper.onMenuShown(row);
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
-
- // Check to see if we want to go directly to the notfication guts
- NotificationMenuRowPlugin provider = notificationRow.getProvider();
- if (provider.shouldShowGutsOnSnapOpen()) {
- MenuItem item = provider.menuItemToExposeOnSnap();
- if (item != null) {
- Point origin = provider.getRevealAnimationOrigin();
- mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
- } else {
- Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
- + "menu item in menuItemtoExposeOnSnap. Skipping.");
- }
-
- // Close the menu row since we went directly to the guts
- resetExposedMenuView(false, true);
- }
- }
- }
- };
@ShadeViewRefactor(RefactorComponent.INPUT)
private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
@@ -6517,7 +6433,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@SelectedRows int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
- mNotifCollection.dismissAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mNotifCollection.dismissAllNotifications(mCurrentUserId);
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
@@ -6546,7 +6462,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
if (selectedRows == ROWS_ALL) {
try {
- mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) {
}
}
@@ -6568,6 +6484,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
NotificationLogger.getNotificationLocation(entry)));
}
+ public void setKeyguardMediaControllorVisible(boolean keyguardMediaControllorVisible) {
+ mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6576,8 +6496,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
- boolean canDragDown = hasActiveNotifications()
- || mKeyguardMediaController.getView().getVisibility() == VISIBLE;
+ boolean canDragDown = hasActiveNotifications() || mKeyguardMediaControllorVisible;
if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
@@ -6655,7 +6574,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public boolean isDragDownAnywhereEnabled() {
return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
- && !mKeyguardBypassController.getBypassEnabled();
+ && !mKeyguardBypassEnabledProvider.getBypassEnabled();
}
};
@@ -6838,4 +6757,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return INVALID;
}
}
+
+ interface KeyguardBypassEnabledProvider {
+ boolean getBypassEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7c29ee2b5483..ca78b2a1fc68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -18,8 +18,10 @@ package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+import android.graphics.Point;
import android.graphics.PointF;
import android.provider.Settings;
+import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
@@ -27,9 +29,20 @@ import android.view.WindowInsets;
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -42,6 +55,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -49,6 +63,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import java.util.function.BiConsumer;
@@ -56,11 +71,15 @@ import java.util.function.BiConsumer;
import javax.inject.Inject;
import javax.inject.Named;
+import kotlin.Unit;
+
/**
* Controller for {@link NotificationStackScrollLayout}.
*/
@StatusBarComponent.StatusBarScope
public class NotificationStackScrollLayoutController {
+ private static final String TAG = "StackScrollerController";
+
private final boolean mAllowLongPress;
private final NotificationGutsManager mNotificationGutsManager;
private final HeadsUpManagerPhone mHeadsUpManager;
@@ -68,9 +87,18 @@ public class NotificationStackScrollLayoutController {
private final TunerService mTunerService;
private final DynamicPrivacyController mDynamicPrivacyController;
private final ConfigurationController mConfigurationController;
+ private final ZenModeController mZenModeController;
+ private final MetricsLogger mMetricsLogger;
+ private final KeyguardMediaController mKeyguardMediaController;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final SysuiColorExtractor mColorExtractor;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+
+ private NotificationStackScrollLayout mView;
+
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
- private NotificationStackScrollLayout mView;
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -78,11 +106,14 @@ public class NotificationStackScrollLayoutController {
@Override
public void onViewAttachedToWindow(View v) {
mConfigurationController.addCallback(mConfigurationListener);
+ mStatusBarStateController.addCallback(
+ mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
}
@Override
public void onViewDetachedFromWindow(View v) {
mConfigurationController.removeCallback(mConfigurationListener);
+ mStatusBarStateController.removeCallback(mStateListener);
}
};
@@ -122,6 +153,91 @@ public class NotificationStackScrollLayoutController {
}
};
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ if (oldState == StatusBarState.SHADE_LOCKED
+ && newState == StatusBarState.KEYGUARD) {
+ mView.requestAnimateEverything();
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setStatusBarState(newState);
+ }
+
+ @Override
+ public void onStatePostChange() {
+ mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
+ mLockscreenUserManager.isAnyProfilePublicMode());
+ mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
+ }
+ };
+
+ private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
+ @Override
+ public void onUserChanged(int userId) {
+ mView.setCurrentUserid(userId);
+ mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
+ }
+ };
+
+ private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
+ @Override
+ public void onMenuClicked(
+ View view, int x, int y, NotificationMenuRowPlugin.MenuItem item) {
+ if (!mAllowLongPress) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION)
+ );
+ }
+ mNotificationGutsManager.openGuts(view, x, y, item);
+ }
+
+ @Override
+ public void onMenuReset(View row) {
+ mView.onMenuReset(row);
+ }
+
+ @Override
+ public void onMenuShown(View row) {
+ if (row instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
+ mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION));
+ mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
+ mView.onMenuShown(row);
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+
+ // Check to see if we want to go directly to the notification guts
+ NotificationMenuRowPlugin provider = notificationRow.getProvider();
+ if (provider.shouldShowGutsOnSnapOpen()) {
+ NotificationMenuRowPlugin.MenuItem item = provider.menuItemToExposeOnSnap();
+ if (item != null) {
+ Point origin = provider.getRevealAnimationOrigin();
+ mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
+ } else {
+ Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
+ + "menu item in menuItemtoExposeOnSnap. Skipping.");
+ }
+
+ // Close the menu row since we went directly to the guts
+ mView.resetExposedMenuView(false, true);
+ }
+ }
+ }
+ };
+
@Inject
public NotificationStackScrollLayoutController(
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
@@ -130,7 +246,14 @@ public class NotificationStackScrollLayoutController {
NotificationRoundnessManager notificationRoundnessManager,
TunerService tunerService,
DynamicPrivacyController dynamicPrivacyController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ SysuiStatusBarStateController statusBarStateController,
+ KeyguardMediaController keyguardMediaController,
+ KeyguardBypassController keyguardBypassController,
+ ZenModeController zenModeController,
+ SysuiColorExtractor colorExtractor,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ MetricsLogger metricsLogger) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -138,19 +261,28 @@ public class NotificationStackScrollLayoutController {
mTunerService = tunerService;
mDynamicPrivacyController = dynamicPrivacyController;
mConfigurationController = configurationController;
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardMediaController = keyguardMediaController;
+ mKeyguardBypassController = keyguardBypassController;
+ mZenModeController = zenModeController;
+ mColorExtractor = colorExtractor;
+ mLockscreenUserManager = lockscreenUserManager;
+ mMetricsLogger = metricsLogger;
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
-
- if (mAllowLongPress) {
- mView.setLongPressListener(mNotificationGutsManager::openGuts);
- }
+ mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled);
mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here?
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
+ mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
+ mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
+
+ mView.setMenuEventListener(mMenuEventListener);
+
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
@@ -165,6 +297,23 @@ public class NotificationStackScrollLayoutController {
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
+ mColorExtractor.addOnColorsChangedListener((colorExtractor, which) -> {
+ final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
+ mView.updateDecorViews(useDarkText);
+ });
+
+ mKeyguardMediaController.setVisibilityChangedListener(visible -> {
+ mView.setKeyguardMediaControllorVisible(visible);
+ if (visible) {
+ mView.generateAddAnimation(
+ mKeyguardMediaController.getView(), false /*fromMoreCard */);
+ } else {
+ mView.generateRemoveAnimation(mKeyguardMediaController.getView());
+ }
+ mView.requestChildrenUpdate();
+ return Unit.INSTANCE;
+ });
+
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
@@ -484,7 +633,7 @@ public class NotificationStackScrollLayoutController {
}
public void updateEmptyShadeView(boolean visible) {
- mView.updateEmptyShadeView(visible);
+ mView.updateEmptyShadeView(visible, mZenModeController.areNotificationsHiddenInShade());
}
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
@@ -646,7 +795,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void notifyGroupChildAdded(ExpandableView row) {
- mView.onViewAddedInternal(row);
+ mView.notifyGroupChildAdded(row);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 1523653dec3c..3dc29a1ae4d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -53,7 +53,6 @@ public class NotificationEntryBuilder {
/* ListEntry properties */
private GroupEntry mParent;
- private int mSection = -1;
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
@@ -68,7 +67,6 @@ public class NotificationEntryBuilder {
mRankingBuilder = new RankingBuilder(source.getRanking());
mParent = source.getParent();
- mSection = source.getSection();
mCreationTime = source.getCreationTime();
}
@@ -104,7 +102,6 @@ public class NotificationEntryBuilder {
/* ListEntry properties */
entry.setParent(mParent);
- entry.getAttachState().setSectionIndex(mSection);
return entry;
}
@@ -117,14 +114,6 @@ public class NotificationEntryBuilder {
}
/**
- * Sets the section.
- */
- public NotificationEntryBuilder setSection(int section) {
- mSection = section;
- return this;
- }
-
- /**
* Sets the SBN directly. If set, causes all calls to delegated SbnBuilder methods to be
* ignored.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 6fa5055c875d..8acb705c744d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -35,6 +35,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static java.util.Collections.singletonList;
+
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,6 +48,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -54,7 +57,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeL
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;
@@ -71,7 +74,6 @@ import org.mockito.Spy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -496,7 +498,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
assertTrue(entry.hasFinishedInitialization());
// WHEN the pipeline is kicked off
- mReadyForBuildListener.onBuildList(Arrays.asList(entry));
+ mReadyForBuildListener.onBuildList(singletonList(entry));
// THEN the entry's initialization time is reset
assertFalse(entry.hasFinishedInitialization());
@@ -609,13 +611,18 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a filter that removes all PACKAGE_4 notifs and sections that divide
// notifs based on package name
mListBuilder.addPreGroupFilter(new PackageFilter(PACKAGE_4));
- final NotifSection pkg1Section = spy(new PackageSection(PACKAGE_1));
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
+ final NotifSectioner pkg1Sectioner = spy(new PackageSectioner(PACKAGE_1));
+ final NotifSectioner pkg2Sectioner = spy(new PackageSectioner(PACKAGE_2));
// NOTE: no package 3 section explicitly added, so notifs with package 3 will get set by
// ShadeListBuilder's sDefaultSection which will demote it to the last section
- final NotifSection pkg4Section = spy(new PackageSection(PACKAGE_4));
- final NotifSection pkg5Section = spy(new PackageSection(PACKAGE_5));
- mListBuilder.setSections(Arrays.asList(pkg1Section, pkg2Section, pkg4Section, pkg5Section));
+ final NotifSectioner pkg4Sectioner = spy(new PackageSectioner(PACKAGE_4));
+ final NotifSectioner pkg5Sectioner = spy(new PackageSectioner(PACKAGE_5));
+ mListBuilder.setSectioners(
+ Arrays.asList(pkg1Sectioner, pkg2Sectioner, pkg4Sectioner, pkg5Sectioner));
+
+ final NotifSection pkg1Section = new NotifSection(pkg1Sectioner, 0);
+ final NotifSection pkg2Section = new NotifSection(pkg2Sectioner, 1);
+ final NotifSection pkg5Section = new NotifSection(pkg5Sectioner, 3);
// WHEN we build a list with different packages
addNotif(0, PACKAGE_4);
@@ -648,72 +655,61 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// THEN the first section (pkg1Section) is called on all top level elements (but
// no children and no entries that were filtered out)
- verify(pkg1Section).isInSection(mEntrySet.get(1));
- verify(pkg1Section).isInSection(mEntrySet.get(2));
- verify(pkg1Section).isInSection(mEntrySet.get(3));
- verify(pkg1Section).isInSection(mEntrySet.get(7));
- verify(pkg1Section).isInSection(mEntrySet.get(8));
- verify(pkg1Section).isInSection(mEntrySet.get(9));
- verify(pkg1Section).isInSection(mBuiltList.get(3));
-
- verify(pkg1Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(10));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(1));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(2));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(7));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(8));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(9));
+ verify(pkg1Sectioner).isInSection(mBuiltList.get(3));
+
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(10));
// THEN the last section (pkg5Section) is not called on any of the entries that were
// filtered or already in a section
- verify(pkg5Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(1));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(2));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(7));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(8));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(10));
-
- verify(pkg5Section).isInSection(mEntrySet.get(3));
- verify(pkg5Section).isInSection(mEntrySet.get(9));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(1));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(2));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(7));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(8));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(10));
+
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(9));
// THEN the correct section is assigned for entries in pkg1Section
- assertEquals(pkg1Section, mEntrySet.get(2).getNotifSection());
- assertEquals(0, mEntrySet.get(2).getSection());
- assertEquals(pkg1Section, mEntrySet.get(7).getNotifSection());
- assertEquals(0, mEntrySet.get(7).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(2).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(7).getSection());
// THEN the correct section is assigned for entries in pkg2Section
- assertEquals(pkg2Section, mEntrySet.get(1).getNotifSection());
- assertEquals(1, mEntrySet.get(1).getSection());
- assertEquals(pkg2Section, mEntrySet.get(8).getNotifSection());
- assertEquals(1, mEntrySet.get(8).getSection());
- assertEquals(pkg2Section, mBuiltList.get(3).getNotifSection());
- assertEquals(1, mBuiltList.get(3).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(1).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(8).getSection());
+ assertEquals(pkg2Section, mBuiltList.get(3).getSection());
// THEN no section was assigned to entries in pkg4Section (since they were filtered)
- assertEquals(null, mEntrySet.get(0).getNotifSection());
- assertEquals(-1, mEntrySet.get(0).getSection());
- assertEquals(null, mEntrySet.get(10).getNotifSection());
- assertEquals(-1, mEntrySet.get(10).getSection());
-
+ assertNull(mEntrySet.get(0).getSection());
+ assertNull(mEntrySet.get(10).getSection());
// THEN the correct section is assigned for entries in pkg5Section
- assertEquals(pkg5Section, mEntrySet.get(9).getNotifSection());
- assertEquals(3, mEntrySet.get(9).getSection());
+ assertEquals(pkg5Section, mEntrySet.get(9).getSection());
// THEN the children entries are assigned the same section as its parent
- assertEquals(mBuiltList.get(3).getNotifSection(), child(5).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(5).entry.getSection());
- assertEquals(mBuiltList.get(3).getNotifSection(), child(6).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(6).entry.getSection());
}
@Test
public void testNotifUsesDefaultSection() {
// GIVEN a Section for Package2
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
- mListBuilder.setSections(Arrays.asList(pkg2Section));
+ final NotifSectioner pkg2Section = spy(new PackageSectioner(PACKAGE_2));
+ mListBuilder.setSectioners(singletonList(pkg2Section));
// WHEN we build a list with pkg1 and pkg2 packages
addNotif(0, PACKAGE_1);
@@ -727,8 +723,8 @@ public class ShadeListBuilderTest extends SysuiTestCase {
);
// THEN the entry that didn't have an explicit section gets assigned the DefaultSection
- assertEquals(1, notif(0).entry.getSection());
- assertNotNull(notif(0).entry.getNotifSection());
+ assertNotNull(notif(0).entry.getSection());
+ assertEquals(1, notif(0).entry.getSectionIndex());
}
@Test
@@ -763,15 +759,15 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a bunch of registered listeners and pluggables
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
NotifPromoter promoter = spy(new IdPromoter(3));
- NotifSection section = spy(new PackageSection(PACKAGE_1));
+ NotifSectioner section = spy(new PackageSectioner(PACKAGE_1));
NotifComparator comparator = spy(new HypeComparator(PACKAGE_4));
NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_5));
mListBuilder.addPreGroupFilter(preGroupFilter);
mListBuilder.addOnBeforeTransformGroupsListener(mOnBeforeTransformGroupsListener);
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
- mListBuilder.setComparators(Collections.singletonList(comparator));
- mListBuilder.setSections(Arrays.asList(section));
+ mListBuilder.setComparators(singletonList(comparator));
+ mListBuilder.setSectioners(singletonList(section));
mListBuilder.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
mListBuilder.addFinalizeFilter(preRenderFilter);
mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
@@ -821,13 +817,13 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a variety of pluggables
NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
NotifPromoter idPromoter = new IdPromoter(4);
- NotifSection section = new PackageSection(PACKAGE_1);
+ NotifSectioner section = new PackageSectioner(PACKAGE_1);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
mListBuilder.addPreGroupFilter(packageFilter);
mListBuilder.addPromoter(idPromoter);
- mListBuilder.setSections(Arrays.asList(section));
- mListBuilder.setComparators(Collections.singletonList(hypeComparator));
+ mListBuilder.setSectioners(singletonList(section));
+ mListBuilder.setComparators(singletonList(hypeComparator));
// GIVEN a set of random notifs
addNotif(0, PACKAGE_1);
@@ -973,7 +969,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
RecordingOnBeforeSortListener listener =
new RecordingOnBeforeSortListener();
mListBuilder.addOnBeforeSortListener(listener);
- mListBuilder.setComparators(Arrays.asList(new HypeComparator(PACKAGE_3)));
+ mListBuilder.setComparators(singletonList(new HypeComparator(PACKAGE_3)));
// GIVEN some new notifs out of order
addNotif(0, PACKAGE_1);
@@ -1093,7 +1089,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
NotifComparator comparator = new HypeComparator(PACKAGE_5);
OnBeforeRenderListListener listener =
(list) -> comparator.invalidateList();
- mListBuilder.setComparators(Collections.singletonList(comparator));
+ mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
// WHEN we try to run the pipeline and the comparator is invalidated
@@ -1420,10 +1416,10 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
/** Represents a section for the passed pkg */
- private static class PackageSection extends NotifSection {
+ private static class PackageSectioner extends NotifSectioner {
private final String mPackage;
- PackageSection(String pkg) {
+ PackageSectioner(String pkg) {
super("PackageSection_" + pkg);
mPackage = pkg;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index ce8ce2e39bcc..639e791cbf23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -21,11 +21,9 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,7 +35,6 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.ArraySet;
import androidx.test.filters.SmallTest;
@@ -48,8 +45,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -61,8 +57,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -78,7 +72,7 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
- private NotifSection mFgsSection;
+ private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
private FakeExecutor mExecutor = new FakeExecutor(mClock);
@@ -111,7 +105,7 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
lifetimeExtenderCaptor.capture());
mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
- mFgsSection = mAppOpsCoordinator.getSection();
+ mFgsSection = mAppOpsCoordinator.getSectioner();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index be5c8a846afb..c49393d2ed34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -25,7 +25,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import org.junit.Assert.assertFalse
@@ -45,7 +45,7 @@ import org.mockito.Mockito.`when` as whenever
class ConversationCoordinatorTest : SysuiTestCase() {
// captured listeners and pluggables:
private lateinit var promoter: NotifPromoter
- private lateinit var peopleSection: NotifSection
+ private lateinit var peopleSectioner: NotifSectioner
@Mock
private lateinit var pipeline: NotifPipeline
@@ -70,7 +70,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
verify(pipeline).addPromoter(notifPromoterCaptor.capture())
promoter = notifPromoterCaptor.value
- peopleSection = coordinator.getSection()
+ peopleSectioner = coordinator.sectioner
entry = NotificationEntryBuilder().setChannel(channel).build()
}
@@ -88,7 +88,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON)
// only put people notifications in this section
- assertTrue(peopleSection.isInSection(entry))
- assertFalse(peopleSection.isInSection(NotificationEntryBuilder().build()))
+ assertTrue(peopleSectioner.isInSection(entry))
+ assertFalse(peopleSectioner.isInSection(NotificationEntryBuilder().build()))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index 730481afe638..fa992a5d5dbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -64,7 +64,7 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
private NotifPromoter mNotifPromoter;
private NotifLifetimeExtender mNotifLifetimeExtender;
private OnHeadsUpChangedListener mOnHeadsUpChangedListener;
- private NotifSection mNotifSection;
+ private NotifSectioner mNotifSectioner;
@Mock private NotifPipeline mNotifPipeline;
@Mock private HeadsUpManager mHeadsUpManager;
@@ -111,7 +111,7 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
mOnHeadsUpChangedListener = headsUpChangedListenerCaptor.getValue();
- mNotifSection = mCoordinator.getSection();
+ mNotifSectioner = mCoordinator.getSectioner();
mNotifLifetimeExtender.setCallback(mEndLifetimeExtension);
mEntry = new NotificationEntryBuilder().build();
}
@@ -132,8 +132,8 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
setCurrentHUN(mEntry);
// THEN only section the current HUN, mEntry
- assertTrue(mNotifSection.isInSection(mEntry));
- assertFalse(mNotifSection.isInSection(new NotificationEntryBuilder().build()));
+ assertTrue(mNotifSectioner.isInSection(mEntry));
+ assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 5f10f38b2ee8..3a7d28ab56ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import org.junit.Before;
@@ -61,8 +61,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
private NotifFilter mCapturedSuspendedFilter;
private NotifFilter mCapturedDozingFilter;
- private NotifSection mAlertingSection;
- private NotifSection mSilentSection;
+ private NotifSectioner mAlertingSectioner;
+ private NotifSectioner mSilentSectioner;
@Before
public void setup() {
@@ -76,8 +76,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0);
mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1);
- mAlertingSection = rankingCoordinator.getAlertingSection();
- mSilentSection = rankingCoordinator.getSilentSection();
+ mAlertingSectioner = rankingCoordinator.getAlertingSectioner();
+ mSilentSectioner = rankingCoordinator.getSilentSectioner();
}
@Test
@@ -146,8 +146,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
// THEN entry is in the alerting section
- assertTrue(mAlertingSection.isInSection(mEntry));
- assertFalse(mSilentSection.isInSection(mEntry));
+ assertTrue(mAlertingSectioner.isInSection(mEntry));
+ assertFalse(mSilentSectioner.isInSection(mEntry));
}
@Test
@@ -156,8 +156,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN entry is in the silent section
- assertFalse(mAlertingSection.isInSection(mEntry));
- assertTrue(mSilentSection.isInSection(mEntry));
+ assertFalse(mAlertingSectioner.isInSection(mEntry));
+ assertTrue(mSilentSectioner.isInSection(mEntry));
}
private RankingBuilder getRankingForUnfilteredNotif() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 9a6674e165e4..bca7b312ff15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -24,9 +24,7 @@ import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
@@ -47,19 +45,15 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -87,14 +81,13 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.leak.LeakDetector;
import org.junit.After;
@@ -103,7 +96,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -135,14 +127,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
- @Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private KeyguardMediaController mKeyguardMediaController;
- @Mock private ZenModeController mZenModeController;
+ @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
- @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private FeatureFlags mFeatureFlags;
- private UserChangedListener mUserChangedListener;
+ @Mock private SysuiStatusBarStateController mStatusBarStateController;
private NotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -172,8 +161,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
- .forClass(UserChangedListener.class);
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
mock(NotificationGroupManager.class),
@@ -211,17 +198,15 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// which refer to members of NotificationStackScrollLayout. The spy
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
- mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
+ mStackScrollerInternal = new NotificationStackScrollLayout(
+ getContext(),
+ null,
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
- mock(SysuiStatusBarStateController.class),
+ mStatusBarStateController,
mHeadsUpManager,
- mKeyguardBypassController,
- mKeyguardMediaController,
new FalsingManagerFake(),
- mLockscreenUserManager,
mock(NotificationGutsManager.class),
- mZenModeController,
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -231,8 +216,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(NotifCollection.class),
mUiEventLoggerFake
);
- verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
- mUserChangedListener = userChangedCaptor.getValue();
+ mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
@@ -269,9 +253,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void updateEmptyView_dndSuppressing() {
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -280,9 +263,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_dndNotSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
}
@@ -291,12 +273,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_noNotificationsToDndSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -312,12 +292,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
- public void testOnStatePostChange_verifyIfProfileIsPublic() {
- mUserChangedListener.onUserChanged(0);
- verify(mLockscreenUserManager).isAnyProfilePublicMode();
- }
-
- @Test
public void manageNotifications_visible() {
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -473,61 +447,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
assertNull(swipeActionHelper.getExposedMenuView());
}
- class LogMatcher implements ArgumentMatcher<LogMaker> {
- private int mCategory, mType;
-
- LogMatcher(int category, int type) {
- mCategory = category;
- mType = type;
- }
- public boolean matches(LogMaker l) {
- return (l.getCategory() == mCategory)
- && (l.getType() == mType);
- }
-
- public String toString() {
- return String.format("LogMaker(%d, %d)", mCategory, mType);
- }
- }
-
- private LogMaker logMatcher(int category, int type) {
- return argThat(new LogMatcher(category, type));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuClickedLogging() {
- // Set up the object under test to have a valid mLongPressListener. We're testing an
- // anonymous-class member, mMenuEventListener, so we need to modify the state of the
- // class itself, not the Mockito spy copied from it. See notes in setup.
- mStackScrollerInternal.setLongPressListener(
- mock(ExpandableNotificationRow.LongPressListener.class));
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
- NotificationMenuRowPlugin.MenuItem.class));
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuShownLogging() { ;
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuShown(row);
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
- }
-
@Test
public void testClearNotifications_All() {
mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index e3acf0213725..83d6ac904bfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -17,25 +17,45 @@
package com.android.systemui.statusbar.notification.stack;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+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 static org.mockito.Mockito.when;
+import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -55,15 +75,27 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
@Mock
private TunerService mTunerService;
@Mock
- private AmbientState mAmbientState;
- @Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock
+ private ZenModeController mZenModeController;
+ @Mock
+ private KeyguardMediaController mKeyguardMediaController;
+ @Mock
+ private SysuiStatusBarStateController mSysuiStatusBarStateController;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+ @Mock
+ private MetricsLogger mMetricsLogger;
- NotificationStackScrollLayoutController mController;
+ private NotificationStackScrollLayoutController mController;
@Before
public void setUp() {
@@ -76,7 +108,14 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mNotificationRoundnessManager,
mTunerService,
mDynamicPrivacyController,
- mConfigurationController
+ mConfigurationController,
+ mSysuiStatusBarStateController,
+ mKeyguardMediaController,
+ mKeyguardBypassController,
+ mZenModeController,
+ mColorExtractor,
+ mNotificationLockscreenUserManager,
+ mMetricsLogger
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -112,4 +151,140 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mController.mConfigurationListener.onDensityOrFontScaleChanged();
verify(mNotificationStackScrollLayout).reinflateViews();
}
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsVisible() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ true /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ true /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsHidden() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ false /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ false /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testOnUserChange_verifySensitiveProfile() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
+ .forClass(UserChangedListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationLockscreenUserManager)
+ .addUserChangedListener(userChangedCaptor.capture());
+ reset(mNotificationStackScrollLayout);
+
+ UserChangedListener changedListener = userChangedCaptor.getValue();
+ changedListener.onUserChanged(0);
+ verify(mNotificationStackScrollLayout).setCurrentUserid(0);
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+ @Test
+ public void testOnStatePostChange_verifyIfProfileIsPublic() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mSysuiStatusBarStateController).addCallback(
+ stateListenerArgumentCaptor.capture(), anyInt());
+
+ StatusBarStateController.StateListener stateListener =
+ stateListenerArgumentCaptor.getValue();
+
+ stateListener.onStatePostChange();
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+
+ @Test
+ public void testOnMenuShownLogging() { ;
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationStackScrollLayout).setMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuShown(row);
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ @Test
+ public void testOnMenuClickedLogging() {
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationStackScrollLayout).setMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuClicked(row, 0, 0, mock(
+ NotificationMenuRowPlugin.MenuItem.class));
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ private LogMaker logMatcher(int category, int type) {
+ return argThat(new LogMatcher(category, type));
+ }
+
+ static class LogMatcher implements ArgumentMatcher<LogMaker> {
+ private int mCategory, mType;
+
+ LogMatcher(int category, int type) {
+ mCategory = category;
+ mType = type;
+ }
+ public boolean matches(LogMaker l) {
+ return (l.getCategory() == mCategory)
+ && (l.getType() == mType);
+ }
+
+ public String toString() {
+ return String.format("LogMaker(%d, %d)", mCategory, mType);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
index 260ff2dafeed..33ece0084906 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
@@ -70,9 +70,7 @@ public class DeviceConfigProxyFake extends DeviceConfigProxy {
for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
Properties.Builder propBuilder = new Properties.Builder(namespace);
- for (String key : mProperties.get(namespace).keySet()) {
- propBuilder.setString(key, mProperties.get(namespace).get(key));
- }
+ propBuilder.setString(name, value);
listener.first.execute(() -> listener.second.onPropertiesChanged(propBuilder.build()));
}
return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
new file mode 100644
index 000000000000..64e89579393e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.systemui.util;
+
+import static android.provider.DeviceConfig.Properties;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceConfigProxyFakeTest extends SysuiTestCase {
+ private static final String NAMESPACE = "foobar";
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private DeviceConfigProxyFake mDeviceConfigProxyFake;
+
+ @Before
+ public void setup() {
+ mDeviceConfigProxyFake = new DeviceConfigProxyFake();
+ }
+
+ @Test
+ public void testOnPropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String key = "foo";
+ String value = "bar";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, key, value, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(key, "")).isEqualTo(value);
+ }
+
+ @Test
+ public void testOnMultiplePropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String keyA = "foo";
+ String valueA = "bar";
+ String keyB = "bada";
+ String valueB = "boom";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyA, valueA, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyA, "")).isEqualTo(valueA);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyB, valueB, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyB, "")).isEqualTo(valueB);
+ }
+
+ private static class TestableListener implements OnPropertiesChangedListener {
+ Properties mProperties;
+
+ TestableListener() {
+ }
+ @Override
+ public void onPropertiesChanged(@NonNull Properties properties) {
+ mProperties = properties;
+ }
+ }
+}
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
index fa85f66489d7..97c3988829fe 100644
--- a/packages/Tethering/AndroidManifestBase.xml
+++ b/packages/Tethering/AndroidManifestBase.xml
@@ -23,6 +23,7 @@
<application
android:label="Tethering"
android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
+ android:directBootAware="true"
+ android:usesCleartextTraffic="true">
</application>
</manifest>
diff --git a/services/Android.bp b/services/Android.bp
index b348b91a1bd7..ef52c2aff002 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -156,10 +156,14 @@ droidstubs {
java_library {
name: "android_system_server_stubs_current",
+ defaults: ["android_stubs_dists_default"],
srcs: [":services-stubs.sources"],
installable: false,
static_libs: ["android_module_lib_stubs_current"],
sdk_version: "none",
system_modules: "none",
java_version: "1.8",
+ dist: {
+ dir: "apistubs/android/system-server",
+ },
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 669bb24e0e77..a75b64ce08f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -284,11 +284,13 @@ public class AccessibilityWindowManager {
* Computes partial interactive region of given windowId.
*
* @param windowId The windowId
+ * @param forceComputeRegion set outRegion when the windowId matches one on the screen even
+ * though the region is not covered by other windows above it.
* @param outRegion The output to which to write the bounds.
- * @return true if outRegion is not empty.
+ * @return {@code true} if outRegion is not empty.
*/
boolean computePartialInteractiveRegionForWindowLocked(int windowId,
- @NonNull Region outRegion) {
+ boolean forceComputeRegion, @NonNull Region outRegion) {
if (mWindows == null) {
return false;
}
@@ -309,6 +311,9 @@ public class AccessibilityWindowManager {
currentWindow.getRegionInScreen(currentWindowRegions);
outRegion.set(currentWindowRegions);
windowInteractiveRegion = outRegion;
+ if (forceComputeRegion) {
+ windowInteractiveRegionChanged = true;
+ }
continue;
}
} else if (currentWindow.getType()
@@ -1240,10 +1245,13 @@ public class AccessibilityWindowManager {
*/
public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
@NonNull Region outRegion) {
- windowId = resolveParentWindowIdLocked(windowId);
- final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId);
+ final int parentWindowId = resolveParentWindowIdLocked(windowId);
+ final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(
+ parentWindowId);
+
if (observer != null) {
- return observer.computePartialInteractiveRegionForWindowLocked(windowId, outRegion);
+ return observer.computePartialInteractiveRegionForWindowLocked(parentWindowId,
+ parentWindowId != windowId, outRegion);
}
return false;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index a2d58c8019fc..b587dd33c4e5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -561,24 +561,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
// stream consistent.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
- if (mGestureDetector.isMultiFingerGesturesEnabled()
- && mGestureDetector.isTwoFingerPassthroughEnabled()) {
- if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = false;
- // If three fingers go down on the bottom edge of the screen, delegate immediately.
- final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- > (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = true;
- }
- }
- if (isOnBottomEdge) {
- mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
- }
- }
- }
}
/**
@@ -644,12 +626,34 @@ public class TouchExplorer extends BaseEventStreamTransformation
break;
default:
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
- return;
+ if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
+ if (event.getPointerCount() == 3) {
+ boolean isOnBottomEdge = true;
+ // If three fingers went down on the bottom edge of the screen, delegate
+ // immediately.
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
+ if (mReceivedPointerTracker.getReceivedPointerDownY(i)
+ < (screenHeight - mEdgeSwipeHeightPixels)) {
+ isOnBottomEdge = false;
+ }
+ }
+ if (isOnBottomEdge) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
+ }
+ mState.startDelegating();
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ }
+ }
+ }
+ } else {
+ // More than two pointers are delegated to the view hierarchy.
+ mState.startDelegating();
+ event = MotionEvent.obtainNoHistory(event);
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
}
- // More than two pointers are delegated to the view hierarchy.
- mState.startDelegating();
- event = MotionEvent.obtainNoHistory(event);
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
break;
}
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index df966c1ea6ac..34e63705d781 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -47,8 +47,8 @@ import java.util.ArrayList;
*
* {@hide}
*/
-public class SystemServiceManager {
- private static final String TAG = "SystemServiceManager";
+public final class SystemServiceManager {
+ private static final String TAG = SystemServiceManager.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int SERVICE_CALL_WARN_TIME_MS = 50;
@@ -250,76 +250,76 @@ public class SystemServiceManager {
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
}
- private @NonNull TargetUser getTargetUser(@UserIdInt int userHandle) {
+ private @NonNull TargetUser getTargetUser(@UserIdInt int userId) {
final TargetUser targetUser;
synchronized (mTargetUsers) {
- targetUser = mTargetUsers.get(userHandle);
+ targetUser = mTargetUsers.get(userId);
}
- Preconditions.checkState(targetUser != null, "No TargetUser for " + userHandle);
+ Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
return targetUser;
}
/**
* Starts the given user.
*/
- public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
+ public void startUser(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) {
// Create cached TargetUser
- final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle);
- Preconditions.checkState(userInfo != null, "No UserInfo for " + userHandle);
+ final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
+ Preconditions.checkState(userInfo != null, "No UserInfo for " + userId);
synchronized (mTargetUsers) {
- mTargetUsers.put(userHandle, new TargetUser(userInfo));
+ mTargetUsers.put(userId, new TargetUser(userInfo));
}
- onUser(t, START, userHandle);
+ onUser(t, START, userId);
}
/**
* Unlocks the given user.
*/
- public void unlockUser(final @UserIdInt int userHandle) {
- onUser(UNLOCKING, userHandle);
+ public void unlockUser(@UserIdInt int userId) {
+ onUser(UNLOCKING, userId);
}
/**
* Called after the user was unlocked.
*/
- public void onUserUnlocked(final @UserIdInt int userHandle) {
- onUser(UNLOCKED, userHandle);
+ public void onUserUnlocked(@UserIdInt int userId) {
+ onUser(UNLOCKED, userId);
}
/**
* Switches to the given user.
*/
- public void switchUser(final @UserIdInt int from, final @UserIdInt int to) {
+ public void switchUser(@UserIdInt int from, @UserIdInt int to) {
onUser(TimingsTraceAndSlog.newAsyncLog(), SWITCH, to, from);
}
/**
* Stops the given user.
*/
- public void stopUser(final @UserIdInt int userHandle) {
- onUser(STOP, userHandle);
+ public void stopUser(@UserIdInt int userId) {
+ onUser(STOP, userId);
}
/**
* Cleans up the given user.
*/
- public void cleanupUser(final @UserIdInt int userHandle) {
- onUser(CLEANUP, userHandle);
+ public void cleanupUser(@UserIdInt int userId) {
+ onUser(CLEANUP, userId);
// Remove cached TargetUser
synchronized (mTargetUsers) {
- mTargetUsers.remove(userHandle);
+ mTargetUsers.remove(userId);
}
}
- private void onUser(@NonNull String onWhat, @UserIdInt int userHandle) {
- onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle);
+ private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
+ onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userId);
}
private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
- @UserIdInt int userHandle) {
- onUser(t, onWhat, userHandle, UserHandle.USER_NULL);
+ @UserIdInt int userId) {
+ onUser(t, onWhat, userId, UserHandle.USER_NULL);
}
private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6d71c8e68f77..19871f993d42 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -315,11 +315,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
mPreciseDataConnectionStates;
- static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
- PhoneStateListener.LISTEN_REGISTRATION_FAILURE
- | PhoneStateListener.LISTEN_BARRING_INFO;
-
- static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
+ // Starting in Q, almost all cellular location requires FINE location enforcement.
+ // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
+ // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
+ static final int ENFORCE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -376,7 +375,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " newDefaultPhoneId=" + newDefaultPhoneId);
}
- //Due to possible risk condition,(notify call back using the new
+ //Due to possible race condition,(notify call back using the new
//defaultSubId comes before new defaultSubId update) we need to recall all
//possible missed notify callback
synchronized (mRecords) {
@@ -909,7 +908,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
@@ -964,7 +964,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -1518,7 +1519,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo
@@ -1797,7 +1799,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -2544,16 +2547,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
boolean shouldCheckLocationPermissions = false;
- if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) {
+ if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
// Everything that requires fine location started in Q. So far...
locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
- // If we're enforcing fine starting in Q, we also want to enforce coarse starting in Q.
- locationQueryBuilder.setMinSdkVersionForCoarse(Build.VERSION_CODES.Q);
- locationQueryBuilder.setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q);
- shouldCheckLocationPermissions = true;
- }
-
- if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
+ // If we're enforcing fine starting in Q, we also want to enforce coarse even for
+ // older SDK versions.
locationQueryBuilder.setMinSdkVersionForCoarse(0);
locationQueryBuilder.setMinSdkVersionForEnforcement(0);
shouldCheckLocationPermissions = true;
@@ -2750,8 +2748,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
mServiceState[phoneId]);
- r.callback.onServiceStateChanged(
- new ServiceState(mServiceState[phoneId]));
+ ServiceState ss = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(ss);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(false));
+ } else {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(true));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2796,7 +2802,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -2862,7 +2869,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
+ mCellIdentity[phoneId]);
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1815dac4c3a8..990a547144a0 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -99,6 +99,7 @@ public class Watchdog {
"android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
+ "android.hardware.audio@7.0::IDevicesFactory",
"android.hardware.biometrics.face@1.0::IBiometricsFace",
"android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
"android.hardware.bluetooth@1.0::IBluetoothHci",
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bf7c68a845c5..0a179e89f757 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1283,6 +1283,7 @@ public class AudioService extends IAudioService.Stub
}
if (isPlatformTelevision()) {
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
updateHdmiCecSinkLocked(mHdmiCecSink | false);
@@ -1302,54 +1303,22 @@ public class AudioService extends IAudioService.Stub
}
}
- /**
- * Update volume states for the given device.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param caller caller of this method
- */
- private void updateVolumeStatesForAudioDevice(int device, String caller) {
+ private void checkAddAllFixedVolumeDevices(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- updateVolumeStates(device, streamType, caller);
- }
- }
-
- /**
- * Update volume states for the given device and given stream.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param streamType streamType to be updated
- * @param caller caller of this method
- */
- private void updateVolumeStates(int device, int streamType, String caller) {
- if (!mStreamStates[streamType].hasIndexForDevice(device)) {
- // set the default value, if device is affected by a full/fix/abs volume rule, it
- // will taken into account in checkFixedVolumeDevices()
- mStreamStates[streamType].setIndex(
- mStreamStates[mStreamVolumeAlias[streamType]]
- .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
- device, caller, true /*hasModifyAudioSettings*/);
- }
-
- // Check if device to be updated is routed for the given audio stream
- List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(
- new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
- for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
- if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
- device)) {
- mStreamStates[streamType].checkFixedVolumeDevices();
+ if (!mStreamStates[streamType].hasIndexForDevice(device)) {
+ // set the default value, if device is affected by a full/fix/abs volume rule, it
+ // will taken into account in checkFixedVolumeDevices()
+ mStreamStates[streamType].setIndex(
+ mStreamStates[mStreamVolumeAlias[streamType]]
+ .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
+ device, caller, true /*hasModifyAudioSettings*/);
+ }
+ mStreamStates[streamType].checkFixedVolumeDevices();
- // Unmute streams if required if device is full volume
- if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) {
- mStreamStates[streamType].mute(false);
- }
+ // Unmute streams if device is full volume
+ if (mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
}
}
}
@@ -1899,13 +1868,8 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
- enforceModifyAudioRoutingPermission();
- return getDevicesForAttributesInt(attributes);
- }
-
- protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt(
- @NonNull AudioAttributes attributes) {
Objects.requireNonNull(attributes);
+ enforceModifyAudioRoutingPermission();
return AudioSystem.getDevicesForAttributes(attributes);
}
@@ -4952,15 +4916,7 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (stream != skipStream) {
- int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
- false /*checkOthers*/);
-
- Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
- for (Integer device : devicesSet) {
- // Update volume states for devices routed for the stream
- updateVolumeStates(device, stream,
- "AudioService#observeDevicesForStreams");
- }
+ mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
}
}
}
@@ -5029,7 +4985,7 @@ public class AudioService extends IAudioService.Stub
+ Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
// make sure we have a volume entry for this device, and that volume is updated according
// to volume behavior
- updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
+ checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
}
/**
@@ -7251,9 +7207,10 @@ public class AudioService extends IAudioService.Stub
// HDMI output
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
}
- updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
- "HdmiPlaybackClient.DisplayStatusCallback");
}
+
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
+ "HdmiPlaybackClient.DisplayStatusCallback");
}
private class MyHdmiControlStatusChangeListenerCallback
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 041bedc3c575..ec12a971e445 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -210,6 +210,7 @@ public class SyncManager {
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
+ private static final boolean USE_WTF_FOR_ACCOUNT_ERROR = false;
private static final int SYNC_OP_STATE_VALID = 0;
// "1" used to include errors 3, 4 and 5 but now it's split up.
@@ -3446,7 +3447,7 @@ public class SyncManager {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist.");
+ logAccountError("SYNC_OP_STATE_INVALID: account doesn't exist.");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT;
}
// Drop this sync request if it isn't syncable.
@@ -3456,14 +3457,14 @@ public class SyncManager {
Slog.v(TAG, " Dropping sync operation: "
+ "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
+ logAccountError("SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
}
if (state == AuthorityInfo.NOT_SYNCABLE) {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
+ logAccountError("SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
return SYNC_OP_STATE_INVALID_NOT_SYNCABLE;
}
@@ -3482,12 +3483,20 @@ public class SyncManager {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network");
+ logAccountError("SYNC_OP_STATE_INVALID: disallowed by settings/network");
return SYNC_OP_STATE_INVALID_SYNC_DISABLED;
}
return SYNC_OP_STATE_VALID;
}
+ private void logAccountError(String message) {
+ if (USE_WTF_FOR_ACCOUNT_ERROR) {
+ Slog.wtf(TAG, message);
+ } else {
+ Slog.e(TAG, message);
+ }
+ }
+
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index dab8c7fc9d48..2c632d96e738 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2174,10 +2174,14 @@ public final class DisplayManagerService extends SystemService {
}
}
- if (callingUid == Process.SYSTEM_UID
- || checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
- flags |= VIRTUAL_DISPLAY_FLAG_TRUSTED;
- } else {
+ if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
+ if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+ throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ + "create a trusted virtual display.");
+ }
+ }
+
+ if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 8777ceacf884..1e02f49c43e4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -36,6 +36,7 @@ import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
+import android.media.session.ParcelableListBinder;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
@@ -905,14 +906,24 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
- public void setQueue(ParceledListSlice queue) throws RemoteException {
+ public void resetQueue() throws RemoteException {
synchronized (mLock) {
- mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
+ mQueue = null;
}
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
}
@Override
+ public IBinder getBinderForSetQueue() throws RemoteException {
+ return new ParcelableListBinder<QueueItem>((list) -> {
+ synchronized (mLock) {
+ mQueue = list;
+ }
+ mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
+ });
+ }
+
+ @Override
public void setQueueTitle(CharSequence title) throws RemoteException {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a8a0e2e937d0..9521611c241d 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1918,7 +1918,7 @@ public class MediaSessionService extends SystemService implements Monitor {
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
final long token = Binder.clearCallingIdentity();
try {
- // Don't perform sanity check between controllerPackageName and controllerUid.
+ // Don't perform check between controllerPackageName and controllerUid.
// When an (activity|service) runs on the another apps process by specifying
// android:process in the AndroidManifest.xml, then PID and UID would have the
// running process' information instead of the (activity|service) that has created
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8af74631fb2e..4b246c3b330c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1284,14 +1284,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
pw.increaseIndent();
List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
+ List<PackageInstallerSession> orphanedChildSessions = new ArrayList<>();
int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- // Do not print finalized staged session as active install sessions
final PackageInstallerSession rootSession = session.hasParentSessionId()
? getSession(session.getParentSessionId())
: session;
+ // Do not print orphaned child sessions as active install sessions
+ if (rootSession == null) {
+ orphanedChildSessions.add(session);
+ continue;
+ }
+
+ // Do not print finalized staged session as active install sessions
if (rootSession.isStagedAndInTerminalState()) {
finalizedSessions.add(session);
continue;
@@ -1303,6 +1310,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
pw.println();
pw.decreaseIndent();
+ if (!orphanedChildSessions.isEmpty()) {
+ // Presence of orphaned sessions indicate leak in cleanup for multi-package and
+ // should be cleaned up.
+ pw.println("Orphaned install sessions:");
+ pw.increaseIndent();
+ N = orphanedChildSessions.size();
+ for (int i = 0; i < N; i++) {
+ final PackageInstallerSession session = orphanedChildSessions.get(i);
+ session.dump(pw);
+ pw.println();
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
+
pw.println("Finalized install sessions:");
pw.increaseIndent();
N = finalizedSessions.size();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9c8b972985eb..5fba8b93ff4c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -367,7 +367,6 @@ import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.permission.PermissionsState;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.VerityUtils;
@@ -1818,7 +1817,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
mDirtyUsers.clear();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -1838,6 +1837,7 @@ public class PackageManagerService extends IPackageManager.Stub
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2518,7 +2518,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
mSettings.onVolumeForgotten(fsUuid);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
};
@@ -3442,6 +3442,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
@@ -3561,7 +3562,7 @@ public class PackageManagerService extends IPackageManager.Stub
// can downgrade to reader
t.traceBegin("write settings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@@ -3765,7 +3766,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
@@ -3776,9 +3777,8 @@ public class PackageManagerService extends IPackageManager.Stub
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
- installPackageFromSystemLIF(stubPkg.getCodePath(),
- null /*allUserHandles*/, null /*origUserHandles*/,
- null /*origPermissionsState*/, true /*writeSettings*/);
+ installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/,
+ null /*origUserHandles*/, true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3792,7 +3792,7 @@ public class PackageManagerService extends IPackageManager.Stub
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return false;
@@ -13092,7 +13092,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
if (sendRemoved) {
- killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+ killApplication(packageName, pkgSetting.appId, userId,
"hiding pkg");
sendApplicationHiddenForUser(packageName, pkgSetting, userId);
return true;
@@ -16280,7 +16280,7 @@ public class PackageManagerService extends IPackageManager.Stub
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -18877,6 +18877,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
outInfo.removedAppId = removedAppId;
}
+ if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0)
+ && !isUpdatedSystemApp(deletedPs)) {
+ mPermissionManager.removePermissionsStateTEMP(removedAppId);
+ }
mPermissionManager.updatePermissions(deletedPs.name, null);
if (deletedPs.sharedUser != null) {
// Remove permissions associated with package. Since runtime
@@ -18886,10 +18890,10 @@ public class PackageManagerService extends IPackageManager.Stub
// package is successful and this causes a change in gids.
boolean shouldKill = false;
for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
- userId);
- shouldKill |= userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_SYSTEM;
+ final int userIdToKill = mPermissionManager
+ .revokeSharedUserPermissionsForDeletedPackageTEMP(deletedPs,
+ userId);
+ shouldKill |= userIdToKill != UserHandle.USER_NULL;
}
// If gids changed, kill all affected packages.
if (shouldKill) {
@@ -18933,7 +18937,7 @@ public class PackageManagerService extends IPackageManager.Stub
// can downgrade to reader
if (writeSettings) {
// Save settings now
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
if (installedStateChanged) {
mSettings.writeKernelMappingLPr(deletedPs);
@@ -19020,8 +19024,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
- outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
- writeSettings);
+ outInfo == null ? null : outInfo.origUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ e.getMessage());
@@ -19052,9 +19055,8 @@ public class PackageManagerService extends IPackageManager.Stub
* Installs a package that's already on the system partition.
*/
private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
- @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
- @Nullable PermissionsState origPermissionState, boolean writeSettings)
- throws PackageManagerException {
+ @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+ throws PackageManagerException {
final File codePath = new File(codePathString);
@ParseFlags int parseFlags =
mDefParseFlags
@@ -19091,12 +19093,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
- // Propagate the permissions state as we do not want to drop on the floor
- // runtime permissions. The update permissions method below will take
- // care of removing obsolete permissions and grant install permissions.
- if (origPermissionState != null) {
- ps.getPermissionsState().copyFrom(origPermissionState);
- }
+ // The update permissions method below will take care of removing obsolete permissions
+ // and granting install permissions.
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
final boolean applyUserRestrictions
@@ -19130,7 +19128,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// can downgrade to reader here
if (writeSettings) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return pkg;
@@ -19204,7 +19202,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
return true;
}
@@ -20396,7 +20394,7 @@ public class PackageManagerService extends IPackageManager.Stub
(parser1, userId1) -> {
synchronized (mLock) {
mSettings.readAllDomainVerificationsLPr(parser1, userId1);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
});
} catch (Exception e) {
@@ -21747,6 +21745,8 @@ public class PackageManagerService extends IPackageManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
boolean checkin = false;
@@ -21942,7 +21942,7 @@ public class PackageManagerService extends IPackageManager.Stub
dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
} else if ("write".equals(cmd)) {
synchronized (mLock) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
pw.println("Settings written.");
return;
}
@@ -22660,7 +22660,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Yay, everything is now upgraded
ver.forceCurrent();
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
for (PackageFreezer freezer : freezers) {
@@ -22710,7 +22710,7 @@ public class PackageManagerService extends IPackageManager.Stub
AttributeCache.instance().removePackage(ps.name);
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -23623,6 +23623,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
mDirtyUsers.remove(userId);
mUserNeedsBadging.delete(userId);
+ mPermissionManager.onUserRemoved(userId);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.removeUserLPw(userId);
mPendingBroadcasts.remove(userId);
mInstantAppRegistry.onUserRemovedLPw(userId);
@@ -23723,7 +23725,9 @@ public class PackageManagerService extends IPackageManager.Stub
boolean readPermissionStateForUser(@UserIdInt int userId) {
synchronized (mPackages) {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
return mPmInternal.isPermissionUpgradeNeeded(userId);
}
}
@@ -25179,7 +25183,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (async) {
scheduleWriteSettingsLocked();
} else {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
}
@@ -25226,7 +25230,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE;
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -25740,6 +25744,17 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
}
+
+ /**
+ * Temporary method that wraps mSettings.writeLPr() and calls
+ * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand.
+ *
+ * TODO(zhanghai): This should be removed once we finish migration of permission storage.
+ */
+ private void writeSettingsLPrTEMP() {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+ mSettings.writeLPr();
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index de0e4b53adab..491b4fc515ce 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,7 +34,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
@@ -68,7 +67,6 @@ import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionsState;
import dalvik.system.VMRuntime;
@@ -968,20 +966,6 @@ public class PackageManagerServiceUtils {
}
/**
- * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
- * could not be found, {@code null} will be returned.
- */
- public static PermissionsState getPermissionsState(
- PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
- final PackageSetting packageSetting = packageManagerInternal.getPackageSetting(
- pkg.getPackageName());
- if (packageSetting == null) {
- return null;
- }
- return packageSetting.getPermissionsState();
- }
-
- /**
* Recursively create target directory
*/
public static void makeDirRecursive(File targetDir, int mode) throws ErrnoException {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index acb149b9ec3d..d545bd4c1531 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -955,93 +955,6 @@ public final class Settings {
}
}
- /*
- * Update the shared user setting when a package with a shared user id is removed. The gids
- * associated with each permission of the deleted package are removed from the shared user'
- * gid list only if its not in use by other permissions of packages in the shared user setting.
- *
- * @return the affected user id
- */
- @UserIdInt
- int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) {
- if ((deletedPs == null) || (deletedPs.pkg == null)) {
- Slog.i(PackageManagerService.TAG,
- "Trying to update info for null package. Just ignoring");
- return UserHandle.USER_NULL;
- }
-
- // No sharedUserId
- if (deletedPs.sharedUser == null) {
- return UserHandle.USER_NULL;
- }
-
- SharedUserSetting sus = deletedPs.sharedUser;
-
- int affectedUserId = UserHandle.USER_NULL;
- // Update permissions
- for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
- BasePermission bp = mPermissions.getPermission(eachPerm);
- if (bp == null) {
- continue;
- }
-
- // Check if another package in the shared user needs the permission.
- boolean used = false;
- for (PackageSetting pkg : sus.packages) {
- if (pkg.pkg != null
- && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
- && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
- used = true;
- break;
- }
- }
- if (used) {
- continue;
- }
-
- PermissionsState permissionsState = sus.getPermissionsState();
- PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
-
- // If the package is shadowing is a disabled system package,
- // do not drop permissions that the shadowed package requests.
- if (disabledPs != null) {
- boolean reqByDisabledSysPkg = false;
- for (String permission : disabledPs.pkg.getRequestedPermissions()) {
- if (permission.equals(eachPerm)) {
- reqByDisabledSysPkg = true;
- break;
- }
- }
- if (reqByDisabledSysPkg) {
- continue;
- }
- }
-
- // Try to revoke as an install permission which is for all users.
- // The package is gone - no need to keep flags for applying policy.
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
-
- if (permissionsState.revokeInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- affectedUserId = UserHandle.USER_ALL;
- }
-
- // Try to revoke as an install permission which is per user.
- if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- if (affectedUserId == UserHandle.USER_NULL) {
- affectedUserId = userId;
- } else if (affectedUserId != userId) {
- // Multiple users affected.
- affectedUserId = UserHandle.USER_ALL;
- }
- }
- }
-
- return affectedUserId;
- }
-
int removePackageLPw(String name) {
final PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -5533,32 +5446,11 @@ public final class Settings {
// Make sure we do not
mHandler.removeMessages(userId);
- for (SettingBase sb : mPackages.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
- for (SettingBase sb : mSharedUsers.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
mPermissionUpgradeNeeded.delete(userId);
mVersions.delete(userId);
mFingerprints.remove(userId);
}
- private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
- PermissionsState permissionsState = sb.getPermissionsState();
- for (PermissionState permissionState
- : permissionsState.getRuntimePermissionStates(userId)) {
- BasePermission bp = mPermissions.getPermission(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
- }
- }
- }
-
public void deleteUserRuntimePermissionsFile(int userId) {
mPersistence.deleteForUser(UserHandle.of(userId));
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d137fd05f793..c1aebd33889c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -84,6 +84,7 @@ import android.os.storage.StorageManager;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
import android.stats.devicepolicy.DevicePolicyEnums;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -141,7 +142,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Service for {@link UserManager}.
@@ -159,6 +159,10 @@ public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
+
+ // TODO(b/164159026): remove once owner_name issue on automotive is fixed
+ // Can be used to track getUsers() / userWithNameLU() behavior
+ public static final boolean DBG_CACHED_USERINFOS = false; // DO NOT SUBMIT WITH TRUE
// Can be used for manual testing of id recycling
private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
@@ -272,6 +276,25 @@ public class UserManagerService extends IUserManager.Stub {
private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
/**
+ * Reference to the {@link UserHandle#SYSTEM} user's UserInfo; it's {@code name} was either
+ * manually set, or it's {@code null}.
+ *
+ * <p>The reference is set just once, but it's {@code name} is updated when it's manually set.
+ */
+ @GuardedBy("mUsersLock")
+ private UserInfo mSystemUserInfo;
+
+ /**
+ * Reference to the {@link UserHandle#SYSTEM} user's UserInfo, with its {@code name} set to
+ * the localized value of {@code owner_name}.
+ *
+ * <p>The reference is set just once, but it's {@code name} is updated everytime the reference
+ * is used and the locale changed.
+ */
+ @GuardedBy("mUsersLock")
+ private UserInfo mSystemUserInfoWithName;
+
+ /**
* Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
*/
@VisibleForTesting
@@ -444,11 +467,6 @@ public class UserManagerService extends IUserManager.Stub {
}
};
- // TODO(b/161915546): remove once userWithName() is fixed / removed
- // Use to debug / dump when user 0 is allocated at userWithName()
- public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE
- public final AtomicInteger mUser0Allocations;
-
/**
* Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
*
@@ -638,7 +656,6 @@ public class UserManagerService extends IUserManager.Stub {
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
- mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
}
void systemReady() {
@@ -784,7 +801,7 @@ public class UserManagerService extends IUserManager.Stub {
|| (excludePreCreated && ui.preCreated)) {
continue;
}
- users.add(userWithName(ui));
+ users.add(userWithNameLU(ui));
}
return users;
}
@@ -853,7 +870,7 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.name = null;
userInfo.iconPath = null;
} else {
- userInfo = userWithName(userInfo);
+ userInfo = userWithNameLU(userInfo);
}
users.add(userInfo);
}
@@ -1310,26 +1327,57 @@ public class UserManagerService extends IUserManager.Stub {
public UserInfo getUserInfo(@UserIdInt int userId) {
checkManageOrCreateUsersPermission("query user");
synchronized (mUsersLock) {
- return userWithName(getUserInfoLU(userId));
+ return userWithNameLU(getUserInfoLU(userId));
}
}
/**
* Returns a UserInfo object with the name filled in, for Owner, or the original
* if the name is already set.
+ *
+ * <p>Note:</p> the Owner name is localized, so the current value must be checked every time
+ * this method is called.
*/
- private UserInfo userWithName(UserInfo orig) {
- if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
- if (DBG_ALLOCATION) {
- final int number = mUser0Allocations.incrementAndGet();
- Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
- }
- UserInfo withName = new UserInfo(orig);
- withName.name = getOwnerName();
- return withName;
- } else {
- return orig;
+ private UserInfo userWithNameLU(UserInfo orig) {
+ // Only the system user uses the owner_name string.
+ if (orig == null || orig.id != UserHandle.USER_SYSTEM) return orig;
+
+ if (mSystemUserInfo == null) {
+ mSystemUserInfo = orig;
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Set mSystemUserInfo:" + mSystemUserInfo.toFullString());
+ }
}
+
+ if (mSystemUserInfo.name != null) {
+ if (DBG_CACHED_USERINFOS) {
+ Slog.v(LOG_TAG, "Returning mSystemUserInfo: " + mSystemUserInfo.toFullString());
+ }
+ return mSystemUserInfo;
+ }
+
+ final String ownerName = getOwnerName();
+
+ if (mSystemUserInfoWithName == null) {
+ mSystemUserInfoWithName = new UserInfo(orig);
+ mSystemUserInfoWithName.name = ownerName;
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Set mSystemUserInfoWithName: "
+ + mSystemUserInfoWithName.toFullString());
+ }
+ } else if (!TextUtils.equals(ownerName, mSystemUserInfoWithName.name)) {
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Updating mSystemUserInfoWithName.name from "
+ + mSystemUserInfoWithName.name + " to " + ownerName);
+ }
+ mSystemUserInfoWithName.name = ownerName;
+ }
+
+ if (DBG_CACHED_USERINFOS) {
+ Slog.v(LOG_TAG, "Returning mSystemUserInfoWithName:"
+ + mSystemUserInfoWithName.toFullString());
+ }
+ return mSystemUserInfoWithName;
}
/** Returns whether the given user type is one of the FULL user types. */
@@ -1482,7 +1530,7 @@ public class UserManagerService extends IUserManager.Stub {
}
final int userId = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mUsersLock) {
- UserInfo userInfo = userWithName(getUserInfoLU(userId));
+ UserInfo userInfo = userWithNameLU(getUserInfoLU(userId));
return userInfo == null ? "" : userInfo.name;
}
}
@@ -1597,6 +1645,13 @@ public class UserManagerService extends IUserManager.Stub {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
+
+ if (DBG_CACHED_USERINFOS && userId == UserHandle.USER_SYSTEM && userData != null
+ && userData.info != mSystemUserInfo) {
+ Slog.wtf(LOG_TAG, "getUserInfoLU(): system user on userData (" + userData.info
+ + ") is not the same as mSystemUserInfo (" + mSystemUserInfo + ")");
+ }
+
return userData != null ? userData.info : null;
}
@@ -4855,8 +4910,15 @@ public class UserManagerService extends IUserManager.Stub {
pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
pw.println(" User version: " + mUserVersion);
pw.println(" Owner name: " + getOwnerName());
- if (DBG_ALLOCATION) {
- pw.println(" System user allocations: " + mUser0Allocations.get());
+ if (mSystemUserInfo == null) {
+ pw.println(" (mSystemUserInfo not set)");
+ } else {
+ pw.println(" System user: " + mSystemUserInfo.toFullString());
+ }
+ if (mSystemUserInfoWithName == null) {
+ pw.println(" (mSystemUserInfoWithName not set)");
+ } else {
+ pw.println(" System user (with name): " + mSystemUserInfoWithName.toFullString());
}
// Dump UserTypes
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index cfa0449aaf33..962638b4f63c 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -38,7 +38,6 @@ import android.util.Slog;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
import com.android.server.pm.PackageSettingBase;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -420,8 +419,7 @@ public final class BasePermission {
}
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
- PackageSetting pkgSetting) {
- final PermissionsState permsState = pkgSetting.getPermissionsState();
+ PermissionsState permsState) {
int index = pkg.getRequestedPermissions().indexOf(name);
if (!permsState.hasRequestedPermission(name) && index == -1) {
throw new SecurityException("Package " + pkg.getPackageName()
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1be74154b53a..f5dd918a18f3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -162,6 +162,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -227,6 +228,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
+ /** Maps from App ID to PermissionsState */
+ private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>();
+
/** Permission controller: User space permission management */
private PermissionControllerManager mPermissionControllerManager;
@@ -671,11 +675,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (pkg == null) {
return 0;
}
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
- return 0;
- }
synchronized (mLock) {
if (mSettings.getPermissionLocked(permName) == null) {
return 0;
@@ -684,7 +683,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
- PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return 0;
+ }
return permissionsState.getPermissionFlags(permName, userId);
}
@@ -771,9 +774,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -789,7 +790,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return;
+ }
+
final boolean hadState =
permissionsState.getRuntimePermissionState(permName, userId) != null;
if (!hadState) {
@@ -864,12 +870,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final boolean[] changed = new boolean[1];
mPackageManagerInt.forEachPackage(pkg -> {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
userId, effectiveFlagMask, effectiveFlagValues);
mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
@@ -923,12 +928,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return PackageManager.PERMISSION_DENIED;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
@@ -1139,9 +1143,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return null;
}
@@ -1451,7 +1455,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1464,8 +1474,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
@@ -1599,9 +1607,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
"revokeRuntimePermission");
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -1613,7 +1619,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1624,8 +1636,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
@@ -2456,14 +2466,36 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ private void onUserRemoved(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int appIdStatesSize = mAppIdStates.size();
+ for (int i = 0; i < appIdStatesSize; i++) {
+ PermissionsState permissionsState = mAppIdStates.valueAt(i);
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mSettings.getPermission(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ }
+ }
+ }
+ }
+
@NonNull
private Set<String> getGrantedPermissions(@NonNull String packageName,
@UserIdInt int userId) {
final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
if (ps == null) {
- return null;
+ return Collections.emptySet();
+ }
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return Collections.emptySet();
}
- final PermissionsState permissionsState = ps.getPermissionsState();
if (!ps.getInstantApp(userId)) {
return permissionsState.getPermissions(userId);
} else {
@@ -2503,7 +2535,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return null;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return null;
+ }
return permissionsState.computeGids(userId);
}
@@ -2541,8 +2577,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return;
}
-
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getOrCreatePermissionsState(ps);
final int[] userIds = getAllUserIds();
@@ -2614,8 +2649,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
- updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
- userIds);
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
+ ps.getSharedUser().getPackages(), permissionsState, userIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -3091,6 +3126,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
updatedUserIds);
}
+ // TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important
+ // for shared users.
// Persist the runtime permissions state for users with changes. If permissions
// were revoked because no app in the shared user declares them we have to
// write synchronously to avoid losing runtime permissions state.
@@ -3554,37 +3591,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final PackageSetting disabledPs = mPackageManagerInt
.getDisabledSystemPackage(pkg.getPackageName());
final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
- if (disabledPs != null
- && disabledPs.getPermissionsState().hasInstallPermission(perm)) {
- // If the original was granted this permission, we take
- // that grant decision as read and propagate it to the
- // update.
- if ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm))) {
- allowed = true;
- }
- } else {
- // The system apk may have been updated with an older
- // version of the one on the data partition, but which
- // granted a new system permission that it didn't have
- // before. In this case we do want to allow the app to
- // now get the new permission if the ancestral apk is
- // privileged to get it.
- if (disabledPs != null && disabledPkg != null
- && isPackageRequestingPermission(disabledPkg, perm)
- && ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm)))) {
- allowed = true;
- }
+ if (disabledPkg != null && isPackageRequestingPermission(disabledPkg, perm)
+ && ((privilegedPermission && disabledPkg.isPrivileged())
+ || (oemPermission && canGrantOemPermission(disabledPkg,
+ perm)))) {
+ allowed = true;
}
} else {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
allowed = (privilegedPermission && pkg.isPrivileged())
- || (oemPermission && pkg.isOem()
- && canGrantOemPermission(ps, perm));
+ || (oemPermission && canGrantOemPermission(pkg, perm));
}
// In any case, don't grant a privileged permission to privileged vendor apps, if
// the permission's protectionLevel does not have the extra 'vendorPrivileged'
@@ -3735,16 +3750,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return false;
}
- private static boolean canGrantOemPermission(PackageSetting ps, String permission) {
- if (!ps.isOem()) {
+ private static boolean canGrantOemPermission(AndroidPackage pkg, String permission) {
+ if (!pkg.isOem()) {
return false;
}
// all oem permissions must explicitly be granted or denied
final Boolean granted =
- SystemConfig.getInstance().getOemPermissions(ps.name).get(permission);
+ SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission);
if (granted == null) {
throw new IllegalStateException("OEM permission" + permission + " requested by package "
- + ps.name + " must be explicitly declared granted or not");
+ + pkg.getPackageName() + " must be explicitly declared granted or not");
}
return Boolean.TRUE == granted;
}
@@ -3757,12 +3772,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Legacy apps have the permission and get user consent on launch.
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return false;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
return permissionsState.isPermissionReviewRequired(userId);
}
@@ -3787,14 +3801,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
- PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
-
final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3838,9 +3850,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg,
@UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid,
@PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
@@ -3958,9 +3970,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int j = 0; j < oldGrantedCount; j++) {
final String permission = oldPermsForUser.valueAt(j);
// Sometimes we create a new permission state instance during update.
- final PermissionsState newPermissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt,
- pkg);
+ final PermissionsState newPermissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ continue;
+ }
if (!newPermissionsState.hasPermission(permission, userId)) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
@@ -3970,12 +3984,100 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ @UserIdInt
+ private int revokeSharedUserPermissionsForDeletedPackage(@NonNull PackageSetting deletedPs,
+ @UserIdInt int userId) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(TAG, "Trying to update info for null package. Just ignoring");
+ return UserHandle.USER_NULL;
+ }
+
+ SharedUserSetting sus = deletedPs.getSharedUser();
+
+ // No sharedUserId
+ if (sus == null) {
+ return UserHandle.USER_NULL;
+ }
+
+ int affectedUserId = UserHandle.USER_NULL;
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
+ BasePermission bp = mSettings.getPermission(eachPerm);
+ if (bp == null) {
+ continue;
+ }
+
+ // Check if another package in the shared user needs the permission.
+ boolean used = false;
+ final List<AndroidPackage> pkgs = sus.getPackages();
+ if (pkgs != null) {
+ for (AndroidPackage pkg : pkgs) {
+ if (pkg != null
+ && !pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+ && pkg.getRequestedPermissions().contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ }
+ if (used) {
+ continue;
+ }
+
+ PermissionsState permissionsState = getPermissionsState(deletedPs.pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName());
+ continue;
+ }
+
+ PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
+ deletedPs.pkg.getPackageName());
+
+ // If the package is shadowing is a disabled system package,
+ // do not drop permissions that the shadowed package requests.
+ if (disabledPs != null) {
+ boolean reqByDisabledSysPkg = false;
+ for (String permission : disabledPs.pkg.getRequestedPermissions()) {
+ if (permission.equals(eachPerm)) {
+ reqByDisabledSysPkg = true;
+ break;
+ }
+ }
+ if (reqByDisabledSysPkg) {
+ continue;
+ }
+ }
+
+ // Try to revoke as an install permission which is for all users.
+ // The package is gone - no need to keep flags for applying policy.
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+
+ if (permissionsState.revokeInstallPermission(bp)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ affectedUserId = UserHandle.USER_ALL;
+ }
+
+ // Try to revoke as a runtime permission which is per user.
+ if (permissionsState.revokeRuntimePermission(bp, userId)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ if (affectedUserId == UserHandle.USER_NULL) {
+ affectedUserId = userId;
+ } else if (affectedUserId != userId) {
+ // Multiple users affected.
+ affectedUserId = UserHandle.USER_ALL;
+ }
+ }
+ }
+
+ return affectedUserId;
+ }
+
@GuardedBy("mLock")
private int[] revokeUnusedSharedUserPermissionsLocked(
- SharedUserSetting suSetting, int[] allUserIds) {
+ List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
- final List<AndroidPackage> pkgList = suSetting.getPackages();
if (pkgList == null || pkgList.size() == 0) {
return EmptyArray.INT;
}
@@ -3993,7 +4095,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- PermissionsState permissionsState = suSetting.getPermissionsState();
// Prune install permissions
List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
final int installPermCount = installPermStates.size();
@@ -4279,12 +4380,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
} else {
mPackageManagerInt.forEachPackage(p -> {
- PackageSetting ps = mPackageManagerInt.getPackageSetting(
- p.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(p);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + p.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
if (permissionsState.getInstallPermissionState(bp.getName()) != null) {
permissionsState.revokeInstallPermission(bp);
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
@@ -4695,6 +4795,67 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return mBackgroundPermissions;
}
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull PackageSetting ps) {
+ return getPermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) {
+ return getPermissionsState(pkg.getUid());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(int appId) {
+ synchronized (mLock) {
+ return mAppIdStates.get(appId);
+ }
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(@NonNull PackageSetting ps) {
+ return getOrCreatePermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(int appId) {
+ synchronized (mLock) {
+ PermissionsState state = mAppIdStates.get(appId);
+ if (state == null) {
+ state = new PermissionsState();
+ mAppIdStates.put(appId, state);
+ }
+ return state;
+ }
+ }
+
+ private void removePermissionsState(int appId) {
+ synchronized (mLock) {
+ mAppIdStates.remove(appId);
+ }
+ }
+
+ private void readPermissionsStateFromPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ mAppIdStates.put(ps.getAppId(), new PermissionsState(ps.getPermissionsState()));
+ }
+ });
+ }
+
+ private void writePermissionsStateToPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ final PermissionsState permissionsState = mAppIdStates.get(ps.getAppId());
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + ps.name);
+ return;
+ }
+ ps.getPermissionsState().copyFrom(permissionsState);
+ }
+ });
+ }
+
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
@@ -4726,6 +4887,29 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
+ @Override
+ public void readPermissionsStateFromPackageSettingsTEMP() {
+ PermissionManagerService.this.readPermissionsStateFromPackageSettings();
+ }
+ @Override
+ public void writePermissionsStateToPackageSettingsTEMP() {
+ PermissionManagerService.this.writePermissionsStateToPackageSettings();
+ }
+ @Override
+ public void onUserRemoved(@UserIdInt int userId) {
+ PermissionManagerService.this.onUserRemoved(userId);
+ }
+ @Override
+ public void removePermissionsStateTEMP(int appId) {
+ PermissionManagerService.this.removePermissionsState(appId);
+ }
+ @Override
+ @UserIdInt
+ public int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId) {
+ return PermissionManagerService.this.revokeSharedUserPermissionsForDeletedPackage(
+ deletedPs, userId);
+ }
@NonNull
@Override
public Set<String> getGrantedPermissions(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index cfa371ddbad3..f319bf495e8b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
+import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.ArrayList;
@@ -265,6 +266,52 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
/**
+ * Read {@code PermissionsState} from package settings.
+ *
+ * TODO(zhanghai): This is a temporary method because we should not expose
+ * {@code PackageSetting} which is a implementation detail that permission should not know.
+ * Instead, it should retrieve the legacy state via a defined API.
+ */
+ public abstract void readPermissionsStateFromPackageSettingsTEMP();
+
+ /**
+ * Write {@code PermissionsState} from to settings.
+ *
+ * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
+ * for permission.
+ */
+ public abstract void writePermissionsStateToPackageSettingsTEMP();
+
+ /**
+ * Notify that a user has been removed and its permission state should be removed as well.
+ */
+ public abstract void onUserRemoved(@UserIdInt int userId);
+
+ /**
+ * Remove the {@code PermissionsState} associated with an app ID, called the same time as the
+ * removal of a {@code PackageSetitng}.
+ *
+ * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app
+ * ID removal via API.
+ */
+ public abstract void removePermissionsStateTEMP(int appId);
+
+ /**
+ * Update the shared user setting when a package with a shared user id is removed. The gids
+ * associated with each permission of the deleted package are removed from the shared user'
+ * gid list only if its not in use by other permissions of packages in the shared user setting.
+ *
+ * TODO(zhanghai): We should not need this when permission no longer sees an incomplete package
+ * state where the updated system package is uninstalled but the disabled system package is yet
+ * to be installed. Then we should handle this in restorePermissionState().
+ *
+ * @return the affected user id, may be a real user ID, USER_ALL, or USER_NULL when none.
+ */
+ @UserIdInt
+ public abstract int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId);
+
+ /**
* Get all the permissions granted to a package.
*/
@NonNull
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 64fa6ca590d2..9316c4657826 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4664,7 +4664,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// case where this is the top activity in a pinned stack.
final boolean isTop = this == stack.getTopNonFinishingActivity();
final boolean isTopNotPinnedStack = stack.isAttached()
- && stack.getDisplayArea().isTopNotPinnedStack(stack);
+ && stack.getDisplayArea().isTopNotFinishNotPinnedStack(stack);
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
@@ -4806,6 +4806,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
}
setState(STARTED, "makeActiveIfNeeded");
+
+ // Update process info while making an activity from invisible to visible, to make
+ // sure the process state is updated to foreground.
+ if (app != null) {
+ app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* activityChange */, true /* updateOomAdj */,
+ true /* addPendingTopUid */);
+ }
+
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StartActivityItem.obtain());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2e879810c085..0215ead7e5de 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3982,9 +3982,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
- // TODO: Not sure if we really need to set the rotation here since we are updating from
- // the display info above...
- mDisplayFrames.mRotation = getRotation();
mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
int seq = mLayoutSeq + 1;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2e03cb80b189..40fc25b41d9f 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -246,6 +246,9 @@ public class DisplayPolicy {
| View.STATUS_BAR_TRANSPARENT
| View.NAVIGATION_BAR_TRANSPARENT;
+ private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR};
+ private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
+
private final WindowManagerService mService;
private final Context mContext;
private final Context mUiContext;
@@ -3353,8 +3356,15 @@ public class DisplayPolicy {
return;
}
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes =
+ (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+ ? Type.navigationBars() : 0)
+ | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+ ? Type.statusBars() : 0);
+
if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
// Don't show status bar when swiping on already visible navigation bar.
// But restore the position of navigation bar if it has been moved by the control
// target.
@@ -3362,14 +3372,13 @@ public class DisplayPolicy {
return;
}
- int insetsTypesToShow = Type.systemBars();
-
if (controlTarget.canShowTransient()) {
- insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- }
- if (insetsTypesToShow != 0) {
- controlTarget.showInsets(insetsTypesToShow, false);
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
+ } else {
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
} else {
boolean sb = mStatusBarController.checkShowTransientBarLw();
@@ -3770,8 +3779,7 @@ public class DisplayPolicy {
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
if (!isNavBarEmpty(vis)) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[] {ITYPE_NAVIGATION_BAR}));
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 3ffc26a7a8ad..5e7ed3f80e43 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.inputmethodservice.InputMethodService;
+import android.view.InsetsState;
import android.view.WindowInsets.Type.InsetsType;
/**
@@ -38,6 +39,13 @@ interface InsetsControlTarget {
}
/**
+ * @return The requested {@link InsetsState} of this target.
+ */
+ default InsetsState getRequestedInsetsState() {
+ return InsetsState.EMPTY;
+ }
+
+ /**
* Instructs the control target to show inset sources.
*
* @param types to specify which types of insets source window should be shown.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index b7287e718bd6..18a25033b1e6 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,7 +42,6 @@ import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
-import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
@@ -153,15 +152,13 @@ class InsetsPolicy {
return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
}
- @InsetsType int showTransient(IntArray types) {
- @InsetsType int showingTransientTypes = 0;
+ void showTransient(@InternalInsetsType int[] types) {
boolean changed = false;
- for (int i = types.size() - 1; i >= 0; i--) {
- final int type = types.get(i);
+ for (int i = types.length - 1; i >= 0; i--) {
+ final @InternalInsetsType int type = types[i];
if (!isHidden(type)) {
continue;
}
- showingTransientTypes |= InsetsState.toPublicType(type);
if (mShowingTransientTypes.indexOf(type) != -1) {
continue;
}
@@ -189,7 +186,6 @@ class InsetsPolicy {
}
});
}
- return showingTransientTypes;
}
void hideTransient() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0529abf89f6e..50c269e23c53 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3820,7 +3820,10 @@ class Task extends WindowContainer<WindowContainer> {
@Override
boolean fillsParent() {
- return matchParentBounds();
+ // From the perspective of policy, we still want to report that this task fills parent
+ // in fullscreen windowing mode even it doesn't match parent bounds because there will be
+ // letterbox around its real content.
+ return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 32511108836e..6550167683a0 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1489,9 +1489,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return stack == getTopStack();
}
- boolean isTopNotPinnedStack(Task stack) {
+ boolean isTopNotFinishNotPinnedStack(Task stack) {
for (int i = getStackCount() - 1; i >= 0; --i) {
final Task current = getStackAt(i);
+ final ActivityRecord topAct = current.getTopNonFinishingActivity();
+ if (topAct == null) {
+ continue;
+ }
if (!current.inPinnedWindowingMode()) {
return current == stack;
}
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 61e9e5082d17..5e81e4008680 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -24,8 +24,6 @@ import android.annotation.NonNull;
import android.util.ArrayMap;
import android.util.Slog;
-import com.android.server.wm.WindowManagerService.H;
-
import java.io.PrintWriter;
/**
@@ -102,7 +100,13 @@ class UnknownAppVisibilityController {
if (DEBUG_UNKNOWN_APP_VISIBILITY) {
Slog.d(TAG, "App launched activity=" + activity);
}
- mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ // If the activity was started with launchTaskBehind, the lifecycle will goes to paused
+ // directly, and the process will pass onResume, so we don't need to waiting resume for it.
+ if (!activity.mLaunchTaskBehind) {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ } else {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RELAYOUT);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cd222a97f4d9..32251976eba1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -929,7 +929,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void setShadowRenderer() {
mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
PowerManager mPowerManager;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 49e623d8dd11..0e455d2a5aa6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -728,7 +728,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* @return The insets state as requested by the client, i.e. the dispatched insets state
* for which the visibilities are overridden with what the client requested.
*/
- InsetsState getRequestedInsetsState() {
+ @Override
+ public InsetsState getRequestedInsetsState() {
return mRequestedInsetsState;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index c29c510b35b5..42ba842f8434 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -17,23 +17,33 @@
package com.android.server.accessibility.magnification;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.Display;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
+/**
+ * Mocks the basic logic of window magnification in System UI. We assume the screen size is
+ * unlimited, so source bounds is always on the center of the mirror window bounds.
+ */
class MockWindowMagnificationConnection {
+ public static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private final IWindowMagnificationConnection mConnection;
private final Binder mBinder;
private IBinder.DeathRecipient mDeathRecipient;
private IWindowMagnificationConnectionCallback mIMirrorWindowCallback;
+ private Rect mMirrorWindowFrame = new Rect(0, 0, 500, 500);
MockWindowMagnificationConnection() throws RemoteException {
mConnection = mock(IWindowMagnificationConnection.class);
@@ -50,6 +60,30 @@ class MockWindowMagnificationConnection {
return null;
}).when(mBinder).linkToDeath(
any(IBinder.DeathRecipient.class), eq(0));
+ stubConnection();
+ }
+
+ private void stubConnection() throws RemoteException {
+ doAnswer((invocation) -> {
+ final int displayId = invocation.getArgument(0);
+ if (displayId != TEST_DISPLAY) {
+ throw new IllegalArgumentException("only support default display :" + displayId);
+ }
+ computeMirrorWindowFrame(invocation.getArgument(1), invocation.getArgument(2));
+
+ mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
+ mMirrorWindowFrame);
+ return null;
+ }).when(mConnection).enableWindowMagnification(anyInt(),
+ anyFloat(), anyFloat(), anyFloat());
+ }
+
+ private void computeMirrorWindowFrame(float centerX, float centerY) {
+ final float offsetX = Float.isNaN(centerX) ? 0
+ : centerX - mMirrorWindowFrame.exactCenterX();
+ final float offsetY = Float.isNaN(centerY) ? 0
+ : centerY - mMirrorWindowFrame.exactCenterY();
+ mMirrorWindowFrame.offset((int) offsetX, (int) offsetY);
}
IWindowMagnificationConnection getConnection() {
@@ -60,12 +94,16 @@ class MockWindowMagnificationConnection {
return mBinder;
}
- public IBinder.DeathRecipient getDeathRecipient() {
+ IBinder.DeathRecipient getDeathRecipient() {
return mDeathRecipient;
}
- public IWindowMagnificationConnectionCallback getConnectionCallback() {
+ IWindowMagnificationConnectionCallback getConnectionCallback() {
return mIMirrorWindowCallback;
}
+
+ public Rect getMirrorWindowFrame() {
+ return new Rect(mMirrorWindowFrame);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
index 2b1bdc59d9c8..ed8dc4e470de 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
@@ -87,15 +87,15 @@ public class TwoFingersDownTest {
secondPointerCoords.x = DEFAULT_X + 10;
secondPointerCoords.y = DEFAULT_Y + 10;
- final MotionEvent pointerDownEvent = TouchEventGenerator.pointerDownEvent(
+ final MotionEvent twoPointersDownEvent = TouchEventGenerator.twoPointersDownEvent(
Display.DEFAULT_DISPLAY, defPointerCoords, secondPointerCoords);
mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
- mGesturesObserver.onMotionEvent(pointerDownEvent, pointerDownEvent, 0);
+ mGesturesObserver.onMotionEvent(twoPointersDownEvent, twoPointersDownEvent, 0);
verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
- MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, pointerDownEvent,
- pointerDownEvent, 0);
+ MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, twoPointersDownEvent,
+ twoPointersDownEvent, 0);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index e580340a29f7..bec9f26672f4 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -16,14 +16,9 @@
package com.android.server.accessibility.magnification;
-import static android.view.MotionEvent.ACTION_POINTER_DOWN;
-
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -63,11 +58,9 @@ public class WindowMagnificationGestureHandlerTest {
public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP;
// Co-prime x and y, to potentially catch x-y-swapped errors
- public static final float DEFAULT_X = 301;
- public static final float DEFAULT_Y = 299;
- //Assume first pointer position (DEFAULT_X,DEFAULT_Y) is in the window.
- public static Rect DEFAULT_WINDOW_FRAME = new Rect(0, 0, 500, 500);
- private static final int DISPLAY_0 = 0;
+ public static final float DEFAULT_TAP_X = 301;
+ public static final float DEFAULT_TAP_Y = 299;
+ private static final int DISPLAY_0 = MockWindowMagnificationConnection.TEST_DISPLAY;
private Context mContext;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -83,14 +76,6 @@ public class WindowMagnificationGestureHandlerTest {
mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class),
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0,
- DEFAULT_WINDOW_FRAME);
- doAnswer((invocation) -> {
- mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0,
- DEFAULT_WINDOW_FRAME);
- return null;
- }).when(mMockConnection.getConnection()).enableWindowMagnification(eq(DISPLAY_0),
- anyFloat(), anyFloat(), anyFloat());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
}
@@ -208,10 +193,11 @@ public class WindowMagnificationGestureHandlerTest {
break;
case STATE_TWO_FINGERS_DOWN: {
goFromStateIdleTo(STATE_SHOW_MAGNIFIER);
- send(downEvent());
+ final Rect frame = mMockConnection.getMirrorWindowFrame();
+ send(downEvent(frame.centerX(), frame.centerY()));
//Second finger is outside the window.
- send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10,
- DEFAULT_WINDOW_FRAME.bottom + 10));
+ send(twoPointerDownEvent(new float[]{frame.centerX(), frame.centerX() + 10},
+ new float[]{frame.centerY(), frame.centerY() + 10}));
}
break;
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
@@ -243,7 +229,8 @@ public class WindowMagnificationGestureHandlerTest {
}
break;
case STATE_TWO_FINGERS_DOWN: {
- send(upEvent());
+ final Rect frame = mMockConnection.getMirrorWindowFrame();
+ send(upEvent(frame.centerX(), frame.centerY()));
returnToNormalFrom(STATE_SHOW_MAGNIFIER);
}
break;
@@ -286,12 +273,8 @@ public class WindowMagnificationGestureHandlerTest {
}
}
- private MotionEvent downEvent() {
- return TouchEventGenerator.downEvent(DISPLAY_0, DEFAULT_X, DEFAULT_Y);
- }
-
- private MotionEvent upEvent() {
- return upEvent(DEFAULT_X, DEFAULT_Y);
+ private MotionEvent downEvent(float x, float y) {
+ return TouchEventGenerator.downEvent(DISPLAY_0, x, y);
}
private MotionEvent upEvent(float x, float y) {
@@ -299,18 +282,18 @@ public class WindowMagnificationGestureHandlerTest {
}
private void tap() {
- send(downEvent());
- send(upEvent());
+ send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+ send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
}
- private MotionEvent pointerEvent(int action, float x, float y) {
+ private MotionEvent twoPointerDownEvent(float[] x, float[] y) {
final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
- defPointerCoords.x = DEFAULT_X;
- defPointerCoords.y = DEFAULT_Y;
+ defPointerCoords.x = x[0];
+ defPointerCoords.y = y[0];
final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
- pointerCoords.x = x;
- pointerCoords.y = y;
- return TouchEventGenerator.pointerDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
+ pointerCoords.x = x[1];
+ pointerCoords.y = y[1];
+ return TouchEventGenerator.twoPointersDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
}
private String stateDump() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index 7cbf3ee46594..a05881f78892 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -43,9 +43,9 @@ public class TouchEventGenerator {
return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
}
- public static MotionEvent pointerDownEvent(int displayId, PointerCoords defPointerCoords,
+ public static MotionEvent twoPointersDownEvent(int displayId, PointerCoords defPointerCoords,
PointerCoords pointerCoords) {
- return generatePointerEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
+ return generateTwoPointersEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
pointerCoords);
}
@@ -59,7 +59,7 @@ public class TouchEventGenerator {
return ev;
}
- private static MotionEvent generatePointerEvent(int displayId, int action,
+ private static MotionEvent generateTwoPointersEvent(int displayId, int action,
PointerCoords defPointerCoords, PointerCoords pointerCoords) {
final long downTime = SystemClock.uptimeMillis();
MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index 946f27e09fdb..d36dcce800eb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -20,7 +20,7 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageParser
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
* This test has to be updated manually whenever the info generation behavior changes, since
* there's no single place where flag -> field is defined besides this test.
*/
-@Presubmit
+@Postsubmit
@RunWith(Parameterized::class)
class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index f96ebda67602..574921cdbd05 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -17,26 +17,20 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import androidx.test.filters.LargeTest
import com.google.common.truth.Expect
-
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.Timeout
-import java.util.concurrent.TimeUnit
/**
* Collects APKs from the device and verifies that the new parsing behavior outputs
* the same exposed Info object as the old parsing logic.
*/
-@Presubmit
+@Postsubmit
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
@get:Rule
- val timeout = Timeout(4, TimeUnit.MINUTES)
-
- @get:Rule
val expect = Expect.create()
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 555906d4c910..608305c33168 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -43,7 +43,6 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import android.platform.test.annotations.Presubmit;
-import android.util.IntArray;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.test.InsetsModeSession;
@@ -242,8 +241,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
}).when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -271,8 +269,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -301,8 +298,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -340,8 +336,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(app);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
policy.updateBarControlTarget(app2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 085230d35c6a..59f8cc8c3412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -346,8 +346,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
provider.getSource().setVisible(false);
- mDisplayContent.getInsetsPolicy().showTransient(
- IntArray.wrap(new int[] { ITYPE_STATUS_BAR }));
+ mDisplayContent.getInsetsPolicy().showTransient(new int[] { ITYPE_STATUS_BAR });
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR));
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index fc54e1de888f..0fe6510b0fce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -50,6 +50,7 @@ import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -245,17 +246,17 @@ public class TaskRecordTests extends WindowTestsBase {
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
final DisplayContent display = new TestDisplayContent.Builder(mAtm,
fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
- assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
// Fix the display orientation to landscape which is the natural rotation (0) for the test
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
- Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new StackBuilder(mRootWindowContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getBottomMostTask();
- ActivityRecord root = task.getTopNonFinishingActivity();
+ final Task task = stack.getBottomMostTask();
+ final ActivityRecord root = task.getTopNonFinishingActivity();
assertEquals(fullScreenBounds, task.getBounds());
@@ -267,7 +268,7 @@ public class TaskRecordTests extends WindowTestsBase {
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
- ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
assertEquals(top, task.getTopNonFinishingActivity());
top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
@@ -304,6 +305,33 @@ public class TaskRecordTests extends WindowTestsBase {
}
@Test
+ public void testReportsOrientationRequestInLetterboxForOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = stack.getBottomMostTask();
+ ActivityRecord root = task.getTopNonFinishingActivity();
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
+ }
+
+ @Test
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
DisplayContent display = new TestDisplayContent.Builder(
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 6ed762283524..78dfd407ff4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -55,6 +55,18 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
}
@Test
+ public void testSkipResume() {
+ final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ activity.mLaunchTaskBehind = true;
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity);
+
+ // Make sure our handler processed the message.
+ waitHandlerIdle(mWm.mH);
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
+ }
+
+ @Test
public void testMultiple() {
final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 09c16595e2c7..52e0953813a0 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -1625,6 +1625,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 1a606b7ae6a7..2a073a1f1d81 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -851,6 +851,19 @@ public class ProvisioningManager {
public static final int KEY_RTT_ENABLED = 66;
/**
+ * An obfuscated string defined by the carrier to indicate VoWiFi entitlement status.
+ *
+ * <p>Implementation note: how to generate the value and how it affects VoWiFi service
+ * should follow carrier requirements. For example, set an empty string could result in
+ * VoWiFi being disabled by IMS service, and set to a specific string could enable.
+ *
+ * <p>Value is in String format.
+ * @see #setProvisioningStringValue(int, String)
+ * @see #getProvisioningStringValue(int)
+ */
+ public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67;
+
+ /**
* Callback for IMS provisioning changes.
*/
public static class Callback {
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index d0cec52dfc86..487786045b8e 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -729,7 +729,8 @@ public class ImsConfig {
// Expand the operator config items as needed here, need to change
// PROVISIONED_CONFIG_END after that.
- public static final int PROVISIONED_CONFIG_END = RTT_SETTING_ENABLED;
+ public static final int PROVISIONED_CONFIG_END =
+ ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID;
// Expand the operator config items as needed here.
}
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
index 9a8e37b19e56..57d6127b1cd1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -88,7 +88,7 @@ class OpenAppWarmTest(
noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
- navBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(enabled = false)
wallpaperLayerBecomesInvisible()
}
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
index 91ec211805f7..279092d716e2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -87,9 +87,9 @@ class OpenAppToSplitScreenTest(
}
layersTrace {
- navBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
+ noUncoveredRegions(rotation, enabled = false)
navBarLayerRotatesAndScales(rotation, bugId = 140855415)
statusBarLayerRotatesScales(rotation)