summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/healthconnect/Android.bp44
-rw-r--r--apct-tests/perftests/healthconnect/AndroidManifest.xml26
-rw-r--r--apct-tests/perftests/healthconnect/AndroidTest.xml61
-rw-r--r--apct-tests/perftests/healthconnect/OWNERS6
-rw-r--r--apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt54
-rw-r--r--core/api/current.txt12
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java7
-rw-r--r--core/java/android/view/SurfaceControl.java95
-rw-r--r--core/java/android/view/View.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java15
-rw-r--r--core/java/android/window/TransitionInfo.java3
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java4
-rw-r--r--media/java/android/media/IMediaRouter2.aidl4
-rw-r--r--media/java/android/media/IMediaRouterService.aidl10
-rw-r--r--media/java/android/media/MediaRoute2Info.java145
-rw-r--r--media/java/android/media/MediaRouter2.java151
-rw-r--r--media/java/android/media/MediaRouter2Manager.java53
-rw-r--r--media/java/android/media/RoutingSessionInfo.java190
-rw-r--r--media/java/android/media/flags/media_better_together.aconfig8
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java57
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt20
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt1
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt8
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt71
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelper.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelperTest.java21
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig6
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt59
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt230
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt21
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt8
-rw-r--r--packages/SystemUI/log/src/com/android/systemui/log/core/LogcatOnlyMessageBuffer.kt76
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt24
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt207
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java43
-rw-r--r--services/core/java/com/android/server/am/UserController.java15
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java24
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java35
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java37
-rw-r--r--services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java54
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java68
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerControllerInterface.java10
-rw-r--r--services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java61
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java32
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java9
-rw-r--r--services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java17
-rw-r--r--services/core/java/com/android/server/media/DeviceRouteController.java24
-rw-r--r--services/core/java/com/android/server/media/LegacyDeviceRouteController.java40
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java21
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java26
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java261
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java57
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java184
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java66
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java38
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd11
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt11
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java250
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java52
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java8
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java8
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java74
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java18
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java94
-rw-r--r--telephony/java/android/telephony/SecurityAlgorithmUpdate.java214
104 files changed, 2802 insertions, 1293 deletions
diff --git a/apct-tests/perftests/healthconnect/Android.bp b/apct-tests/perftests/healthconnect/Android.bp
new file mode 100644
index 000000000000..c2d0a6f200a0
--- /dev/null
+++ b/apct-tests/perftests/healthconnect/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "HealthConnectPerfTests",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "apct-perftests-utils",
+ "collector-device-lib-platform",
+ ],
+
+ libs: ["android.test.base"],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/healthconnect/AndroidManifest.xml b/apct-tests/perftests/healthconnect/AndroidManifest.xml
new file mode 100644
index 000000000000..6a6370b6214a
--- /dev/null
+++ b/apct-tests/perftests/healthconnect/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.perftests.healthconnect">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.healthconnect"/>
+</manifest>
diff --git a/apct-tests/perftests/healthconnect/AndroidTest.xml b/apct-tests/perftests/healthconnect/AndroidTest.xml
new file mode 100644
index 000000000000..5036202a9f4a
--- /dev/null
+++ b/apct-tests/perftests/healthconnect/AndroidTest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs HealthConnectPerfTests metric instrumentation.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-metric-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="HealthConnectPerfTests.apk" />
+ </target_preparer>
+
+ <!-- Needed for pushing the trace config file -->
+ <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" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.healthconnect" />
+ <option name="hidden-api-checks" value="false"/>
+
+ <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+ </test>
+</configuration>
diff --git a/apct-tests/perftests/healthconnect/OWNERS b/apct-tests/perftests/healthconnect/OWNERS
new file mode 100644
index 000000000000..da0b46adeaef
--- /dev/null
+++ b/apct-tests/perftests/healthconnect/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 1219472
+
+arkivanov@google.com
+jstembridge@google.com
+pratyushmore@google.com
+itsleo@google.com
diff --git a/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt b/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt
new file mode 100644
index 000000000000..21a4ca048f62
--- /dev/null
+++ b/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.perftests.healthconnect
+
+import android.health.connect.HealthConnectManager
+import android.os.SystemClock
+import android.perftests.utils.PerfStatusReporter
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Read/write benchmark tests for [HealthConnectManager]
+ *
+ * Build/Install/Run: atest HealthConnectReadWritePerfTest
+ */
+@RunWith(AndroidJUnit4::class)
+class HealthConnectReadWritePerfTest {
+
+ @get:Rule
+ val perfStatusReporter = PerfStatusReporter()
+
+ private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
+
+ private val manager by lazy {
+ requireNotNull(context.getSystemService(HealthConnectManager::class.java))
+ }
+
+ /**
+ * A first empty test just to setup the test package and make sure it runs properly.
+ */
+ @Test
+ fun placeholder() {
+ val state = perfStatusReporter.benchmarkState
+ while (state.keepRunning()) {
+ SystemClock.sleep(100)
+ }
+ }
+} \ No newline at end of file
diff --git a/core/api/current.txt b/core/api/current.txt
index ace00fcb58aa..ecb242a6a217 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -23972,6 +23972,7 @@ package android.media {
method @Nullable public android.net.Uri getIconUri();
method @NonNull public String getId();
method @NonNull public CharSequence getName();
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus();
method public int getType();
method public int getVolume();
method public int getVolumeHandling();
@@ -23989,6 +23990,9 @@ package android.media {
field public static final String FEATURE_REMOTE_VIDEO_PLAYBACK = "android.media.route.feature.REMOTE_VIDEO_PLAYBACK";
field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2; // 0x2
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER = 0; // 0x0
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER = 1; // 0x1
field public static final int TYPE_BLE_HEADSET = 26; // 0x1a
field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
@@ -24029,6 +24033,7 @@ package android.media {
method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.MediaRoute2Info.Builder setSuitabilityStatus(int);
method @NonNull public android.media.MediaRoute2Info.Builder setType(int);
method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityPublic();
method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityRestricted(@NonNull java.util.Set<java.lang.String>);
@@ -24242,6 +24247,7 @@ package android.media {
method public void release();
method public void selectRoute(@NonNull android.media.MediaRoute2Info);
method public void setVolume(int);
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public boolean wasTransferRequestedBySelf();
}
public abstract static class MediaRouter2.TransferCallback {
@@ -24639,12 +24645,16 @@ package android.media {
method @Nullable public CharSequence getName();
method @NonNull public java.util.List<java.lang.String> getSelectableRoutes();
method @NonNull public java.util.List<java.lang.String> getSelectedRoutes();
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getTransferReason();
method @NonNull public java.util.List<java.lang.String> getTransferableRoutes();
method public int getVolume();
method public int getVolumeHandling();
method public int getVolumeMax();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.RoutingSessionInfo> CREATOR;
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int TRANSFER_REASON_APP = 2; // 0x2
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int TRANSFER_REASON_FALLBACK = 0; // 0x0
+ field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int TRANSFER_REASON_SYSTEM_REQUEST = 1; // 0x1
}
public static final class RoutingSessionInfo.Builder {
@@ -24665,6 +24675,8 @@ package android.media {
method @NonNull public android.media.RoutingSessionInfo.Builder removeTransferableRoute(@NonNull String);
method @NonNull public android.media.RoutingSessionInfo.Builder setControlHints(@Nullable android.os.Bundle);
method @NonNull public android.media.RoutingSessionInfo.Builder setName(@Nullable CharSequence);
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.RoutingSessionInfo.Builder setTransferInitiator(@Nullable android.os.UserHandle, @Nullable String);
+ method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.RoutingSessionInfo.Builder setTransferReason(int);
method @NonNull public android.media.RoutingSessionInfo.Builder setVolume(int);
method @NonNull public android.media.RoutingSessionInfo.Builder setVolumeHandling(int);
method @NonNull public android.media.RoutingSessionInfo.Builder setVolumeMax(int);
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index ffd7212a7525..86024ea41363 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -751,6 +751,13 @@ public abstract class DisplayManagerInternal {
*/
boolean blockScreenOn(Runnable unblocker);
+ /** Get the current brightness levels used to determine automatic brightness based on lux
+ * levels. */
+ float[] getCurrentAutoBrightnessLevels();
+
+ /** Get the current lux levels used to determine automatic brightness. */
+ float[] getCurrentAutoBrightnessLuxLevels();
+
/** Returns whether displayoffload supports the given display state. */
static boolean isSupportedOffloadState(int displayState) {
return Display.isSuspendedState(displayState);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index cbbe7856178d..b957b31a5bb7 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -22,7 +22,6 @@ import static android.graphics.Matrix.MSKEW_X;
import static android.graphics.Matrix.MSKEW_Y;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
-import static android.view.Display.INVALID_DISPLAY;
import static android.view.SurfaceControlProto.HASH_CODE;
import static android.view.SurfaceControlProto.LAYER_ID;
import static android.view.SurfaceControlProto.NAME;
@@ -38,7 +37,6 @@ import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
@@ -53,13 +51,8 @@ import android.hardware.HardwareBuffer;
import android.hardware.OverlayProperties;
import android.hardware.SyncFence;
import android.hardware.display.DeviceProductInfo;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
-import android.hardware.display.IDisplayManager;
-import android.hardware.display.IVirtualDisplayCallback;
-import android.hardware.display.VirtualDisplay;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.opengl.EGLDisplay;
import android.opengl.EGLSync;
@@ -68,8 +61,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -2355,92 +2346,6 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Because this API is now going through {@link DisplayManager}, orientation and displayRect
- * will automatically be computed based on configuration changes. Because of this, the params
- * orientation and displayRect are ignored
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
- publicAlternatives = "Use {@code VirtualDisplay#resize(int, int, int)} instead.",
- trackingBug = 247078497)
- public static void setDisplayProjection(IBinder displayToken, int orientation,
- Rect layerStackRect, Rect displayRect) {
- DisplayManagerGlobal.getInstance().resizeVirtualDisplay(
- IVirtualDisplayCallback.Stub.asInterface(displayToken), layerStackRect.width(),
- layerStackRect.height(), 1);
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
- publicAlternatives = "Use {@code MediaProjection#createVirtualDisplay()} with flag "
- + " {@code VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for mirroring instead.",
- trackingBug = 247078497)
- public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
- IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
- if (b == null) {
- throw new UnsupportedOperationException();
- }
-
- IDisplayManager dm = IDisplayManager.Stub.asInterface(b);
- try {
- dm.setDisplayIdToMirror(displayToken, layerStack);
- } catch (RemoteException e) {
- throw new UnsupportedOperationException(e);
- }
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
- publicAlternatives = "Use {@code VirtualDisplay#setSurface(Surface)} instead.",
- trackingBug = 247078497)
- public static void setDisplaySurface(IBinder displayToken, Surface surface) {
- IVirtualDisplayCallback virtualDisplayCallback =
- IVirtualDisplayCallback.Stub.asInterface(displayToken);
- DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- dm.setVirtualDisplaySurface(virtualDisplayCallback, surface);
- }
-
- /**
- * Secure is no longer supported because this is only called from outside system which cannot
- * create secure displays.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
- publicAlternatives = "Use {@code MediaProjection#createVirtualDisplay()} or "
- + "{@code DisplayManager#createVirtualDisplay()} instead.",
- trackingBug = 247078497)
- public static IBinder createDisplay(String name, boolean secure) {
- if (name == null) {
- throw new IllegalArgumentException("name must not be null");
- }
-
- // We don't have a size yet so pass in 1 for width and height since 0 is invalid
- VirtualDisplay vd = DisplayManager.createVirtualDisplay(name, 1 /* width */, 1 /* height */,
- INVALID_DISPLAY, null /* Surface */);
- return vd == null ? null : vd.getToken().asBinder();
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
- publicAlternatives = "Use {@code VirtualDisplay#release()} instead.",
- trackingBug = 247078497)
- public static void destroyDisplay(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
-
- DisplayManagerGlobal.getInstance().releaseVirtualDisplay(
- IVirtualDisplayCallback.Stub.asInterface(displayToken));
- }
-
- /**
* Returns whether protected content is supported in GPU composition.
* @hide
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e4b709e66fbc..ec994590e339 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -32,6 +32,7 @@ import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_H
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
+import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.flags.Flags.viewVelocityApi;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
@@ -2309,6 +2310,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
+ private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
static {
EMPTY_STATE_SET = StateSet.get(0);
@@ -2393,6 +2395,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
| StateSet.VIEW_STATE_PRESSED);
sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
+ sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
}
/**
@@ -33084,11 +33087,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private void votePreferredFrameRate() {
// use toolkitSetFrameRate flag to gate the change
- if (sToolkitSetFrameRateReadOnlyFlagValue) {
- ViewRootImpl viewRootImpl = getViewRootImpl();
- float sizePercentage = getSizePercentage();
- int frameRateCateogry = calculateFrameRateCategory(sizePercentage);
- if (viewRootImpl != null && sizePercentage > 0) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ float sizePercentage = getSizePercentage();
+ int frameRateCateogry = calculateFrameRateCategory(sizePercentage);
+ if (viewRootImpl != null && sizePercentage > 0) {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
if (mPreferredFrameRate < 0) {
if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE) {
frameRateCateogry = FRAME_RATE_CATEGORY_NO_PREFERENCE;
@@ -33104,6 +33107,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
viewRootImpl.votePreferredFrameRateCategory(frameRateCateogry);
}
+ if (sToolkitMetricsForFrameRateDecisionFlagValue) {
+ viewRootImpl.recordViewPercentage(sizePercentage);
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 185328277dfd..487b15c03292 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -827,6 +827,8 @@ public final class ViewRootImpl implements ViewParent,
private boolean mInsetsAnimationRunning;
private long mPreviousFrameDrawnTime = -1;
+ // The largest view size percentage to the display size. Used on trace to collect metric.
+ private float mLargestChildPercentage = 0.0f;
/**
* The resolved pointer icon type requested by this window.
@@ -1066,6 +1068,7 @@ public final class ViewRootImpl implements ViewParent,
private String mTag = TAG;
private String mFpsTraceName;
+ private String mLargestViewTraceName;
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
@@ -1317,6 +1320,7 @@ public final class ViewRootImpl implements ViewParent,
attrs = mWindowAttributes;
setTag();
mFpsTraceName = "FPS of " + getTitle();
+ mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle();
if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
& WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
@@ -4738,6 +4742,10 @@ public final class ViewRootImpl implements ViewParent,
long fps = NANOS_PER_SEC / timeDiff;
Trace.setCounter(mFpsTraceName, fps);
mPreviousFrameDrawnTime = expectedDrawnTime;
+
+ long percentage = (long) (mLargestChildPercentage * 100);
+ Trace.setCounter(mLargestViewTraceName, percentage);
+ mLargestChildPercentage = 0.0f;
}
private void reportDrawFinished(@Nullable Transaction t, int seqId) {
@@ -5058,6 +5066,7 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_FPS) {
trackFPS();
}
+
if (sToolkitMetricsForFrameRateDecisionFlagValue) {
collectFrameRateDecisionMetrics();
}
@@ -12261,4 +12270,10 @@ public final class ViewRootImpl implements ViewParent,
void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) {
mWindowlessBackKeyCallback = callback;
}
+
+ void recordViewPercentage(float percentage) {
+ if (!Trace.isEnabled()) return;
+ // Record the largest view of percentage to the display size.
+ mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage);
+ }
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 5bfa3d759a66..7c9340e72f72 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -165,6 +165,9 @@ public final class TransitionInfo implements Parcelable {
public static final int FLAGS_IS_NON_APP_WINDOW =
FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD | FLAG_IS_SYSTEM_WINDOW;
+ /** The change will not participate in the animation. */
+ public static final int FLAGS_IS_OCCLUDED_NO_ANIMATION = FLAG_IS_OCCLUDED | FLAG_NO_ANIMATION;
+
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
FLAG_NONE,
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d0de5f0e4104..5400c5848f02 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6862,4 +6862,8 @@
<!-- Whether the media player is shown on the quick settings -->
<bool name="config_quickSettingsShowMediaPlayer">true</bool>
+
+ <!-- Defines suitability of the built-in speaker route.
+ Refer to {@link MediaRoute2Info} to see supported values. -->
+ <integer name="config_mediaRouter_builtInSpeakerSuitability">0</integer>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 38943306b962..eeef19291c4f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5306,4 +5306,7 @@
<java-symbol type="bool" name="config_viewBasedRotaryEncoderHapticsEnabled" />
<java-symbol type="bool" name="config_quickSettingsShowMediaPlayer" />
+
+ <!-- Android MediaRouter framework configs. -->
+ <java-symbol type="integer" name="config_mediaRouter_builtInSpeakerSuitability" />
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index af69b5272ad5..b0d8b47b170a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -757,6 +757,10 @@ public class Transitions implements RemoteCallable<Transitions>,
}
if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
allOccluded = false;
+ } else if (change.hasAllFlags(TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION)) {
+ // Remove the change because it should be invisible in the animation.
+ info.getChanges().remove(i);
+ continue;
}
// The change has already animated by back gesture, don't need to play transition
// animation on it.
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index 29bfd1acae17..e2dddad274e1 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -19,6 +19,7 @@ package android.media;
import android.media.MediaRoute2Info;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
+import android.os.UserHandle;
/**
* @hide
@@ -35,5 +36,6 @@ oneway interface IMediaRouter2 {
* Call MediaRouterService#requestCreateSessionWithRouter2 to pass the result.
*/
void requestCreateSessionByManager(long uniqueRequestId, in RoutingSessionInfo oldSession,
- in MediaRoute2Info route);
+ in MediaRoute2Info route, in UserHandle transferInitiatorUserHandle,
+ in String transferInitiatorPackageName);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index fa4d1a1ff935..04e99ea8a57f 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -64,7 +64,8 @@ interface IMediaRouterService {
void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, long managerRequestId,
in RoutingSessionInfo oldSession, in MediaRoute2Info route,
- in @nullable Bundle sessionHints);
+ in @nullable Bundle sessionHints, in UserHandle transferInitiatorUserHandle,
+ in String transferInitiatorPackageName);
void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
@@ -84,13 +85,16 @@ interface IMediaRouterService {
void stopScan(IMediaRouter2Manager manager);
void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
- in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route);
+ in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route,
+ in UserHandle transferInitiatorUserHandle, in String transferInitiatorPackageName);
void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
String sessionId, in MediaRoute2Info route);
void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
String sessionId, in MediaRoute2Info route);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)")
void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
- String sessionId, in MediaRoute2Info route);
+ String sessionId, in MediaRoute2Info route,
+ in UserHandle transferInitiatorUserHandle, String transferInitiatorPackageName);
void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
String sessionId, int volume);
void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 8ad35876989d..0eabe66e9a69 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -19,6 +19,7 @@ package android.media;
import static android.media.MediaRouter2Utils.toUniqueId;
import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
+import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES;
import android.annotation.FlaggedApi;
@@ -479,6 +480,37 @@ public final class MediaRoute2Info implements Parcelable {
public static final String FEATURE_REMOTE_GROUP_PLAYBACK =
"android.media.route.feature.REMOTE_GROUP_PLAYBACK";
+ /** Indicates the route is always suitable for media playback. */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER = 0;
+
+ /**
+ * Indicates that the route is suitable for media playback only after explicit user selection.
+ */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER = 1;
+
+ /** Indicates that the route is never suitable for media playback. */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2;
+
+ /**
+ * Route suitability status.
+ *
+ * <p>Signals whether the route is suitable to play media.
+ *
+ * @hide
+ */
+ @IntDef(
+ value = {
+ SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER,
+ SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER,
+ SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public @interface SuitabilityStatus {}
+
private final String mId;
private final CharSequence mName;
private final List<String> mFeatures;
@@ -500,6 +532,7 @@ public final class MediaRoute2Info implements Parcelable {
private final String mProviderId;
private final boolean mIsVisibilityRestricted;
private final Set<String> mAllowedPackages;
+ @SuitabilityStatus private final int mSuitabilityStatus;
MediaRoute2Info(@NonNull Builder builder) {
mId = builder.mId;
@@ -521,6 +554,7 @@ public final class MediaRoute2Info implements Parcelable {
mProviderId = builder.mProviderId;
mIsVisibilityRestricted = builder.mIsVisibilityRestricted;
mAllowedPackages = builder.mAllowedPackages;
+ mSuitabilityStatus = builder.mSuitabilityStatus;
}
MediaRoute2Info(@NonNull Parcel in) {
@@ -544,6 +578,7 @@ public final class MediaRoute2Info implements Parcelable {
mProviderId = in.readString();
mIsVisibilityRestricted = in.readBoolean();
mAllowedPackages = Set.of(in.createString8Array());
+ mSuitabilityStatus = in.readInt();
}
/**
@@ -778,6 +813,13 @@ public final class MediaRoute2Info implements Parcelable {
|| mAllowedPackages.contains(packageName);
}
+ /** Returns the route suitability status. */
+ @SuitabilityStatus
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public int getSuitabilityStatus() {
+ return mSuitabilityStatus;
+ }
+
/**
* Dumps the current state of the object to the given {@code pw} as a human-readable string.
*
@@ -809,6 +851,7 @@ public final class MediaRoute2Info implements Parcelable {
pw.println(indent + "mProviderId=" + mProviderId);
pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted);
pw.println(indent + "mAllowedPackages=" + mAllowedPackages);
+ pw.println(indent + "mSuitabilityStatus=" + mSuitabilityStatus);
}
private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) {
@@ -861,39 +904,74 @@ public final class MediaRoute2Info implements Parcelable {
&& Objects.equals(mDeduplicationIds, other.mDeduplicationIds)
&& Objects.equals(mProviderId, other.mProviderId)
&& (mIsVisibilityRestricted == other.mIsVisibilityRestricted)
- && Objects.equals(mAllowedPackages, other.mAllowedPackages);
+ && Objects.equals(mAllowedPackages, other.mAllowedPackages)
+ && mSuitabilityStatus == other.mSuitabilityStatus;
}
@Override
public int hashCode() {
// Note: mExtras is not included.
- return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription,
- mConnectionState, mClientPackageName, mPackageName, mVolumeHandling, mVolumeMax,
- mVolume, mAddress, mDeduplicationIds, mProviderId, mIsVisibilityRestricted,
- mAllowedPackages);
+ return Objects.hash(
+ mId,
+ mName,
+ mFeatures,
+ mType,
+ mIsSystem,
+ mIconUri,
+ mDescription,
+ mConnectionState,
+ mClientPackageName,
+ mPackageName,
+ mVolumeHandling,
+ mVolumeMax,
+ mVolume,
+ mAddress,
+ mDeduplicationIds,
+ mProviderId,
+ mIsVisibilityRestricted,
+ mAllowedPackages,
+ mSuitabilityStatus);
}
@Override
public String toString() {
// Note: mExtras is not printed here.
- StringBuilder result = new StringBuilder()
- .append("MediaRoute2Info{ ")
- .append("id=").append(getId())
- .append(", name=").append(getName())
- .append(", features=").append(getFeatures())
- .append(", iconUri=").append(getIconUri())
- .append(", description=").append(getDescription())
- .append(", connectionState=").append(getConnectionState())
- .append(", clientPackageName=").append(getClientPackageName())
- .append(", volumeHandling=").append(getVolumeHandling())
- .append(", volumeMax=").append(getVolumeMax())
- .append(", volume=").append(getVolume())
- .append(", address=").append(getAddress())
- .append(", deduplicationIds=").append(String.join(",", getDeduplicationIds()))
- .append(", providerId=").append(getProviderId())
- .append(", isVisibilityRestricted=").append(mIsVisibilityRestricted)
- .append(", allowedPackages=").append(String.join(",", mAllowedPackages))
- .append(" }");
+ StringBuilder result =
+ new StringBuilder()
+ .append("MediaRoute2Info{ ")
+ .append("id=")
+ .append(getId())
+ .append(", name=")
+ .append(getName())
+ .append(", features=")
+ .append(getFeatures())
+ .append(", iconUri=")
+ .append(getIconUri())
+ .append(", description=")
+ .append(getDescription())
+ .append(", connectionState=")
+ .append(getConnectionState())
+ .append(", clientPackageName=")
+ .append(getClientPackageName())
+ .append(", volumeHandling=")
+ .append(getVolumeHandling())
+ .append(", volumeMax=")
+ .append(getVolumeMax())
+ .append(", volume=")
+ .append(getVolume())
+ .append(", address=")
+ .append(getAddress())
+ .append(", deduplicationIds=")
+ .append(String.join(",", getDeduplicationIds()))
+ .append(", providerId=")
+ .append(getProviderId())
+ .append(", isVisibilityRestricted=")
+ .append(mIsVisibilityRestricted)
+ .append(", allowedPackages=")
+ .append(String.join(",", mAllowedPackages))
+ .append(", suitabilityStatus=")
+ .append(mSuitabilityStatus)
+ .append(" }");
return result.toString();
}
@@ -923,6 +1001,7 @@ public final class MediaRoute2Info implements Parcelable {
dest.writeString(mProviderId);
dest.writeBoolean(mIsVisibilityRestricted);
dest.writeString8Array(mAllowedPackages.toArray(new String[0]));
+ dest.writeInt(mSuitabilityStatus);
}
private static String getDeviceTypeString(@Type int deviceType) {
@@ -1005,6 +1084,7 @@ public final class MediaRoute2Info implements Parcelable {
private String mProviderId;
private boolean mIsVisibilityRestricted;
private Set<String> mAllowedPackages;
+ @SuitabilityStatus private int mSuitabilityStatus;
/**
* Constructor for builder to create {@link MediaRoute2Info}.
@@ -1028,6 +1108,7 @@ public final class MediaRoute2Info implements Parcelable {
mFeatures = new ArrayList<>();
mDeduplicationIds = Set.of();
mAllowedPackages = Set.of();
+ mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
}
/**
@@ -1075,6 +1156,7 @@ public final class MediaRoute2Info implements Parcelable {
mProviderId = routeInfo.mProviderId;
mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted;
mAllowedPackages = routeInfo.mAllowedPackages;
+ mSuitabilityStatus = routeInfo.mSuitabilityStatus;
}
/**
@@ -1318,6 +1400,23 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
+ * Sets route suitability status.
+ *
+ * <p>The default value is {@link
+ * MediaRoute2Info#SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER}.
+ *
+ * <p> Apps are not supposed to set {@link
+ * MediaRoute2Info#SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER}. Publishing a non-system
+ * route with such status throws {@link SecurityException}.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public Builder setSuitabilityStatus(@SuitabilityStatus int suitabilityStatus) {
+ mSuitabilityStatus = suitabilityStatus;
+ return this;
+ }
+
+ /**
* Builds the {@link MediaRoute2Info media route info}.
*
* @throws IllegalArgumentException if no features are added.
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index ba26df922f23..5e235515c852 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -17,6 +17,7 @@
package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2;
import static com.android.media.flags.Flags.FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2;
@@ -699,15 +700,48 @@ public final class MediaRouter2 {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+ @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
- mImpl.transfer(controller.getRoutingSessionInfo(), route);
+ mImpl.transfer(
+ controller.getRoutingSessionInfo(),
+ route,
+ android.os.Process.myUserHandle(),
+ mContext.getPackageName());
+ }
+
+ /**
+ * Transfers the media of a routing controller to the given route.
+ *
+ * <p>This will be no-op for non-system media routers.
+ *
+ * @param controller a routing controller controlling media routing.
+ * @param route the route you want to transfer the media to.
+ * @param transferInitiatorUserHandle the user handle of the app that initiated the transfer
+ * request.
+ * @param transferInitiatorPackageName the package name of the app that initiated the transfer.
+ * This value is used with the user handle to populate {@link
+ * RoutingController#wasTransferRequestedBySelf()}.
+ * @hide
+ */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public void transfer(
+ @NonNull RoutingController controller,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
+ mImpl.transfer(
+ controller.getRoutingSessionInfo(),
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
void requestCreateController(
@NonNull RoutingController controller,
@NonNull MediaRoute2Info route,
- long managerRequestId) {
+ long managerRequestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
final int requestId = mNextRequestId.getAndIncrement();
@@ -736,7 +770,9 @@ public final class MediaRouter2 {
managerRequestId,
controller.getRoutingSessionInfo(),
route,
- controllerHints);
+ controllerHints,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} catch (RemoteException ex) {
Log.e(TAG, "createControllerForTransfer: "
+ "Failed to request for creating a controller.", ex);
@@ -1053,7 +1089,11 @@ public final class MediaRouter2 {
}
void onRequestCreateControllerByManagerOnHandler(
- RoutingSessionInfo oldSession, MediaRoute2Info route, long managerRequestId) {
+ RoutingSessionInfo oldSession,
+ MediaRoute2Info route,
+ long managerRequestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
Log.i(
TAG,
TextUtils.formatSimple(
@@ -1070,7 +1110,8 @@ public final class MediaRouter2 {
if (controller == null) {
return;
}
- requestCreateController(controller, route, managerRequestId);
+ requestCreateController(controller, route, managerRequestId, transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
private List<MediaRoute2Info> getSortedRoutes(
@@ -1469,6 +1510,21 @@ public final class MediaRouter2 {
}
/**
+ * Returns whether the transfer was requested by the calling app (as determined by comparing
+ * {@link UserHandle} and package name).
+ */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public boolean wasTransferRequestedBySelf() {
+ RoutingSessionInfo sessionInfo = getRoutingSessionInfo();
+
+ UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
+ String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
+
+ return Objects.equals(android.os.Process.myUserHandle(), transferInitiatorUserHandle)
+ && Objects.equals(mContext.getPackageName(), transferInitiatorPackageName);
+ }
+
+ /**
* Returns the current {@link RoutingSessionInfo} associated to this controller.
*/
@NonNull
@@ -1980,14 +2036,20 @@ public final class MediaRouter2 {
@Override
public void requestCreateSessionByManager(
- long managerRequestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
+ long managerRequestId,
+ RoutingSessionInfo oldSession,
+ MediaRoute2Info route,
+ UserHandle transferInitiatorUserHandle,
+ String transferInitiatorPackageName) {
mHandler.sendMessage(
obtainMessage(
MediaRouter2::onRequestCreateControllerByManagerOnHandler,
MediaRouter2.this,
oldSession,
route,
- managerRequestId));
+ managerRequestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName));
}
}
@@ -2027,7 +2089,11 @@ public final class MediaRouter2 {
void stop();
- void transfer(RoutingSessionInfo sessionInfo, MediaRoute2Info route);
+ void transfer(
+ @NonNull RoutingSessionInfo sessionInfo,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName);
List<RoutingController> getControllers();
@@ -2220,7 +2286,11 @@ public final class MediaRouter2 {
List<RoutingSessionInfo> sessionInfos = getRoutingSessions();
RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1);
- transfer(targetSession, route);
+ transfer(
+ targetSession,
+ route,
+ android.os.Process.myUserHandle(),
+ mContext.getPackageName());
}
@Override
@@ -2243,14 +2313,24 @@ public final class MediaRouter2 {
*
* @param sessionInfo The {@link RoutingSessionInfo routing session} to transfer.
* @param route The {@link MediaRoute2Info route} to transfer to.
- * @see #transferToRoute(RoutingSessionInfo, MediaRoute2Info)
+ * @param transferInitiatorUserHandle The user handle of the app that initiated the
+ * transfer.
+ * @param transferInitiatorPackageName The package name if of the app that initiated the
+ * transfer.
+ * @see #transferToRoute(RoutingSessionInfo, MediaRoute2Info, UserHandle, String)
* @see #requestCreateSession(RoutingSessionInfo, MediaRoute2Info)
*/
@Override
+ @SuppressWarnings("AndroidFrameworkRequiresPermission")
public void transfer(
- @NonNull RoutingSessionInfo sessionInfo, @NonNull MediaRoute2Info route) {
+ @NonNull RoutingSessionInfo sessionInfo,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
Objects.requireNonNull(route, "route must not be null");
+ Objects.requireNonNull(transferInitiatorUserHandle);
+ Objects.requireNonNull(transferInitiatorPackageName);
Log.v(
TAG,
@@ -2268,9 +2348,14 @@ public final class MediaRouter2 {
}
if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
- transferToRoute(sessionInfo, route);
+ transferToRoute(
+ sessionInfo,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} else {
- requestCreateSession(sessionInfo, route);
+ requestCreateSession(sessionInfo, route, transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
}
@@ -2282,21 +2367,30 @@ public final class MediaRouter2 {
* RoutingSessionInfo routing session's} {@link RoutingSessionInfo#getTransferableRoutes()
* transferable routes list}. Otherwise, the request will fail.
*
- * <p>Use {@link #requestCreateSession(RoutingSessionInfo, MediaRoute2Info)} to request
- * an out-of-session transfer.
+ * <p>Use {@link #requestCreateSession(RoutingSessionInfo, MediaRoute2Info)} to request an
+ * out-of-session transfer.
*
* @param session The {@link RoutingSessionInfo routing session} to transfer.
* @param route The {@link MediaRoute2Info route} to transfer to. Must be one of the {@link
* RoutingSessionInfo routing session's} {@link
* RoutingSessionInfo#getTransferableRoutes() transferable routes}.
*/
+ @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
private void transferToRoute(
- @NonNull RoutingSessionInfo session, @NonNull MediaRoute2Info route) {
+ @NonNull RoutingSessionInfo session,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
int requestId = createTransferRequest(session, route);
try {
mMediaRouterService.transferToRouteWithManager(
- mClient, requestId, session.getId(), route);
+ mClient,
+ requestId,
+ session.getId(),
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -2317,7 +2411,10 @@ public final class MediaRouter2 {
* @param route The {@link MediaRoute2Info route} to transfer to.
*/
private void requestCreateSession(
- @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
if (TextUtils.isEmpty(oldSession.getClientPackageName())) {
Log.w(TAG, "requestCreateSession: Can't create a session without package name.");
this.onTransferFailed(oldSession, route);
@@ -2328,7 +2425,12 @@ public final class MediaRouter2 {
try {
mMediaRouterService.requestCreateSessionWithManager(
- mClient, requestId, oldSession, route);
+ mClient,
+ requestId,
+ oldSession,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -3055,7 +3157,8 @@ public final class MediaRouter2 {
return;
}
- requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE);
+ requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE,
+ android.os.Process.myUserHandle(), mContext.getPackageName());
}
@Override
@@ -3071,7 +3174,11 @@ public final class MediaRouter2 {
* #transferTo(MediaRoute2Info)}.
*/
@Override
- public void transfer(RoutingSessionInfo sessionInfo, MediaRoute2Info route) {
+ public void transfer(
+ @NonNull RoutingSessionInfo sessionInfo,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
// Do nothing.
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 830708cb38b2..06c0996785c2 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -18,9 +18,11 @@ package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -28,6 +30,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -467,30 +470,42 @@ public final class MediaRouter2Manager {
* <p>Same as {@link #transfer(RoutingSessionInfo, MediaRoute2Info)}, but resolves the routing
* session based on the provided package name.
*/
- public void transfer(@NonNull String packageName, @NonNull MediaRoute2Info route) {
+ @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+ public void transfer(
+ @NonNull String packageName,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle userHandle) {
Objects.requireNonNull(packageName, "packageName must not be null");
Objects.requireNonNull(route, "route must not be null");
List<RoutingSessionInfo> sessionInfos = getRoutingSessions(packageName);
RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1);
- transfer(targetSession, route);
+ transfer(targetSession, route, userHandle, packageName);
}
/**
* Transfers a routing session to a media route.
+ *
* <p>{@link Callback#onTransferred} or {@link Callback#onTransferFailed} will be called
* depending on the result.
*
* @param sessionInfo the routing session info to transfer
* @param route the route transfer to
- *
+ * @param transferInitiatorUserHandle the user handle of an app initiated the transfer
+ * @param transferInitiatorPackageName the package name of an app initiated the transfer
* @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)
* @see Callback#onTransferFailed(RoutingSessionInfo, MediaRoute2Info)
*/
- public void transfer(@NonNull RoutingSessionInfo sessionInfo,
- @NonNull MediaRoute2Info route) {
+ @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+ public void transfer(
+ @NonNull RoutingSessionInfo sessionInfo,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
Objects.requireNonNull(route, "route must not be null");
+ Objects.requireNonNull(transferInitiatorUserHandle);
+ Objects.requireNonNull(transferInitiatorPackageName);
Log.v(TAG, "Transferring routing session. session= " + sessionInfo + ", route=" + route);
@@ -503,9 +518,11 @@ public final class MediaRouter2Manager {
}
if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
- transferToRoute(sessionInfo, route);
+ transferToRoute(
+ sessionInfo, route, transferInitiatorUserHandle, transferInitiatorPackageName);
} else {
- requestCreateSession(sessionInfo, route);
+ requestCreateSession(sessionInfo, route, transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
}
@@ -873,19 +890,30 @@ public final class MediaRouter2Manager {
*
* @hide
*/
- private void transferToRoute(@NonNull RoutingSessionInfo session,
- @NonNull MediaRoute2Info route) {
+ @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+ private void transferToRoute(
+ @NonNull RoutingSessionInfo session,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
int requestId = createTransferRequest(session, route);
try {
mMediaRouterService.transferToRouteWithManager(
- mClient, requestId, session.getId(), route);
+ mClient,
+ requestId,
+ session.getId(),
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
- private void requestCreateSession(RoutingSessionInfo oldSession, MediaRoute2Info route) {
+ private void requestCreateSession(RoutingSessionInfo oldSession, MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiationPackageName) {
if (TextUtils.isEmpty(oldSession.getClientPackageName())) {
Log.w(TAG, "requestCreateSession: Can't create a session without package name.");
notifyTransferFailed(oldSession, route);
@@ -896,7 +924,8 @@ public final class MediaRouter2Manager {
try {
mMediaRouterService.requestCreateSessionWithManager(
- mClient, requestId, oldSession, route);
+ mClient, requestId, oldSession, route, transferInitiatorUserHandle,
+ transferInitiationPackageName);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index a77c9432f197..d28c26df6749 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -16,18 +16,25 @@
package android.media;
+import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.TextUtils;
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -55,6 +62,33 @@ public final class RoutingSessionInfo implements Parcelable {
private static final String KEY_GROUP_ROUTE = "androidx.mediarouter.media.KEY_GROUP_ROUTE";
private static final String KEY_VOLUME_HANDLING = "volumeHandling";
+ /**
+ * Indicates that the transfer happened by the default logic without explicit system's or user's
+ * request.
+ *
+ * <p>For example, an automatically connected Bluetooth device will have this transfer reason.
+ */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int TRANSFER_REASON_FALLBACK = 0;
+
+ /** Indicates that the transfer happened from within a privileged application. */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int TRANSFER_REASON_SYSTEM_REQUEST = 1;
+
+ /** Indicates that the transfer happened from a non-privileged app. */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public static final int TRANSFER_REASON_APP = 2;
+
+ /**
+ * Indicates the transfer reason.
+ *
+ * @hide
+ */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ @IntDef(value = {TRANSFER_REASON_FALLBACK, TRANSFER_REASON_SYSTEM_REQUEST, TRANSFER_REASON_APP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransferReason {}
+
@NonNull
final String mId;
@Nullable
@@ -82,6 +116,10 @@ public final class RoutingSessionInfo implements Parcelable {
final Bundle mControlHints;
final boolean mIsSystemSession;
+ @TransferReason final int mTransferReason;
+
+ @Nullable final UserHandle mTransferInitiatorUserHandle;
+ @Nullable final String mTransferInitiatorPackageName;
RoutingSessionInfo(@NonNull Builder builder) {
Objects.requireNonNull(builder, "builder must not be null.");
@@ -116,6 +154,9 @@ public final class RoutingSessionInfo implements Parcelable {
volumeAdjustmentForRemoteGroupSessions);
mControlHints = updateVolumeHandlingInHints(builder.mControlHints, mVolumeHandling);
+ mTransferReason = builder.mTransferReason;
+ mTransferInitiatorUserHandle = builder.mTransferInitiatorUserHandle;
+ mTransferInitiatorPackageName = builder.mTransferInitiatorPackageName;
}
RoutingSessionInfo(@NonNull Parcel src) {
@@ -140,6 +181,9 @@ public final class RoutingSessionInfo implements Parcelable {
mControlHints = src.readBundle();
mIsSystemSession = src.readBoolean();
+ mTransferReason = src.readInt();
+ mTransferInitiatorUserHandle = src.readParcelable(null, android.os.UserHandle.class);
+ mTransferInitiatorPackageName = src.readString();
}
@Nullable
@@ -330,6 +374,27 @@ public final class RoutingSessionInfo implements Parcelable {
return mIsSystemSession;
}
+ /** Returns the transfer reason for this routing session. */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ @TransferReason
+ public int getTransferReason() {
+ return mTransferReason;
+ }
+
+ /** @hide */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ @Nullable
+ public UserHandle getTransferInitiatorUserHandle() {
+ return mTransferInitiatorUserHandle;
+ }
+
+ /** @hide */
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ @Nullable
+ public String getTransferInitiatorPackageName() {
+ return mTransferInitiatorPackageName;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -351,6 +416,13 @@ public final class RoutingSessionInfo implements Parcelable {
dest.writeInt(mVolume);
dest.writeBundle(mControlHints);
dest.writeBoolean(mIsSystemSession);
+ dest.writeInt(mTransferReason);
+ if (mTransferInitiatorUserHandle != null) {
+ mTransferInitiatorUserHandle.writeToParcel(dest, /* flags= */ 0);
+ } else {
+ dest.writeParcelable(null, /* flags= */ 0);
+ }
+ dest.writeString(mTransferInitiatorPackageName);
}
/**
@@ -379,6 +451,9 @@ public final class RoutingSessionInfo implements Parcelable {
pw.println(indent + "mVolume=" + mVolume);
pw.println(indent + "mControlHints=" + mControlHints);
pw.println(indent + "mIsSystemSession=" + mIsSystemSession);
+ pw.println(indent + "mTransferReason=" + mTransferReason);
+ pw.println(indent + "mtransferInitiatorUserHandle=" + mTransferInitiatorUserHandle);
+ pw.println(indent + "mtransferInitiatorPackageName=" + mTransferInitiatorPackageName);
}
@Override
@@ -406,39 +481,69 @@ public final class RoutingSessionInfo implements Parcelable {
&& Objects.equals(mTransferableRoutes, other.mTransferableRoutes)
&& (mVolumeHandling == other.mVolumeHandling)
&& (mVolumeMax == other.mVolumeMax)
- && (mVolume == other.mVolume);
+ && (mVolume == other.mVolume)
+ && (mTransferReason == other.mTransferReason)
+ && Objects.equals(mTransferInitiatorUserHandle, other.mTransferInitiatorUserHandle)
+ && Objects.equals(
+ mTransferInitiatorPackageName, other.mTransferInitiatorPackageName);
}
@Override
public int hashCode() {
- return Objects.hash(mId, mName, mOwnerPackageName, mClientPackageName, mProviderId,
- mSelectedRoutes, mSelectableRoutes, mDeselectableRoutes, mTransferableRoutes,
- mVolumeMax, mVolumeHandling, mVolume);
+ return Objects.hash(
+ mId,
+ mName,
+ mOwnerPackageName,
+ mClientPackageName,
+ mProviderId,
+ mSelectedRoutes,
+ mSelectableRoutes,
+ mDeselectableRoutes,
+ mTransferableRoutes,
+ mVolumeMax,
+ mVolumeHandling,
+ mVolume,
+ mTransferReason,
+ mTransferInitiatorUserHandle,
+ mTransferInitiatorPackageName);
}
@Override
public String toString() {
- StringBuilder result = new StringBuilder()
- .append("RoutingSessionInfo{ ")
- .append("sessionId=").append(getId())
- .append(", name=").append(getName())
- .append(", clientPackageName=").append(getClientPackageName())
- .append(", selectedRoutes={")
- .append(String.join(",", getSelectedRoutes()))
- .append("}")
- .append(", selectableRoutes={")
- .append(String.join(",", getSelectableRoutes()))
- .append("}")
- .append(", deselectableRoutes={")
- .append(String.join(",", getDeselectableRoutes()))
- .append("}")
- .append(", transferableRoutes={")
- .append(String.join(",", getTransferableRoutes()))
- .append("}")
- .append(", volumeHandling=").append(getVolumeHandling())
- .append(", volumeMax=").append(getVolumeMax())
- .append(", volume=").append(getVolume())
- .append(" }");
+ StringBuilder result =
+ new StringBuilder()
+ .append("RoutingSessionInfo{ ")
+ .append("sessionId=")
+ .append(getId())
+ .append(", name=")
+ .append(getName())
+ .append(", clientPackageName=")
+ .append(getClientPackageName())
+ .append(", selectedRoutes={")
+ .append(String.join(",", getSelectedRoutes()))
+ .append("}")
+ .append(", selectableRoutes={")
+ .append(String.join(",", getSelectableRoutes()))
+ .append("}")
+ .append(", deselectableRoutes={")
+ .append(String.join(",", getDeselectableRoutes()))
+ .append("}")
+ .append(", transferableRoutes={")
+ .append(String.join(",", getTransferableRoutes()))
+ .append("}")
+ .append(", volumeHandling=")
+ .append(getVolumeHandling())
+ .append(", volumeMax=")
+ .append(getVolumeMax())
+ .append(", volume=")
+ .append(getVolume())
+ .append(", transferReason=")
+ .append(getTransferReason())
+ .append(", transferInitiatorUserHandle=")
+ .append(getTransferInitiatorUserHandle())
+ .append(", transferInitiatorPackageName=")
+ .append(getTransferInitiatorPackageName())
+ .append(" }");
return result.toString();
}
@@ -494,6 +599,9 @@ public final class RoutingSessionInfo implements Parcelable {
@Nullable
private Bundle mControlHints;
private boolean mIsSystemSession;
+ @TransferReason private int mTransferReason = TRANSFER_REASON_FALLBACK;
+ @Nullable private UserHandle mTransferInitiatorUserHandle;
+ @Nullable private String mTransferInitiatorPackageName;
/**
* Constructor for builder to create {@link RoutingSessionInfo}.
@@ -555,6 +663,9 @@ public final class RoutingSessionInfo implements Parcelable {
mControlHints = sessionInfo.mControlHints;
mIsSystemSession = sessionInfo.mIsSystemSession;
+ mTransferReason = sessionInfo.mTransferReason;
+ mTransferInitiatorUserHandle = sessionInfo.mTransferInitiatorUserHandle;
+ mTransferInitiatorPackageName = sessionInfo.mTransferInitiatorPackageName;
}
/**
@@ -784,6 +895,35 @@ public final class RoutingSessionInfo implements Parcelable {
}
/**
+ * Sets transfer reason for the current session.
+ *
+ * <p>By default the transfer reason is set to {@link
+ * RoutingSessionInfo#TRANSFER_REASON_FALLBACK}.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public Builder setTransferReason(@TransferReason int transferReason) {
+ mTransferReason = transferReason;
+ return this;
+ }
+
+ /**
+ * Sets the user handle and package name of the process that initiated the transfer.
+ *
+ * <p>By default the transfer initiation user handle and package name are set to {@code
+ * null}.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
+ public Builder setTransferInitiator(
+ @Nullable UserHandle transferInitiatorUserHandle,
+ @Nullable String transferInitiatorPackageName) {
+ mTransferInitiatorUserHandle = transferInitiatorUserHandle;
+ mTransferInitiatorPackageName = transferInitiatorPackageName;
+ return this;
+ }
+
+ /**
* Builds a routing session info.
*
* @throws IllegalArgumentException if no selected routes are added.
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 07f63e5441af..3da52ccbafed 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -69,3 +69,11 @@ flag {
description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos."
bug: "314324170"
}
+
+flag {
+ name: "enable_built_in_speaker_route_suitability_statuses"
+ namespace: "media_solutions"
+ description: "Make MediaRoute2Info provide information about routes suitability for transfer."
+ bug: "279555229"
+}
+
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 8ed4bf2b9cc3..c836df3b2c4d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -385,7 +385,9 @@ public class MediaRouter2ManagerTest {
MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
assertThat(routeToSelect).isNotNull();
- mManager.transfer(mPackageName, routeToSelect);
+ mManager.transfer(
+ mPackageName, routeToSelect,
+ android.os.Process.myUserHandle());
assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
assertThat(mManager.getRemoteSessions()).hasSize(1);
}
@@ -411,7 +413,9 @@ public class MediaRouter2ManagerTest {
assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
- mManager.transfer(mPackageName, routeToSelect);
+ mManager.transfer(
+ mPackageName, routeToSelect,
+ android.os.Process.myUserHandle());
assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
@@ -450,7 +454,11 @@ public class MediaRouter2ManagerTest {
.addFeature(FEATURE_REMOTE_PLAYBACK)
.build();
- mManager.transfer(mManager.getSystemRoutingSession(null), unknownRoute);
+ mManager.transfer(
+ mManager.getSystemRoutingSession(null),
+ unknownRoute,
+ android.os.Process.myUserHandle(),
+ mContext.getPackageName());
assertThat(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
assertThat(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
}
@@ -484,7 +492,11 @@ public class MediaRouter2ManagerTest {
assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
assertThat(mRouter2.getControllers()).hasSize(1);
- mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect);
+ mManager.transfer(
+ mManager.getRoutingSessions(mPackageName).get(0),
+ routeToSelect,
+ android.os.Process.myUserHandle(),
+ mContext.getPackageName());
assertThat(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(2);
@@ -516,7 +528,11 @@ public class MediaRouter2ManagerTest {
}
});
awaitOnRouteChangedManager(
- () -> mManager.transfer(mPackageName, routes.get(ROUTE_ID1)),
+ () ->
+ mManager.transfer(
+ mPackageName,
+ routes.get(ROUTE_ID1),
+ android.os.Process.myUserHandle()),
ROUTE_ID1,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
@@ -527,7 +543,11 @@ public class MediaRouter2ManagerTest {
RoutingSessionInfo sessionInfo = sessions.get(1);
awaitOnRouteChangedManager(
- () -> mManager.transfer(mPackageName, routes.get(ROUTE_ID5_TO_TRANSFER_TO)),
+ () ->
+ mManager.transfer(
+ mPackageName,
+ routes.get(ROUTE_ID5_TO_TRANSFER_TO),
+ android.os.Process.myUserHandle()),
ROUTE_ID5_TO_TRANSFER_TO,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
@@ -585,9 +605,11 @@ public class MediaRouter2ManagerTest {
assertThat(route1).isNotNull();
assertThat(route2).isNotNull();
- mManager.transfer(mPackageName, route1);
+ mManager.transfer(
+ mPackageName, route1, android.os.Process.myUserHandle());
assertThat(successLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
- mManager.transfer(mPackageName, route2);
+ mManager.transfer(
+ mPackageName, route2, android.os.Process.myUserHandle());
assertThat(successLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
// onTransferFailed/onSessionReleased should not be called.
@@ -634,7 +656,11 @@ public class MediaRouter2ManagerTest {
List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
RoutingSessionInfo targetSession = sessions.get(sessions.size() - 1);
- mManager.transfer(targetSession, routes.get(ROUTE_ID6_TO_BE_IGNORED));
+ mManager.transfer(
+ targetSession,
+ routes.get(ROUTE_ID6_TO_BE_IGNORED),
+ android.os.Process.myUserHandle(),
+ mContext.getPackageName());
assertThat(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
assertThat(onFailedLatch.await(MediaRouter2Manager.TRANSFER_TIMEOUT_MS,
@@ -705,7 +731,10 @@ public class MediaRouter2ManagerTest {
}
});
- mManager.transfer(mPackageName, routes.get(ROUTE_ID1));
+ mManager.transfer(
+ mPackageName,
+ routes.get(ROUTE_ID1),
+ android.os.Process.myUserHandle());
assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
@@ -860,7 +889,8 @@ public class MediaRouter2ManagerTest {
});
mRouter2.setOnGetControllerHintsListener(listener);
- mManager.transfer(mPackageName, route);
+ mManager.transfer(
+ mPackageName, route, android.os.Process.myUserHandle());
assertThat(hintLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
assertThat(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
@@ -905,7 +935,10 @@ public class MediaRouter2ManagerTest {
}
});
- mManager.transfer(mPackageName, routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
+ mManager.transfer(
+ mPackageName,
+ routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT),
+ android.os.Process.myUserHandle());
assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
index 66bd6f502274..d5cf1a35b4df 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
@@ -26,6 +26,7 @@ import androidx.compose.material.icons.outlined.Error
import androidx.compose.material.icons.outlined.PowerOff
import androidx.compose.material.icons.outlined.Shield
import androidx.compose.material.icons.outlined.WarningAmber
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -78,24 +79,19 @@ object CardPageProvider : SettingsPageProvider {
imageVector = Icons.Outlined.WarningAmber,
buttons = listOf(
CardButton(text = "Action") {},
- CardButton(text = "Action", isMain = true) {},
- )
+ ),
+ tintColor = MaterialTheme.colorScheme.error,
+ containerColor = MaterialTheme.colorScheme.errorContainer,
)
)
}
@Composable
private fun SettingsCardWithoutIcon() {
- var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCard(
CardModel(
title = stringResource(R.string.sample_title),
text = stringResource(R.string.sample_text),
- isVisible = { isVisible },
- onDismiss = { isVisible = false },
- buttons = listOf(
- CardButton(text = "Action") {},
- ),
)
)
}
@@ -104,6 +100,7 @@ object CardPageProvider : SettingsPageProvider {
fun SampleSettingsCollapsibleCard() {
val context = LocalContext.current
var isVisible0 by rememberSaveable { mutableStateOf(true) }
+ var isVisible1 by rememberSaveable { mutableStateOf(true) }
val cards = remember {
mutableStateListOf(
CardModel(
@@ -114,16 +111,17 @@ object CardPageProvider : SettingsPageProvider {
onDismiss = { isVisible0 = false },
buttons = listOf(
CardButton(text = "Action") {},
- )
+ ),
),
CardModel(
title = context.getString(R.string.sample_title),
text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.Shield,
+ isVisible = { isVisible1 },
+ onDismiss = { isVisible1 = false },
buttons = listOf(
CardButton(text = "Action") {},
- CardButton(text = "Main action", isMain = true) {},
- )
+ ),
)
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index 993cb4ac85e5..c143390f269c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -37,7 +37,6 @@ object SettingsDimension {
val itemPaddingAround = 8.dp
val itemDividerHeight = 32.dp
- val iconSmall = 16.dp
val iconLarge = 48.dp
/** The size when app icon is displayed in list. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
index b18a1bc01388..b2a8b87a4495 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
@@ -16,11 +16,11 @@
package com.android.settingslib.spa.widget.card
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
data class CardButton(
val text: String,
- val isMain: Boolean = false,
val onClick: () -> Unit,
)
@@ -38,4 +38,10 @@ data class CardModel(
val onDismiss: (() -> Unit)? = null,
val buttons: List<CardButton> = emptyList(),
+
+ /** If specified, this color will be used to tint the icon and the buttons. */
+ val tintColor: Color = Color.Unspecified,
+
+ /** If specified, this color will be used to tint the icon and the buttons. */
+ val containerColor: Color = Color.Unspecified,
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
index 7eec8888f025..c7845fa724d4 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
@@ -23,26 +23,26 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.WarningAmber
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -72,11 +72,14 @@ fun SettingsCard(content: @Composable ColumnScope.() -> Unit) {
}
@Composable
-fun SettingsCardContent(content: @Composable ColumnScope.() -> Unit) {
+fun SettingsCardContent(
+ containerColor: Color = Color.Unspecified,
+ content: @Composable ColumnScope.() -> Unit,
+) {
Card(
shape = CornerExtraSmall,
colors = CardDefaults.cardColors(
- containerColor = SettingsTheme.colorScheme.surface,
+ containerColor = containerColor.takeOrElse { SettingsTheme.colorScheme.surface },
),
modifier = Modifier
.fillMaxWidth()
@@ -95,37 +98,43 @@ fun SettingsCard(model: CardModel) {
@Composable
internal fun SettingsCardImpl(model: CardModel) {
AnimatedVisibility(visible = model.isVisible()) {
- SettingsCardContent {
+ SettingsCardContent(containerColor = model.containerColor) {
Column(
- modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
+ modifier = Modifier.padding(
+ horizontal = SettingsDimension.dialogItemPaddingHorizontal,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
) {
- CardHeader(model.imageVector, model.onDismiss)
+ CardHeader(model.imageVector, model.tintColor, model.onDismiss)
SettingsTitle(model.title)
SettingsBody(model.text)
- Buttons(model.buttons)
+ Buttons(model.buttons, model.tintColor)
}
}
}
}
@Composable
-fun CardHeader(imageVector: ImageVector?, onDismiss: (() -> Unit)? = null) {
+fun CardHeader(imageVector: ImageVector?, iconColor: Color, onDismiss: (() -> Unit)? = null) {
+ if (imageVector != null || onDismiss != null) {
+ Spacer(Modifier.height(SettingsDimension.buttonPaddingVertical))
+ }
Row(Modifier.fillMaxWidth()) {
- CardIcon(imageVector)
+ CardIcon(imageVector, iconColor)
Spacer(modifier = Modifier.weight(1f))
DismissButton(onDismiss)
}
}
@Composable
-private fun CardIcon(imageVector: ImageVector?) {
+private fun CardIcon(imageVector: ImageVector?, color: Color) {
if (imageVector != null) {
Icon(
imageVector = imageVector,
contentDescription = null,
modifier = Modifier.size(SettingsDimension.itemIconSize),
- tint = MaterialTheme.colorScheme.primary,
+ tint = color.takeOrElse { MaterialTheme.colorScheme.primary },
)
}
}
@@ -146,52 +155,35 @@ private fun DismissButton(onDismiss: (() -> Unit)?) {
contentDescription = stringResource(
androidx.compose.material3.R.string.m3c_snackbar_dismiss
),
- modifier = Modifier.size(SettingsDimension.iconSmall),
+ modifier = Modifier.padding(SettingsDimension.paddingSmall),
)
}
}
}
@Composable
-private fun Buttons(buttons: List<CardButton>) {
+private fun Buttons(buttons: List<CardButton>, color: Color) {
if (buttons.isNotEmpty()) {
Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = SettingsDimension.itemPaddingAround),
+ modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(
space = SettingsDimension.itemPaddingEnd,
alignment = Alignment.End,
),
) {
for (button in buttons) {
- Button(button)
+ Button(button, color)
}
}
+ } else {
+ Spacer(Modifier.height(SettingsDimension.itemPaddingAround))
}
}
@Composable
-private fun Button(button: CardButton) {
- if (button.isMain) {
- Button(
- onClick = button.onClick,
- colors = ButtonDefaults.buttonColors(
- containerColor = SettingsTheme.colorScheme.primaryContainer,
- ),
- ) {
- Text(
- text = button.text,
- color = SettingsTheme.colorScheme.onPrimaryContainer,
- )
- }
- } else {
- OutlinedButton(onClick = button.onClick) {
- Text(
- text = button.text,
- color = MaterialTheme.colorScheme.onSurface,
- )
- }
+private fun Button(button: CardButton, color: Color) {
+ TextButton(onClick = button.onClick) {
+ Text(text = button.text, color = color)
}
}
@@ -206,7 +198,6 @@ private fun SettingsCardPreview() {
imageVector = Icons.Outlined.WarningAmber,
buttons = listOf(
CardButton(text = "Action") {},
- CardButton(text = "Action", isMain = true) {},
)
)
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
index 6e36490beac7..c34df653f03c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
@@ -141,7 +141,6 @@ private fun SettingsCollapsibleCardPreview() {
imageVector = Icons.Outlined.Shield,
buttons = listOf(
CardButton(text = "Action") {},
- CardButton(text = "Main action", isMain = true) {},
)
)
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelper.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelper.java
index c9512cd01aa3..8eaea0e3561b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelper.java
@@ -151,7 +151,9 @@ public class HearingAidAudioRoutingHelper {
private boolean removePreferredDeviceForStrategies(List<AudioProductStrategy> strategies) {
boolean status = true;
for (AudioProductStrategy strategy : strategies) {
- status &= mAudioManager.removePreferredDeviceForStrategy(strategy);
+ if (mAudioManager.getPreferredDeviceForStrategy(strategy) != null) {
+ status &= mAudioManager.removePreferredDeviceForStrategy(strategy);
+ }
}
return status;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
index d5b5af7a98c4..97bbf12fd055 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
@@ -81,14 +81,17 @@ public class ManagerInfoMediaManager extends InfoMediaManager {
@Override
protected void transferToRoute(@NonNull MediaRoute2Info route) {
- mRouterManager.transfer(mPackageName, route);
+ // TODO: b/279555229 - provide real user handle of a caller.
+ mRouterManager.transfer(mPackageName, route, android.os.Process.myUserHandle());
}
@Override
protected boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device) {
final RoutingSessionInfo info = mRouterManager.getSystemRoutingSession(null);
if (info != null) {
- mRouterManager.transfer(info, device.mRouteInfo);
+ // TODO: b/279555229 - provide real user handle and package name of a caller.
+ mRouterManager.transfer(
+ info, device.mRouteInfo, android.os.Process.myUserHandle(), mPackageName);
return true;
}
return false;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelperTest.java
index 8b5ea30e17fe..c83524462b15 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingHelperTest.java
@@ -18,8 +18,10 @@ package com.android.settingslib.bluetooth;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +45,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -79,6 +82,8 @@ public class HearingAidAudioRoutingHelperTest {
when(mAudioDeviceInfo.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).thenReturn(
new AudioDeviceInfo[]{mAudioDeviceInfo});
+ doReturn(Collections.emptyList()).when(mAudioManager).getPreferredDevicesForStrategy(
+ any(AudioProductStrategy.class));
when(mAudioStrategy.getAudioAttributesForLegacyStreamType(
AudioManager.STREAM_MUSIC))
.thenReturn((new AudioAttributes.Builder()).build());
@@ -92,7 +97,10 @@ public class HearingAidAudioRoutingHelperTest {
}
@Test
- public void setPreferredDeviceRoutingStrategies_valueAuto_callRemoveStrategy() {
+ public void setPreferredDeviceRoutingStrategies_hadValueThenValueAuto_callRemoveStrategy() {
+ when(mAudioManager.getPreferredDeviceForStrategy(mAudioStrategy)).thenReturn(
+ mHearingDeviceAttribute);
+
mHelper.setPreferredDeviceRoutingStrategies(List.of(mAudioStrategy),
mHearingDeviceAttribute,
HearingAidAudioRoutingConstants.RoutingValue.AUTO);
@@ -101,6 +109,17 @@ public class HearingAidAudioRoutingHelperTest {
}
@Test
+ public void setPreferredDeviceRoutingStrategies_NoValueThenValueAuto_notCallRemoveStrategy() {
+ when(mAudioManager.getPreferredDeviceForStrategy(mAudioStrategy)).thenReturn(null);
+
+ mHelper.setPreferredDeviceRoutingStrategies(List.of(mAudioStrategy),
+ mHearingDeviceAttribute,
+ HearingAidAudioRoutingConstants.RoutingValue.AUTO);
+
+ verify(mAudioManager, never()).removePreferredDeviceForStrategy(mAudioStrategy);
+ }
+
+ @Test
public void setPreferredDeviceRoutingStrategies_valueHearingDevice_callSetStrategy() {
mHelper.setPreferredDeviceRoutingStrategies(List.of(mAudioStrategy),
mHearingDeviceAttribute,
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 782b850a5c0c..98a2d9ff2d19 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -276,3 +276,9 @@ flag {
bug: "312784809"
}
+flag {
+ name: "bluetooth_qs_tile_dialog_auto_on_toggle"
+ namespace: "systemui"
+ description: "Displays the auto on toggle in the bluetooth QS tile dialog"
+ bug: "316985153"
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index b9d66432b5f2..2bfa7d9bbd7b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -33,6 +33,8 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
+import com.android.systemui.log.core.LogcatOnlyMessageBuffer
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.Logger
import com.android.systemui.log.core.MessageBuffer
import java.io.PrintWriter
@@ -51,12 +53,13 @@ class AnimatableClockView @JvmOverloads constructor(
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
- var messageBuffer: MessageBuffer? = null
- set(value) {
- logger = if (value != null) Logger(value, TAG) else null
- }
-
- private var logger: Logger? = null
+ // To protect us from issues from this being null while the TextView constructor is running, we
+ // implement the get method and ensure a value is returned before initialization is complete.
+ private var logger = DEFAULT_LOGGER
+ get() = field ?: DEFAULT_LOGGER
+ var messageBuffer: MessageBuffer
+ get() = logger.buffer
+ set(value) { logger = Logger(value, TAG) }
private val time = Calendar.getInstance()
@@ -133,8 +136,8 @@ class AnimatableClockView @JvmOverloads constructor(
}
override fun onAttachedToWindow() {
+ logger.d("onAttachedToWindow")
super.onAttachedToWindow()
- logger?.d("onAttachedToWindow")
refreshFormat()
}
@@ -150,13 +153,13 @@ class AnimatableClockView @JvmOverloads constructor(
time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis()
contentDescription = DateFormat.format(descFormat, time)
val formattedText = DateFormat.format(format, time)
- logger?.d({ "refreshTime: new formattedText=$str1" }) { str1 = formattedText?.toString() }
+ logger.d({ "refreshTime: new formattedText=$str1" }) { str1 = formattedText?.toString() }
// Setting text actually triggers a layout pass (because the text view is set to
// wrap_content width and TextView always relayouts for this). Avoid needless
// relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) {
text = formattedText
- logger?.d({ "refreshTime: done setting new time text to: $str1" }) {
+ logger.d({ "refreshTime: done setting new time text to: $str1" }) {
str1 = formattedText?.toString()
}
// Because the TextLayout may mutate under the hood as a result of the new text, we
@@ -165,21 +168,22 @@ class AnimatableClockView @JvmOverloads constructor(
// without being notified TextInterpolator being notified.
if (layout != null) {
textAnimator?.updateLayout(layout)
- logger?.d("refreshTime: done updating textAnimator layout")
+ logger.d("refreshTime: done updating textAnimator layout")
}
requestLayout()
- logger?.d("refreshTime: after requestLayout")
+ logger.d("refreshTime: after requestLayout")
}
}
fun onTimeZoneChanged(timeZone: TimeZone?) {
+ logger.d({ "onTimeZoneChanged($str1)" }) { str1 = timeZone?.toString() }
time.timeZone = timeZone
refreshFormat()
- logger?.d({ "onTimeZoneChanged newTimeZone=$str1" }) { str1 = timeZone?.toString() }
}
@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ logger.d("onMeasure")
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val animator = textAnimator
if (animator == null) {
@@ -189,10 +193,10 @@ class AnimatableClockView @JvmOverloads constructor(
} else {
animator.updateLayout(layout)
}
- logger?.d("onMeasure")
}
override fun onDraw(canvas: Canvas) {
+ logger.d({ "onDraw($str1)"}) { str1 = text.toString() }
// Use textAnimator to render text if animation is enabled.
// Otherwise default to using standard draw functions.
if (isAnimationEnabled) {
@@ -201,22 +205,23 @@ class AnimatableClockView @JvmOverloads constructor(
} else {
super.onDraw(canvas)
}
- logger?.d("onDraw")
}
override fun invalidate() {
+ @Suppress("UNNECESSARY_SAFE_CALL")
+ // logger won't be initialized when called by TextView's constructor
+ logger.d("invalidate")
super.invalidate()
- logger?.d("invalidate")
}
override fun onTextChanged(
- text: CharSequence,
- start: Int,
- lengthBefore: Int,
- lengthAfter: Int
+ text: CharSequence,
+ start: Int,
+ lengthBefore: Int,
+ lengthAfter: Int
) {
+ logger.d({ "onTextChanged($str1)" }) { str1 = text.toString() }
super.onTextChanged(text, start, lengthBefore, lengthAfter)
- logger?.d({ "onTextChanged text=$str1" }) { str1 = text.toString() }
}
fun setLineSpacingScale(scale: Float) {
@@ -230,7 +235,7 @@ class AnimatableClockView @JvmOverloads constructor(
}
fun animateColorChange() {
- logger?.d("animateColorChange")
+ logger.d("animateColorChange")
setTextStyle(
weight = lockScreenWeight,
textSize = -1f,
@@ -252,7 +257,7 @@ class AnimatableClockView @JvmOverloads constructor(
}
fun animateAppearOnLockscreen() {
- logger?.d("animateAppearOnLockscreen")
+ logger.d("animateAppearOnLockscreen")
setTextStyle(
weight = dozingWeight,
textSize = -1f,
@@ -278,7 +283,7 @@ class AnimatableClockView @JvmOverloads constructor(
if (isAnimationEnabled && textAnimator == null) {
return
}
- logger?.d("animateFoldAppear")
+ logger.d("animateFoldAppear")
setTextStyle(
weight = lockScreenWeightInternal,
textSize = -1f,
@@ -305,7 +310,7 @@ class AnimatableClockView @JvmOverloads constructor(
// Skip charge animation if dozing animation is already playing.
return
}
- logger?.d("animateCharge")
+ logger.d("animateCharge")
val startAnimPhase2 = Runnable {
setTextStyle(
weight = if (isDozing()) dozingWeight else lockScreenWeight,
@@ -329,7 +334,7 @@ class AnimatableClockView @JvmOverloads constructor(
}
fun animateDoze(isDozing: Boolean, animate: Boolean) {
- logger?.d("animateDoze")
+ logger.d("animateDoze")
setTextStyle(
weight = if (isDozing) dozingWeight else lockScreenWeight,
textSize = -1f,
@@ -448,7 +453,7 @@ class AnimatableClockView @JvmOverloads constructor(
isSingleLineInternal && !use24HourFormat -> Patterns.sClockView12
else -> DOUBLE_LINE_FORMAT_12_HOUR
}
- logger?.d({ "refreshFormat format=$str1" }) { str1 = format?.toString() }
+ logger.d({ "refreshFormat($str1)" }) { str1 = format?.toString() }
descFormat = if (use24HourFormat) Patterns.sClockView24 else Patterns.sClockView12
refreshTime()
@@ -552,6 +557,8 @@ class AnimatableClockView @JvmOverloads constructor(
companion object {
private val TAG = AnimatableClockView::class.simpleName!!
+ private val DEFAULT_LOGGER = Logger(LogcatOnlyMessageBuffer(LogLevel.WARNING), TAG)
+
const val ANIMATION_DURATION_FOLD_TO_AOD: Int = 600
private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm"
private const val DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm"
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index cdd074d872c0..41bde5298c66 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -21,20 +21,16 @@ import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.UserHandle
import android.provider.Settings
-import android.util.Log
import androidx.annotation.OpenForTesting
-import com.android.systemui.log.LogMessageImpl
import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.core.LogMessage
+import com.android.systemui.log.core.LogcatOnlyMessageBuffer
import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.log.core.MessageInitializer
-import com.android.systemui.log.core.MessagePrinter
import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.plugins.clocks.ClockProvider
import com.android.systemui.plugins.clocks.ClockProviderPlugin
@@ -77,32 +73,6 @@ private fun <TKey : Any, TVal : Any> ConcurrentHashMap<TKey, TVal>.concurrentGet
return result ?: value
}
-private val TMP_MESSAGE: LogMessage by lazy { LogMessageImpl.Factory.create() }
-
-private inline fun Logger?.tryLog(
- tag: String,
- level: LogLevel,
- messageInitializer: MessageInitializer,
- noinline messagePrinter: MessagePrinter,
- ex: Throwable? = null,
-) {
- if (this != null) {
- // Wrap messagePrinter to convert it from crossinline to noinline
- this.log(level, messagePrinter, ex, messageInitializer)
- } else {
- messageInitializer(TMP_MESSAGE)
- val msg = messagePrinter(TMP_MESSAGE)
- when (level) {
- LogLevel.VERBOSE -> Log.v(tag, msg, ex)
- LogLevel.DEBUG -> Log.d(tag, msg, ex)
- LogLevel.INFO -> Log.i(tag, msg, ex)
- LogLevel.WARNING -> Log.w(tag, msg, ex)
- LogLevel.ERROR -> Log.e(tag, msg, ex)
- LogLevel.WTF -> Log.wtf(tag, msg, ex)
- }
- }
-}
-
/** ClockRegistry aggregates providers and plugins */
open class ClockRegistry(
val context: Context,
@@ -114,12 +84,15 @@ open class ClockRegistry(
val handleAllUsers: Boolean,
defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
- messageBuffer: MessageBuffer? = null,
+ val clockBuffers: ClockMessageBuffers? = null,
val keepAllLoaded: Boolean,
subTag: String,
var isTransitClockEnabled: Boolean = false,
) {
private val TAG = "${ClockRegistry::class.simpleName} ($subTag)"
+ private val logger: Logger =
+ Logger(clockBuffers?.infraMessageBuffer ?: LogcatOnlyMessageBuffer(LogLevel.DEBUG), TAG)
+
interface ClockChangeListener {
// Called when the active clock changes
fun onCurrentClockChanged() {}
@@ -128,7 +101,6 @@ open class ClockRegistry(
fun onAvailableClocksChanged() {}
}
- private val logger: Logger? = if (messageBuffer != null) Logger(messageBuffer, TAG) else null
private val availableClocks = ConcurrentHashMap<ClockId, ClockInfo>()
private val clockChangeListeners = mutableListOf<ClockChangeListener>()
private val settingObserver =
@@ -157,21 +129,15 @@ open class ClockRegistry(
val knownClocks = KNOWN_PLUGINS.get(manager.getPackage())
if (knownClocks == null) {
- logger.tryLog(
- TAG,
- LogLevel.WARNING,
- { str1 = manager.getPackage() },
- { "Loading unrecognized clock package: $str1" }
- )
+ logger.w({ "Loading unrecognized clock package: $str1" }) {
+ str1 = manager.getPackage()
+ }
return true
}
- logger.tryLog(
- TAG,
- LogLevel.INFO,
- { str1 = manager.getPackage() },
- { "Skipping initial load of known clock package package: $str1" }
- )
+ logger.i({ "Skipping initial load of known clock package package: $str1" }) {
+ str1 = manager.getPackage()
+ }
var isCurrentClock = false
var isClockListChanged = false
@@ -185,19 +151,14 @@ open class ClockRegistry(
}
if (manager != info.manager) {
- logger.tryLog(
- TAG,
- LogLevel.ERROR,
- {
- str1 = id
- str2 = info.manager.toString()
- str3 = manager.toString()
- },
- {
- "Clock Id conflict on attach: " +
- "$str1 is double registered by $str2 and $str3"
- }
- )
+ logger.e({
+ "Clock Id conflict on attach: " +
+ "$str1 is double registered by $str2 and $str3"
+ }) {
+ str1 = id
+ str2 = info.manager.toString()
+ str3 = manager.toString()
+ }
continue
}
@@ -219,6 +180,8 @@ open class ClockRegistry(
pluginContext: Context,
manager: PluginLifecycleManager<ClockProviderPlugin>
) {
+ plugin.initialize(clockBuffers)
+
var isClockListChanged = false
for (clock in plugin.getClocks()) {
val id = clock.clockId
@@ -233,19 +196,14 @@ open class ClockRegistry(
}
if (manager != info.manager) {
- logger.tryLog(
- TAG,
- LogLevel.ERROR,
- {
- str1 = id
- str2 = info.manager.toString()
- str3 = manager.toString()
- },
- {
- "Clock Id conflict on load: " +
- "$str1 is double registered by $str2 and $str3"
- }
- )
+ logger.e({
+ "Clock Id conflict on load: " +
+ "$str1 is double registered by $str2 and $str3"
+ }) {
+ str1 = id
+ str2 = info.manager.toString()
+ str3 = manager.toString()
+ }
manager.unloadPlugin()
continue
}
@@ -268,19 +226,14 @@ open class ClockRegistry(
val id = clock.clockId
val info = availableClocks[id]
if (info?.manager != manager) {
- logger.tryLog(
- TAG,
- LogLevel.ERROR,
- {
- str1 = id
- str2 = info?.manager.toString()
- str3 = manager.toString()
- },
- {
- "Clock Id conflict on unload: " +
- "$str1 is double registered by $str2 and $str3"
- }
- )
+ logger.e({
+ "Clock Id conflict on unload: " +
+ "$str1 is double registered by $str2 and $str3"
+ }) {
+ str1 = id
+ str2 = info?.manager.toString()
+ str3 = manager.toString()
+ }
continue
}
info.provider = null
@@ -350,7 +303,7 @@ open class ClockRegistry(
ClockSettings.deserialize(json)
} catch (ex: Exception) {
- logger.tryLog(TAG, LogLevel.ERROR, {}, { "Failed to parse clock settings" }, ex)
+ logger.e("Failed to parse clock settings", ex)
null
}
settings = result
@@ -379,7 +332,7 @@ open class ClockRegistry(
)
}
} catch (ex: Exception) {
- logger.tryLog(TAG, LogLevel.ERROR, {}, { "Failed to set clock settings" }, ex)
+ logger.e("Failed to set clock settings", ex)
}
settings = value
}
@@ -451,7 +404,8 @@ open class ClockRegistry(
}
init {
- // Register default clock designs
+ // Initialize & register default clock designs
+ defaultClockProvider.initialize(clockBuffers)
for (clock in defaultClockProvider.getClocks()) {
availableClocks[clock.clockId] = ClockInfo(clock, defaultClockProvider, null)
}
@@ -514,12 +468,7 @@ open class ClockRegistry(
fun verifyLoadedProviders() {
val shouldSchedule = isQueued.compareAndSet(false, true)
if (!shouldSchedule) {
- logger.tryLog(
- TAG,
- LogLevel.VERBOSE,
- {},
- { "verifyLoadedProviders: shouldSchedule=false" }
- )
+ logger.v("verifyLoadedProviders: shouldSchedule=false")
return
}
@@ -528,12 +477,7 @@ open class ClockRegistry(
synchronized(availableClocks) {
isQueued.set(false)
if (keepAllLoaded) {
- logger.tryLog(
- TAG,
- LogLevel.INFO,
- {},
- { "verifyLoadedProviders: keepAllLoaded=true" }
- )
+ logger.i("verifyLoadedProviders: keepAllLoaded=true")
// Enforce that all plugins are loaded if requested
for ((_, info) in availableClocks) {
info.manager?.loadPlugin()
@@ -543,12 +487,7 @@ open class ClockRegistry(
val currentClock = availableClocks[currentClockId]
if (currentClock == null) {
- logger.tryLog(
- TAG,
- LogLevel.INFO,
- {},
- { "verifyLoadedProviders: currentClock=null" }
- )
+ logger.i("verifyLoadedProviders: currentClock=null")
// Current Clock missing, load no plugins and use default
for ((_, info) in availableClocks) {
info.manager?.unloadPlugin()
@@ -556,12 +495,7 @@ open class ClockRegistry(
return@launch
}
- logger.tryLog(
- TAG,
- LogLevel.INFO,
- {},
- { "verifyLoadedProviders: load currentClock" }
- )
+ logger.i("verifyLoadedProviders: load currentClock")
val currentManager = currentClock.manager
currentManager?.loadPlugin()
@@ -577,30 +511,26 @@ open class ClockRegistry(
private fun onConnected(info: ClockInfo) {
val isCurrent = currentClockId == info.metadata.clockId
- logger.tryLog(
- TAG,
+ logger.log(
if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
- {
- str1 = info.metadata.clockId
- str2 = info.manager.toString()
- bool1 = isCurrent
- },
{ "Connected $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
- )
+ ) {
+ str1 = info.metadata.clockId
+ str2 = info.manager.toString()
+ bool1 = isCurrent
+ }
}
private fun onLoaded(info: ClockInfo) {
val isCurrent = currentClockId == info.metadata.clockId
- logger.tryLog(
- TAG,
+ logger.log(
if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
- {
- str1 = info.metadata.clockId
- str2 = info.manager.toString()
- bool1 = isCurrent
- },
{ "Loaded $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
- )
+ ) {
+ str1 = info.metadata.clockId
+ str2 = info.manager.toString()
+ bool1 = isCurrent
+ }
if (isCurrent) {
triggerOnCurrentClockChanged()
@@ -609,16 +539,14 @@ open class ClockRegistry(
private fun onUnloaded(info: ClockInfo) {
val isCurrent = currentClockId == info.metadata.clockId
- logger.tryLog(
- TAG,
+ logger.log(
if (isCurrent) LogLevel.WARNING else LogLevel.DEBUG,
- {
- str1 = info.metadata.clockId
- str2 = info.manager.toString()
- bool1 = isCurrent
- },
{ "Unloaded $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
- )
+ ) {
+ str1 = info.metadata.clockId
+ str2 = info.manager.toString()
+ bool1 = isCurrent
+ }
if (isCurrent) {
triggerOnCurrentClockChanged()
@@ -627,16 +555,14 @@ open class ClockRegistry(
private fun onDisconnected(info: ClockInfo) {
val isCurrent = currentClockId == info.metadata.clockId
- logger.tryLog(
- TAG,
+ logger.log(
if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
- {
- str1 = info.metadata.clockId
- str2 = info.manager.toString()
- bool1 = isCurrent
- },
{ "Disconnected $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
- )
+ ) {
+ str1 = info.metadata.clockId
+ str2 = info.manager.toString()
+ bool1 = isCurrent
+ }
}
fun getClocks(): List<ClockMetadata> {
@@ -676,23 +602,13 @@ open class ClockRegistry(
if (isEnabled && clockId.isNotEmpty()) {
val clock = createClock(clockId)
if (clock != null) {
- logger.tryLog(TAG, LogLevel.INFO, { str1 = clockId }, { "Rendering clock $str1" })
+ logger.i({ "Rendering clock $str1" }) { str1 = clockId }
return clock
} else if (availableClocks.containsKey(clockId)) {
- logger.tryLog(
- TAG,
- LogLevel.WARNING,
- { str1 = clockId },
- { "Clock $str1 not loaded; using default" }
- )
+ logger.w({ "Clock $str1 not loaded; using default" }) { str1 = clockId }
verifyLoadedProviders()
} else {
- logger.tryLog(
- TAG,
- LogLevel.ERROR,
- { str1 = clockId },
- { "Clock $str1 not found; using default" }
- )
+ logger.e({ "Clock $str1 not found; using default" }) { str1 = clockId }
}
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 01c03b1f25f6..99d321695d04 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -33,6 +33,7 @@ import com.android.systemui.plugins.clocks.ClockEvents
import com.android.systemui.plugins.clocks.ClockFaceConfig
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
import com.android.systemui.plugins.clocks.WeatherData
@@ -41,8 +42,6 @@ import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
-private val TAG = DefaultClockController::class.simpleName
-
/**
* Controls the default clock visuals.
*
@@ -56,6 +55,7 @@ class DefaultClockController(
private val settings: ClockSettings?,
private val hasStepClockAnimation: Boolean = false,
private val migratedClocks: Boolean = false,
+ messageBuffers: ClockMessageBuffers? = null,
) : ClockController {
override val smallClock: DefaultClockFaceController
override val largeClock: LargeClockFaceController
@@ -83,13 +83,15 @@ class DefaultClockController(
DefaultClockFaceController(
layoutInflater.inflate(R.layout.clock_default_small, parent, false)
as AnimatableClockView,
- settings?.seedColor
+ settings?.seedColor,
+ messageBuffers?.smallClockMessageBuffer
)
largeClock =
LargeClockFaceController(
layoutInflater.inflate(R.layout.clock_default_large, parent, false)
as AnimatableClockView,
- settings?.seedColor
+ settings?.seedColor,
+ messageBuffers?.largeClockMessageBuffer
)
clocks = listOf(smallClock.view, largeClock.view)
@@ -110,6 +112,7 @@ class DefaultClockController(
open inner class DefaultClockFaceController(
override val view: AnimatableClockView,
var seedColor: Int?,
+ messageBuffer: MessageBuffer?,
) : ClockFaceController {
// MAGENTA is a placeholder, and will be assigned correctly in initialize
@@ -120,12 +123,6 @@ class DefaultClockController(
override val config = ClockFaceConfig()
override val layout = DefaultClockFaceLayout(view)
- override var messageBuffer: MessageBuffer?
- get() = view.messageBuffer
- set(value) {
- view.messageBuffer = value
- }
-
override var animations: DefaultClockAnimations = DefaultClockAnimations(view, 0f, 0f)
internal set
@@ -134,6 +131,7 @@ class DefaultClockController(
currentColor = seedColor!!
}
view.setColors(DOZE_COLOR, currentColor)
+ messageBuffer?.let { view.messageBuffer = it }
}
override val events =
@@ -188,7 +186,8 @@ class DefaultClockController(
inner class LargeClockFaceController(
view: AnimatableClockView,
seedColor: Int?,
- ) : DefaultClockFaceController(view, seedColor) {
+ messageBuffer: MessageBuffer?,
+ ) : DefaultClockFaceController(view, seedColor, messageBuffer) {
override val layout = DefaultClockFaceLayout(view)
override val config =
ClockFaceConfig(hasCustomPositionUpdatedAnimation = hasStepClockAnimation)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index a219be53bd1a..20f87a059656 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -20,6 +20,7 @@ import android.view.LayoutInflater
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.plugins.clocks.ClockProvider
import com.android.systemui.plugins.clocks.ClockSettings
@@ -35,6 +36,12 @@ class DefaultClockProvider(
val hasStepClockAnimation: Boolean = false,
val migratedClocks: Boolean = false
) : ClockProvider {
+ private var messageBuffers: ClockMessageBuffers? = null
+
+ override fun initialize(buffers: ClockMessageBuffers?) {
+ messageBuffers = buffers
+ }
+
override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID))
override fun createClock(settings: ClockSettings): ClockController {
@@ -49,6 +56,7 @@ class DefaultClockProvider(
settings,
hasStepClockAnimation,
migratedClocks,
+ messageBuffers,
)
}
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/core/LogcatOnlyMessageBuffer.kt b/packages/SystemUI/log/src/com/android/systemui/log/core/LogcatOnlyMessageBuffer.kt
new file mode 100644
index 000000000000..006b521ad867
--- /dev/null
+++ b/packages/SystemUI/log/src/com/android/systemui/log/core/LogcatOnlyMessageBuffer.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.core
+
+import android.util.Log
+import com.android.systemui.log.LogMessageImpl
+
+/**
+ * A simple implementation of [MessageBuffer] that forwards messages to [android.util.Log]
+ * immediately. This defeats the intention behind [LogBuffer] and should only be used when
+ * [LogBuffer]s are unavailable in a certain context.
+ */
+class LogcatOnlyMessageBuffer(
+ val targetLogLevel: LogLevel,
+) : MessageBuffer {
+ private val singleMessage = LogMessageImpl.Factory.create()
+ private var isObtained: Boolean = false
+
+ @Synchronized
+ override fun obtain(
+ tag: String,
+ level: LogLevel,
+ messagePrinter: MessagePrinter,
+ exception: Throwable?,
+ ): LogMessage {
+ if (isObtained) {
+ throw UnsupportedOperationException(
+ "Message has already been obtained. Call order is incorrect."
+ )
+ }
+
+ singleMessage.reset(tag, level, System.currentTimeMillis(), messagePrinter, exception)
+ isObtained = true
+ return singleMessage
+ }
+
+ @Synchronized
+ override fun commit(message: LogMessage) {
+ if (singleMessage != message) {
+ throw IllegalArgumentException("Message argument is not the expected message.")
+ }
+ if (!isObtained) {
+ throw UnsupportedOperationException(
+ "Message has not been obtained. Call order is incorrect."
+ )
+ }
+
+ if (message.level >= targetLogLevel) {
+ val strMessage = message.messagePrinter(message)
+ when (message.level) {
+ LogLevel.VERBOSE -> Log.v(message.tag, strMessage, message.exception)
+ LogLevel.DEBUG -> Log.d(message.tag, strMessage, message.exception)
+ LogLevel.INFO -> Log.i(message.tag, strMessage, message.exception)
+ LogLevel.WARNING -> Log.w(message.tag, strMessage, message.exception)
+ LogLevel.ERROR -> Log.e(message.tag, strMessage, message.exception)
+ LogLevel.WTF -> Log.wtf(message.tag, strMessage, message.exception)
+ }
+ }
+
+ isObtained = false
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 1c5f221f2efb..4436be7cd7d7 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -41,16 +41,13 @@ interface ClockProviderPlugin : Plugin, ClockProvider {
/** Interface for building clocks and providing information about those clocks */
interface ClockProvider {
+ /** Initializes the clock provider with debug log buffers */
+ fun initialize(buffers: ClockMessageBuffers?)
+
/** Returns metadata for all clocks this provider knows about */
fun getClocks(): List<ClockMetadata>
/** Initializes and returns the target clock design */
- @Deprecated("Use overload with ClockSettings")
- fun createClock(id: ClockId): ClockController {
- return createClock(ClockSettings(id, null))
- }
-
- /** Initializes and returns the target clock design */
fun createClock(settings: ClockSettings): ClockController
/** A static thumbnail for rendering in some examples */
@@ -98,11 +95,20 @@ interface ClockFaceController {
/** Triggers for various animations */
val animations: ClockAnimations
-
- /** Some clocks may log debug information */
- var messageBuffer: MessageBuffer?
}
+/** For clocks that want to report debug information */
+data class ClockMessageBuffers(
+ /** Message buffer for general infra */
+ val infraMessageBuffer: MessageBuffer,
+
+ /** Message buffer for small clock renering */
+ val smallClockMessageBuffer: MessageBuffer,
+
+ /** Message buffer for large clock rendering */
+ val largeClockMessageBuffer: MessageBuffer,
+)
+
/** Specifies layout information for the */
interface ClockFaceLayout {
/** All clock views to add to the root constraint layout before applying constraints. */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index d8c1e41465db..131eb6b63df3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -367,7 +367,7 @@ public class QuickStepContract {
/**
* Corner radius that should be used on windows in order to cover the display.
* These values are expressed in pixels because they should not respect display or font
- * scaling, this means that we don't have to reload them on config changes.
+ * scaling. The corner radius may change when folding/unfolding the device.
*/
public static float getWindowCornerRadius(Context context) {
return ScreenDecorationsUtils.getWindowCornerRadius(context);
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 76abad8ae863..bcc20448297d 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -45,12 +45,11 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
import com.android.systemui.log.core.LogLevel.DEBUG
-import com.android.systemui.log.dagger.KeyguardLargeClockLog
-import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceController
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockTickRate
import com.android.systemui.plugins.clocks.AlarmData
import com.android.systemui.plugins.clocks.WeatherData
@@ -91,117 +90,120 @@ constructor(
private val context: Context,
@Main private val mainExecutor: DelayableExecutor,
@Background private val bgExecutor: Executor,
- @KeyguardSmallClockLog private val smallLogBuffer: LogBuffer?,
- @KeyguardLargeClockLog private val largeLogBuffer: LogBuffer?,
+ private val clockBuffers: ClockMessageBuffers,
private val featureFlags: FeatureFlags,
private val zenModeController: ZenModeController,
) {
+ var loggers = listOf(
+ clockBuffers.infraMessageBuffer,
+ clockBuffers.smallClockMessageBuffer,
+ clockBuffers.largeClockMessageBuffer
+ ).map { Logger(it, TAG) }
+
var clock: ClockController? = null
+ get() = field
set(value) {
- smallClockOnAttachStateChangeListener?.let {
- field?.smallClock?.view?.removeOnAttachStateChangeListener(it)
- smallClockFrame?.viewTreeObserver
- ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
- }
- largeClockOnAttachStateChangeListener?.let {
- field?.largeClock?.view?.removeOnAttachStateChangeListener(it)
- }
-
+ disconnectClock(field)
field = value
- if (value != null) {
- smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
- value.smallClock.messageBuffer = smallLogBuffer
- largeLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
- value.largeClock.messageBuffer = largeLogBuffer
-
- value.initialize(resources, dozeAmount, 0f)
-
- if (!regionSamplingEnabled) {
- updateColors()
- } else {
- clock?.let {
- smallRegionSampler = createRegionSampler(
- it.smallClock.view,
- mainExecutor,
- bgExecutor,
- regionSamplingEnabled,
- isLockscreen = true,
- ::updateColors
- )?.apply { startRegionSampler() }
-
- largeRegionSampler = createRegionSampler(
- it.largeClock.view,
- mainExecutor,
- bgExecutor,
- regionSamplingEnabled,
- isLockscreen = true,
- ::updateColors
- )?.apply { startRegionSampler() }
-
- updateColors()
- }
- }
- updateFontSizes()
- updateTimeListeners()
- weatherData?.let {
- if (WeatherData.DEBUG) {
- Log.i(TAG, "Pushing cached weather data to new clock: $it")
- }
- value.events.onWeatherDataChanged(it)
- }
- zenData?.let {
- value.events.onZenDataChanged(it)
- }
- alarmData?.let {
- value.events.onAlarmDataChanged(it)
- }
+ connectClock(value)
+ }
- smallClockOnAttachStateChangeListener =
- object : OnAttachStateChangeListener {
- var pastVisibility: Int? = null
- override fun onViewAttachedToWindow(view: View) {
- value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
- // Match the asing for view.parent's layout classes.
- smallClockFrame = view.parent as ViewGroup
- smallClockFrame?.let { frame ->
- pastVisibility = frame.visibility
- onGlobalLayoutListener = OnGlobalLayoutListener {
- val currentVisibility = frame.visibility
- if (pastVisibility != currentVisibility) {
- pastVisibility = currentVisibility
- // when small clock is visible,
- // recalculate bounds and sample
- if (currentVisibility == View.VISIBLE) {
- smallRegionSampler?.stopRegionSampler()
- smallRegionSampler?.startRegionSampler()
- }
- }
- }
- frame.viewTreeObserver
- .addOnGlobalLayoutListener(onGlobalLayoutListener)
- }
- }
+ private fun disconnectClock(clock: ClockController?) {
+ if (clock == null) { return; }
+ smallClockOnAttachStateChangeListener?.let {
+ clock.smallClock.view.removeOnAttachStateChangeListener(it)
+ smallClockFrame?.viewTreeObserver
+ ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
+ }
+ largeClockOnAttachStateChangeListener?.let {
+ clock.largeClock.view.removeOnAttachStateChangeListener(it)
+ }
+ }
- override fun onViewDetachedFromWindow(p0: View) {
- smallClockFrame?.viewTreeObserver
- ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
- }
- }
- value.smallClock.view
- .addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
+ private fun connectClock(clock: ClockController?) {
+ if (clock == null) { return; }
+ val clockStr = clock.toString()
+ loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } }
- largeClockOnAttachStateChangeListener =
- object : OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(p0: View) {
- value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
- }
- override fun onViewDetachedFromWindow(p0: View) {
+ clock.initialize(resources, dozeAmount, 0f)
+
+ if (!regionSamplingEnabled) {
+ updateColors()
+ } else {
+ smallRegionSampler = createRegionSampler(
+ clock.smallClock.view,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ isLockscreen = true,
+ ::updateColors
+ ).apply { startRegionSampler() }
+
+ largeRegionSampler = createRegionSampler(
+ clock.largeClock.view,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ isLockscreen = true,
+ ::updateColors
+ ).apply { startRegionSampler() }
+
+ updateColors()
+ }
+ updateFontSizes()
+ updateTimeListeners()
+
+ weatherData?.let {
+ if (WeatherData.DEBUG) {
+ Log.i(TAG, "Pushing cached weather data to new clock: $it")
+ }
+ clock.events.onWeatherDataChanged(it)
+ }
+ zenData?.let {
+ clock.events.onZenDataChanged(it)
+ }
+ alarmData?.let {
+ clock.events.onAlarmDataChanged(it)
+ }
+
+ smallClockOnAttachStateChangeListener = object : OnAttachStateChangeListener {
+ var pastVisibility: Int? = null
+ override fun onViewAttachedToWindow(view: View) {
+ clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+ // Match the asing for view.parent's layout classes.
+ smallClockFrame = (view.parent as ViewGroup)?.also { frame ->
+ pastVisibility = frame.visibility
+ onGlobalLayoutListener = OnGlobalLayoutListener {
+ val currentVisibility = frame.visibility
+ if (pastVisibility != currentVisibility) {
+ pastVisibility = currentVisibility
+ // when small clock is visible,
+ // recalculate bounds and sample
+ if (currentVisibility == View.VISIBLE) {
+ smallRegionSampler?.stopRegionSampler()
+ smallRegionSampler?.startRegionSampler()
+ }
}
+ }
+ frame.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
}
- value.largeClock.view
- .addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
+ }
+
+ override fun onViewDetachedFromWindow(p0: View) {
+ smallClockFrame?.viewTreeObserver
+ ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
}
}
+ clock.smallClock.view.addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
+
+ largeClockOnAttachStateChangeListener = object : OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(p0: View) {
+ clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+ }
+ override fun onViewDetachedFromWindow(p0: View) {}
+ }
+ clock.largeClock.view.addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
+ }
@VisibleForTesting
var smallClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
@@ -247,6 +249,7 @@ constructor(
largeClock.events.onRegionDarknessChanged(isRegionDark)
}
}
+
protected open fun createRegionSampler(
sampledView: View,
mainExecutor: Executor?,
@@ -254,7 +257,7 @@ constructor(
regionSamplingEnabled: Boolean,
isLockscreen: Boolean,
updateColors: () -> Unit
- ): RegionSampler? {
+ ): RegionSampler {
return RegionSampler(
sampledView,
mainExecutor,
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index 661ce2ce60ba..878a5d88f164 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -28,9 +28,8 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.clocks.ClockMessageBuffers;
import com.android.systemui.res.R;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.clocks.DefaultClockProvider;
@@ -56,7 +55,7 @@ public abstract class ClockRegistryModule {
FeatureFlags featureFlags,
@Main Resources resources,
LayoutInflater layoutInflater,
- @KeyguardClockLog LogBuffer logBuffer) {
+ ClockMessageBuffers clockBuffers) {
ClockRegistry registry = new ClockRegistry(
context,
pluginManager,
@@ -72,7 +71,7 @@ public abstract class ClockRegistryModule {
featureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION),
migrateClocksToBlueprint()),
context.getString(R.string.lockscreen_clock_id_fallback),
- logBuffer,
+ clockBuffers,
/* keepAllLoaded = */ false,
/* subTag = */ "System",
/* isTransitClockEnabled = */ featureFlags.isEnabled(Flags.TRANSIT_CLOCK));
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index 7d290c3c61fd..05fe0b25381d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -32,8 +32,6 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.res.R
import kotlinx.coroutines.launch
-private val TAG = KeyguardClockViewBinder::class.simpleName
-
object KeyguardClockViewBinder {
@JvmStatic
fun bind(
@@ -74,12 +72,6 @@ object KeyguardClockViewBinder {
applyConstraints(clockSection, keyguardRootView, true)
}
}
- launch {
- if (!migrateClocksToBlueprint()) return@launch
- viewModel.hasCustomWeatherDataDisplay.collect {
- applyConstraints(clockSection, keyguardRootView, true)
- }
- }
}
}
}
@@ -132,7 +124,7 @@ object KeyguardClockViewBinder {
fun applyConstraints(
clockSection: ClockSection,
rootView: ConstraintLayout,
- animated: Boolean
+ animated: Boolean,
) {
val constraintSet = ConstraintSet().apply { clone(rootView) }
clockSection.applyConstraints(constraintSet)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 954d2cf6ed8a..e36819b54524 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -16,13 +16,19 @@
package com.android.systemui.keyguard.ui.binder
+import android.transition.TransitionManager
+import android.view.View
+import androidx.constraintlayout.helper.widget.Layer
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import kotlinx.coroutines.launch
object KeyguardSmartspaceViewBinder {
@JvmStatic
@@ -30,15 +36,63 @@ object KeyguardSmartspaceViewBinder {
smartspaceSection: SmartspaceSection,
keyguardRootView: ConstraintLayout,
clockViewModel: KeyguardClockViewModel,
+ smartspaceViewModel: KeyguardSmartspaceViewModel,
) {
keyguardRootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- clockViewModel.hasCustomWeatherDataDisplay.collect {
- val constraintSet = ConstraintSet().apply { clone(keyguardRootView) }
- smartspaceSection.applyConstraints(constraintSet)
- constraintSet.applyTo(keyguardRootView)
+ launch {
+ clockViewModel.hasCustomWeatherDataDisplay.collect { hasCustomWeatherDataDisplay
+ ->
+ if (hasCustomWeatherDataDisplay) {
+ removeDateWeatherToBurnInLayer(keyguardRootView, smartspaceViewModel)
+ } else {
+ addDateWeatherToBurnInLayer(keyguardRootView, smartspaceViewModel)
+ }
+ clockViewModel.burnInLayer?.updatePostLayout(keyguardRootView)
+ val constraintSet = ConstraintSet().apply { clone(keyguardRootView) }
+ smartspaceSection.applyConstraints(constraintSet)
+ TransitionManager.beginDelayedTransition(keyguardRootView)
+ constraintSet.applyTo(keyguardRootView)
+ }
}
}
}
}
+
+ private fun addDateWeatherToBurnInLayer(
+ constraintLayout: ConstraintLayout,
+ smartspaceViewModel: KeyguardSmartspaceViewModel
+ ) {
+ val burnInLayer = constraintLayout.requireViewById<Layer>(R.id.burn_in_layer)
+ burnInLayer.apply {
+ if (
+ smartspaceViewModel.isSmartspaceEnabled &&
+ smartspaceViewModel.isDateWeatherDecoupled
+ ) {
+ val dateView = constraintLayout.requireViewById<View>(smartspaceViewModel.dateId)
+ val weatherView =
+ constraintLayout.requireViewById<View>(smartspaceViewModel.weatherId)
+ addView(weatherView)
+ addView(dateView)
+ }
+ }
+ }
+
+ private fun removeDateWeatherToBurnInLayer(
+ constraintLayout: ConstraintLayout,
+ smartspaceViewModel: KeyguardSmartspaceViewModel
+ ) {
+ val burnInLayer = constraintLayout.requireViewById<Layer>(R.id.burn_in_layer)
+ burnInLayer.apply {
+ if (
+ smartspaceViewModel.isSmartspaceEnabled &&
+ smartspaceViewModel.isDateWeatherDecoupled
+ ) {
+ val dateView = smartspaceViewModel.dateView
+ val weatherView = smartspaceViewModel.weatherView
+ removeView(weatherView)
+ removeView(dateView)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
index f890ae612ccc..16539db648bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
@@ -30,6 +30,8 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSec
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule
+import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeNotificationStackScrollLayoutSection
import com.android.systemui.util.kotlin.getOrNull
@@ -59,6 +61,8 @@ constructor(
aodNotificationIconsSection: AodNotificationIconsSection,
aodBurnInSection: AodBurnInSection,
communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
+ smartspaceSection: SmartspaceSection,
+ clockSection: SplitShadeClockSection,
) : KeyguardBlueprint {
override val id: String = ID
@@ -73,8 +77,10 @@ constructor(
splitShadeNotificationStackScrollLayoutSection,
splitShadeGuidelines,
aodNotificationIconsSection,
+ smartspaceSection,
aodBurnInSection,
communalTutorialIndicatorSection,
+ clockSection,
defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
index 8166b454fcff..d89e1e41d1bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
@@ -23,7 +23,6 @@ import androidx.constraintlayout.helper.widget.Layer
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.Flags.migrateClocksToBlueprint
-import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
@@ -38,7 +37,6 @@ constructor(
private val context: Context,
private val clockViewModel: KeyguardClockViewModel,
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
- private val featureFlags: FeatureFlagsClassic,
) : KeyguardSection() {
lateinit var burnInLayer: Layer
@@ -59,6 +57,8 @@ constructor(
}
}
if (migrateClocksToBlueprint()) {
+ // weather and date parts won't be added here, cause their visibility doesn't align
+ // with others in burnInLayer
addSmartspaceViews(constraintLayout)
}
constraintLayout.addView(burnInLayer)
@@ -89,14 +89,6 @@ constructor(
val smartspaceView =
constraintLayout.requireViewById<View>(smartspaceViewModel.smartspaceViewId)
addView(smartspaceView)
- if (smartspaceViewModel.isDateWeatherDecoupled) {
- val dateView =
- constraintLayout.requireViewById<View>(smartspaceViewModel.dateId)
- val weatherView =
- constraintLayout.requireViewById<View>(smartspaceViewModel.weatherId)
- addView(weatherView)
- addView(dateView)
- }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index 39a0547ded26..b429ab4fac0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -28,7 +28,6 @@ import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.common.ui.ConfigurationState
-import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
@@ -49,7 +48,6 @@ class AodNotificationIconsSection
constructor(
private val context: Context,
private val configurationState: ConfigurationState,
- private val featureFlags: FeatureFlagsClassic,
private val iconBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
@@ -119,14 +117,8 @@ constructor(
}
constraintSet.apply {
if (migrateClocksToBlueprint()) {
- connect(
- nicId,
- TOP,
- smartspaceViewModel.smartspaceViewId,
- topAlignment,
- bottomMargin
- )
- setGoneMargin(nicId, topAlignment, bottomMargin)
+ connect(nicId, TOP, smartspaceViewModel.smartspaceViewId, BOTTOM, bottomMargin)
+ setGoneMargin(nicId, BOTTOM, bottomMargin)
} else {
connect(nicId, TOP, R.id.keyguard_status_view, topAlignment, bottomMargin)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 1df920aab833..656c75c7bfec 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -27,7 +27,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
-import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder
@@ -50,19 +50,21 @@ internal fun ConstraintSet.setAlpha(
alpha: Float,
) = views.forEach { view -> this.setAlpha(view.id, alpha) }
-class ClockSection
+open class ClockSection
@Inject
constructor(
private val clockInteractor: KeyguardClockInteractor,
- private val keyguardClockViewModel: KeyguardClockViewModel,
- val smartspaceViewModel: KeyguardSmartspaceViewModel,
+ protected val keyguardClockViewModel: KeyguardClockViewModel,
+ private val smartspaceViewModel: KeyguardSmartspaceViewModel,
private val context: Context,
private val splitShadeStateController: SplitShadeStateController,
- private val featureFlags: FeatureFlagsClassic,
) : KeyguardSection() {
override fun addViews(constraintLayout: ConstraintLayout) {}
override fun bindData(constraintLayout: ConstraintLayout) {
+ if (!Flags.migrateClocksToBlueprint()) {
+ return
+ }
KeyguardClockViewBinder.bind(
this,
constraintLayout,
@@ -72,6 +74,9 @@ constructor(
}
override fun applyConstraints(constraintSet: ConstraintSet) {
+ if (!Flags.migrateClocksToBlueprint()) {
+ return
+ }
clockInteractor.clock?.let { clock ->
constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet))
}
@@ -94,16 +99,6 @@ constructor(
}
}
- var largeClockEndGuideline = PARENT_ID
-
- // Return if largeClockEndGuideline changes,
- // and use it to decide whether to refresh blueprint
- fun setClockShouldBeCentered(shouldBeCentered: Boolean): Boolean {
- val previousValue = largeClockEndGuideline
- largeClockEndGuideline = if (shouldBeCentered) PARENT_ID else R.id.split_shade_guideline
- return previousValue != largeClockEndGuideline
- }
-
private fun getTargetClockFace(clock: ClockController): ClockFaceLayout =
if (keyguardClockViewModel.useLargeClock) getLargeClockFace(clock)
else getSmallClockFace(clock)
@@ -113,10 +108,10 @@ constructor(
private fun getLargeClockFace(clock: ClockController): ClockFaceLayout = clock.largeClock.layout
private fun getSmallClockFace(clock: ClockController): ClockFaceLayout = clock.smallClock.layout
- fun applyDefaultConstraints(constraints: ConstraintSet) {
+ open fun applyDefaultConstraints(constraints: ConstraintSet) {
constraints.apply {
connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START)
- connect(R.id.lockscreen_clock_view_large, END, largeClockEndGuideline, END)
+ connect(R.id.lockscreen_clock_view_large, END, PARENT_ID, END)
connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.lock_icon_view, TOP)
var largeClockTopMargin =
context.resources.getDimensionPixelSize(R.dimen.status_bar_height) +
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 368b388062a1..8cd51cd3b1e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.Context
-import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -36,7 +35,7 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
-class SmartspaceSection
+open class SmartspaceSection
@Inject
constructor(
val keyguardClockViewModel: KeyguardClockViewModel,
@@ -45,9 +44,13 @@ constructor(
val smartspaceController: LockscreenSmartspaceController,
val keyguardUnlockAnimationController: KeyguardUnlockAnimationController,
) : KeyguardSection() {
- private var smartspaceView: View? = null
- private var weatherView: View? = null
- private var dateView: View? = null
+ var smartspaceView by keyguardSmartspaceViewModel::smartspaceView
+ var weatherView by keyguardSmartspaceViewModel::weatherView
+ var dateView by keyguardSmartspaceViewModel::dateView
+
+ val smartspaceViewId = keyguardSmartspaceViewModel.smartspaceViewId
+ val weatherViewId = keyguardSmartspaceViewModel.weatherId
+ val dateViewId = keyguardSmartspaceViewModel.dateId
override fun addViews(constraintLayout: ConstraintLayout) {
if (!migrateClocksToBlueprint()) {
@@ -67,10 +70,21 @@ constructor(
}
override fun bindData(constraintLayout: ConstraintLayout) {
- KeyguardSmartspaceViewBinder.bind(this, constraintLayout, keyguardClockViewModel)
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
+ KeyguardSmartspaceViewBinder.bind(
+ this,
+ constraintLayout,
+ keyguardClockViewModel,
+ keyguardSmartspaceViewModel,
+ )
}
override fun applyConstraints(constraintSet: ConstraintSet) {
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
// Generally, weather should be next to dateView
// smartspace should be below date & weather views
constraintSet.apply {
@@ -130,7 +144,20 @@ constructor(
}
}
}
- updateVisibility(constraintSet)
+ }
+ updateVisibility(constraintSet)
+ }
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
+ listOf(smartspaceView, dateView, weatherView).forEach {
+ it?.let {
+ if (it.parent == constraintLayout) {
+ constraintLayout.removeView(it)
+ }
+ }
}
}
@@ -158,14 +185,4 @@ constructor(
}
}
}
-
- override fun removeViews(constraintLayout: ConstraintLayout) {
- listOf(smartspaceView, dateView, weatherView).forEach {
- it?.let {
- if (it.parent == constraintLayout) {
- constraintLayout.removeView(it)
- }
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt
new file mode 100644
index 000000000000..1302bfa6fc31
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import javax.inject.Inject
+
+class SplitShadeClockSection
+@Inject
+constructor(
+ clockInteractor: KeyguardClockInteractor,
+ keyguardClockViewModel: KeyguardClockViewModel,
+ smartspaceViewModel: KeyguardSmartspaceViewModel,
+ context: Context,
+ splitShadeStateController: SplitShadeStateController,
+) :
+ ClockSection(
+ clockInteractor,
+ keyguardClockViewModel,
+ smartspaceViewModel,
+ context,
+ splitShadeStateController
+ ) {
+ override fun applyDefaultConstraints(constraints: ConstraintSet) {
+ super.applyDefaultConstraints(constraints)
+ val largeClockEndGuideline =
+ if (keyguardClockViewModel.clockShouldBeCentered.value) ConstraintSet.PARENT_ID
+ else R.id.split_shade_guideline
+ constraints.apply {
+ connect(
+ R.id.lockscreen_clock_view_large,
+ ConstraintSet.END,
+ largeClockEndGuideline,
+ ConstraintSet.END
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index b0b5c81dd11c..0f8e67340cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -23,7 +23,6 @@ import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
@@ -72,25 +71,9 @@ constructor(
return
}
constraintSet.apply {
- val bottomMargin =
- context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
-
- if (migrateClocksToBlueprint()) {
- connect(
- R.id.nssl_placeholder,
- TOP,
- smartspaceViewModel.smartspaceViewId,
- TOP,
- bottomMargin
- )
- setGoneMargin(R.id.nssl_placeholder, TOP, bottomMargin)
- } else {
- val splitShadeTopMargin =
- context.resources.getDimensionPixelSize(
- R.dimen.large_screen_shade_header_height
- )
- connect(R.id.nssl_placeholder, TOP, PARENT_ID, TOP, splitShadeTopMargin)
- }
+ val splitShadeTopMargin =
+ context.resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
+ connect(R.id.nssl_placeholder, TOP, PARENT_ID, TOP, splitShadeTopMargin)
connect(R.id.nssl_placeholder, START, PARENT_ID, START)
connect(R.id.nssl_placeholder, END, PARENT_ID, END)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 3aeff61c15e7..528a2eebc9cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -27,8 +27,8 @@ import com.android.systemui.keyguard.shared.model.SettingsClockSize
import com.android.systemui.plugins.clocks.ClockController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
@@ -79,10 +79,10 @@ constructor(
?: false
)
- val clockShouldBeCentered: Flow<Boolean> =
+ val clockShouldBeCentered: StateFlow<Boolean> =
keyguardInteractor.clockShouldBeCentered.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = true
+ initialValue = false
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index 4541458892bb..26e7ee8f561b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
import android.util.Log
+import android.view.View
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
@@ -25,7 +26,7 @@ import javax.inject.Inject
@SysUISingleton
class KeyguardSmartspaceViewModel
@Inject
-constructor(val context: Context, smartspaceController: LockscreenSmartspaceController) {
+constructor(val context: Context, val smartspaceController: LockscreenSmartspaceController) {
val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled()
val isWeatherEnabled: Boolean = smartspaceController.isWeatherEnabled()
val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled()
@@ -38,6 +39,10 @@ constructor(val context: Context, smartspaceController: LockscreenSmartspaceCont
val weatherId: Int
get() = getId("weather_smartspace_view")
+ var smartspaceView: View? = null
+ var weatherView: View? = null
+ var dateView: View? = null
+
private fun getId(name: String): Int {
return context.resources.getIdentifier(name, "id", context.packageName).also {
if (it == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index d8bb3e65392f..0d5ba641b599 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -26,6 +26,7 @@ import com.android.systemui.log.echo.LogcatEchoTrackerDebug;
import com.android.systemui.log.echo.LogcatEchoTrackerProd;
import com.android.systemui.log.table.TableLogBuffer;
import com.android.systemui.log.table.TableLogBufferFactory;
+import com.android.systemui.plugins.clocks.ClockMessageBuffers;
import com.android.systemui.qs.QSFragmentLegacy;
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
import com.android.systemui.qs.pipeline.shared.TileSpec;
@@ -417,6 +418,18 @@ public class LogModule {
}
/**
+ * Provides a {@link ClockMessageBuffers} which contains the keyguard clock message buffers.
+ */
+ @Provides
+ public static ClockMessageBuffers provideKeyguardClockMessageBuffers(
+ @KeyguardClockLog LogBuffer infraClockLog,
+ @KeyguardSmallClockLog LogBuffer smallClockLog,
+ @KeyguardLargeClockLog LogBuffer largeClockLog
+ ) {
+ return new ClockMessageBuffers(infraClockLog, smallClockLog, largeClockLog);
+ }
+
+ /**
* Provides a {@link LogBuffer} for use by {@link com.android.keyguard.KeyguardUpdateMonitor}.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index 2345667f0409..83b6f0d40aff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -19,16 +19,21 @@ import android.os.IBinder;
import android.service.quicksettings.IQSTileService;
import android.util.Log;
+import androidx.annotation.NonNull;
+
public class QSTileServiceWrapper {
private static final String TAG = "IQSTileServiceWrapper";
+ @NonNull
private final IQSTileService mService;
- public QSTileServiceWrapper(IQSTileService service) {
+ public QSTileServiceWrapper(@NonNull IQSTileService service) {
mService = service;
}
+ // This can never be null, as it's the constructor parameter and it's final
+ @NonNull
public IBinder asBinder() {
return mService.asBinder();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index e08eb37b79ba..880289e88813 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -40,6 +40,7 @@ import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
@@ -54,8 +55,10 @@ import dagger.assisted.AssistedInject;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
/**
* Manages the lifecycle of a TileService.
@@ -101,8 +104,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements
private final ActivityManager mActivityManager;
private Set<Integer> mQueuedMessages = new ArraySet<>();
- @Nullable
- private volatile QSTileServiceWrapper mWrapper;
+ @NonNull
+ private volatile Optional<QSTileServiceWrapper> mOptionalWrapper = Optional.empty();
private boolean mListening;
private IBinder mClickBinder;
@@ -222,6 +225,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
// Only try a new binding if we are not currently bound.
mIsBound.compareAndSet(false, bindServices());
if (!mIsBound.get()) {
+ Log.d(TAG, "Failed to bind to service");
mContext.unbindService(this);
}
} catch (SecurityException e) {
@@ -281,7 +285,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
service.linkToDeath(this, 0);
} catch (RemoteException e) {
}
- mWrapper = wrapper;
+ mOptionalWrapper = Optional.of(wrapper);
handlePendingMessages();
}
@@ -368,6 +372,10 @@ public class TileLifecycleManager extends BroadcastReceiver implements
* are supposed to be bound, we will try to bind after some amount of time.
*/
private void handleDeath() {
+ if (!mIsBound.get()) {
+ // If we are already not bound, don't do anything else.
+ return;
+ }
mExecutor.execute(() -> {
if (!mIsBound.get()) {
// If we are already not bound, don't do anything else.
@@ -522,7 +530,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onTileAdded() {
if (mDebug) Log.d(TAG, "onTileAdded " + getComponent());
- if (mWrapper == null || !mWrapper.onTileAdded()) {
+ if (isNullOrFailedAction(mOptionalWrapper, QSTileServiceWrapper::onTileAdded)) {
queueMessage(MSG_ON_ADDED);
handleDeath();
}
@@ -531,7 +539,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onTileRemoved() {
if (mDebug) Log.d(TAG, "onTileRemoved " + getComponent());
- if (mWrapper == null || !mWrapper.onTileRemoved()) {
+ if (isNullOrFailedAction(mOptionalWrapper, QSTileServiceWrapper::onTileRemoved)) {
queueMessage(MSG_ON_REMOVED);
handleDeath();
}
@@ -541,7 +549,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
public void onStartListening() {
if (mDebug) Log.d(TAG, "onStartListening " + getComponent());
mListening = true;
- if (mWrapper != null && !mWrapper.onStartListening()) {
+ if (isNotNullAndFailedAction(mOptionalWrapper, QSTileServiceWrapper::onStartListening)) {
handleDeath();
}
}
@@ -550,7 +558,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
public void onStopListening() {
if (mDebug) Log.d(TAG, "onStopListening " + getComponent());
mListening = false;
- if (mWrapper != null && !mWrapper.onStopListening()) {
+ if (isNotNullAndFailedAction(mOptionalWrapper, QSTileServiceWrapper::onStopListening)) {
handleDeath();
}
}
@@ -558,7 +566,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onClick(IBinder iBinder) {
if (mDebug) Log.d(TAG, "onClick " + iBinder + " " + getComponent() + " " + mUser);
- if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+ if (isNullOrFailedAction(mOptionalWrapper, (wrapper) -> wrapper.onClick(iBinder))) {
mClickBinder = iBinder;
queueMessage(MSG_ON_CLICK);
handleDeath();
@@ -568,7 +576,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onUnlockComplete() {
if (mDebug) Log.d(TAG, "onUnlockComplete " + getComponent());
- if (mWrapper == null || !mWrapper.onUnlockComplete()) {
+ if (isNullOrFailedAction(mOptionalWrapper, QSTileServiceWrapper::onUnlockComplete)) {
queueMessage(MSG_ON_UNLOCK_COMPLETE);
handleDeath();
}
@@ -577,7 +585,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Nullable
@Override
public IBinder asBinder() {
- return mWrapper != null ? mWrapper.asBinder() : null;
+ return mOptionalWrapper.map(QSTileServiceWrapper::asBinder).orElse(null);
}
@Override
@@ -591,18 +599,42 @@ public class TileLifecycleManager extends BroadcastReceiver implements
}
private void freeWrapper() {
- if (mWrapper != null) {
+ if (mOptionalWrapper.isPresent()) {
try {
- mWrapper.asBinder().unlinkToDeath(this, 0);
+ mOptionalWrapper.ifPresent(
+ (wrapper) -> wrapper.asBinder().unlinkToDeath(this, 0)
+ );
} catch (NoSuchElementException e) {
Log.w(TAG, "Trying to unlink not linked recipient for component"
+ mIntent.getComponent().flattenToShortString());
}
- mWrapper = null;
+ mOptionalWrapper = Optional.empty();
}
}
public interface TileChangeListener {
void onTileChanged(ComponentName tile);
}
+
+ /**
+ * Returns true if the Optional is empty OR performing the action on the content of the Optional
+ * (when not empty) fails.
+ */
+ private static boolean isNullOrFailedAction(
+ Optional<QSTileServiceWrapper> optionalWrapper,
+ Predicate<QSTileServiceWrapper> action
+ ) {
+ return !optionalWrapper.map(action::test).orElse(false);
+ }
+
+ /**
+ * Returns true if the Optional is not empty AND performing the action on the content of
+ * the Optional fails.
+ */
+ private static boolean isNotNullAndFailedAction(
+ Optional<QSTileServiceWrapper> optionalWrapper,
+ Predicate<QSTileServiceWrapper> action
+ ) {
+ return !optionalWrapper.map(action::test).orElse(true);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 878e6faf32e7..17eb3c83fefe 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1720,9 +1720,12 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
// To prevent the weather clock from overlapping with the notification shelf on AOD, we use
// the small clock here
- if (mKeyguardStatusViewController.isLargeClockBlockingNotificationShelf()
- && hasVisibleNotifications() && isOnAod()) {
- return SMALL;
+ // With migrateClocksToBlueprint, weather clock will have behaviors similar to other clocks
+ if (!migrateClocksToBlueprint()) {
+ if (mKeyguardStatusViewController.isLargeClockBlockingNotificationShelf()
+ && hasVisibleNotifications() && isOnAod()) {
+ return SMALL;
+ }
}
return LARGE;
}
@@ -1742,8 +1745,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
} else {
layout = mNotificationContainerParent;
}
+
if (migrateClocksToBlueprint()) {
- mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
+ mKeyguardInteractor.setClockShouldBeCentered(mSplitShadeEnabled && shouldBeCentered);
} else {
mKeyguardStatusViewController.updateAlignment(
layout, mSplitShadeEnabled, shouldBeCentered, animate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2740cc6682a6..11456ffaa4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -453,11 +453,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public void initNotificationIconArea() {
ViewGroup notificationIconArea = mStatusBar.requireViewById(R.id.notification_icon_area);
if (NotificationIconContainerRefactor.isEnabled()) {
- mNotificationIconAreaInner =
- LayoutInflater.from(getContext())
- .inflate(R.layout.notification_icon_area, notificationIconArea, true);
+ LayoutInflater.from(getContext())
+ .inflate(R.layout.notification_icon_area, notificationIconArea, true);
NotificationIconContainer notificationIcons =
notificationIconArea.requireViewById(R.id.notificationIcons);
+ mNotificationIconAreaInner = notificationIcons;
mNicBindingDisposable = mNicViewBinder.bindWhileAttached(notificationIcons);
} else {
mNotificationIconAreaInner =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 6f58bc2fcc9f..e6637e60b146 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -30,13 +30,15 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogcatOnlyMessageBuffer
import com.android.systemui.plugins.clocks.ClockAnimations
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockEvents
import com.android.systemui.plugins.clocks.ClockFaceConfig
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockTickRate
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -94,9 +96,9 @@ class ClockEventControllerTest : SysuiTestCase() {
@Mock private lateinit var largeClockEvents: ClockFaceEvents
@Mock private lateinit var parentView: View
private lateinit var repository: FakeKeyguardRepository
- @Mock private lateinit var smallLogBuffer: LogBuffer
- @Mock private lateinit var largeLogBuffer: LogBuffer
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG)
+ private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer)
private lateinit var underTest: ClockEventController
@Mock private lateinit var zenModeController: ZenModeController
@@ -140,8 +142,7 @@ class ClockEventControllerTest : SysuiTestCase() {
context,
mainExecutor,
bgExecutor,
- smallLogBuffer,
- largeLogBuffer,
+ clockBuffers,
withDeps.featureFlags,
zenModeController
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index e89b61f6d44e..dc0d9c5f987e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -20,7 +20,6 @@ package com.android.systemui.keyguard.ui.view.layout.sections
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
@@ -43,7 +42,6 @@ class ClockSectionTest : SysuiTestCase() {
@Mock private lateinit var keyguardClockViewModel: KeyguardClockViewModel
@Mock private lateinit var smartspaceViewModel: KeyguardSmartspaceViewModel
@Mock private lateinit var splitShadeStateController: SplitShadeStateController
- private var featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
private lateinit var underTest: ClockSection
@@ -88,7 +86,6 @@ class ClockSectionTest : SysuiTestCase() {
smartspaceViewModel,
mContext,
splitShadeStateController,
- featureFlags
)
}
@@ -147,24 +144,6 @@ class ClockSectionTest : SysuiTestCase() {
assetSmallClockTop(cs, expectedSmallClockTopMargin)
}
- @Test
- fun testLargeClockShouldBeCentered() {
- underTest.setClockShouldBeCentered(true)
- val cs = ConstraintSet()
- underTest.applyDefaultConstraints(cs)
- val constraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
- assertThat(constraint.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID)
- }
-
- @Test
- fun testLargeClockShouldNotBeCentered() {
- underTest.setClockShouldBeCentered(false)
- val cs = ConstraintSet()
- underTest.applyDefaultConstraints(cs)
- val constraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
- assertThat(constraint.layout.endToEnd).isEqualTo(R.id.split_shade_guideline)
- }
-
private fun setLargeClock(useLargeClock: Boolean) {
whenever(keyguardClockViewModel.useLargeClock).thenReturn(useLargeClock)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
index bff27f6910ab..740110b4fee0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -69,14 +69,13 @@ class SmartspaceSectionTest : SysuiTestCase() {
keyguardUnlockAnimationController,
)
constraintLayout = ConstraintLayout(mContext)
- whenever(lockscreenSmartspaceController.buildAndConnectView(constraintLayout))
- .thenReturn(smartspaceView)
- whenever(lockscreenSmartspaceController.buildAndConnectWeatherView(constraintLayout))
- .thenReturn(weatherView)
- whenever(lockscreenSmartspaceController.buildAndConnectDateView(constraintLayout))
- .thenReturn(dateView)
+ whenever(keyguardSmartspaceViewModel.smartspaceView).thenReturn(smartspaceView)
+ whenever(keyguardSmartspaceViewModel.weatherView).thenReturn(weatherView)
+ whenever(keyguardSmartspaceViewModel.dateView).thenReturn(dateView)
whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay)
.thenReturn(hasCustomWeatherDataDisplay)
+ whenever(keyguardSmartspaceViewModel.smartspaceController)
+ .thenReturn(lockscreenSmartspaceController)
constraintSet = ConstraintSet()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 459a74c82da4..ee1be10607cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -24,7 +24,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION
import com.android.systemui.SysuiTestCase
-import com.android.systemui.collectLastValue
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.coroutines.collectLastValue
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index ee94cbbcfd79..ee27c5c9ba0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.TRANSIT_CLOCK
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.plugins.clocks.ClockProviderPlugin
import com.android.systemui.plugins.clocks.ClockSettings
@@ -128,6 +129,7 @@ class ClockRegistryTest : SysuiTestCase() {
override fun createClock(settings: ClockSettings): ClockController =
createCallbacks[settings.clockId!!]!!(settings.clockId!!)
override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!(id)
+ override fun initialize(buffers: ClockMessageBuffers?) { }
fun addClock(
id: ClockId,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index fef262f50306..e0e8d1f51884 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -26,6 +26,7 @@ import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.customization.R
+import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.shared.clocks.DefaultClockController.Companion.DOZE_COLOR
import com.android.systemui.util.mockito.any
@@ -49,6 +50,9 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+private fun DefaultClockProvider.createClock(id: ClockId): DefaultClockController =
+ createClock(ClockSettings(id, null)) as DefaultClockController
+
@RunWith(AndroidTestingRunner::class)
@SmallTest
class DefaultClockProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 14751c2dc29e..54d3607c7a83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -36,6 +36,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
import android.view.View;
import androidx.test.filters.SmallTest;
@@ -91,7 +92,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private NotificationIconAreaController mMockNotificationAreaController;
private ShadeExpansionStateManager mShadeExpansionStateManager;
- private View mNotificationAreaInner;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
@@ -270,15 +270,15 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@Test
@@ -310,7 +310,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are hidden
assertEquals(View.INVISIBLE, getClockView().getVisibility());
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
@@ -326,7 +326,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are shown
assertEquals(View.VISIBLE, getClockView().getVisibility());
- assertEquals(View.VISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@@ -343,7 +343,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are hidden
assertEquals(View.INVISIBLE, getClockView().getVisibility());
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
// WHEN the shade is updated to no longer be open
@@ -354,7 +354,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are shown
assertEquals(View.VISIBLE, getClockView().getVisibility());
- assertEquals(View.VISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@@ -368,7 +368,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are shown
assertEquals(View.VISIBLE, getClockView().getVisibility());
- assertEquals(View.VISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@@ -382,7 +382,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are hidden
assertEquals(View.GONE, getClockView().getVisibility());
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
@@ -396,7 +396,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are hidden
assertEquals(View.GONE, getClockView().getVisibility());
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
// WHEN the transition has finished
@@ -405,7 +405,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
// THEN all views are shown
assertEquals(View.VISIBLE, getClockView().getVisibility());
- assertEquals(View.VISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@@ -438,7 +438,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.VISIBLE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@Test
@@ -503,8 +503,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
fragment.disable(DEFAULT_DISPLAY, 0, 0, true);
// Notification area is hidden without delay
- assertEquals(0f, mNotificationAreaInner.getAlpha(), 0.01);
- assertEquals(View.INVISIBLE, mNotificationAreaInner.getVisibility());
+ assertEquals(0f, getNotificationAreaView().getAlpha(), 0.01);
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@Test
@@ -723,11 +723,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private void setUpNotificationIconAreaController() {
mMockNotificationAreaController = mock(NotificationIconAreaController.class);
-
- mNotificationAreaInner = new View(mContext);
-
- when(mMockNotificationAreaController.getNotificationInnerAreaView()).thenReturn(
- mNotificationAreaInner);
+ View notificationAreaInner =
+ LayoutInflater.from(mContext).inflate(R.layout.notification_icon_area, null);
+ when(mMockNotificationAreaController.getNotificationInnerAreaView())
+ .thenReturn(notificationAreaInner);
}
/**
@@ -782,4 +781,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private View getEndSideContentView() {
return mFragment.getView().findViewById(R.id.status_bar_end_side_content);
}
+
+ private View getNotificationAreaView() {
+ return mFragment.getView().findViewById(R.id.notificationIcons);
+ }
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index badd7f085e56..2b81dbcb6fb2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2059,9 +2059,6 @@ class UserController implements Handler.Callback {
mTargetUserId = targetUserId;
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
- if (android.multiuser.Flags.useAllCpusDuringUserSwitch()) {
- mInjector.setHasTopUi(true);
- }
if (userSwitchUiEnabled) {
UserInfo currentUserInfo = getUserInfo(currentUserId);
Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
@@ -2130,9 +2127,6 @@ class UserController implements Handler.Callback {
}
private void endUserSwitch() {
- if (android.multiuser.Flags.useAllCpusDuringUserSwitch()) {
- mInjector.setHasTopUi(false);
- }
final int nextUserId;
synchronized (mLock) {
nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL);
@@ -3816,15 +3810,6 @@ class UserController implements Handler.Callback {
getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId);
}
- void setHasTopUi(boolean hasTopUi) {
- try {
- Slogf.i(TAG, "Setting hasTopUi to " + hasTopUi);
- mService.setHasTopUi(hasTopUi);
- } catch (RemoteException e) {
- Slogf.e(TAG, "Failed to allow using all CPU cores", e);
- }
- }
-
void onSystemUserVisibilityChanged(boolean visible) {
getUserManagerInternal().onSystemUserVisibilityChanged(visible);
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 3024dd27b5c4..2d6177d9d27b 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -403,7 +403,8 @@ public class AutomaticBrightnessController {
| (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
| (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
? BrightnessEvent.FLAG_DOZE_SCALE : 0)
- | (isInIdleMode() ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
+ | (getMode() == AUTO_BRIGHTNESS_MODE_IDLE
+ ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
}
if (!mAmbientLuxValid) {
@@ -514,7 +515,8 @@ public class AutomaticBrightnessController {
if (mLoggingEnabled) {
Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
}
- if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy) && !isInIdleMode()) {
+ if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)
+ && getMode() != AUTO_BRIGHTNESS_MODE_IDLE) {
mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL,
mCurrentBrightnessMapper.getShortTermModelTimeout());
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
@@ -555,7 +557,7 @@ public class AutomaticBrightnessController {
boolean shouldResetShortTermModel) {
if (mBrightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT)
.setBrightnessConfiguration(configuration)) {
- if (!isInIdleMode() && shouldResetShortTermModel) {
+ if (getMode() != AUTO_BRIGHTNESS_MODE_IDLE && shouldResetShortTermModel) {
resetShortTermModel();
}
return true;
@@ -563,8 +565,9 @@ public class AutomaticBrightnessController {
return false;
}
- public boolean isInIdleMode() {
- return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE;
+ @AutomaticBrightnessController.AutomaticBrightnessMode
+ public int getMode() {
+ return mCurrentBrightnessMapper.getMode();
}
public void dump(PrintWriter pw) {
@@ -620,8 +623,7 @@ public class AutomaticBrightnessController {
pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
- pw.println(" Current mode="
- + autoBrightnessModeToString(mCurrentBrightnessMapper.getMode()));
+ pw.println(" Current mode=" + autoBrightnessModeToString(getMode()));
pw.println();
for (int i = 0; i < mBrightnessMappingStrategyMap.size(); i++) {
@@ -743,7 +745,7 @@ public class AutomaticBrightnessController {
lux = 0;
}
mAmbientLux = lux;
- if (isInIdleMode()) {
+ if (getMode() == AUTO_BRIGHTNESS_MODE_IDLE) {
mAmbientBrighteningThreshold =
mAmbientBrightnessThresholdsIdle.getBrighteningThreshold(lux);
mAmbientDarkeningThreshold =
@@ -835,7 +837,7 @@ public class AutomaticBrightnessController {
}
earliestValidTime = mAmbientLightRingBuffer.getTime(i);
}
- return earliestValidTime + (isInIdleMode()
+ return earliestValidTime + (getMode() == AUTO_BRIGHTNESS_MODE_IDLE
? mBrighteningLightDebounceConfigIdle : mBrighteningLightDebounceConfig);
}
@@ -848,7 +850,7 @@ public class AutomaticBrightnessController {
}
earliestValidTime = mAmbientLightRingBuffer.getTime(i);
}
- return earliestValidTime + (isInIdleMode()
+ return earliestValidTime + (getMode() == AUTO_BRIGHTNESS_MODE_IDLE
? mDarkeningLightDebounceConfigIdle : mDarkeningLightDebounceConfig);
}
@@ -973,7 +975,7 @@ public class AutomaticBrightnessController {
mPreThresholdBrightness = mScreenAutoBrightness;
}
mScreenAutoBrightness = newScreenAutoBrightness;
- if (isInIdleMode()) {
+ if (getMode() == AUTO_BRIGHTNESS_MODE_IDLE) {
mScreenBrighteningThreshold = clampScreenBrightness(
mScreenBrightnessThresholdsIdle.getBrighteningThreshold(
newScreenAutoBrightness));
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 6a4b00f7551f..8405e0a52084 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -23,12 +23,14 @@ import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIG
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
import android.annotation.Nullable;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.BrightnessCorrection;
import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.LongArray;
import android.util.MathUtils;
import android.util.Pair;
@@ -80,45 +82,50 @@ public abstract class BrightnessMappingStrategy {
* Creates a BrightnessMapping strategy. We do not create a simple mapping strategy for idle
* mode.
*
- * @param resources
+ * @param context
* @param displayDeviceConfig
* @param mode The auto-brightness mode. Different modes use different brightness curves
* @param displayWhiteBalanceController
* @return the BrightnessMappingStrategy
*/
@Nullable
- static BrightnessMappingStrategy create(Resources resources,
+ static BrightnessMappingStrategy create(Context context,
DisplayDeviceConfig displayDeviceConfig,
@AutomaticBrightnessController.AutomaticBrightnessMode int mode,
- DisplayWhiteBalanceController displayWhiteBalanceController) {
+ @Nullable DisplayWhiteBalanceController displayWhiteBalanceController) {
// Display independent, mode dependent values
float[] brightnessLevelsNits = null;
float[] brightnessLevels = null;
float[] luxLevels = null;
+ int preset = Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_FOR_ALS,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, UserHandle.USER_CURRENT);
switch (mode) {
case AUTO_BRIGHTNESS_MODE_DEFAULT -> {
brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
- luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode);
- brightnessLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevels(mode);
+ luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode, preset);
+ brightnessLevels =
+ displayDeviceConfig.getAutoBrightnessBrighteningLevels(mode, preset);
}
case AUTO_BRIGHTNESS_MODE_IDLE -> {
- brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
+ brightnessLevelsNits = getFloatArray(context.getResources().obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle));
- luxLevels = getLuxLevels(resources.getIntArray(
+ luxLevels = getLuxLevels(context.getResources().getIntArray(
com.android.internal.R.array.config_autoBrightnessLevelsIdle));
}
case AUTO_BRIGHTNESS_MODE_DOZE -> {
- luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode);
- brightnessLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevels(mode);
+ luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode, preset);
+ brightnessLevels =
+ displayDeviceConfig.getAutoBrightnessBrighteningLevels(mode, preset);
}
}
// Display independent, mode independent values
- float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
+ float autoBrightnessAdjustmentMaxGamma = context.getResources().getFraction(
com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
1, 1);
- long shortTermModelTimeout = resources.getInteger(
+ long shortTermModelTimeout = context.getResources().getInteger(
com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
// Display dependent values - used for physical mapping strategy nits -> brightness
@@ -823,6 +830,8 @@ public abstract class BrightnessMappingStrategy {
private float mAutoBrightnessAdjustment;
private float mUserLux;
private float mUserBrightness;
+
+ @Nullable
private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
@AutomaticBrightnessController.AutomaticBrightnessMode
@@ -838,7 +847,7 @@ public abstract class BrightnessMappingStrategy {
public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
float[] brightness, float maxGamma,
@AutomaticBrightnessController.AutomaticBrightnessMode int mode,
- DisplayWhiteBalanceController displayWhiteBalanceController) {
+ @Nullable DisplayWhiteBalanceController displayWhiteBalanceController) {
Preconditions.checkArgument(nits.length != 0 && brightness.length != 0,
"Nits and brightness arrays must not be empty!");
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a6f42d7677b2..bd22e1d21dea 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -1592,24 +1592,13 @@ public class DisplayDeviceConfig {
/**
* @param mode The auto-brightness mode
- * @return The default auto-brightness brightening ambient lux levels for the specified mode
- * and the normal brightness preset
- */
- public float[] getAutoBrightnessBrighteningLevelsLux(
- @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
- if (mDisplayBrightnessMapping == null) {
- return null;
- }
- return mDisplayBrightnessMapping.getLuxArray(mode);
- }
-
- /**
- * @param mode The auto-brightness mode
* @param preset The brightness preset. Presets are used on devices that allow users to choose
* from a set of predefined options in display auto-brightness settings.
- * @return Auto brightness brightening ambient lux levels for the specified mode and preset
+ * @return The default auto-brightness brightening ambient lux levels for the specified mode
+ * and preset
*/
- public float[] getAutoBrightnessBrighteningLevelsLux(String mode, String preset) {
+ public float[] getAutoBrightnessBrighteningLevelsLux(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset) {
if (mDisplayBrightnessMapping == null) {
return null;
}
@@ -1628,24 +1617,12 @@ public class DisplayDeviceConfig {
/**
* @param mode The auto-brightness mode
- * @return The default auto-brightness brightening levels for the specified mode and the normal
- * brightness preset
- */
- public float[] getAutoBrightnessBrighteningLevels(
- @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
- if (mDisplayBrightnessMapping == null) {
- return null;
- }
- return mDisplayBrightnessMapping.getBrightnessArray(mode);
- }
-
- /**
- * @param mode The auto-brightness mode
* @param preset The brightness preset. Presets are used on devices that allow users to choose
* from a set of predefined options in display auto-brightness settings.
- * @return Auto brightness brightening backlight levels for the specified mode and preset
+ * @return The default auto-brightness brightening levels for the specified mode and preset
*/
- public float[] getAutoBrightnessBrighteningLevels(String mode, String preset) {
+ public float[] getAutoBrightnessBrighteningLevels(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset) {
if (mDisplayBrightnessMapping == null) {
return null;
}
diff --git a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
index 4e341a9c19b4..c17709144e1d 100644
--- a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
+++ b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
@@ -65,6 +65,16 @@ public class DisplayOffloadSessionImpl implements DisplayManagerInternal.Display
return true;
}
+ @Override
+ public float[] getCurrentAutoBrightnessLevels() {
+ return mDisplayPowerController.getCurrentAutoBrightnessLevels();
+ }
+
+ @Override
+ public float[] getCurrentAutoBrightnessLuxLevels() {
+ return mDisplayPowerController.getCurrentAutoBrightnessLuxLevels();
+ }
+
/**
* Start the offload session. The method returns if the session is already active.
* @return Whether the session was started successfully
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2685efecd6a1..c17378d790bd 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -735,7 +735,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mCdsi = null;
}
- setUpAutoBrightness(resources, handler);
+ setUpAutoBrightness(context, handler);
mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic()
&& !resources.getBoolean(
@@ -1075,7 +1075,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
loadBrightnessRampRates();
loadProximitySensor();
loadNitsRange(mContext.getResources());
- setUpAutoBrightness(mContext.getResources(), mHandler);
+ setUpAutoBrightness(mContext, mHandler);
reloadReduceBrightColours();
setAnimatorRampSpeeds(/* isIdleMode= */ false);
mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig);
@@ -1119,7 +1119,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
setAnimatorRampSpeeds(mAutomaticBrightnessController != null
- && mAutomaticBrightnessController.isInIdleMode());
+ && mAutomaticBrightnessController.getMode() == AUTO_BRIGHTNESS_MODE_IDLE);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
noteScreenState(mPowerState.getScreenState());
@@ -1145,7 +1145,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
handleBrightnessModeChange();
}
- private void setUpAutoBrightness(Resources resources, Handler handler) {
+ private void setUpAutoBrightness(Context context, Handler handler) {
mUseSoftwareAutoBrightnessConfig = mDisplayDeviceConfig.isAutoBrightnessAvailable();
if (!mUseSoftwareAutoBrightnessConfig) {
@@ -1155,21 +1155,19 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
SparseArray<BrightnessMappingStrategy> brightnessMappers = new SparseArray<>();
BrightnessMappingStrategy defaultModeBrightnessMapper =
- mInjector.getDefaultModeBrightnessMapper(resources, mDisplayDeviceConfig,
+ mInjector.getDefaultModeBrightnessMapper(context, mDisplayDeviceConfig,
mDisplayWhiteBalanceController);
brightnessMappers.append(AUTO_BRIGHTNESS_MODE_DEFAULT,
defaultModeBrightnessMapper);
- final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
+ final boolean isIdleScreenBrightnessEnabled = context.getResources().getBoolean(
R.bool.config_enableIdleScreenBrightnessMode);
if (isIdleScreenBrightnessEnabled) {
BrightnessMappingStrategy idleModeBrightnessMapper =
- BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig,
- AUTO_BRIGHTNESS_MODE_IDLE,
- mDisplayWhiteBalanceController);
+ BrightnessMappingStrategy.create(context, mDisplayDeviceConfig,
+ AUTO_BRIGHTNESS_MODE_IDLE, mDisplayWhiteBalanceController);
if (idleModeBrightnessMapper != null) {
- brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE,
- idleModeBrightnessMapper);
+ brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE, idleModeBrightnessMapper);
}
}
@@ -1181,7 +1179,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
if (defaultModeBrightnessMapper != null) {
- final float dozeScaleFactor = resources.getFraction(
+ final float dozeScaleFactor = context.getResources().getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
@@ -1265,14 +1263,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
.getAutoBrightnessBrighteningLightDebounceIdle();
long darkeningLightDebounceIdle = mDisplayDeviceConfig
.getAutoBrightnessDarkeningLightDebounceIdle();
- boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
+ boolean autoBrightnessResetAmbientLuxAfterWarmUp = context.getResources().getBoolean(
com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
- int lightSensorWarmUpTimeConfig = resources.getInteger(
+ int lightSensorWarmUpTimeConfig = context.getResources().getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
- int lightSensorRate = resources.getInteger(
+ int lightSensorRate = context.getResources().getInteger(
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
- int initialLightSensorRate = resources.getInteger(
+ int initialLightSensorRate = context.getResources().getInteger(
com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate);
if (initialLightSensorRate == -1) {
initialLightSensorRate = lightSensorRate;
@@ -1992,7 +1990,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
boolean isIncreasing = animateValue > currentBrightness;
final float rampSpeed;
final boolean idle = mAutomaticBrightnessController != null
- && mAutomaticBrightnessController.isInIdleMode();
+ && mAutomaticBrightnessController.getMode()
+ == AUTO_BRIGHTNESS_MODE_IDLE;
if (isIncreasing && slowChange) {
rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
: mBrightnessRampRateSlowIncrease;
@@ -2216,6 +2215,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
@Override
+ public float[] getCurrentAutoBrightnessLevels() {
+ // The old DPC is no longer supported
+ return new float[0];
+ }
+
+ @Override
+ public float[] getCurrentAutoBrightnessLuxLevels() {
+ // The old DPC is no longer supported
+ return new float[0];
+ }
+
+ @Override
public BrightnessInfo getBrightnessInfo() {
synchronized (mCachedBrightnessInfo) {
return new BrightnessInfo(
@@ -2900,7 +2911,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// or the nits is invalid.
if (brightnessIsTemporary
|| mAutomaticBrightnessController == null
- || mAutomaticBrightnessController.isInIdleMode()
+ || mAutomaticBrightnessController.getMode() == AUTO_BRIGHTNESS_MODE_IDLE
|| !autobrightnessEnabled
|| mBrightnessTracker == null
|| !mUseAutoBrightness
@@ -3645,12 +3656,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
userNits);
}
- BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
- return BrightnessMappingStrategy.create(resources,
- displayDeviceConfig, AUTO_BRIGHTNESS_MODE_DEFAULT,
- displayWhiteBalanceController);
+ return BrightnessMappingStrategy.create(context, displayDeviceConfig,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, displayWhiteBalanceController);
}
HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index c088a6dfa95f..2efda087d4ac 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessPresetToString;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -624,7 +625,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
mCdsi = null;
}
- setUpAutoBrightness(resources, handler);
+ setUpAutoBrightness(context, handler);
mColorFadeEnabled = mInjector.isColorFadeEnabled()
&& !resources.getBoolean(
@@ -905,7 +906,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
// updated here.
loadBrightnessRampRates();
loadNitsRange(mContext.getResources());
- setUpAutoBrightness(mContext.getResources(), mHandler);
+ setUpAutoBrightness(mContext, mHandler);
reloadReduceBrightColours();
setAnimatorRampSpeeds(/* isIdleMode= */ false);
@@ -950,7 +951,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
setAnimatorRampSpeeds(mAutomaticBrightnessController != null
- && mAutomaticBrightnessController.isInIdleMode());
+ && mAutomaticBrightnessController.getMode() == AUTO_BRIGHTNESS_MODE_IDLE);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
noteScreenState(mPowerState.getScreenState());
@@ -976,10 +977,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
+ if (mFlags.areAutoBrightnessModesEnabled()) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_ALS),
+ /* notifyForDescendants= */ false, mSettingsObserver, UserHandle.USER_CURRENT);
+ }
handleBrightnessModeChange();
}
- private void setUpAutoBrightness(Resources resources, Handler handler) {
+ private void setUpAutoBrightness(Context context, Handler handler) {
mUseSoftwareAutoBrightnessConfig = mDisplayDeviceConfig.isAutoBrightnessAvailable();
if (!mUseSoftwareAutoBrightnessConfig) {
@@ -989,16 +995,16 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
SparseArray<BrightnessMappingStrategy> brightnessMappers = new SparseArray<>();
BrightnessMappingStrategy defaultModeBrightnessMapper =
- mInjector.getDefaultModeBrightnessMapper(resources, mDisplayDeviceConfig,
+ mInjector.getDefaultModeBrightnessMapper(context, mDisplayDeviceConfig,
mDisplayWhiteBalanceController);
brightnessMappers.append(AUTO_BRIGHTNESS_MODE_DEFAULT,
defaultModeBrightnessMapper);
- final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
+ final boolean isIdleScreenBrightnessEnabled = context.getResources().getBoolean(
R.bool.config_enableIdleScreenBrightnessMode);
if (isIdleScreenBrightnessEnabled) {
BrightnessMappingStrategy idleModeBrightnessMapper =
- BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig,
+ BrightnessMappingStrategy.create(context, mDisplayDeviceConfig,
AUTO_BRIGHTNESS_MODE_IDLE,
mDisplayWhiteBalanceController);
if (idleModeBrightnessMapper != null) {
@@ -1008,7 +1014,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
}
BrightnessMappingStrategy dozeModeBrightnessMapper =
- BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig,
+ BrightnessMappingStrategy.create(context, mDisplayDeviceConfig,
AUTO_BRIGHTNESS_MODE_DOZE, mDisplayWhiteBalanceController);
if (mFlags.areAutoBrightnessModesEnabled() && dozeModeBrightnessMapper != null) {
brightnessMappers.put(AUTO_BRIGHTNESS_MODE_DOZE, dozeModeBrightnessMapper);
@@ -1022,7 +1028,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
}
if (defaultModeBrightnessMapper != null) {
- final float dozeScaleFactor = resources.getFraction(
+ final float dozeScaleFactor = context.getResources().getFraction(
R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
@@ -1106,14 +1112,14 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
.getAutoBrightnessBrighteningLightDebounceIdle();
long darkeningLightDebounceIdle = mDisplayDeviceConfig
.getAutoBrightnessDarkeningLightDebounceIdle();
- boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
+ boolean autoBrightnessResetAmbientLuxAfterWarmUp = context.getResources().getBoolean(
R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
- int lightSensorWarmUpTimeConfig = resources.getInteger(
+ int lightSensorWarmUpTimeConfig = context.getResources().getInteger(
R.integer.config_lightSensorWarmupTime);
- int lightSensorRate = resources.getInteger(
+ int lightSensorRate = context.getResources().getInteger(
R.integer.config_autoBrightnessLightSensorRate);
- int initialLightSensorRate = resources.getInteger(
+ int initialLightSensorRate = context.getResources().getInteger(
R.integer.config_autoBrightnessInitialLightSensorRate);
if (initialLightSensorRate == -1) {
initialLightSensorRate = lightSensorRate;
@@ -1359,7 +1365,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
// Switch to doze auto-brightness mode if needed
if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
- && !mAutomaticBrightnessController.isInIdleMode()) {
+ && mAutomaticBrightnessController.getMode() != AUTO_BRIGHTNESS_MODE_IDLE) {
setAutomaticScreenBrightnessMode(Display.isDozeState(state)
? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
}
@@ -1648,7 +1654,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
boolean isIncreasing = animateValue > currentBrightness;
final float rampSpeed;
final boolean idle = mAutomaticBrightnessController != null
- && mAutomaticBrightnessController.isInIdleMode();
+ && mAutomaticBrightnessController.getMode()
+ == AUTO_BRIGHTNESS_MODE_IDLE;
if (isIncreasing && slowChange) {
rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
: mBrightnessRampRateSlowIncrease;
@@ -1880,6 +1887,18 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
}
@Override
+ public float[] getCurrentAutoBrightnessLevels() {
+ return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
+ mAutomaticBrightnessController.getMode());
+ }
+
+ @Override
+ public float[] getCurrentAutoBrightnessLuxLevels() {
+ return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
+ mAutomaticBrightnessController.getMode());
+ }
+
+ @Override
public BrightnessInfo getBrightnessInfo() {
synchronized (mCachedBrightnessInfo) {
return new BrightnessInfo(
@@ -2454,7 +2473,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
// or the nits is invalid.
if (brightnessIsTemporary
|| mAutomaticBrightnessController == null
- || mAutomaticBrightnessController.isInIdleMode()
+ || mAutomaticBrightnessController.getMode() == AUTO_BRIGHTNESS_MODE_IDLE
|| !autobrightnessEnabled
|| mBrightnessTracker == null
|| !shouldUseAutoBrightness
@@ -2999,6 +3018,16 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
public void onChange(boolean selfChange, Uri uri) {
if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE))) {
handleBrightnessModeChange();
+ } else if (uri.equals(Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS_FOR_ALS))) {
+ int preset = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_FOR_ALS,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL,
+ UserHandle.USER_CURRENT);
+ Slog.i(mTag, "Setting up auto-brightness for preset "
+ + autoBrightnessPresetToString(preset));
+ setUpAutoBrightness(mContext, mHandler);
+ sendUpdatePowerState();
} else {
handleSettingsChange(false /* userSwitch */);
}
@@ -3117,12 +3146,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
userNits);
}
- BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
- return BrightnessMappingStrategy.create(resources,
- displayDeviceConfig, AUTO_BRIGHTNESS_MODE_DEFAULT,
- displayWhiteBalanceController);
+ return BrightnessMappingStrategy.create(context, displayDeviceConfig,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, displayWhiteBalanceController);
}
HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index c27918430254..5b350db5fa7b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -237,4 +237,14 @@ public interface DisplayPowerControllerInterface {
* Indicate that boot has been completed and the screen is ready to update.
*/
void onBootCompleted();
+
+ /**
+ * Get the current brightness levels used to determine automatic brightness based on lux levels.
+ */
+ float[] getCurrentAutoBrightnessLevels();
+
+ /**
+ * Get the current lux levels used to determine automatic brightness.
+ */
+ float[] getCurrentAutoBrightnessLuxLevels();
}
diff --git a/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java b/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java
index 8f123291d89c..6978686faa12 100644
--- a/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java
+++ b/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java
@@ -22,6 +22,7 @@ import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIG
import android.content.Context;
import android.os.PowerManager;
+import android.provider.Settings;
import android.util.Spline;
import com.android.internal.display.BrightnessSynchronizer;
@@ -38,9 +39,9 @@ import java.util.Map;
*/
public class DisplayBrightnessMappingConfig {
- private static final String DEFAULT_BRIGHTNESS_PRESET_NAME = "normal";
private static final String DEFAULT_BRIGHTNESS_MAPPING_KEY =
- AutoBrightnessModeName._default.getRawName() + "_" + DEFAULT_BRIGHTNESS_PRESET_NAME;
+ AutoBrightnessModeName._default.getRawName() + "_"
+ + AutoBrightnessSettingName.normal.getRawName();
/**
* Array of desired screen brightness in nits corresponding to the lux values
@@ -152,22 +153,15 @@ public class DisplayBrightnessMappingConfig {
/**
* @param mode The auto-brightness mode
- * @return The default auto-brightness brightening ambient lux levels for the specified mode
- * and the normal brightness preset
- */
- public float[] getLuxArray(@AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
- return mBrightnessLevelsLuxMap.get(
- autoBrightnessModeToString(mode) + "_" + DEFAULT_BRIGHTNESS_PRESET_NAME);
- }
-
- /**
- * @param mode The auto-brightness mode
* @param preset The brightness preset. Presets are used on devices that allow users to choose
* from a set of predefined options in display auto-brightness settings.
- * @return Auto brightness brightening ambient lux levels for the specified mode and preset
+ * @return The default auto-brightness brightening ambient lux levels for the specified mode
+ * and preset
*/
- public float[] getLuxArray(String mode, String preset) {
- return mBrightnessLevelsLuxMap.get(mode + "_" + preset);
+ public float[] getLuxArray(@AutomaticBrightnessController.AutomaticBrightnessMode int mode,
+ int preset) {
+ return mBrightnessLevelsLuxMap.get(
+ autoBrightnessModeToString(mode) + "_" + autoBrightnessPresetToString(preset));
}
/**
@@ -179,23 +173,14 @@ public class DisplayBrightnessMappingConfig {
/**
* @param mode The auto-brightness mode
- * @return The default auto-brightness brightening levels for the specified mode and the normal
- * brightness preset
- */
- public float[] getBrightnessArray(
- @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
- return mBrightnessLevelsMap.get(
- autoBrightnessModeToString(mode) + "_" + DEFAULT_BRIGHTNESS_PRESET_NAME);
- }
-
- /**
- * @param mode The auto-brightness mode
* @param preset The brightness preset. Presets are used on devices that allow users to choose
* from a set of predefined options in display auto-brightness settings.
- * @return Auto brightness brightening ambient lux levels for the specified mode and preset
+ * @return The default auto-brightness brightening levels for the specified mode and preset
*/
- public float[] getBrightnessArray(String mode, String preset) {
- return mBrightnessLevelsMap.get(mode + "_" + preset);
+ public float[] getBrightnessArray(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset) {
+ return mBrightnessLevelsMap.get(
+ autoBrightnessModeToString(mode) + "_" + autoBrightnessPresetToString(preset));
}
@Override
@@ -247,6 +232,24 @@ public class DisplayBrightnessMappingConfig {
}
}
+ /**
+ * @param preset The brightness preset. Presets are used on devices that allow users to choose
+ * from a set of predefined options in display auto-brightness settings.
+ * @return The string representing the preset
+ */
+ public static String autoBrightnessPresetToString(int preset) {
+ return switch (preset) {
+ case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM ->
+ AutoBrightnessSettingName.dim.getRawName();
+ case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL ->
+ AutoBrightnessSettingName.normal.getRawName();
+ case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT ->
+ AutoBrightnessSettingName.bright.getRawName();
+ default -> throw new IllegalArgumentException(
+ "Unknown auto-brightness preset value: " + preset);
+ };
+ }
+
private float[] brightnessArrayIntToFloat(int[] brightnessInt,
Spline backlightToBrightnessSpline) {
float[] brightnessFloat = new float[brightnessInt.length];
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 64abb81d0e7a..81204ef5d7ed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -1314,7 +1314,6 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
*/
protected void disableDevice(
boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
- removeAction(AbsoluteVolumeAudioStatusAction.class);
removeAction(SetAudioVolumeLevelDiscoveryAction.class);
removeAction(ActiveSourceAction.class);
removeAction(ResendCecCommandAction.class);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 29303aab6fa9..6157402279a9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -308,7 +308,6 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
removeAction(OneTouchPlayAction.class);
removeAction(DevicePowerStatusAction.class);
- removeAction(AbsoluteVolumeAudioStatusAction.class);
super.disableDevice(initiatedByCec, callback);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 5831b29437dc..1cd267dee2fe 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1336,7 +1336,6 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
removeAction(OneTouchRecordAction.class);
removeAction(TimerRecordingAction.class);
removeAction(NewDeviceAction.class);
- removeAction(AbsoluteVolumeAudioStatusAction.class);
// Remove pending actions.
removeAction(RequestActiveSourceAction.class);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 92537064f766..eaf754dc7520 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3793,6 +3793,11 @@ public class HdmiControlService extends SystemService {
}
}
});
+
+ // Make sure we switch away from absolute volume behavior (AVB) when entering standby.
+ // We do this because AVB should not be used unless AbsoluteVolumeAudioStatusAction exists,
+ // and the action cannot exist in standby because there are no local devices.
+ checkAndUpdateAbsoluteVolumeBehavior();
}
boolean canGoToStandby() {
@@ -4446,10 +4451,11 @@ public class HdmiControlService extends SystemService {
* This allows the volume level of the System Audio device to be tracked and set by Android.
*
* Absolute volume behavior requires the following conditions:
- * 1. If the System Audio Device is an Audio System: System Audio Mode is active
- * 2. All AVB-capable audio output devices are already using full/absolute volume behavior
- * 3. CEC volume is enabled
- * 4. The System Audio device supports the <Set Audio Volume Level> message
+ * 1. The device is not in standby or transient to standby
+ * 2. If the System Audio Device is an Audio System: System Audio Mode is active
+ * 3. All AVB-capable audio output devices are already using full/absolute volume behavior
+ * 4. CEC volume is enabled
+ * 5. The System Audio device supports the <Set Audio Volume Level> message
*
* This method enables adjust-only absolute volume behavior on TV panels when conditions
* 1, 2, and 3 are met, but condition 4 is not. This allows TVs to track the volume level of
@@ -4465,10 +4471,16 @@ public class HdmiControlService extends SystemService {
return;
}
+ // Condition 1: The device is not in standby or transient to standby
+ if (mPowerStatusController != null && isPowerStandbyOrTransient()) {
+ switchToFullVolumeBehavior();
+ return;
+ }
+
HdmiCecLocalDevice localCecDevice;
if (isTvDevice() && tv() != null) {
localCecDevice = tv();
- // Condition 1: TVs need System Audio Mode to be active
+ // Condition 2: TVs need System Audio Mode to be active
// (Doesn't apply to Playback Devices, where if SAM isn't active, we assume the
// TV is the System Audio Device instead.)
if (!isSystemAudioActivated()) {
@@ -4485,7 +4497,7 @@ public class HdmiControlService extends SystemService {
HdmiDeviceInfo systemAudioDeviceInfo = getDeviceInfo(
localCecDevice.findAudioReceiverAddress());
- // Condition 2: All AVB-capable audio outputs already use full/absolute volume behavior
+ // Condition 3: All AVB-capable audio outputs already use full/absolute volume behavior
// We only need to check the first AVB-capable audio output because only TV panels
// have more than one of them, and they always have the same volume behavior.
@AudioManager.DeviceVolumeBehavior int currentVolumeBehavior =
@@ -4493,7 +4505,7 @@ public class HdmiControlService extends SystemService {
boolean alreadyUsingFullOrAbsoluteVolume =
FULL_AND_ABSOLUTE_VOLUME_BEHAVIORS.contains(currentVolumeBehavior);
- // Condition 3: CEC volume is enabled
+ // Condition 4: CEC volume is enabled
boolean cecVolumeEnabled =
getHdmiCecVolumeControl() == HdmiControlManager.VOLUME_CONTROL_ENABLED;
@@ -4509,7 +4521,7 @@ public class HdmiControlService extends SystemService {
return;
}
- // Condition 4: The System Audio device supports <Set Audio Volume Level>
+ // Condition 5: The System Audio device supports <Set Audio Volume Level>
switch (systemAudioDeviceInfo.getDeviceFeatures().getSetAudioVolumeLevelSupport()) {
case DeviceFeatures.FEATURE_SUPPORTED:
if (currentVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
@@ -4556,6 +4568,8 @@ public class HdmiControlService extends SystemService {
* are currently used. Removes the action for handling volume updates for these behaviors.
*/
private void switchToFullVolumeBehavior() {
+ Slog.d(TAG, "Switching to full volume behavior");
+
if (playback() != null) {
playback().removeAvbAudioStatusAction();
} else if (tv() != null) {
@@ -4597,12 +4611,14 @@ public class HdmiControlService extends SystemService {
// Otherwise, enable adjust-only AVB on TVs only.
if (systemAudioDevice.getDeviceFeatures().getSetAudioVolumeLevelSupport()
== DeviceFeatures.FEATURE_SUPPORTED) {
+ Slog.d(TAG, "Enabling absolute volume behavior");
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior(
device, volumeInfo, mServiceThreadExecutor,
mAbsoluteVolumeChangedListener, true);
}
} else if (tv() != null) {
+ Slog.d(TAG, "Enabling adjust-only absolute volume behavior");
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeAdjustOnlyBehavior(
device, volumeInfo, mServiceThreadExecutor,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 773293f83323..a6c5ad5ffc6c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -356,15 +356,6 @@ final class InputMethodUtils {
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR));
}
- List<String> getEnabledInputMethodNames() {
- List<String> result = new ArrayList<>();
- for (Pair<String, ArrayList<String>> pair :
- getEnabledInputMethodsAndSubtypeListLocked()) {
- result.add(pair.first);
- }
- return result;
- }
-
void appendAndPutEnabledInputMethodLocked(String id) {
if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
// Add in the newly enabled input method.
diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
index 850449595d74..0eb9166371dc 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
@@ -87,6 +87,8 @@ import java.util.Objects;
@NonNull private final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallbackImpl();
+ @MediaRoute2Info.SuitabilityStatus private final int mBuiltInSpeakerSuitabilityStatus;
+
@NonNull
private final AudioManager.OnDevicesForAttributesChangedListener
mOnDevicesForAttributesChangedListener = this::onDevicesForAttributesChangedListener;
@@ -113,6 +115,10 @@ import java.util.Objects;
mHandler = new Handler(Objects.requireNonNull(looper));
mStrategyForMedia = Objects.requireNonNull(strategyForMedia);
mOnDeviceRouteChangedListener = Objects.requireNonNull(onDeviceRouteChangedListener);
+
+ mBuiltInSpeakerSuitabilityStatus =
+ DeviceRouteController.getBuiltInSpeakerSuitabilityStatus(mContext);
+
mBluetoothRouteController =
new AudioPoliciesBluetoothRouteController(
mContext, btAdapter, this::rebuildAvailableRoutesAndNotify);
@@ -373,14 +379,19 @@ import java.util.Objects;
// from getting an id using BluetoothRouteController#getRouteIdForBluetoothAddress.
routeId = systemRouteInfo.mDefaultRouteId;
}
- return new MediaRoute2Info.Builder(routeId, humanReadableName)
+ MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(routeId, humanReadableName)
.setType(systemRouteInfo.mMediaRoute2InfoType)
.setAddress(address)
.setSystemRoute(true)
.addFeature(FEATURE_LIVE_AUDIO)
.addFeature(FEATURE_LOCAL_PLAYBACK)
- .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
- .build();
+ .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED);
+
+ if (systemRouteInfo.mMediaRoute2InfoType == MediaRoute2Info.TYPE_BUILTIN_SPEAKER) {
+ builder.setSuitabilityStatus(mBuiltInSpeakerSuitabilityStatus);
+ }
+
+ return builder.build();
}
/**
diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java
index 9f175a9a0277..8b62cc974862 100644
--- a/services/core/java/com/android/server/media/DeviceRouteController.java
+++ b/services/core/java/com/android/server/media/DeviceRouteController.java
@@ -81,6 +81,30 @@ import java.util.List;
}
}
+ /** Returns device route availability status. */
+ @MediaRoute2Info.SuitabilityStatus
+ static int getBuiltInSpeakerSuitabilityStatus(@NonNull Context context) {
+ if (!Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
+ // Route is always suitable if the flag is disabled.
+ return MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
+ }
+
+ int availabilityStatus =
+ context.getResources()
+ .getInteger(
+ com.android.internal.R.integer
+ .config_mediaRouter_builtInSpeakerSuitability);
+
+ switch (availabilityStatus) {
+ case MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER:
+ case MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER:
+ case MediaRoute2Info.SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER:
+ return availabilityStatus;
+ default:
+ return MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
+ }
+ }
+
/** Returns the currently selected device (built-in or wired) route. */
@NonNull
MediaRoute2Info getSelectedRoute();
diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
index c0f28346705c..65b0ad0d61a0 100644
--- a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
@@ -72,6 +72,8 @@ import java.util.Objects;
@NonNull
private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver();
+ @MediaRoute2Info.SuitabilityStatus private final int mBuiltInSpeakerSuitabilityStatus;
+
private int mDeviceVolume;
private MediaRoute2Info mDeviceRoute;
@@ -90,6 +92,9 @@ import java.util.Objects;
mAudioManager = audioManager;
mAudioService = audioService;
+ mBuiltInSpeakerSuitabilityStatus =
+ DeviceRouteController.getBuiltInSpeakerSuitabilityStatus(mContext);
+
AudioRoutesInfo newAudioRoutes = null;
try {
newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
@@ -165,19 +170,28 @@ import java.util.Objects;
}
synchronized (this) {
- return new MediaRoute2Info.Builder(
- DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString())
- .setVolumeHandling(mAudioManager.isVolumeFixed()
- ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
- : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
- .setVolume(mDeviceVolume)
- .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
- .setType(type)
- .addFeature(FEATURE_LIVE_AUDIO)
- .addFeature(FEATURE_LIVE_VIDEO)
- .addFeature(FEATURE_LOCAL_PLAYBACK)
- .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
- .build();
+ MediaRoute2Info.Builder builder =
+ new MediaRoute2Info.Builder(
+ DEVICE_ROUTE_ID,
+ mContext.getResources().getText(name).toString())
+ .setVolumeHandling(
+ mAudioManager.isVolumeFixed()
+ ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
+ : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolume(mDeviceVolume)
+ .setVolumeMax(
+ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .setType(type)
+ .addFeature(FEATURE_LIVE_AUDIO)
+ .addFeature(FEATURE_LIVE_VIDEO)
+ .addFeature(FEATURE_LOCAL_PLAYBACK)
+ .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED);
+
+ if (type == TYPE_BUILTIN_SPEAKER) {
+ builder.setSuitabilityStatus(mBuiltInSpeakerSuitabilityStatus);
+ }
+
+ return builder.build();
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 8149847d70c0..1bc2a5eb1351 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -24,6 +24,7 @@ import android.media.MediaRoute2ProviderInfo;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
+import android.os.UserHandle;
import com.android.internal.annotations.GuardedBy;
@@ -54,8 +55,15 @@ abstract class MediaRoute2Provider {
mCallback = callback;
}
- public abstract void requestCreateSession(long requestId, String packageName, String routeId,
- @Nullable Bundle sessionHints);
+ public abstract void requestCreateSession(
+ long requestId,
+ String packageName,
+ String routeId,
+ @Nullable Bundle sessionHints,
+ @RoutingSessionInfo.TransferReason int transferReason,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName);
+
public abstract void releaseSession(long requestId, String sessionId);
public abstract void updateDiscoveryPreference(
@@ -63,7 +71,14 @@ abstract class MediaRoute2Provider {
public abstract void selectRoute(long requestId, String sessionId, String routeId);
public abstract void deselectRoute(long requestId, String sessionId, String routeId);
- public abstract void transferToRoute(long requestId, String sessionId, String routeId);
+
+ public abstract void transferToRoute(
+ long requestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
+ String sessionId,
+ String routeId,
+ @RoutingSessionInfo.TransferReason int transferReason);
public abstract void setRouteVolume(long requestId, String routeId, int volume);
public abstract void setSessionVolume(long requestId, String sessionId, int volume);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 330818ed17ca..ae889d8255c6 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -98,8 +98,14 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void requestCreateSession(long requestId, String packageName, String routeId,
- Bundle sessionHints) {
+ public void requestCreateSession(
+ long requestId,
+ String packageName,
+ String routeId,
+ Bundle sessionHints,
+ @RoutingSessionInfo.TransferReason int transferReason,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
if (mConnectionReady) {
mActiveConnection.requestCreateSession(requestId, packageName, routeId, sessionHints);
updateBinding();
@@ -141,7 +147,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void transferToRoute(long requestId, String sessionId, String routeId) {
+ public void transferToRoute(
+ long requestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
+ String sessionId,
+ String routeId,
+ @RoutingSessionInfo.TransferReason int transferReason) {
if (mConnectionReady) {
mActiveConnection.transferToRoute(requestId, sessionId, routeId);
}
@@ -649,6 +661,14 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
+ "Disallowed route: "
+ route);
}
+
+ if (route.getSuitabilityStatus()
+ == MediaRoute2Info.SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER) {
+ throw new SecurityException(
+ "Only the system is allowed to set not suitable for transfer status. "
+ + "Disallowed route: "
+ + route);
+ }
}
Connection connection = mConnectionRef.get();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 5e18727459c6..38f0df41db04 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -337,18 +337,47 @@ class MediaRouter2ServiceImpl {
}
}
- public void requestCreateSessionWithRouter2(@NonNull IMediaRouter2 router, int requestId,
- long managerRequestId, @NonNull RoutingSessionInfo oldSession,
- @NonNull MediaRoute2Info route, Bundle sessionHints) {
+ public void requestCreateSessionWithRouter2(
+ @NonNull IMediaRouter2 router,
+ int requestId,
+ long managerRequestId,
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ Bundle sessionHints,
+ @Nullable UserHandle transferInitiatorUserHandle,
+ @Nullable String transferInitiatorPackageName) {
Objects.requireNonNull(router, "router must not be null");
Objects.requireNonNull(oldSession, "oldSession must not be null");
Objects.requireNonNull(route, "route must not be null");
+ synchronized (mLock) {
+ if (managerRequestId == MediaRoute2ProviderService.REQUEST_ID_NONE
+ || transferInitiatorUserHandle == null
+ || transferInitiatorPackageName == null) {
+ final IBinder binder = router.asBinder();
+ final RouterRecord routerRecord = mAllRouterRecords.get(binder);
+
+ transferInitiatorUserHandle = Binder.getCallingUserHandle();
+ if (routerRecord != null) {
+ transferInitiatorPackageName = routerRecord.mPackageName;
+ } else {
+ transferInitiatorPackageName = mContext.getPackageName();
+ }
+ }
+ }
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionWithRouter2Locked(requestId, managerRequestId,
- router, oldSession, route, sessionHints);
+ requestCreateSessionWithRouter2Locked(
+ requestId,
+ managerRequestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName,
+ router,
+ oldSession,
+ route,
+ sessionHints);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +428,11 @@ class MediaRouter2ServiceImpl {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
}
+ UserHandle userHandle = Binder.getCallingUserHandle();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- transferToRouteWithRouter2Locked(router, uniqueSessionId, route);
+ transferToRouteWithRouter2Locked(router, userHandle, uniqueSessionId, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -588,16 +618,28 @@ class MediaRouter2ServiceImpl {
}
}
- public void requestCreateSessionWithManager(@NonNull IMediaRouter2Manager manager,
- int requestId, @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
+ public void requestCreateSessionWithManager(
+ @NonNull IMediaRouter2Manager manager,
+ int requestId,
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
Objects.requireNonNull(manager, "manager must not be null");
Objects.requireNonNull(oldSession, "oldSession must not be null");
Objects.requireNonNull(route, "route must not be null");
+ Objects.requireNonNull(transferInitiatorUserHandle);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionWithManagerLocked(requestId, manager, oldSession, route);
+ requestCreateSessionWithManagerLocked(
+ requestId,
+ manager,
+ oldSession,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -640,18 +682,32 @@ class MediaRouter2ServiceImpl {
}
}
- public void transferToRouteWithManager(@NonNull IMediaRouter2Manager manager, int requestId,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ public void transferToRouteWithManager(
+ @NonNull IMediaRouter2Manager manager,
+ int requestId,
+ @NonNull String uniqueSessionId,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
}
Objects.requireNonNull(route, "route must not be null");
+ Objects.requireNonNull(transferInitiatorUserHandle);
+ Objects.requireNonNull(transferInitiatorPackageName);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- transferToRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
+ transferToRouteWithManagerLocked(
+ requestId,
+ manager,
+ uniqueSessionId,
+ route,
+ RoutingSessionInfo.TRANSFER_REASON_SYSTEM_REQUEST,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1038,9 +1094,15 @@ class MediaRouter2ServiceImpl {
}
@GuardedBy("mLock")
- private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
- @NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
- @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
+ private void requestCreateSessionWithRouter2Locked(
+ int requestId,
+ long managerRequestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
+ @NonNull IMediaRouter2 router,
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ @Nullable Bundle sessionHints) {
final IBinder binder = router.asBinder();
final RouterRecord routerRecord = mAllRouterRecords.get(binder);
@@ -1114,9 +1176,16 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
+ obtainMessage(
+ UserHandler::requestCreateSessionWithRouter2OnHandler,
routerRecord.mUserRecord.mHandler,
- uniqueRequestId, managerRequestId, routerRecord, oldSession, route,
+ uniqueRequestId,
+ managerRequestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName,
+ routerRecord,
+ oldSession,
+ route,
sessionHints));
}
@@ -1165,8 +1234,11 @@ class MediaRouter2ServiceImpl {
}
@GuardedBy("mLock")
- private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ private void transferToRouteWithRouter2Locked(
+ @NonNull IMediaRouter2 router,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String uniqueSessionId,
+ @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
final RouterRecord routerRecord = mAllRouterRecords.get(binder);
@@ -1191,9 +1263,16 @@ class MediaRouter2ServiceImpl {
routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID)));
} else {
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::transferToRouteOnHandler,
+ obtainMessage(
+ UserHandler::transferToRouteOnHandler,
routerRecord.mUserRecord.mHandler,
- DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
+ DUMMY_REQUEST_ID,
+ transferInitiatorUserHandle,
+ routerRecord.mPackageName,
+ routerRecord,
+ uniqueSessionId,
+ route,
+ RoutingSessionInfo.TRANSFER_REASON_APP));
}
}
@@ -1416,9 +1495,13 @@ class MediaRouter2ServiceImpl {
}
@GuardedBy("mLock")
- private void requestCreateSessionWithManagerLocked(int requestId,
- @NonNull IMediaRouter2Manager manager, @NonNull RoutingSessionInfo oldSession,
- @NonNull MediaRoute2Info route) {
+ private void requestCreateSessionWithManagerLocked(
+ int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord == null) {
return;
@@ -1464,9 +1547,16 @@ class MediaRouter2ServiceImpl {
// Before requesting to the provider, get session hints from the media router.
// As a return, media router will request to create a session.
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestRouterCreateSessionOnHandler,
+ obtainMessage(
+ UserHandler::requestRouterCreateSessionOnHandler,
routerRecord.mUserRecord.mHandler,
- uniqueRequestId, routerRecord, managerRecord, oldSession, route));
+ uniqueRequestId,
+ routerRecord,
+ managerRecord,
+ oldSession,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName));
}
@GuardedBy("mLock")
@@ -1521,9 +1611,14 @@ class MediaRouter2ServiceImpl {
}
@GuardedBy("mLock")
- private void transferToRouteWithManagerLocked(int requestId,
+ private void transferToRouteWithManagerLocked(
+ int requestId,
@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId,
+ @NonNull MediaRoute2Info route,
+ @RoutingSessionInfo.TransferReason int transferReason,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1541,9 +1636,16 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::transferToRouteOnHandler,
+ obtainMessage(
+ UserHandler::transferToRouteOnHandler,
managerRecord.mUserRecord.mHandler,
- uniqueRequestId, routerRecord, uniqueSessionId, route));
+ uniqueRequestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName,
+ routerRecord,
+ uniqueSessionId,
+ route,
+ transferReason));
}
@GuardedBy("mLock")
@@ -1850,6 +1952,19 @@ class MediaRouter2ServiceImpl {
}
}
+ public void notifySessionCreated(int requestId, @NonNull RoutingSessionInfo sessionInfo) {
+ try {
+ mRouter.notifySessionCreated(
+ requestId, maybeClearTransferInitiatorIdentity(sessionInfo));
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "Failed to notify router of the session creation."
+ + " Router probably died.",
+ ex);
+ }
+ }
+
/**
* Sends the corresponding router an update for the given session.
*
@@ -1857,12 +1972,27 @@ class MediaRouter2ServiceImpl {
*/
public void notifySessionInfoChanged(RoutingSessionInfo sessionInfo) {
try {
- mRouter.notifySessionInfoChanged(sessionInfo);
+ mRouter.notifySessionInfoChanged(maybeClearTransferInitiatorIdentity(sessionInfo));
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
}
}
+ private RoutingSessionInfo maybeClearTransferInitiatorIdentity(
+ @NonNull RoutingSessionInfo sessionInfo) {
+ UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
+ String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
+
+ if (!Objects.equals(UserHandle.of(mUserRecord.mUserId), transferInitiatorUserHandle)
+ || !Objects.equals(mPackageName, transferInitiatorPackageName)) {
+ return new RoutingSessionInfo.Builder(sessionInfo)
+ .setTransferInitiator(null, null)
+ .build();
+ }
+
+ return sessionInfo;
+ }
+
/**
* Returns a filtered copy of {@code routes} that contains only the routes that are {@link
* MediaRoute2Info#isVisibleTo visible} to the router corresponding to this record.
@@ -2307,9 +2437,14 @@ class MediaRouter2ServiceImpl {
return -1;
}
- private void requestRouterCreateSessionOnHandler(long uniqueRequestId,
- @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
- @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
+ private void requestRouterCreateSessionOnHandler(
+ long uniqueRequestId,
+ @NonNull RouterRecord routerRecord,
+ @NonNull ManagerRecord managerRecord,
+ @NonNull RoutingSessionInfo oldSession,
+ @NonNull MediaRoute2Info route,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
try {
if (route.isSystemRoute() && !routerRecord.hasSystemRoutingPermission()) {
// The router lacks permission to modify system routing, so we hide system
@@ -2317,7 +2452,11 @@ class MediaRouter2ServiceImpl {
route = mSystemProvider.getDefaultRoute();
}
routerRecord.mRouter.requestCreateSessionByManager(
- uniqueRequestId, oldSession, route);
+ uniqueRequestId,
+ oldSession,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
} catch (RemoteException ex) {
Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
+ "Failed to request. Router probably died.", ex);
@@ -2326,10 +2465,15 @@ class MediaRouter2ServiceImpl {
}
}
- private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
- long managerRequestId, @NonNull RouterRecord routerRecord,
+ private void requestCreateSessionWithRouter2OnHandler(
+ long uniqueRequestId,
+ long managerRequestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
+ @NonNull RouterRecord routerRecord,
@NonNull RoutingSessionInfo oldSession,
- @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
+ @NonNull MediaRoute2Info route,
+ @Nullable Bundle sessionHints) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
@@ -2345,8 +2489,19 @@ class MediaRouter2ServiceImpl {
managerRequestId, oldSession, route);
mSessionCreationRequests.add(request);
- provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
- route.getOriginalId(), sessionHints);
+ int transferReason = RoutingSessionInfo.TRANSFER_REASON_APP;
+ if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
+ transferReason = RoutingSessionInfo.TRANSFER_REASON_SYSTEM_REQUEST;
+ }
+
+ provider.requestCreateSession(
+ uniqueRequestId,
+ routerRecord.mPackageName,
+ route.getOriginalId(),
+ sessionHints,
+ transferReason,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
// routerRecord can be null if the session is system's or RCN.
@@ -2386,9 +2541,14 @@ class MediaRouter2ServiceImpl {
}
// routerRecord can be null if the session is system's or RCN.
- private void transferToRouteOnHandler(long uniqueRequestId,
+ private void transferToRouteOnHandler(
+ long uniqueRequestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId,
+ @NonNull MediaRoute2Info route,
+ @RoutingSessionInfo.TransferReason int transferReason) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"transferring to")) {
return;
@@ -2399,8 +2559,13 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.transferToRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
- route.getOriginalId());
+ provider.transferToRoute(
+ uniqueRequestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName,
+ getOriginalId(uniqueSessionId),
+ route.getOriginalId(),
+ transferReason);
}
// routerRecord is null if and only if the session is created without the request, which
@@ -2535,6 +2700,7 @@ class MediaRouter2ServiceImpl {
// session info from them.
sessionInfo = mSystemProvider.getDefaultSessionInfo();
}
+ // TODO: b/279555229 - replace with matchingRequest.mRouterRecord.notifySessionCreated.
notifySessionCreatedToRouter(
matchingRequest.mRouterRecord,
toOriginalRequestId(uniqueRequestId),
@@ -2648,12 +2814,7 @@ class MediaRouter2ServiceImpl {
private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
int requestId, @NonNull RoutingSessionInfo sessionInfo) {
- try {
- routerRecord.mRouter.notifySessionCreated(requestId, sessionInfo);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify router of the session creation."
- + " Router probably died.", ex);
- }
+ routerRecord.notifySessionCreated(requestId, sessionInfo);
}
private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index e562b3f0845c..7dd13142f52e 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -461,11 +461,24 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
- long managerRequestId, RoutingSessionInfo oldSession,
- MediaRoute2Info route, Bundle sessionHints) {
- mService2.requestCreateSessionWithRouter2(router, requestId, managerRequestId,
- oldSession, route, sessionHints);
+ public void requestCreateSessionWithRouter2(
+ IMediaRouter2 router,
+ int requestId,
+ long managerRequestId,
+ RoutingSessionInfo oldSession,
+ MediaRoute2Info route,
+ Bundle sessionHints,
+ @Nullable UserHandle transferInitiatorUserHandle,
+ @Nullable String transferInitiatorPackageName) {
+ mService2.requestCreateSessionWithRouter2(
+ router,
+ requestId,
+ managerRequestId,
+ oldSession,
+ route,
+ sessionHints,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
// Binder call
@@ -580,9 +593,20 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void requestCreateSessionWithManager(IMediaRouter2Manager manager,
- int requestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
- mService2.requestCreateSessionWithManager(manager, requestId, oldSession, route);
+ public void requestCreateSessionWithManager(
+ IMediaRouter2Manager manager,
+ int requestId,
+ RoutingSessionInfo oldSession,
+ MediaRoute2Info route,
+ UserHandle transferInitiatorUserHandle,
+ String transferInitiatorPackageName) {
+ mService2.requestCreateSessionWithManager(
+ manager,
+ requestId,
+ oldSession,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
// Binder call
@@ -601,9 +625,20 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
- String sessionId, MediaRoute2Info route) {
- mService2.transferToRouteWithManager(manager, requestId, sessionId, route);
+ public void transferToRouteWithManager(
+ IMediaRouter2Manager manager,
+ int requestId,
+ String sessionId,
+ MediaRoute2Info route,
+ UserHandle transferInitiatorUserHandle,
+ String transferInitiatorPackageName) {
+ mService2.transferToRouteWithManager(
+ manager,
+ requestId,
+ sessionId,
+ route,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 9d151c27e7c7..f7210dd1ef70 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -26,6 +27,7 @@ import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.media.MediaRouter2Utils;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
@@ -39,6 +41,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.media.flags.Flags;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -79,6 +82,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
@GuardedBy("mRequestLock")
private volatile SessionCreationRequest mPendingSessionCreationRequest;
+ private final Object mTransferLock = new Object();
+ @GuardedBy("mTransferLock")
+ @Nullable private volatile SessionCreationRequest mPendingTransferRequest;
+
SystemMediaRoute2Provider(Context context, UserHandle user) {
super(COMPONENT_NAME);
mIsSystemRouteProvider = true;
@@ -146,17 +153,30 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void requestCreateSession(long requestId, String packageName, String routeId,
- Bundle sessionHints) {
+ public void requestCreateSession(
+ long requestId,
+ String packageName,
+ String routeId,
+ Bundle sessionHints,
+ @RoutingSessionInfo.TransferReason int transferReason,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
// Assume a router without MODIFY_AUDIO_ROUTING permission can't request with
// a route ID different from the default route ID. The service should've filtered.
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
mCallback.onSessionCreated(this, requestId, mDefaultSessionInfo);
return;
}
- if (TextUtils.equals(routeId, mSelectedRouteId)) {
- mCallback.onSessionCreated(this, requestId, mSessionInfos.get(0));
- return;
+
+ if (!Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
+ if (TextUtils.equals(routeId, mSelectedRouteId)) {
+ RoutingSessionInfo currentSessionInfo;
+ synchronized (mLock) {
+ currentSessionInfo = mSessionInfos.get(0);
+ }
+ mCallback.onSessionCreated(this, requestId, currentSessionInfo);
+ return;
+ }
}
synchronized (mRequestLock) {
@@ -165,10 +185,23 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
mCallback.onRequestFailed(this, mPendingSessionCreationRequest.mRequestId,
MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
}
- mPendingSessionCreationRequest = new SessionCreationRequest(requestId, routeId);
+ mPendingSessionCreationRequest =
+ new SessionCreationRequest(
+ requestId,
+ routeId,
+ RoutingSessionInfo.TRANSFER_REASON_FALLBACK,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
}
- transferToRoute(requestId, SYSTEM_SESSION_ID, routeId);
+ // Only unprivileged routers call this method, therefore we use TRANSFER_REASON_APP.
+ transferToRoute(
+ requestId,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName,
+ SYSTEM_SESSION_ID,
+ routeId,
+ transferReason);
}
@Override
@@ -193,12 +226,31 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void transferToRoute(long requestId, String sessionId, String routeId) {
+ public void transferToRoute(
+ long requestId,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName,
+ String sessionId,
+ String routeId,
+ @RoutingSessionInfo.TransferReason int transferReason) {
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
// The currently selected route is the default route.
Log.w(TAG, "Ignoring transfer to " + MediaRoute2Info.ROUTE_ID_DEFAULT);
return;
}
+
+ if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
+ synchronized (mTransferLock) {
+ mPendingTransferRequest =
+ new SessionCreationRequest(
+ requestId,
+ routeId,
+ transferReason,
+ transferInitiatorUserHandle,
+ transferInitiatorPackageName);
+ }
+ }
+
MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
boolean isAvailableDeviceRoute =
mDeviceRouteController.getAvailableRoutes().stream()
@@ -218,6 +270,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
mDeviceRouteController.transferTo(null);
mBluetoothRouteController.transferTo(routeId);
}
+
+ if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()
+ && updateSessionInfosIfNeeded()) {
+ notifySessionInfoUpdated();
+ }
}
@Override
@@ -322,9 +379,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
MediaRoute2Info selectedRoute = selectedDeviceRoute;
MediaRoute2Info selectedBtRoute = mBluetoothRouteController.getSelectedRoute();
+ List<String> transferableRoutes = new ArrayList<>();
+
if (selectedBtRoute != null) {
selectedRoute = selectedBtRoute;
- builder.addTransferableRoute(selectedDeviceRoute.getId());
+ transferableRoutes.add(selectedDeviceRoute.getId());
}
mSelectedRouteId = selectedRoute.getId();
mDefaultRoute =
@@ -337,12 +396,54 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
for (MediaRoute2Info route : mDeviceRouteController.getAvailableRoutes()) {
String routeId = route.getId();
if (!mSelectedRouteId.equals(routeId)) {
- builder.addTransferableRoute(routeId);
+ transferableRoutes.add(routeId);
}
}
}
for (MediaRoute2Info route : mBluetoothRouteController.getTransferableRoutes()) {
- builder.addTransferableRoute(route.getId());
+ transferableRoutes.add(route.getId());
+ }
+
+ for (String route : transferableRoutes) {
+ builder.addTransferableRoute(route);
+ }
+
+ if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
+ int transferReason = RoutingSessionInfo.TRANSFER_REASON_FALLBACK;
+ UserHandle transferInitiatorUserHandle = null;
+ String transferInitiatorPackageName = null;
+
+ if (oldSessionInfo != null
+ && containsSelectedRouteWithId(oldSessionInfo, selectedRoute.getId())) {
+ transferReason = oldSessionInfo.getTransferReason();
+ transferInitiatorUserHandle = oldSessionInfo.getTransferInitiatorUserHandle();
+ transferInitiatorPackageName = oldSessionInfo.getTransferInitiatorPackageName();
+ }
+
+ synchronized (mTransferLock) {
+ if (mPendingTransferRequest != null) {
+ boolean isTransferringToTheSelectedRoute =
+ mPendingTransferRequest.isTargetRoute(selectedRoute);
+ boolean canBePotentiallyTransferred =
+ mPendingTransferRequest.isInsideOfRoutesList(transferableRoutes);
+
+ if (isTransferringToTheSelectedRoute) {
+ transferReason = mPendingTransferRequest.mTransferReason;
+ transferInitiatorUserHandle =
+ mPendingTransferRequest.mTransferInitiatorUserHandle;
+ transferInitiatorPackageName =
+ mPendingTransferRequest.mTransferInitiatorPackageName;
+
+ mPendingTransferRequest = null;
+ } else if (!canBePotentiallyTransferred) {
+ mPendingTransferRequest = null;
+ }
+ }
+ }
+
+ builder.setTransferReason(transferReason)
+ .setTransferInitiator(
+ transferInitiatorUserHandle, transferInitiatorPackageName);
}
RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build();
@@ -424,6 +525,22 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
return false;
}
+ private boolean containsSelectedRouteWithId(
+ @Nullable RoutingSessionInfo sessionInfo, @NonNull String selectedRouteId) {
+ if (sessionInfo == null) {
+ return false;
+ }
+
+ List<String> selectedRoutes = sessionInfo.getSelectedRoutes();
+
+ if (selectedRoutes.size() != 1) {
+ throw new IllegalStateException("Selected routes list should contain only 1 route id.");
+ }
+
+ String oldSelectedRouteId = MediaRouter2Utils.getOriginalId(selectedRoutes.get(0));
+ return oldSelectedRouteId != null && oldSelectedRouteId.equals(selectedRouteId);
+ }
+
void publishProviderState() {
updateProviderState();
notifyProviderState();
@@ -452,12 +569,47 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
private static class SessionCreationRequest {
- final long mRequestId;
- final String mRouteId;
+ private final long mRequestId;
+ @NonNull private final String mRouteId;
+
+ @RoutingSessionInfo.TransferReason private final int mTransferReason;
+
+ @NonNull private final UserHandle mTransferInitiatorUserHandle;
+ @NonNull private final String mTransferInitiatorPackageName;
+
+ SessionCreationRequest(
+ long requestId,
+ @NonNull String routeId,
+ @RoutingSessionInfo.TransferReason int transferReason,
+ @NonNull UserHandle transferInitiatorUserHandle,
+ @NonNull String transferInitiatorPackageName) {
+ mRequestId = requestId;
+ mRouteId = routeId;
+ mTransferReason = transferReason;
+ mTransferInitiatorUserHandle = transferInitiatorUserHandle;
+ mTransferInitiatorPackageName = transferInitiatorPackageName;
+ }
+
+ private boolean isTargetRoute(@Nullable MediaRoute2Info route2Info) {
+ if (route2Info == null) {
+ return false;
+ }
+
+ return isTargetRoute(route2Info.getId());
+ }
+
+ private boolean isTargetRoute(@Nullable String routeId) {
+ return mRouteId.equals(routeId);
+ }
+
+ private boolean isInsideOfRoutesList(@NonNull List<String> routesList) {
+ for (String routeId : routesList) {
+ if (isTargetRoute(routeId)) {
+ return true;
+ }
+ }
- SessionCreationRequest(long requestId, String routeId) {
- this.mRequestId = requestId;
- this.mRouteId = routeId;
+ return false;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 135a467cc6b0..f49d51c70c1d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5617,7 +5617,8 @@ public class NotificationManagerService extends SystemService {
return !isCompatChangeEnabled
|| isCallerSystemOrSystemUi()
|| hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid),
- AssociationRequest.DEVICE_PROFILE_WATCH);
+ Set.of(AssociationRequest.DEVICE_PROFILE_WATCH,
+ AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION));
}
private void enforcePolicyAccess(String pkg, String method) {
@@ -10800,7 +10801,7 @@ public class NotificationManagerService extends SystemService {
}
private boolean hasCompanionDevice(String pkg, @UserIdInt int userId,
- @Nullable @AssociationRequest.DeviceProfile String withDeviceProfile) {
+ @Nullable Set</* @AssociationRequest.DeviceProfile */ String> withDeviceProfiles) {
if (mCompanionManager == null) {
mCompanionManager = getCompanionManager();
}
@@ -10812,7 +10813,7 @@ public class NotificationManagerService extends SystemService {
try {
List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId);
for (AssociationInfo association : associations) {
- if (withDeviceProfile == null || withDeviceProfile.equals(
+ if (withDeviceProfiles == null || withDeviceProfiles.contains(
association.getDeviceProfile())) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1ce87a7b6af3..145eb3b8464c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -125,6 +125,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
+import static android.window.TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -683,6 +684,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
+ // TODO(b/317000737): Replace it with visibility states lookup.
int mTransitionChangeFlags;
/** Whether we need to setup the animation to animate only within the letterbox. */
@@ -5468,8 +5470,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Defer committing visibility until transition starts.
if (isCollecting) {
// It may be occluded by the activity above that calls convertFromTranslucent().
- if (!visible && mTransitionController.inPlayingTransition(this)) {
- mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
+ // Or it may be restoring transient launch to invisible when finishing transition.
+ if (!visible) {
+ if (mTransitionController.inPlayingTransition(this)) {
+ mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
+ } else if (mTransitionController.inFinishingTransition(this)) {
+ mTransitionChangeFlags |= FLAGS_IS_OCCLUDED_NO_ANIMATION;
+ }
}
return;
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 24c953b127bc..eed46fee1ae1 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -36,6 +36,7 @@ import static com.android.window.flags.Flags.balShowToastsBlocked;
import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -152,36 +153,25 @@ public class BackgroundActivityStartController {
static final int BAL_ALLOW_SDK_SANDBOX = 10;
static String balCodeToString(@BalCode int balCode) {
- switch (balCode) {
- case BAL_ALLOW_ALLOWLISTED_COMPONENT:
- return "BAL_ALLOW_ALLOWLISTED_COMPONENT";
- case BAL_ALLOW_ALLOWLISTED_UID:
- return "BAL_ALLOW_ALLOWLISTED_UID";
- case BAL_ALLOW_DEFAULT:
- return "BAL_ALLOW_DEFAULT";
- case BAL_ALLOW_FOREGROUND:
- return "BAL_ALLOW_FOREGROUND";
- case BAL_ALLOW_GRACE_PERIOD:
- return "BAL_ALLOW_GRACE_PERIOD";
- case BAL_ALLOW_PENDING_INTENT:
- return "BAL_ALLOW_PENDING_INTENT";
- case BAL_ALLOW_PERMISSION:
- return "BAL_ALLOW_PERMISSION";
- case BAL_ALLOW_SAW_PERMISSION:
- return "BAL_ALLOW_SAW_PERMISSION";
- case BAL_ALLOW_SDK_SANDBOX:
- return "BAL_ALLOW_SDK_SANDBOX";
- case BAL_ALLOW_VISIBLE_WINDOW:
- return "BAL_ALLOW_VISIBLE_WINDOW";
- case BAL_BLOCK:
- return "BAL_BLOCK";
- default:
- throw new IllegalArgumentException("Unexpected value: " + balCode);
- }
+ return switch (balCode) {
+ case BAL_ALLOW_ALLOWLISTED_COMPONENT -> "BAL_ALLOW_ALLOWLISTED_COMPONENT";
+ case BAL_ALLOW_ALLOWLISTED_UID -> "BAL_ALLOW_ALLOWLISTED_UID";
+ case BAL_ALLOW_DEFAULT -> "BAL_ALLOW_DEFAULT";
+ case BAL_ALLOW_FOREGROUND -> "BAL_ALLOW_FOREGROUND";
+ case BAL_ALLOW_GRACE_PERIOD -> "BAL_ALLOW_GRACE_PERIOD";
+ case BAL_ALLOW_PENDING_INTENT -> "BAL_ALLOW_PENDING_INTENT";
+ case BAL_ALLOW_PERMISSION -> "BAL_ALLOW_PERMISSION";
+ case BAL_ALLOW_SAW_PERMISSION -> "BAL_ALLOW_SAW_PERMISSION";
+ case BAL_ALLOW_SDK_SANDBOX -> "BAL_ALLOW_SDK_SANDBOX";
+ case BAL_ALLOW_VISIBLE_WINDOW -> "BAL_ALLOW_VISIBLE_WINDOW";
+ case BAL_BLOCK -> "BAL_BLOCK";
+ default -> throw new IllegalArgumentException("Unexpected value: " + balCode);
+ };
}
@GuardedBy("mService.mGlobalLock")
- private HashMap<Integer, FinishedActivityEntry> mTaskIdToFinishedActivity = new HashMap<>();
+ private final HashMap<Integer, FinishedActivityEntry> mTaskIdToFinishedActivity =
+ new HashMap<>();
@GuardedBy("mService.mGlobalLock")
private FinishedActivityEntry mTopFinishedActivity = null;
@@ -467,9 +457,8 @@ public class BackgroundActivityStartController {
return !blocks();
}
- BalVerdict setOnlyCreatorAllows(boolean onlyCreatorAllows) {
+ void setOnlyCreatorAllows(boolean onlyCreatorAllows) {
mOnlyCreatorAllows = onlyCreatorAllows;
- return this;
}
boolean onlyCreatorAllows() {
@@ -481,10 +470,6 @@ public class BackgroundActivityStartController {
return this;
}
- private boolean isBasedOnRealCaller() {
- return mBasedOnRealCaller;
- }
-
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(balCodeToString(mCode));
@@ -583,15 +568,14 @@ public class BackgroundActivityStartController {
BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state);
if (!state.hasRealCaller()) {
- BalVerdict resultForRealCaller = null; // nothing to compute
if (resultForCaller.allows()) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed. "
- + state.dump(resultForCaller, resultForRealCaller));
+ + state.dump(resultForCaller, resultForCaller));
}
return statsLog(resultForCaller, state);
}
- return abortLaunch(state, resultForCaller, resultForRealCaller);
+ return abortLaunch(state, resultForCaller, resultForCaller);
}
// The realCaller result is only calculated for PendingIntents (indicated by a valid
@@ -910,7 +894,7 @@ public class BackgroundActivityStartController {
/**
* Check if the app allows BAL.
- *
+ * <p>
* See {@link BackgroundLaunchProcessController#areBackgroundActivityStartsAllowed(int, int,
* String, int, boolean, boolean, boolean, long, long, long)} for details on the
* exceptions.
@@ -1277,7 +1261,7 @@ public class BackgroundActivityStartController {
* 2. Or top of an adjacent task fragment to (1)
* <p>
* The 'sourceRecord' can be considered top even if it is 'finishing'
- *
+ * <p>
* Returns a class where the elements are:
* <pre>
* shouldBlockActivityStart: {@code true} if we should actually block the transition (takes into
@@ -1340,7 +1324,7 @@ public class BackgroundActivityStartController {
/**
* Determines if a source is allowed to add or remove activities from the task,
* if the current ActivityRecord is above it in the stack
- *
+ * <p>
* A transition is blocked ({@code false} returned) if all of the following are met:
* <pre>
* 1. The source activity and the current activity record belong to different apps
@@ -1485,8 +1469,8 @@ public class BackgroundActivityStartController {
if (code == BAL_ALLOW_PENDING_INTENT
&& (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) {
- String activityName =
- intent != null ? intent.getComponent().flattenToShortString() : "";
+ String activityName = intent != null
+ ? requireNonNull(intent.getComponent()).flattenToShortString() : "";
FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
activityName,
BAL_ALLOW_PENDING_INTENT,
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f020bfa8cbc7..3117db5f27f0 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -43,6 +43,7 @@ import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
+import static android.window.TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
@@ -3067,6 +3068,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
Slog.e(TAG, "Unexpected launch-task-behind operation in shell transition");
flags |= FLAG_TASK_LAUNCHING_BEHIND;
}
+ if ((topActivity.mTransitionChangeFlags & FLAGS_IS_OCCLUDED_NO_ANIMATION)
+ == FLAGS_IS_OCCLUDED_NO_ANIMATION) {
+ flags |= FLAGS_IS_OCCLUDED_NO_ANIMATION;
+ }
}
if (task.voiceSession != null) {
flags |= FLAG_IS_VOICE_INTERACTION;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9c21e4c0121e..ec4bdf91bcca 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -202,7 +202,6 @@ import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
import android.os.PowerManager;
-import android.os.PowerManager.WakeReason;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -702,11 +701,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
private final Region mTapExcludeRegion = new Region();
- /**
- * Used for testing because the real PowerManager is final.
- */
- private PowerManagerWrapper mPowerManagerWrapper;
-
private static final StringBuilder sTmpSB = new StringBuilder();
/**
@@ -1061,34 +1055,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mOnBackInvokedCallbackInfo;
}
- interface PowerManagerWrapper {
- void wakeUp(long time, @WakeReason int reason, String details);
-
- boolean isInteractive();
-
- }
-
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
- this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
- ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
- @Override
- public void wakeUp(long time, @WakeReason int reason, String details) {
- service.mPowerManager.wakeUp(time, reason, details);
- }
-
- @Override
- public boolean isInteractive() {
- return service.mPowerManager.isInteractive();
- }
- });
- }
-
- WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
- int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
- PowerManagerWrapper powerManagerWrapper) {
super(service);
mTmpTransaction = service.mTransactionFactory.get();
mSession = s;
@@ -1106,7 +1075,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mViewVisibility = viewVisibility;
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
- mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
mActivityRecord != null
@@ -2831,12 +2799,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean canTurnScreenOn = mActivityRecord == null || mActivityRecord.currentLaunchCanTurnScreenOn();
if (allowTheaterMode && canTurnScreenOn
- && (mWmService.mAtmService.isDreaming()
- || !mPowerManagerWrapper.isInteractive())) {
+ && (mWmService.mAtmService.isDreaming()
+ || !mWmService.mPowerManager.isInteractive())) {
if (DEBUG_VISIBILITY || DEBUG_POWER) {
Slog.v(TAG, "Relayout window turning screen on: " + this);
}
- mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
+ mWmService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION, "android.server.wm:SCREEN_ON_FLAG");
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 807874522b8c..3cbceec5b9cd 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -632,7 +632,7 @@
<xs:annotation name="final"/>
</xs:element>
<xs:element name="mode" type="AutoBrightnessModeName" minOccurs="0"/>
- <xs:element name="setting" type="xs:string" minOccurs="0"/>
+ <xs:element name="setting" type="AutoBrightnessSettingName" minOccurs="0"/>
</xs:complexType>
<!-- Represents a point in the display brightness mapping, representing the lux level from the
@@ -775,4 +775,13 @@
<xs:enumeration value="doze"/>
</xs:restriction>
</xs:simpleType>
+
+ <!-- Predefined auto-brighntess settings -->
+ <xs:simpleType name="AutoBrightnessSettingName">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="dim"/>
+ <xs:enumeration value="normal"/>
+ <xs:enumeration value="bright"/>
+ </xs:restriction>
+ </xs:simpleType>
</xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 91172a334bb1..79ea274e2fca 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -23,6 +23,13 @@ package com.android.server.display.config {
enum_constant public static final com.android.server.display.config.AutoBrightnessModeName idle;
}
+ public enum AutoBrightnessSettingName {
+ method public String getRawName();
+ enum_constant public static final com.android.server.display.config.AutoBrightnessSettingName bright;
+ enum_constant public static final com.android.server.display.config.AutoBrightnessSettingName dim;
+ enum_constant public static final com.android.server.display.config.AutoBrightnessSettingName normal;
+ }
+
public class BlockingZoneConfig {
ctor public BlockingZoneConfig();
method public final com.android.server.display.config.BlockingZoneThreshold getBlockingZoneThreshold();
@@ -227,10 +234,10 @@ package com.android.server.display.config {
ctor public LuxToBrightnessMapping();
method @NonNull public final com.android.server.display.config.NonNegativeFloatToFloatMap getMap();
method public com.android.server.display.config.AutoBrightnessModeName getMode();
- method public String getSetting();
+ method public com.android.server.display.config.AutoBrightnessSettingName getSetting();
method public final void setMap(@NonNull com.android.server.display.config.NonNegativeFloatToFloatMap);
method public void setMode(com.android.server.display.config.AutoBrightnessModeName);
- method public void setSetting(String);
+ method public void setSetting(com.android.server.display.config.AutoBrightnessSettingName);
}
public class NitsMap {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index f4eaa5b7046c..fb73aff44c64 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
import static org.junit.Assert.assertEquals;
@@ -29,21 +30,22 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.display.BrightnessConfiguration;
import android.os.PowerManager;
+import android.provider.Settings;
+import android.testing.TestableContext;
import android.util.MathUtils;
import android.util.Spline;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
-
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import java.util.Arrays;
@@ -154,15 +156,23 @@ public class BrightnessMappingStrategyTest {
private static final float TOLERANCE = 0.0001f;
- @Mock
- DisplayWhiteBalanceController mMockDwbc;
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
+
+ @Before
+ public void setUp() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_FOR_ALS,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL);
+ }
@Test
public void testSimpleStrategyMappingAtControlPoints() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 0; i < LUX_LEVELS.length; i++) {
assertEquals(DISPLAY_LEVELS[i], simple.getBrightness(LUX_LEVELS[i]), TOLERANCE);
@@ -171,10 +181,10 @@ public class BrightnessMappingStrategyTest {
@Test
public void testSimpleStrategyMappingBetweenControlPoints() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -186,10 +196,10 @@ public class BrightnessMappingStrategyTest {
@Test
public void testSimpleStrategyIgnoresNewConfiguration() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
final float[] lux = { 0f, 1f };
final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
@@ -202,10 +212,10 @@ public class BrightnessMappingStrategyTest {
@Test
public void testSimpleStrategyIgnoresNullConfiguration() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
strategy.setBrightnessConfiguration(null);
final int n = DISPLAY_LEVELS.length;
@@ -216,11 +226,11 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyMappingAtControlPoints() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS)
.build();
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel = MathUtils.map(DISPLAY_RANGE_NITS[0], DISPLAY_RANGE_NITS[1],
@@ -235,11 +245,11 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyMappingBetweenControlPoints() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setBrightnessRange(BACKLIGHT_RANGE_ZERO_TO_ONE)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS).build();
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
Spline brightnessToNits =
Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
@@ -254,11 +264,11 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyUsesNewConfigurations() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS)
.build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
final float[] lux = {0f, 1f};
final float[] nits = {
@@ -281,11 +291,11 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyRecalculateSplines() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS)
.build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
float[] adjustedNits50p = new float[DISPLAY_RANGE_NITS.length];
for (int i = 0; i < DISPLAY_RANGE_NITS.length; i++) {
adjustedNits50p[i] = DISPLAY_RANGE_NITS[i] * 0.5f;
@@ -326,12 +336,12 @@ public class BrightnessMappingStrategyTest {
@Test
public void testDefaultStrategyIsPhysical() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevels(DISPLAY_LEVELS)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS)
.build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
}
@@ -342,19 +352,19 @@ public class BrightnessMappingStrategyTest {
float tmp = lux[idx];
lux[idx] = lux[idx + 1];
lux[idx + 1] = tmp;
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(lux)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNull(strategy);
// And make sure we get the same result even if it's monotone but not increasing.
lux[idx] = lux[idx + 1];
ddc = new DdcBuilder().setAutoBrightnessLevelsLux(lux)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS).build();
- strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
- mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(mContext, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ /* displayWhiteBalanceController= */ null);
assertNull(strategy);
}
@@ -365,74 +375,74 @@ public class BrightnessMappingStrategyTest {
// Make sure it's strictly increasing so that the only failure is the differing array
// lengths
lux[lux.length - 1] = lux[lux.length - 2] + 1;
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(lux)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNull(strategy);
ddc = new DdcBuilder().setAutoBrightnessLevelsLux(lux)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS)
.setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
- mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(mContext, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ /* displayWhiteBalanceController= */ null);
assertNull(strategy);
// Extra backlight level
final float[] backlight = Arrays.copyOf(DISPLAY_LEVELS, DISPLAY_LEVELS.length + 1);
backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
- res = createResources();
+ setUpResources();
ddc = new DdcBuilder().setAutoBrightnessLevels(backlight).build();
- strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
- mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(mContext, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ /* displayWhiteBalanceController= */ null);
assertNull(strategy);
// Extra nits level
final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length + 1);
nits[nits.length - 1] = nits[nits.length - 2] + 1;
- res = createResources();
+ setUpResources();
ddc = new DdcBuilder().setAutoBrightnessLevelsNits(nits)
.setAutoBrightnessLevels(EMPTY_FLOAT_ARRAY).build();
- strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
- mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(mContext, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ /* displayWhiteBalanceController= */ null);
assertNull(strategy);
}
@Test
public void testPhysicalStrategyRequiresNitsMapping() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setNitsRange(EMPTY_FLOAT_ARRAY).build();
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertNull(physical);
}
@Test
public void testStrategiesAdaptToUserDataPoint() {
- Resources res = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setBrightnessRange(BACKLIGHT_RANGE_ZERO_TO_ONE)
.setAutoBrightnessLevelsNits(DISPLAY_LEVELS_NITS).build();
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc));
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null));
ddc = new DdcBuilder().setBrightnessRange(BACKLIGHT_RANGE_ZERO_TO_ONE)
.setAutoBrightnessLevels(DISPLAY_LEVELS).build();
- res = createResources();
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc));
+ setUpResources();
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null));
}
@Test
public void testIdleModeConfigLoadsCorrectly() {
- Resources res = createResources(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE);
+ setUpResources(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE);
DisplayDeviceConfig ddc = new DdcBuilder().setBrightnessRange(BACKLIGHT_RANGE_ZERO_TO_ONE)
.build();
// Create an idle mode bms
// This will fail if it tries to fetch the wrong configuration.
- BrightnessMappingStrategy bms = BrightnessMappingStrategy.create(res, ddc,
+ BrightnessMappingStrategy bms = BrightnessMappingStrategy.create(mContext, ddc,
AUTO_BRIGHTNESS_MODE_IDLE,
- mMockDwbc);
+ /* displayWhiteBalanceController= */ null);
assertNotNull("BrightnessMappingStrategy should not be null", bms);
// Ensure that the config is the one we set
@@ -500,36 +510,31 @@ public class BrightnessMappingStrategyTest {
assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.0001f /*tolerance*/);
}
- private Resources createResources() {
- return createResources(EMPTY_INT_ARRAY, EMPTY_FLOAT_ARRAY);
+ private void setUpResources() {
+ setUpResources(EMPTY_INT_ARRAY, EMPTY_FLOAT_ARRAY);
}
- private Resources createResources(int[] luxLevelsIdle, float[] brightnessLevelsNitsIdle) {
-
- Resources mockResources = mock(Resources.class);
+ private void setUpResources(int[] luxLevelsIdle, float[] brightnessLevelsNitsIdle) {
if (luxLevelsIdle.length > 0) {
int[] luxLevelsIdleResource = Arrays.copyOfRange(luxLevelsIdle, 1,
luxLevelsIdle.length);
- when(mockResources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLevelsIdle))
- .thenReturn(luxLevelsIdleResource);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_autoBrightnessLevelsIdle,
+ luxLevelsIdleResource);
}
TypedArray mockBrightnessLevelNitsIdle = createFloatTypedArray(brightnessLevelsNitsIdle);
- when(mockResources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle))
- .thenReturn(mockBrightnessLevelNitsIdle);
-
- when(mockResources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessSettingMinimum))
- .thenReturn(1);
- when(mockResources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessSettingMaximum))
- .thenReturn(255);
- when(mockResources.getFraction(
- com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma, 1, 1))
- .thenReturn(MAXIMUM_GAMMA);
- return mockResources;
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle,
+ mockBrightnessLevelNitsIdle);
+
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum, 1);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_screenBrightnessSettingMaximum, 255);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
+ MAXIMUM_GAMMA);
}
private TypedArray createFloatTypedArray(float[] vals) {
@@ -570,11 +575,11 @@ public class BrightnessMappingStrategyTest {
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
- Resources resources = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(GAMMA_CORRECTION_LUX)
.setAutoBrightnessLevelsNits(GAMMA_CORRECTION_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
// Let's start with a validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -600,11 +605,11 @@ public class BrightnessMappingStrategyTest {
final float y1 = GAMMA_CORRECTION_SPLINE.interpolate(x1);
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
- Resources resources = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(GAMMA_CORRECTION_LUX)
.setAutoBrightnessLevelsNits(GAMMA_CORRECTION_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
// Validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -627,11 +632,11 @@ public class BrightnessMappingStrategyTest {
public void testGammaCorrectionExtremeChangeAtCenter() {
// Extreme changes (e.g. setting brightness to 0.0 or 1.0) can't be gamma corrected, so we
// just make sure the adjustment reflects the change.
- Resources resources = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(GAMMA_CORRECTION_LUX)
.setAutoBrightnessLevelsNits(GAMMA_CORRECTION_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 1.0f);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
@@ -650,11 +655,11 @@ public class BrightnessMappingStrategyTest {
final float y0 = GAMMA_CORRECTION_SPLINE.interpolate(x0);
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y4 = GAMMA_CORRECTION_SPLINE.interpolate(x4);
- Resources resources = createResources();
+ setUpResources();
DisplayDeviceConfig ddc = new DdcBuilder().setAutoBrightnessLevelsLux(GAMMA_CORRECTION_LUX)
.setAutoBrightnessLevelsNits(GAMMA_CORRECTION_NITS).build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, /* displayWhiteBalanceController= */ null);
// Validity, as per tradition:
assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -679,15 +684,33 @@ public class BrightnessMappingStrategyTest {
@Test
public void testGetMode() {
- Resources res = createResources(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE);
+ setUpResources(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE);
DisplayDeviceConfig ddc = new DdcBuilder().setBrightnessRange(BACKLIGHT_RANGE_ZERO_TO_ONE)
.build();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
- AUTO_BRIGHTNESS_MODE_IDLE,
- mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(mContext, ddc,
+ AUTO_BRIGHTNESS_MODE_IDLE, /* displayWhiteBalanceController= */ null);
assertEquals(AUTO_BRIGHTNESS_MODE_IDLE, strategy.getMode());
}
+ @Test
+ public void testAutoBrightnessModeAndPreset() {
+ int mode = AUTO_BRIGHTNESS_MODE_DOZE;
+ int preset = Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM;
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, preset);
+
+ setUpResources();
+ DisplayDeviceConfig ddc = new DdcBuilder()
+ .setAutoBrightnessLevels(mode, preset, DISPLAY_LEVELS)
+ .setAutoBrightnessLevelsLux(mode, preset, LUX_LEVELS).build();
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(mContext, ddc, mode,
+ /* displayWhiteBalanceController= */ null);
+ assertNotNull("BrightnessMappingStrategy should not be null", simple);
+ for (int i = 0; i < LUX_LEVELS.length; i++) {
+ assertEquals(DISPLAY_LEVELS[i], simple.getBrightness(LUX_LEVELS[i]), TOLERANCE);
+ }
+ }
+
private static class DdcBuilder {
private DisplayDeviceConfig mDdc;
@@ -695,10 +718,11 @@ public class BrightnessMappingStrategyTest {
mDdc = mock(DisplayDeviceConfig.class);
when(mDdc.getNits()).thenReturn(DISPLAY_RANGE_NITS);
when(mDdc.getBrightness()).thenReturn(DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT);
- when(mDdc.getAutoBrightnessBrighteningLevelsLux(AUTO_BRIGHTNESS_MODE_DEFAULT))
- .thenReturn(LUX_LEVELS);
+ when(mDdc.getAutoBrightnessBrighteningLevelsLux(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL)).thenReturn(LUX_LEVELS);
when(mDdc.getAutoBrightnessBrighteningLevelsNits()).thenReturn(EMPTY_FLOAT_ARRAY);
- when(mDdc.getAutoBrightnessBrighteningLevels(AUTO_BRIGHTNESS_MODE_DEFAULT))
+ when(mDdc.getAutoBrightnessBrighteningLevels(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL))
.thenReturn(EMPTY_FLOAT_ARRAY);
}
@@ -713,8 +737,15 @@ public class BrightnessMappingStrategyTest {
}
DdcBuilder setAutoBrightnessLevelsLux(float[] luxLevels) {
- when(mDdc.getAutoBrightnessBrighteningLevelsLux(AUTO_BRIGHTNESS_MODE_DEFAULT))
- .thenReturn(luxLevels);
+ when(mDdc.getAutoBrightnessBrighteningLevelsLux(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL)).thenReturn(luxLevels);
+ return this;
+ }
+
+ DdcBuilder setAutoBrightnessLevelsLux(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset,
+ float[] luxLevels) {
+ when(mDdc.getAutoBrightnessBrighteningLevelsLux(mode, preset)).thenReturn(luxLevels);
return this;
}
@@ -724,7 +755,16 @@ public class BrightnessMappingStrategyTest {
}
DdcBuilder setAutoBrightnessLevels(float[] brightnessLevels) {
- when(mDdc.getAutoBrightnessBrighteningLevels(AUTO_BRIGHTNESS_MODE_DEFAULT))
+ when(mDdc.getAutoBrightnessBrighteningLevels(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL))
+ .thenReturn(brightnessLevels);
+ return this;
+ }
+
+ DdcBuilder setAutoBrightnessLevels(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset,
+ float[] brightnessLevels) {
+ when(mDdc.getAutoBrightnessBrighteningLevels(mode, preset))
.thenReturn(brightnessLevels);
return this;
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 61c60765c966..7a84406f1b08 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import static com.android.internal.display.BrightnessSynchronizer.brightnessIntToFloat;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
import static com.android.server.display.config.SensorData.SupportedMode;
import static com.android.server.display.utils.DeviceConfigParsingUtils.ambientBrightnessThresholdsIntToFloat;
import static com.android.server.display.utils.DeviceConfigParsingUtils.displayBrightnessThresholdsIntToFloat;
@@ -41,6 +42,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.display.DisplayManagerInternal;
import android.os.Temperature;
+import android.provider.Settings;
import android.util.SparseArray;
import android.util.Spline;
import android.view.SurfaceControl;
@@ -609,10 +611,12 @@ public final class DisplayDeviceConfigTest {
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(),
new float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA);
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
- AUTO_BRIGHTNESS_MODE_DEFAULT), new float[]{0.0f, 110.0f, 500.0f}, ZERO_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL),
+ new float[]{0.0f, 110.0f, 500.0f}, ZERO_DELTA);
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
- AUTO_BRIGHTNESS_MODE_DEFAULT), new float[]{brightnessIntToFloat(50),
- brightnessIntToFloat(100), brightnessIntToFloat(150)}, SMALL_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL),
+ new float[]{brightnessIntToFloat(50), brightnessIntToFloat(100),
+ brightnessIntToFloat(150)}, SMALL_DELTA);
// Test thresholds
assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(), ZERO_DELTA);
@@ -739,31 +743,39 @@ public final class DisplayDeviceConfigTest {
assertArrayEquals(new float[]{0.0f, 80},
mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
- AUTO_BRIGHTNESS_MODE_DEFAULT), ZERO_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), ZERO_DELTA);
assertArrayEquals(new float[]{0.2f, 0.3f},
mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
- AUTO_BRIGHTNESS_MODE_DEFAULT), SMALL_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), SMALL_DELTA);
assertArrayEquals(new float[]{0.0f, 90},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux("default", "dim"),
- ZERO_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM), ZERO_DELTA);
assertArrayEquals(new float[]{0.3f, 0.4f},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels("default", "dim"),
- SMALL_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM), SMALL_DELTA);
assertArrayEquals(new float[]{0.0f, 95},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux("doze", "normal"),
- ZERO_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
+ AUTO_BRIGHTNESS_MODE_DOZE,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), ZERO_DELTA);
assertArrayEquals(new float[]{0.35f, 0.45f},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels("doze", "normal"),
- SMALL_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
+ AUTO_BRIGHTNESS_MODE_DOZE,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), SMALL_DELTA);
assertArrayEquals(new float[]{0.0f, 100},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux("doze", "bright"),
- ZERO_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
+ AUTO_BRIGHTNESS_MODE_DOZE,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT), ZERO_DELTA);
assertArrayEquals(new float[]{0.4f, 0.5f},
- mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels("doze", "bright"),
- SMALL_DELTA);
+ mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
+ AUTO_BRIGHTNESS_MODE_DOZE,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT), SMALL_DELTA);
}
@Test
@@ -776,10 +788,12 @@ public final class DisplayDeviceConfigTest {
assertArrayEquals(new float[]{brightnessIntToFloat(50), brightnessIntToFloat(100),
brightnessIntToFloat(150)},
mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(
- AUTO_BRIGHTNESS_MODE_DEFAULT), SMALL_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), SMALL_DELTA);
assertArrayEquals(new float[]{0, 110, 500},
mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(
- AUTO_BRIGHTNESS_MODE_DEFAULT), ZERO_DELTA);
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL), ZERO_DELTA);
assertArrayEquals(new float[]{2, 200, 600},
mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), SMALL_DELTA);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index ffdc8b431c39..7a708487293e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -775,7 +775,7 @@ public final class DisplayPowerController2Test {
final float hdrBrightness = 0.3f;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
- when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+ when(mHolder.automaticBrightnessController.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE);
when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
any(BrightnessEvent.class))).thenReturn(sdrBrightness);
when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(1.0f);
@@ -1234,7 +1234,7 @@ public final class DisplayPowerController2Test {
float brightness = 0.6f;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
- when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+ when(mHolder.automaticBrightnessController.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE);
when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
any(BrightnessEvent.class))).thenReturn(brightness);
@@ -1597,7 +1597,7 @@ public final class DisplayPowerController2Test {
public void testDoesNotSwitchFromIdleToDozeAutoBrightnessMode() {
when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
- when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+ when(mHolder.automaticBrightnessController.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -1905,7 +1905,7 @@ public final class DisplayPowerController2Test {
}
@Override
- BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return mBrightnessMappingStrategy;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 64cdac464720..d69c140716f3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1164,7 +1164,7 @@ public final class DisplayPowerControllerTest {
float brightness = 0.6f;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
- when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+ when(mHolder.automaticBrightnessController.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE);
when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
any(BrightnessEvent.class))).thenReturn(brightness);
@@ -1669,7 +1669,7 @@ public final class DisplayPowerControllerTest {
}
@Override
- BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return mBrightnessMappingStrategy;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
index a63d01b6225a..e7da26ea38b1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
@@ -456,6 +456,14 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
}
@Test
+ public void avbEnabled_standby_avbDisabled() {
+ enableAbsoluteVolumeBehavior();
+ mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
+ assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ }
+
+ @Test
public void avbEnabled_cecVolumeDisabled_avbDisabled() {
enableAbsoluteVolumeBehavior();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a0e49a616a28..884ea31504bc 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -13616,7 +13616,31 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
- public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy() throws RemoteException {
+ public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy()
+ throws RemoteException {
+ setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
+ AssociationRequest.DEVICE_PROFILE_WATCH, true);
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy()
+ throws RemoteException {
+ setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
+ AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy()
+ throws RemoteException {
+ setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
+ AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
+ }
+
+ private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
+ @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
+ throws RemoteException {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
@@ -13626,14 +13650,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mCompanionMgr.getAssociations(anyString(), anyInt()))
.thenReturn(ImmutableList.of(
new AssociationInfo.Builder(1, mUserId, "package")
- .setDisplayName("My watch")
- .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .setDisplayName("My connected device")
+ .setDeviceProfile(deviceProfile)
.build()));
NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
mBinderService.setNotificationPolicy("package", policy, false);
- verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt());
+ if (canSetGlobalPolicy) {
+ verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt());
+ } else {
+ verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(anyString(), anyInt(),
+ eq(policy), anyInt());
+ }
}
@Test
@@ -13703,7 +13732,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
- public void setInterruptionFilter_watchCompanionApp_setsGlobalPolicy() throws RemoteException {
+ public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException {
+ setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
+ AssociationRequest.DEVICE_PROFILE_WATCH, true);
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException {
+ setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
+ AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen()
+ throws RemoteException {
+ setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
+ AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
+ }
+
+ private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
+ @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
+ throws RemoteException {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
@@ -13713,14 +13764,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mCompanionMgr.getAssociations(anyString(), anyInt()))
.thenReturn(ImmutableList.of(
new AssociationInfo.Builder(1, mUserId, "package")
- .setDisplayName("My watch")
- .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .setDisplayName("My connected device")
+ .setDeviceProfile(deviceProfile)
.build()));
mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
- verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
- eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), eq("package"), anyInt());
+ if (canSetGlobalPolicy) {
+ verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
+ eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), eq("package"), anyInt());
+ } else {
+ verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(anyString(), anyInt(),
+ eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
+ }
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 85c6f9e9b2fe..718c59875c1a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -202,8 +202,7 @@ public class ActivityRecordTests extends WindowTestsBase {
}
private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
- return new TestStartingWindowOrganizer(mAtm,
- mSystemServicesTestRule.getPowerManagerWrapper());
+ return new TestStartingWindowOrganizer(mAtm);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 51f0404e2396..8cd9ff359111 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -134,7 +134,6 @@ public class SystemServicesTestRule implements TestRule {
private StaticMockitoSession mMockitoSession;
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
- private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
private Runnable mOnBeforeServicesCreated;
@@ -360,7 +359,6 @@ public class SystemServicesTestRule implements TestRule {
}
private void setUpWindowManagerService() {
- mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
TestWindowManagerPolicy wmPolicy = new TestWindowManagerPolicy();
TestDisplayWindowSettingsProvider testDisplayWindowSettingsProvider =
new TestDisplayWindowSettingsProvider();
@@ -485,10 +483,6 @@ public class SystemServicesTestRule implements TestRule {
return mAtmService;
}
- WindowState.PowerManagerWrapper getPowerManagerWrapper() {
- return mPowerManagerWrapper;
- }
-
/** Creates a no-op wakelock object. */
PowerManager.WakeLock createStubbedWakeLock(boolean needVerification) {
if (needVerification) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 2007f680f1ae..75e252f9a415 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -52,7 +52,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -368,28 +367,26 @@ public class WindowStateTests extends WindowTestsBase {
firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
- final WindowState.PowerManagerWrapper powerManagerWrapper =
- mSystemServicesTestRule.getPowerManagerWrapper();
- reset(powerManagerWrapper);
+ final var powerManager = mWm.mPowerManager;
+ clearInvocations(powerManager);
firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManager).wakeUp(anyLong(), anyInt(), anyString());
- reset(powerManagerWrapper);
+ clearInvocations(powerManager);
secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManager).wakeUp(anyLong(), anyInt(), anyString());
}
private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow,
boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) {
- final WindowState.PowerManagerWrapper powerManagerWrapper =
- mSystemServicesTestRule.getPowerManagerWrapper();
- reset(powerManagerWrapper);
+ final var powerManager = mWm.mPowerManager;
+ clearInvocations(powerManager);
appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */);
if (expectedWakeupCalled) {
- verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManager).wakeUp(anyLong(), anyInt(), anyString());
} else {
- verify(powerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
+ verify(powerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
}
// If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false
// because the state will be consumed.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 616a23e7ab5b..a5f6190f2d51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -637,14 +637,12 @@ class WindowTestsBase extends SystemServiceTestsBase {
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow, IWindow iwindow) {
return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId),
- ownerCanAddInternalSystemWindow, mWm, getTestSession(token), iwindow,
- mSystemServicesTestRule.getPowerManagerWrapper());
+ ownerCanAddInternalSystemWindow, mWm, getTestSession(token), iwindow);
}
static WindowState createWindow(WindowState parent, int type, WindowToken token,
String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow,
- WindowManagerService service, Session session, IWindow iWindow,
- WindowState.PowerManagerWrapper powerManagerWrapper) {
+ WindowManagerService service, Session session, IWindow iWindow) {
SystemServicesTestRule.checkHoldsLock(service.mGlobalLock);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
@@ -652,9 +650,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
attrs.packageName = "test";
final WindowState w = new WindowState(service, session, iWindow, token, parent,
- OP_NONE, attrs, VISIBLE, ownerId, userId,
- ownerCanAddInternalSystemWindow,
- powerManagerWrapper);
+ OP_NONE, attrs, VISIBLE, ownerId, userId, ownerCanAddInternalSystemWindow);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
// adding it to the token...
token.addWindow(w);
@@ -1738,17 +1734,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
static class TestStartingWindowOrganizer extends WindowOrganizerTests.StubOrganizer {
private final ActivityTaskManagerService mAtm;
private final WindowManagerService mWMService;
- private final WindowState.PowerManagerWrapper mPowerManagerWrapper;
private Runnable mRunnableWhenAddingSplashScreen;
private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>();
private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>();
- TestStartingWindowOrganizer(ActivityTaskManagerService service,
- WindowState.PowerManagerWrapper powerManagerWrapper) {
+ TestStartingWindowOrganizer(ActivityTaskManagerService service) {
mAtm = service;
mWMService = mAtm.mWindowManager;
- mPowerManagerWrapper = powerManagerWrapper;
mAtm.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer(Runnable::run);
mAtm.mTaskOrganizerController.registerTaskOrganizer(this);
}
@@ -1767,8 +1760,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
final WindowState window = WindowTestsBase.createWindow(null,
TYPE_APPLICATION_STARTING, activity,
"Starting window", 0 /* ownerId */, 0 /* userId*/,
- false /* internalWindows */, mWMService, createTestSession(mAtm), iWindow,
- mPowerManagerWrapper);
+ false /* internalWindows */, mWMService, createTestSession(mAtm), iWindow);
activity.mStartingWindow = window;
mAppWindowMap.put(info.appToken, window);
mTaskAppMap.put(info.taskInfo.taskId, info.appToken);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d38e3217852d..c7b84a3b9530 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3721,19 +3721,19 @@ public class CarrierConfigManager {
* This configuration allows the system UI to display different 5G icons for different 5G
* scenarios.
*
- * There are five 5G scenarios:
- * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
- * millimeter wave.
- * 2. connected: device currently connected to 5G cell as the secondary cell but not using
- * millimeter wave.
- * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability(not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in IDLE state.
- * 4. not_restricted_rrc_con: device camped on a network that has 5G capability(not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in CONNECTED state.
- * 5. restricted: device camped on a network that has 5G capability(not necessary to connect a
- * 5G cell as a secondary cell) but the use of 5G is restricted.
+ * There are six 5G scenarios for icon configuration:
+ * 1. connected_mmwave: device currently connected to 5G cell as the primary or secondary cell
+ * and considered NR advanced.
+ * 2. connected: device currently connected to 5G cell as the primary or secondary cell but not
+ * considered NR advanced.
+ * 3. connected_rrc_idle: device currently connected to 5G cell as the primary or secondary cell
+ * and RRC currently in IDLE state.
+ * 4. not_restricted_rrc_idle: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in IDLE state.
+ * 5. not_restricted_rrc_con: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in CONNECTED state.
+ * 6. restricted: device camped on a network that has 5G capability but the use of 5G is
+ * restricted.
*
* The configured string contains multiple key-value pairs separated by comma. For each pair,
* the key and value are separated by a colon. The key corresponds to a 5G status above and
@@ -3754,21 +3754,21 @@ public class CarrierConfigManager {
* This configuration allows the system UI to determine how long to continue to display 5G icons
* when the device switches between different 5G scenarios.
*
- * There are seven 5G scenarios:
- * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
- * millimeter wave.
- * 2. connected: device currently connected to 5G cell as the secondary cell but not using
- * millimeter wave.
- * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability (not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in IDLE state.
- * 4. not_restricted_rrc_con: device camped on a network that has 5G capability (not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in CONNECTED state.
- * 5. restricted: device camped on a network that has 5G capability (not necessary to connect a
- * 5G cell as a secondary cell) but the use of 5G is restricted.
- * 6. legacy: device is not camped on a network that has 5G capability
- * 7. any: any of the above scenarios
+ * There are eight 5G scenarios:
+ * 1. connected_mmwave: device currently connected to 5G cell as the primary or secondary cell
+ * and considered NR advanced.
+ * 2. connected: device currently connected to 5G cell as the primary or secondary cell but not
+ * considered NR advanced.
+ * 3. connected_rrc_idle: device currently connected to 5G cell as the primary or secondary cell
+ * and RRC currently in IDLE state.
+ * 4. not_restricted_rrc_idle: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in IDLE state.
+ * 5. not_restricted_rrc_con: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in CONNECTED state.
+ * 6. restricted: device camped on a network that has 5G capability but the use of 5G is
+ * restricted.
+ * 7. legacy: device is not camped on a network that has 5G capability
+ * 8. any: any of the above scenarios
*
* The configured string contains various timer rules separated by a semicolon.
* Each rule will have three items: prior 5G scenario, current 5G scenario, and grace period
@@ -3776,8 +3776,8 @@ public class CarrierConfigManager {
* 5G scenario, the system UI will continue to show the icon for the prior 5G scenario (defined
* in {@link #KEY_5G_ICON_CONFIGURATION_STRING}) for the amount of time specified by the grace
* period. If the prior 5G scenario is reestablished, the timer will reset and start again if
- * the UE changes 5G scenarios again. Defined states (5G scenarios #1-5) take precedence over
- * 'any' (5G scenario #6), and unspecified transitions have a default grace period of 0.
+ * the UE changes 5G scenarios again. Defined states (5G scenarios #1-7) take precedence over
+ * 'any' (5G scenario #8), and unspecified transitions have a default grace period of 0.
* The order of rules in the configuration determines the priority (the first applicable timer
* rule will be used).
*
@@ -3800,21 +3800,21 @@ public class CarrierConfigManager {
* This configuration extends {@link #KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING} to allow the
* system UI to continue displaying 5G icons after the initial timer expires.
*
- * There are seven 5G scenarios:
- * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
- * millimeter wave.
- * 2. connected: device currently connected to 5G cell as the secondary cell but not using
- * millimeter wave.
- * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability (not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in IDLE state.
- * 4. not_restricted_rrc_con: device camped on a network that has 5G capability (not necessary
- * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
- * currently in CONNECTED state.
- * 5. restricted: device camped on a network that has 5G capability (not necessary to connect a
- * 5G cell as a secondary cell) but the use of 5G is restricted.
- * 6. legacy: device is not camped on a network that has 5G capability
- * 7. any: any of the above scenarios
+ * There are eight 5G scenarios:
+ * 1. connected_mmwave: device currently connected to 5G cell as the primary or secondary cell
+ * and considered NR advanced.
+ * 2. connected: device currently connected to 5G cell as the primary or secondary cell but not
+ * considered NR advanced.
+ * 3. connected_rrc_idle: device currently connected to 5G cell as the primary or secondary cell
+ * and RRC currently in IDLE state.
+ * 4. not_restricted_rrc_idle: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in IDLE state.
+ * 5. not_restricted_rrc_con: device camped on a network that has 5G capability and the use of
+ * 5G is not restricted and RRC currently in CONNECTED state.
+ * 6. restricted: device camped on a network that has 5G capability but the use of 5G is
+ * restricted.
+ * 7. legacy: device is not camped on a network that has 5G capability
+ * 8. any: any of the above scenarios
*
* The configured string contains various timer rules separated by a semicolon.
* Each rule will have three items: primary 5G scenario, secondary 5G scenario, and
@@ -3824,7 +3824,7 @@ public class CarrierConfigManager {
* period. If the primary 5G scenario is reestablished, the timers will reset and the system UI
* will continue to display the icon for the primary 5G scenario without interruption. If the
* secondary 5G scenario is lost, the timer will reset and the icon will reflect the true state.
- * Defined states (5G scenarios #1-5) take precedence over 'any' (5G scenario #6), and
+ * Defined states (5G scenarios #1-7) take precedence over 'any' (5G scenario #8), and
* unspecified transitions have a default grace period of 0. The order of rules in the
* configuration determines the priority (the first applicable timer rule will be used).
*
@@ -10608,7 +10608,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_USE_CALL_WAITING_USSD_BOOL, false);
sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
- "connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G,"
+ "connected_mmwave:5G,connected:5G,connected_rrc_idle:5G,not_restricted_rrc_idle:5G,"
+ "not_restricted_rrc_con:5G");
sDefaults.putString(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "");
sDefaults.putString(KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "");
diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
new file mode 100644
index 000000000000..61d7ead67a21
--- /dev/null
+++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * A single occurrence capturing a notable change to previously reported
+ * cryptography algorithms for a given network and network event.
+ *
+ * @hide
+ */
+public final class SecurityAlgorithmUpdate implements Parcelable {
+ private static final String TAG = "SecurityAlgorithmUpdate";
+
+ private @ConnectionEvent int mConnectionEvent;
+ private @SecurityAlgorithm int mEncryption;
+ private @SecurityAlgorithm int mIntegrity;
+ private boolean mIsUnprotectedEmergency;
+
+ public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent,
+ @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity,
+ boolean isUnprotectedEmergency) {
+ mConnectionEvent = connectionEvent;
+ mEncryption = encryption;
+ mIntegrity = integrity;
+ mIsUnprotectedEmergency = isUnprotectedEmergency;
+ }
+
+ private SecurityAlgorithmUpdate(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public @ConnectionEvent int getConnectionEvent() {
+ return mConnectionEvent;
+ }
+
+ public @SecurityAlgorithm int getEncryption() {
+ return mEncryption;
+ }
+
+ public @SecurityAlgorithm int getIntegrity() {
+ return mIntegrity;
+ }
+
+ public boolean isUnprotectedEmergency() {
+ return mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mConnectionEvent);
+ out.writeInt(mEncryption);
+ out.writeInt(mIntegrity);
+ out.writeBoolean(mIsUnprotectedEmergency);
+ }
+
+ private void readFromParcel(@NonNull Parcel in) {
+ mConnectionEvent = in.readInt();
+ mEncryption = in.readInt();
+ mIntegrity = in.readInt();
+ mIsUnprotectedEmergency = in.readBoolean();
+ }
+
+ public static final Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR =
+ new Parcelable.Creator<SecurityAlgorithmUpdate>() {
+ public SecurityAlgorithmUpdate createFromParcel(Parcel in) {
+ return new SecurityAlgorithmUpdate(in);
+ }
+
+ public SecurityAlgorithmUpdate[] newArray(int size) {
+ return new SecurityAlgorithmUpdate[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return TAG + ":{ mConnectionEvent = " + mConnectionEvent + " mEncryption = " + mEncryption
+ + " mIntegrity = " + mIntegrity + " mIsUnprotectedEmergency = "
+ + mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SecurityAlgorithmUpdate)) return false;
+ SecurityAlgorithmUpdate that = (SecurityAlgorithmUpdate) o;
+ return mConnectionEvent == that.mConnectionEvent
+ && mEncryption == that.mEncryption
+ && mIntegrity == that.mIntegrity
+ && mIsUnprotectedEmergency == that.mIsUnprotectedEmergency;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency);
+ }
+
+ public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0;
+ public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1;
+ public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2;
+ public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3;
+ public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4;
+ public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5;
+ public static final int CONNECTION_EVENT_VOLTE_SIP = 6;
+ public static final int CONNECTION_EVENT_VOLTE_RTP = 7;
+ public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 8;
+ public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 9;
+ public static final int CONNECTION_EVENT_VONR_SIP = 10;
+ public static final int CONNECTION_EVENT_VONR_RTP = 11;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {CONNECTION_EVENT_CS_SIGNALLING_GSM,
+ CONNECTION_EVENT_PS_SIGNALLING_GPRS, CONNECTION_EVENT_CS_SIGNALLING_3G,
+ CONNECTION_EVENT_PS_SIGNALLING_3G, CONNECTION_EVENT_NAS_SIGNALLING_LTE,
+ CONNECTION_EVENT_AS_SIGNALLING_LTE, CONNECTION_EVENT_VOLTE_SIP,
+ CONNECTION_EVENT_VOLTE_RTP, CONNECTION_EVENT_NAS_SIGNALLING_5G,
+ CONNECTION_EVENT_AS_SIGNALLING_5G, CONNECTION_EVENT_VONR_SIP,
+ CONNECTION_EVENT_VONR_RTP})
+ public @interface ConnectionEvent {
+ }
+
+ public static final int SECURITY_ALGORITHM_A50 = 0;
+ public static final int SECURITY_ALGORITHM_A51 = 1;
+ public static final int SECURITY_ALGORITHM_A52 = 2;
+ public static final int SECURITY_ALGORITHM_A53 = 3;
+ public static final int SECURITY_ALGORITHM_A54 = 4;
+ public static final int SECURITY_ALGORITHM_GEA0 = 14;
+ public static final int SECURITY_ALGORITHM_GEA1 = 15;
+ public static final int SECURITY_ALGORITHM_GEA2 = 16;
+ public static final int SECURITY_ALGORITHM_GEA3 = 17;
+ public static final int SECURITY_ALGORITHM_GEA4 = 18;
+ public static final int SECURITY_ALGORITHM_GEA5 = 19;
+ public static final int SECURITY_ALGORITHM_UEA0 = 29;
+ public static final int SECURITY_ALGORITHM_UEA1 = 30;
+ public static final int SECURITY_ALGORITHM_UEA2 = 31;
+ public static final int SECURITY_ALGORITHM_EEA0 = 41;
+ public static final int SECURITY_ALGORITHM_EEA1 = 42;
+ public static final int SECURITY_ALGORITHM_EEA2 = 43;
+ public static final int SECURITY_ALGORITHM_EEA3 = 44;
+ public static final int SECURITY_ALGORITHM_NEA0 = 55;
+ public static final int SECURITY_ALGORITHM_NEA1 = 56;
+ public static final int SECURITY_ALGORITHM_NEA2 = 57;
+ public static final int SECURITY_ALGORITHM_NEA3 = 58;
+ public static final int SECURITY_ALGORITHM_SIP_NULL = 68;
+ public static final int SECURITY_ALGORITHM_AES_GCM = 69;
+ public static final int SECURITY_ALGORITHM_AES_GMAC = 70;
+ public static final int SECURITY_ALGORITHM_AES_CBC = 71;
+ public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72;
+ public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73;
+ public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74;
+ public static final int SECURITY_ALGORITHM_HMAC_SHA1_96_NULL = 75;
+ public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 76;
+ public static final int SECURITY_ALGORITHM_HMAC_MD5_96_NULL = 77;
+ public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87;
+ public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88;
+ public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89;
+ public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99;
+ public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100;
+ public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101;
+ public static final int SECURITY_ALGORITHM_UNKNOWN = 113;
+ public static final int SECURITY_ALGORITHM_OTHER = 114;
+ public static final int SECURITY_ALGORITHM_ORYX = 124;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {SECURITY_ALGORITHM_A50, SECURITY_ALGORITHM_A51,
+ SECURITY_ALGORITHM_A52, SECURITY_ALGORITHM_A53,
+ SECURITY_ALGORITHM_A54, SECURITY_ALGORITHM_GEA0, SECURITY_ALGORITHM_GEA1,
+ SECURITY_ALGORITHM_GEA2, SECURITY_ALGORITHM_GEA3, SECURITY_ALGORITHM_GEA4,
+ SECURITY_ALGORITHM_GEA5, SECURITY_ALGORITHM_UEA0, SECURITY_ALGORITHM_UEA1,
+ SECURITY_ALGORITHM_UEA2, SECURITY_ALGORITHM_EEA0, SECURITY_ALGORITHM_EEA1,
+ SECURITY_ALGORITHM_EEA2, SECURITY_ALGORITHM_EEA3, SECURITY_ALGORITHM_NEA0,
+ SECURITY_ALGORITHM_NEA1, SECURITY_ALGORITHM_NEA2, SECURITY_ALGORITHM_NEA3,
+ SECURITY_ALGORITHM_SIP_NULL, SECURITY_ALGORITHM_AES_GCM,
+ SECURITY_ALGORITHM_AES_GMAC, SECURITY_ALGORITHM_AES_CBC,
+ SECURITY_ALGORITHM_DES_EDE3_CBC, SECURITY_ALGORITHM_AES_EDE3_CBC,
+ SECURITY_ALGORITHM_HMAC_SHA1_96, SECURITY_ALGORITHM_HMAC_SHA1_96_NULL,
+ SECURITY_ALGORITHM_HMAC_MD5_96, SECURITY_ALGORITHM_HMAC_MD5_96_NULL,
+ SECURITY_ALGORITHM_SRTP_AES_COUNTER, SECURITY_ALGORITHM_SRTP_AES_F8,
+ SECURITY_ALGORITHM_SRTP_HMAC_SHA1, SECURITY_ALGORITHM_ENCR_AES_GCM_16,
+ SECURITY_ALGORITHM_ENCR_AES_CBC, SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128,
+ SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_OTHER, SECURITY_ALGORITHM_ORYX})
+ public @interface SecurityAlgorithm {
+ }
+
+}