Merge "Implement screenshot smart actions with new action provider" into main
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8913d6d..e53bd39 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6982,7 +6982,7 @@
}
} else {
// No package, perhaps it was removed?
- Slog.e(TAG, "Package [" + packages[i] + "] reported as REPLACED,"
+ Slog.d(TAG, "Package [" + packages[i] + "] reported as REPLACED,"
+ " but missing application info. Assuming REMOVED.");
mPackages.remove(packages[i]);
mResourcePackages.remove(packages[i]);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 1425063..6b2baa7 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -36,13 +36,6 @@
}
flag {
- name: "cross_user_suspension_enabled"
- namespace: "enterprise"
- description: "Allow holders of INTERACT_ACROSS_USERS_FULL to suspend apps in different users."
- bug: "263464464"
-}
-
-flag {
name: "cross_user_suspension_enabled_ro"
namespace: "enterprise"
description: "Allow holders of INTERACT_ACROSS_USERS_FULL to suspend apps in different users."
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8bc5e8c..9e316a2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3771,6 +3771,10 @@
* <li><em>{@link android.content.Intent#EXTRA_PHONE_NUMBER}</em> -
* the phone number originally intended to be dialed.</li>
* </ul>
+ * <p class="note">Starting in Android 15, this broadcast is no longer sent as an ordered
+ * broadcast. The <code>resultData</code> no longer has any effect and will not determine the
+ * actual routing of the call. Further, receivers of this broadcast do not get foreground
+ * priority and cannot launch background activities.</p>
* <p>Once the broadcast is finished, the resultData is used as the actual
* number to call. If <code>null</code>, no call will be placed.</p>
* <p>It is perfectly acceptable for multiple receivers to process the
@@ -3811,8 +3815,8 @@
* {@link android.telecom.CallRedirectionService} API. Apps that perform call screening
* should use the {@link android.telecom.CallScreeningService} API. Apps which need to be
* notified of basic call state should use
- * {@link android.telephony.PhoneStateListener#onCallStateChanged(int, String)} to determine
- * when a new outgoing call is placed.
+ * {@link android.telephony.TelephonyCallback.CallStateListener} to determine when a new
+ * outgoing call is placed.
*/
@Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java
index 64fc4c2..e583627 100644
--- a/core/java/android/hardware/devicestate/DeviceState.java
+++ b/core/java/android/hardware/devicestate/DeviceState.java
@@ -399,16 +399,8 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mIdentifier);
dest.writeString8(mName);
-
- dest.writeInt(mSystemProperties.size());
- for (int i = 0; i < mSystemProperties.size(); i++) {
- dest.writeInt(mSystemProperties.valueAt(i));
- }
-
- dest.writeInt(mPhysicalProperties.size());
- for (int i = 0; i < mPhysicalProperties.size(); i++) {
- dest.writeInt(mPhysicalProperties.valueAt(i));
- }
+ dest.writeArraySet(mSystemProperties);
+ dest.writeArraySet(mPhysicalProperties);
}
@NonNull
@@ -417,16 +409,11 @@
public DeviceState.Configuration createFromParcel(Parcel source) {
int identifier = source.readInt();
String name = source.readString8();
- ArraySet<@DeviceStateProperties Integer> systemProperties = new ArraySet<>();
- int systemPropertySize = source.readInt();
- for (int i = 0; i < systemPropertySize; i++) {
- systemProperties.add(source.readInt());
- }
- ArraySet<@DeviceStateProperties Integer> physicalProperties = new ArraySet<>();
- int physicalPropertySize = source.readInt();
- for (int j = 0; j < physicalPropertySize; j++) {
- physicalProperties.add(source.readInt());
- }
+ ArraySet<@SystemDeviceStateProperties Integer> systemProperties =
+ (ArraySet<Integer>) source.readArraySet(null /* classLoader */);
+ ArraySet<@PhysicalDeviceStateProperties Integer> physicalProperties =
+ (ArraySet<Integer>) source.readArraySet(null /* classLoader */);
+
return new DeviceState.Configuration(identifier, name, systemProperties,
physicalProperties);
}
diff --git a/core/java/android/hardware/devicestate/OWNERS b/core/java/android/hardware/devicestate/OWNERS
new file mode 100644
index 0000000..d9b0e2e
--- /dev/null
+++ b/core/java/android/hardware/devicestate/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/devicestate/OWNERS
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6c6e8b2..188ad8f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -203,9 +203,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
- value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
- FRAME_RATE_COMPATIBILITY_EXACT, FRAME_RATE_COMPATIBILITY_NO_VOTE,
- FRAME_RATE_COMPATIBILITY_MIN, FRAME_RATE_COMPATIBILITY_GTE})
+ value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE})
public @interface FrameRateCompatibility {}
// From native_window.h. Keep these in sync.
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 356eac3..e6a2a6c 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3956,6 +3956,9 @@
@Override
public int getNavigationBarColor() {
+ if (mEdgeToEdgeEnforced) {
+ return Color.TRANSPARENT;
+ }
return mNavigationBarColor;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index ce8a460..0867a44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -2329,6 +2329,12 @@
mMainExecutor.execute(() ->
mController.showUserEducation(new Point(positionX, positionY)));
}
+
+ @Override
+ public void setBubbleBarLocation(BubbleBarLocation location) {
+ mMainExecutor.execute(() ->
+ mController.setBubbleBarLocation(location));
+ }
}
private class BubblesImpl implements Bubbles {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 7a5afec..16134d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.graphics.Rect;
import com.android.wm.shell.bubbles.IBubblesListener;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
/**
* Interface that is exposed to remote callers (launcher) to manipulate the bubbles feature when
@@ -42,4 +43,5 @@
oneway void showUserEducation(in int positionX, in int positionY) = 8;
+ oneway void setBubbleBarLocation(in BubbleBarLocation location) = 9;
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarLocation.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarLocation.aidl
new file mode 100644
index 0000000..3c5beeb
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarLocation.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.common.bubbles;
+
+parcelable BubbleBarLocation;
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 235456c..3b4fb9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -1069,7 +1069,7 @@
}
private boolean allAppsAreTranslucent(ArrayList<TaskState> tasks) {
- if (tasks == null || tasks.isEmpty()) {
+ if (tasks == null) {
return false;
}
for (int i = tasks.size() - 1; i >= 0; --i) {
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 2a0648d..7ed67dc 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -23,6 +23,9 @@
import android.annotation.TestApi;
import android.app.Activity;
import android.app.ActivityOptions.LaunchCookie;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.Overridable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -66,6 +69,18 @@
private static final String TAG = "MediaProjectionManager";
/**
+ * This change id ensures that users are presented with a choice of capturing a single app
+ * or the entire screen when initiating a MediaProjection session, overriding the usage of
+ * MediaProjectionConfig#createConfigForDefaultDisplay.
+ *
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION = 316897322L;
+
+ /**
* Intent extra to customize the permission dialog based on the host app's preferences.
* @hide
*/
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index af89f63..4bfc629 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -25,6 +25,13 @@
}
flag {
+ name: "notification_heads_up_cycling"
+ namespace: "systemui"
+ description: "Heads-up notification cycling animation for the Notification Avalanche feature."
+ bug: "316404716"
+}
+
+flag {
name: "notification_minimalism_prototype"
namespace: "systemui"
description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 28fd785..f6f07a5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -32,8 +32,10 @@
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -62,7 +64,10 @@
) {
OutlinedIconToggleButton(
modifier =
- Modifier.height(64.dp).fillMaxWidth().semantics { contentDescription = label },
+ Modifier.height(64.dp).fillMaxWidth().semantics {
+ role = Role.Switch
+ contentDescription = label
+ },
checked = viewModel.isChecked,
onCheckedChange = onCheckedChange,
shape = RoundedCornerShape(28.dp),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt
new file mode 100644
index 0000000..312c14d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryImplTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import android.content.applicationContext
+import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.user.data.repository.userRepository
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.PolicyRestriction
+import com.android.systemui.utils.UserRestrictionChecker
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BrightnessPolicyRepositoryImplTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private val fakeUserRepository = kosmos.fakeUserRepository
+
+ private val mockUserRestrictionChecker: UserRestrictionChecker = mock {
+ whenever(checkIfRestrictionEnforced(any(), anyString(), anyInt())).thenReturn(null)
+ whenever(hasBaseUserRestriction(any(), anyString(), anyInt())).thenReturn(false)
+ }
+
+ private val underTest =
+ with(kosmos) {
+ BrightnessPolicyRepositoryImpl(
+ userRepository,
+ mockUserRestrictionChecker,
+ applicationContext,
+ testDispatcher,
+ )
+ }
+
+ @Test
+ fun noRestrictionByDefaultForAllUsers() =
+ with(kosmos) {
+ testScope.runTest {
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.NoRestriction)
+
+ fakeUserRepository.asMainUser()
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.NoRestriction)
+ }
+ }
+
+ @Test
+ fun restrictDefaultUser() =
+ with(kosmos) {
+ testScope.runTest {
+ val enforcedAdmin: EnforcedAdmin =
+ EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(RESTRICTION)
+
+ whenever(
+ mockUserRestrictionChecker.checkIfRestrictionEnforced(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.getSelectedUserInfo().id)
+ )
+ )
+ .thenReturn(enforcedAdmin)
+
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.Restricted(enforcedAdmin))
+
+ fakeUserRepository.asMainUser()
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.NoRestriction)
+ }
+ }
+
+ @Test
+ fun restrictMainUser() =
+ with(kosmos) {
+ testScope.runTest {
+ val enforcedAdmin: EnforcedAdmin =
+ EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(RESTRICTION)
+
+ whenever(
+ mockUserRestrictionChecker.checkIfRestrictionEnforced(
+ any(),
+ eq(RESTRICTION),
+ eq(userRepository.mainUserId)
+ )
+ )
+ .thenReturn(enforcedAdmin)
+
+ val restrictions by collectLastValue(underTest.restrictionPolicy)
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.NoRestriction)
+
+ fakeUserRepository.asMainUser()
+
+ assertThat(restrictions).isEqualTo(PolicyRestriction.Restricted(enforcedAdmin))
+ }
+ }
+
+ private companion object {
+ val RESTRICTION = UserManager.DISALLOW_CONFIG_BRIGHTNESS
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
new file mode 100644
index 0000000..e39ad4f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import android.hardware.display.BrightnessInfo
+import android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE
+import android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.brightness.data.model.LinearBrightness
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ScreenBrightnessDisplayManagerRepositoryTest : SysuiTestCase() {
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ private val kosmos = testKosmos()
+
+ private var currentBrightnessInfo = BrightnessInfo()
+
+ @Mock private lateinit var displayManager: DisplayManager
+ @Mock private lateinit var display: Display
+
+ private val displayId = 0
+
+ private lateinit var underTest: ScreenBrightnessDisplayManagerRepository
+
+ @Before
+ fun setUp() {
+ underTest =
+ ScreenBrightnessDisplayManagerRepository(
+ displayId,
+ displayManager,
+ kosmos.applicationCoroutineScope,
+ kosmos.testDispatcher,
+ )
+
+ whenever(displayManager.getDisplay(displayId)).thenReturn(display)
+ // Using then answer so it will be retrieved in every call
+ whenever(display.brightnessInfo).thenAnswer { currentBrightnessInfo }
+ }
+
+ @Test
+ fun startingBrightnessInfo() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness by collectLastValue(underTest.linearBrightness)
+ val minBrightness by collectLastValue(underTest.minLinearBrightness)
+ val maxBrightness by collectLastValue(underTest.maxLinearBrightness)
+ runCurrent()
+
+ assertThat(brightness?.floatValue).isEqualTo(currentBrightnessInfo.brightness)
+ assertThat(minBrightness?.floatValue)
+ .isEqualTo(currentBrightnessInfo.brightnessMinimum)
+ assertThat(maxBrightness?.floatValue)
+ .isEqualTo(currentBrightnessInfo.brightnessMaximum)
+ }
+ }
+
+ @Test
+ fun followsChangingBrightnessInfo() =
+ with(kosmos) {
+ testScope.runTest {
+ val listenerCaptor = argumentCaptor<DisplayManager.DisplayListener>()
+
+ val brightness by collectLastValue(underTest.linearBrightness)
+ val minBrightness by collectLastValue(underTest.minLinearBrightness)
+ val maxBrightness by collectLastValue(underTest.maxLinearBrightness)
+ runCurrent()
+
+ verify(displayManager)
+ .registerDisplayListener(
+ capture(listenerCaptor),
+ eq(null),
+ eq(EVENT_FLAG_DISPLAY_BRIGHTNESS),
+ )
+
+ val newBrightness = BrightnessInfo(0.6f, 0.3f, 0.9f)
+ changeBrightnessInfoAndNotify(newBrightness, listenerCaptor.value)
+
+ assertThat(brightness?.floatValue).isEqualTo(currentBrightnessInfo.brightness)
+ assertThat(minBrightness?.floatValue)
+ .isEqualTo(currentBrightnessInfo.brightnessMinimum)
+ assertThat(maxBrightness?.floatValue)
+ .isEqualTo(currentBrightnessInfo.brightnessMaximum)
+ }
+ }
+
+ @Test
+ fun minMaxWhenNotCollecting() =
+ with(kosmos) {
+ testScope.runTest {
+ currentBrightnessInfo = BrightnessInfo(0.5f, 0.1f, 0.7f)
+ val (min, max) = underTest.getMinMaxLinearBrightness()
+ assertThat(min.floatValue).isEqualTo(currentBrightnessInfo.brightnessMinimum)
+ assertThat(max.floatValue).isEqualTo(currentBrightnessInfo.brightnessMaximum)
+ }
+ }
+
+ @Test
+ fun minMaxWhenCollecting() =
+ with(kosmos) {
+ testScope.runTest {
+ val listenerCaptor = argumentCaptor<DisplayManager.DisplayListener>()
+
+ val brightness by collectLastValue(underTest.linearBrightness)
+ runCurrent()
+
+ verify(displayManager)
+ .registerDisplayListener(
+ capture(listenerCaptor),
+ eq(null),
+ eq(EVENT_FLAG_DISPLAY_BRIGHTNESS),
+ )
+
+ changeBrightnessInfoAndNotify(
+ BrightnessInfo(0.5f, 0.1f, 0.7f),
+ listenerCaptor.value
+ )
+ runCurrent()
+
+ val (min, max) = underTest.getMinMaxLinearBrightness()
+ assertThat(min.floatValue).isEqualTo(currentBrightnessInfo.brightnessMinimum)
+ assertThat(max.floatValue).isEqualTo(currentBrightnessInfo.brightnessMaximum)
+ }
+ }
+
+ @Test
+ fun setTemporaryBrightness_insideBounds() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness = 0.3f
+ underTest.setTemporaryBrightness(LinearBrightness(brightness))
+ runCurrent()
+
+ verify(displayManager).setTemporaryBrightness(displayId, brightness)
+ verify(displayManager, never()).setBrightness(anyInt(), anyFloat())
+ }
+ }
+
+ @Test
+ fun setTemporaryBrightness_outsideBounds() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness = 1.3f
+ underTest.setTemporaryBrightness(LinearBrightness(brightness))
+ runCurrent()
+
+ verify(displayManager)
+ .setTemporaryBrightness(displayId, currentBrightnessInfo.brightnessMaximum)
+ verify(displayManager, never()).setBrightness(anyInt(), anyFloat())
+ }
+ }
+
+ @Test
+ fun setBrightness_insideBounds() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness = 0.3f
+ underTest.setBrightness(LinearBrightness(brightness))
+ runCurrent()
+
+ verify(displayManager).setBrightness(displayId, brightness)
+ verify(displayManager, never()).setTemporaryBrightness(anyInt(), anyFloat())
+ }
+ }
+
+ @Test
+ fun setBrightness_outsideBounds() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness = 1.3f
+ underTest.setBrightness(LinearBrightness(brightness))
+ runCurrent()
+
+ verify(displayManager)
+ .setBrightness(displayId, currentBrightnessInfo.brightnessMaximum)
+ verify(displayManager, never()).setTemporaryBrightness(anyInt(), anyFloat())
+ }
+ }
+
+ private fun changeBrightnessInfoAndNotify(
+ newValue: BrightnessInfo,
+ listener: DisplayManager.DisplayListener,
+ ) {
+ currentBrightnessInfo = newValue
+ listener.onDisplayChanged(displayId)
+ }
+
+ companion object {
+ fun BrightnessInfo(
+ brightness: Float = 0f,
+ minBrightness: Float = 0f,
+ maxBrightness: Float = 1f,
+ ): BrightnessInfo {
+ return BrightnessInfo(
+ brightness,
+ minBrightness,
+ maxBrightness,
+ HIGH_BRIGHTNESS_MODE_OFF,
+ 1f,
+ BRIGHTNESS_MAX_REASON_NONE,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt
new file mode 100644
index 0000000..85a4bcf
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.RestrictedLockUtils
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.brightness.data.repository.BrightnessPolicyRepository
+import com.android.systemui.brightness.data.repository.brightnessPolicyRepository
+import com.android.systemui.brightness.data.repository.fakeBrightnessPolicyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.utils.PolicyRestriction
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BrightnessPolicyEnforcementInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private val mockActivityStarter = kosmos.activityStarter
+ private val fakeBrightnessPolicyEnforcementInteractor = kosmos.fakeBrightnessPolicyRepository
+
+ private val underTest =
+ with(kosmos) {
+ BrightnessPolicyEnforcementInteractor(
+ brightnessPolicyRepository,
+ activityStarter,
+ )
+ }
+
+ @Test
+ fun restriction() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeBrightnessPolicyRepository.setCurrentUserUnrestricted()
+
+ val restriction by collectLastValue(underTest.brightnessPolicyRestriction)
+
+ assertThat(restriction).isEqualTo(PolicyRestriction.NoRestriction)
+
+ fakeBrightnessPolicyRepository.setCurrentUserRestricted()
+
+ assertThat(restriction).isInstanceOf(PolicyRestriction.Restricted::class.java)
+ }
+ }
+
+ @Test
+ fun startRestrictionDialog() =
+ with(kosmos) {
+ testScope.runTest {
+ val enforcedAdmin =
+ EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(
+ BrightnessPolicyRepository.RESTRICTION
+ )
+ .apply {
+ component = TEST_COMPONENT
+ user = UserHandle.of(TEST_USER)
+ }
+
+ underTest.startAdminSupportDetailsDialog(
+ PolicyRestriction.Restricted(enforcedAdmin)
+ )
+
+ val intentCaptor = argumentCaptor<Intent>()
+
+ verify(mockActivityStarter)
+ .postStartActivityDismissingKeyguard(
+ capture(intentCaptor),
+ eq(0),
+ )
+
+ val expectedIntent =
+ RestrictedLockUtils.getShowAdminSupportDetailsIntent(enforcedAdmin)
+
+ with(intentCaptor.value) {
+ assertThat(action).isEqualTo(expectedIntent.action)
+ assertThat(extras!!.kindofEquals(expectedIntent.extras)).isTrue()
+ }
+ }
+ }
+
+ private companion object {
+ val TEST_COMPONENT = ComponentName("pkg", ".cls")
+ val TEST_USER = 10
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt
new file mode 100644
index 0000000..33c44f8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.display.BrightnessUtils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.brightness.data.model.LinearBrightness
+import com.android.systemui.brightness.data.repository.fakeScreenBrightnessRepository
+import com.android.systemui.brightness.data.repository.screenBrightnessRepository
+import com.android.systemui.brightness.shared.GammaBrightness
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ScreenBrightnessInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private val underTest = ScreenBrightnessInteractor(kosmos.screenBrightnessRepository)
+
+ @Test
+ fun gammaBrightness() =
+ with(kosmos) {
+ testScope.runTest {
+ val gammaBrightness by collectLastValue(underTest.gammaBrightness)
+
+ val brightness = 0.3f
+ val min = 0f
+ val max = 1f
+
+ with(fakeScreenBrightnessRepository) {
+ setBrightness(LinearBrightness(brightness))
+ setMinMaxBrightness(LinearBrightness(min), LinearBrightness(max))
+ }
+ runCurrent()
+
+ assertThat(gammaBrightness?.value)
+ .isEqualTo(BrightnessUtils.convertLinearToGammaFloat(brightness, min, max))
+ }
+ }
+
+ @Test
+ fun gammaBrightness_constrained() =
+ with(kosmos) {
+ testScope.runTest {
+ val gammaBrightness by collectLastValue(underTest.gammaBrightness)
+
+ val brightness = 0.3f
+ val min = 0.2f
+ val max = 0.8f
+
+ with(fakeScreenBrightnessRepository) {
+ setBrightness(LinearBrightness(brightness))
+ setMinMaxBrightness(LinearBrightness(min), LinearBrightness(max))
+ }
+ runCurrent()
+
+ assertThat(gammaBrightness?.value)
+ .isEqualTo(BrightnessUtils.convertLinearToGammaFloat(brightness, min, max))
+ }
+ }
+
+ @Test
+ fun setTemporaryBrightness() =
+ with(kosmos) {
+ testScope.runTest {
+ val temporaryBrightness by
+ collectLastValue(fakeScreenBrightnessRepository.temporaryBrightness)
+ val brightness by collectLastValue(underTest.gammaBrightness)
+
+ val gammaBrightness = 30000
+ underTest.setTemporaryBrightness(GammaBrightness(gammaBrightness))
+
+ val (min, max) = fakeScreenBrightnessRepository.getMinMaxLinearBrightness()
+
+ val expectedTemporaryBrightness =
+ BrightnessUtils.convertGammaToLinearFloat(
+ gammaBrightness,
+ min.floatValue,
+ max.floatValue
+ )
+ assertThat(temporaryBrightness!!.floatValue)
+ .isWithin(1e-5f)
+ .of(expectedTemporaryBrightness)
+ assertThat(brightness!!.value).isNotEqualTo(gammaBrightness)
+ }
+ }
+
+ @Test
+ fun setBrightness() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness by collectLastValue(fakeScreenBrightnessRepository.linearBrightness)
+
+ val gammaBrightness = 30000
+ underTest.setBrightness(GammaBrightness(gammaBrightness))
+
+ val (min, max) = fakeScreenBrightnessRepository.getMinMaxLinearBrightness()
+
+ val expectedBrightness =
+ BrightnessUtils.convertGammaToLinearFloat(
+ gammaBrightness,
+ min.floatValue,
+ max.floatValue
+ )
+ assertThat(brightness!!.floatValue).isWithin(1e-5f).of(expectedBrightness)
+ }
+ }
+
+ @Test
+ fun maxGammaBrightness() {
+ assertThat(underTest.maxGammaBrightness)
+ .isEqualTo(GammaBrightness(BrightnessUtils.GAMMA_SPACE_MAX))
+ }
+
+ @Test
+ fun minGammaBrightness() {
+ assertThat(underTest.minGammaBrightness)
+ .isEqualTo(GammaBrightness(BrightnessUtils.GAMMA_SPACE_MIN))
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
new file mode 100644
index 0000000..0058ee4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 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.brightness.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.display.BrightnessUtils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.brightness.data.model.LinearBrightness
+import com.android.systemui.brightness.data.repository.fakeScreenBrightnessRepository
+import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforcementInteractor
+import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
+import com.android.systemui.brightness.shared.GammaBrightness
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BrightnessSliderViewModelTest : SysuiTestCase() {
+
+ private val minBrightness = 0f
+ private val maxBrightness = 1f
+
+ private val kosmos = testKosmos()
+
+ private val underTest =
+ with(kosmos) {
+ BrightnessSliderViewModel(
+ screenBrightnessInteractor,
+ brightnessPolicyEnforcementInteractor,
+ )
+ }
+
+ @Before
+ fun setUp() {
+ kosmos.fakeScreenBrightnessRepository.setMinMaxBrightness(
+ LinearBrightness(minBrightness),
+ LinearBrightness(maxBrightness)
+ )
+ }
+
+ @Test
+ fun brightnessChangeInRepository_changeInFlow() =
+ with(kosmos) {
+ testScope.runTest {
+ val gammaBrightness by collectLastValue(underTest.currentBrightness)
+
+ var brightness = 0.6f
+ fakeScreenBrightnessRepository.setBrightness(LinearBrightness(brightness))
+
+ assertThat(gammaBrightness!!.value)
+ .isEqualTo(
+ BrightnessUtils.convertLinearToGammaFloat(
+ brightness,
+ minBrightness,
+ maxBrightness
+ )
+ )
+
+ brightness = 0.2f
+ fakeScreenBrightnessRepository.setBrightness(LinearBrightness(brightness))
+
+ assertThat(gammaBrightness!!.value)
+ .isEqualTo(
+ BrightnessUtils.convertLinearToGammaFloat(
+ brightness,
+ minBrightness,
+ maxBrightness
+ )
+ )
+ }
+ }
+
+ @Test
+ fun maxGammaBrightness() {
+ assertThat(underTest.maxBrightness)
+ .isEqualTo(GammaBrightness(BrightnessUtils.GAMMA_SPACE_MAX))
+ }
+
+ @Test
+ fun minGammaBrightness() {
+ assertThat(underTest.minBrightness)
+ .isEqualTo(GammaBrightness(BrightnessUtils.GAMMA_SPACE_MIN))
+ }
+
+ @Test
+ fun dragging_temporaryBrightnessSet_currentBrightnessDoesntChange() =
+ with(kosmos) {
+ testScope.runTest {
+ val temporaryBrightness by
+ collectLastValue(fakeScreenBrightnessRepository.temporaryBrightness)
+ val brightness by collectLastValue(underTest.currentBrightness)
+
+ val newBrightness = underTest.maxBrightness.value / 3
+ val expectedTemporaryBrightness =
+ BrightnessUtils.convertGammaToLinearFloat(
+ newBrightness,
+ minBrightness,
+ maxBrightness
+ )
+ val drag = Drag.Dragging(GammaBrightness(newBrightness))
+
+ underTest.onDrag(drag)
+
+ assertThat(temporaryBrightness!!.floatValue)
+ .isWithin(1e-5f)
+ .of(expectedTemporaryBrightness)
+ assertThat(brightness!!.value).isNotEqualTo(newBrightness)
+ }
+ }
+
+ @Test
+ fun draggingStopped_currentBrightnessChanges() =
+ with(kosmos) {
+ testScope.runTest {
+ val brightness by collectLastValue(underTest.currentBrightness)
+
+ val newBrightness = underTest.maxBrightness.value / 3
+ val drag = Drag.Stopped(GammaBrightness(newBrightness))
+
+ underTest.onDrag(drag)
+
+ assertThat(brightness!!.value).isEqualTo(newBrightness)
+ }
+ }
+
+ @Test
+ fun label() {
+ assertThat(underTest.label)
+ .isEqualTo(Text.Resource(R.string.quick_settings_brightness_dialog_title))
+ }
+
+ @Test
+ fun icon() {
+ assertThat(underTest.icon)
+ .isEqualTo(
+ Icon.Resource(
+ R.drawable.ic_brightness_full,
+ ContentDescription.Resource(underTest.label.res),
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 6a86801..0f8fc38 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -63,7 +63,6 @@
import java.util.Collections;
import java.util.Optional;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@@ -119,6 +118,7 @@
private static final float TOUCH_REGION = .3f;
private static final int SCREEN_WIDTH_PX = 1024;
private static final int SCREEN_HEIGHT_PX = 100;
+ private static final float MIN_BOUNCER_HEIGHT = .05f;
private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100);
private static final UserInfo CURRENT_USER_INFO = new UserInfo(
@@ -142,6 +142,7 @@
mFlingAnimationUtils,
mFlingAnimationUtilsClosing,
TOUCH_REGION,
+ MIN_BOUNCER_HEIGHT,
mUiEventLogger);
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
@@ -160,9 +161,9 @@
*/
@Test
public void testSessionStart() {
- mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion);
+ mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, null);
- verify(mRegion).op(mRectCaptor.capture(), eq(Region.Op.UNION));
+ verify(mRegion).union(mRectCaptor.capture());
final Rect bounds = mRectCaptor.getValue();
final Rect expected = new Rect();
@@ -194,6 +195,85 @@
UP,
}
+ @Test
+ public void testSwipeUp_whenBouncerInitiallyShowing_reduceHeightWithExclusionRects() {
+ mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
+ new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX));
+ verify(mRegion).union(mRectCaptor.capture());
+ final Rect bounds = mRectCaptor.getValue();
+
+ final Rect expected = new Rect();
+ final float minBouncerHeight =
+ SCREEN_HEIGHT_PX * MIN_BOUNCER_HEIGHT;
+ final int minAllowableBottom = SCREEN_HEIGHT_PX - Math.round(minBouncerHeight);
+
+ expected.set(0, minAllowableBottom , SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);
+
+ assertThat(bounds).isEqualTo(expected);
+
+ onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
+ }
+
+ @Test
+ public void testSwipeUp_exclusionRectAtTop_doesNotIntersectGestureArea() {
+ mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
+ new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX / 4));
+ verify(mRegion).union(mRectCaptor.capture());
+ final Rect bounds = mRectCaptor.getValue();
+
+ final Rect expected = new Rect();
+ final int gestureAreaTop = SCREEN_HEIGHT_PX - Math.round(SCREEN_HEIGHT_PX * TOUCH_REGION);
+ expected.set(0, gestureAreaTop, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);
+
+ assertThat(bounds).isEqualTo(expected);
+ onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
+ }
+
+ @Test
+ public void testSwipeUp_exclusionRectBetweenNormalAndMinimumSwipeArea() {
+ final int normalSwipeAreaTop = SCREEN_HEIGHT_PX
+ - Math.round(SCREEN_HEIGHT_PX * TOUCH_REGION);
+ final int minimumSwipeAreaTop = SCREEN_HEIGHT_PX
+ - Math.round(SCREEN_HEIGHT_PX * MIN_BOUNCER_HEIGHT);
+
+ Rect exclusionRect = new Rect(0, 0, SCREEN_WIDTH_PX,
+ (normalSwipeAreaTop + minimumSwipeAreaTop) / 2);
+
+ mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, exclusionRect);
+
+ verify(mRegion).union(mRectCaptor.capture());
+
+ final Rect bounds = mRectCaptor.getValue();
+ final Rect expected = new Rect();
+
+ final int expectedSwipeAreaBottom = exclusionRect.bottom;
+ expected.set(0, expectedSwipeAreaBottom, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);
+
+ assertThat(bounds).isEqualTo(expected);
+
+ onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
+ }
+
+ private static void onSessionStartHelper(BouncerSwipeTouchHandler touchHandler,
+ DreamTouchHandler.TouchSession touchSession,
+ NotificationShadeWindowController notificationShadeWindowController) {
+ touchHandler.onSessionStart(touchSession);
+ verify(notificationShadeWindowController).setForcePluginOpen(eq(true), any());
+ ArgumentCaptor<InputChannelCompat.InputEventListener> eventListenerCaptor =
+ ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
+ ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+ ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(touchSession).registerGestureListener(gestureListenerCaptor.capture());
+ verify(touchSession).registerInputListener(eventListenerCaptor.capture());
+
+ // A touch within range at the bottom of the screen should trigger listening
+ assertThat(gestureListenerCaptor.getValue()
+ .onScroll(Mockito.mock(MotionEvent.class),
+ Mockito.mock(MotionEvent.class),
+ 1,
+ 2)).isTrue();
+ }
+
/**
* Makes sure swiping up when bouncer initially showing doesn't change the expansion amount.
*/
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 30564bb..29f286f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
@@ -47,12 +48,14 @@
@EnableFlags(NotificationThrottleHun.FLAG_NAME)
class AvalancheControllerTest : SysuiTestCase() {
- private val mAvalancheController = AvalancheController()
-
// For creating mocks
@get:Rule var rule: MockitoRule = MockitoJUnit.rule()
@Mock private val runnableMock: Runnable? = null
+ // For creating AvalancheController
+ @Mock private lateinit var dumpManager: DumpManager
+ private lateinit var mAvalancheController: AvalancheController
+
// For creating TestableHeadsUpManager
@Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
private val mUiEventLoggerFake = UiEventLoggerFake()
@@ -73,7 +76,10 @@
)
.then { i: InvocationOnMock -> i.getArgument(0) }
- // Initialize TestableHeadsUpManager here instead of at declaration, when mocks will be null
+ // Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
+ // declaration, where mocks are null
+ mAvalancheController = AvalancheController(dumpManager)
+
testableHeadsUpManager =
TestableHeadsUpManager(
mContext,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 3dc4495..7c130be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -45,6 +45,7 @@
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -73,7 +74,9 @@
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
- private AvalancheController mAvalancheController = new AvalancheController();
+
+ @Mock private DumpManager dumpManager;
+ private AvalancheController mAvalancheController;
@Mock private AccessibilityManagerWrapper mAccessibilityMgr;
@@ -130,6 +133,7 @@
public void SysuiSetup() throws Exception {
super.SysuiSetup();
mSetFlagsRule.disableFlags(NotificationThrottleHun.FLAG_NAME);
+ mAvalancheController = new AvalancheController(dumpManager);
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index 61a79d8..a8a75c0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -32,6 +32,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
@@ -76,7 +77,8 @@
@Mock private UiEventLogger mUiEventLogger;
@Mock private JavaAdapter mJavaAdapter;
@Mock private ShadeInteractor mShadeInteractor;
- private AvalancheController mAvalancheController = new AvalancheController();
+ @Mock private DumpManager dumpManager;
+ private AvalancheController mAvalancheController;
private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
TestableHeadsUpManagerPhone(
@@ -154,6 +156,8 @@
mDependency.injectMockDependency(NotificationShadeWindowController.class);
mContext.getOrCreateTestableResources().addOverride(
R.integer.ambient_notification_extension_time, 500);
+
+ mAvalancheController = new AvalancheController(dumpManager);
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
index 6f7f20b..462f36d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
@@ -35,7 +35,6 @@
import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.mediaOutputActionsInteractor
import com.android.systemui.volume.mediaOutputInteractor
-import com.android.systemui.volume.panel.volumePanelViewModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -62,7 +61,6 @@
MediaOutputViewModel(
applicationContext,
testScope.backgroundScope,
- volumePanelViewModel,
mediaOutputActionsInteractor,
mediaDeviceSessionInteractor,
mediaOutputInteractor,
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fe8f2ff..f2288a4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1867,6 +1867,10 @@
.2
</item>
+ <item name="dream_overlay_bouncer_min_region_screen_percentage" format="float" type="dimen">
+ .05
+ </item>
+
<!-- The padding applied to the dream overlay container -->
<dimen name="dream_overlay_container_padding_start">0dp</dimen>
<dimen name="dream_overlay_container_padding_end">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 893887f..d88b3dc 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -45,6 +45,7 @@
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -158,6 +159,10 @@
/** Show the bouncer if necessary and set the relevant states. */
@JvmOverloads
fun show(isScrimmed: Boolean) {
+ // When the scene container framework is enabled, instead of calling this, call
+ // SceneInteractor#changeScene(Scenes.Bouncer, ...).
+ SceneContainerFlag.assertInLegacyMode()
+
if (primaryBouncerView.delegate == null && !Flags.composeBouncer()) {
Log.d(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/dagger/ScreenBrightnessModule.kt b/packages/SystemUI/src/com/android/systemui/brightness/dagger/ScreenBrightnessModule.kt
new file mode 100644
index 0000000..2b9fc73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/dagger/ScreenBrightnessModule.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.brightness.dagger
+
+import com.android.systemui.brightness.data.repository.BrightnessPolicyRepository
+import com.android.systemui.brightness.data.repository.BrightnessPolicyRepositoryImpl
+import com.android.systemui.brightness.data.repository.ScreenBrightnessDisplayManagerRepository
+import com.android.systemui.brightness.data.repository.ScreenBrightnessRepository
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface ScreenBrightnessModule {
+
+ @Binds
+ fun bindScreenBrightnessRepository(
+ impl: ScreenBrightnessDisplayManagerRepository
+ ): ScreenBrightnessRepository
+
+ @Binds
+ fun bindPolicyRepository(impl: BrightnessPolicyRepositoryImpl): BrightnessPolicyRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/model/LinearBrightness.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/model/LinearBrightness.kt
new file mode 100644
index 0000000..608f301
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/data/model/LinearBrightness.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.model
+
+@JvmInline
+value class LinearBrightness(val floatValue: Float) {
+ fun clamp(min: LinearBrightness, max: LinearBrightness): LinearBrightness {
+ return if (floatValue < min.floatValue) {
+ min
+ } else if (floatValue > max.floatValue) {
+ max
+ } else {
+ this
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt
new file mode 100644
index 0000000..c018ecb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepository.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import android.content.Context
+import android.os.UserManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.utils.PolicyRestriction
+import com.android.systemui.utils.UserRestrictionChecker
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.mapLatest
+
+/** Checks whether the current user is restricted to change the brightness ([RESTRICTION]) */
+interface BrightnessPolicyRepository {
+
+ /**
+ * Indicates whether the current user is restricted to change the brightness. As there is no way
+ * to determine when a restriction has been added/removed. This value may be fetched eagerly and
+ * not updated (unless the user changes) per flow.
+ */
+ val restrictionPolicy: Flow<PolicyRestriction>
+
+ companion object {
+ const val RESTRICTION = UserManager.DISALLOW_CONFIG_BRIGHTNESS
+ }
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class BrightnessPolicyRepositoryImpl
+@Inject
+constructor(
+ userRepository: UserRepository,
+ private val userRestrictionChecker: UserRestrictionChecker,
+ @Application private val applicationContext: Context,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : BrightnessPolicyRepository {
+ override val restrictionPolicy =
+ userRepository.selectedUserInfo
+ .mapLatest { user ->
+ userRestrictionChecker
+ .checkIfRestrictionEnforced(
+ applicationContext,
+ BrightnessPolicyRepository.RESTRICTION,
+ user.id
+ )
+ ?.let { PolicyRestriction.Restricted(it) }
+ ?: PolicyRestriction.NoRestriction
+ }
+ .flowOn(backgroundDispatcher)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt
new file mode 100644
index 0000000..9ed11d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import android.annotation.SuppressLint
+import android.hardware.display.BrightnessInfo
+import android.hardware.display.DisplayManager
+import com.android.systemui.brightness.data.model.LinearBrightness
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.DisplayId
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Repository for tracking brightness in the current display.
+ *
+ * Values are in a linear space, as used by [DisplayManager].
+ */
+interface ScreenBrightnessRepository {
+ /** Current brightness as a value between [minLinearBrightness] and [maxLinearBrightness] */
+ val linearBrightness: Flow<LinearBrightness>
+
+ /** Current minimum value for the brightness */
+ val minLinearBrightness: Flow<LinearBrightness>
+
+ /** Current maximum value for the brightness */
+ val maxLinearBrightness: Flow<LinearBrightness>
+
+ /** Gets the current values for min and max brightness */
+ suspend fun getMinMaxLinearBrightness(): Pair<LinearBrightness, LinearBrightness>
+
+ /**
+ * Sets the temporary value for the brightness. This should change the display brightness but
+ * not trigger any updates.
+ */
+ fun setTemporaryBrightness(value: LinearBrightness)
+
+ /** Sets the brightness definitively. */
+ fun setBrightness(value: LinearBrightness)
+}
+
+@SuppressLint("MissingPermission")
+@SysUISingleton
+class ScreenBrightnessDisplayManagerRepository
+@Inject
+constructor(
+ @DisplayId private val displayId: Int,
+ private val displayManager: DisplayManager,
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundContext: CoroutineContext,
+) : ScreenBrightnessRepository {
+
+ private val apiQueue =
+ Channel<SetBrightnessMethod>(
+ capacity = UNLIMITED,
+ )
+
+ init {
+ applicationScope.launch(backgroundContext) {
+ for (call in apiQueue) {
+ val bounds = getMinMaxLinearBrightness()
+ val value = call.value.clamp(bounds.first, bounds.second).floatValue
+ when (call) {
+ is SetBrightnessMethod.Temporary -> {
+ displayManager.setTemporaryBrightness(displayId, value)
+ }
+ is SetBrightnessMethod.Permanent -> {
+ displayManager.setBrightness(displayId, value)
+ }
+ }
+ }
+ }
+ }
+
+ private val brightnessInfo: StateFlow<BrightnessInfo?> =
+ conflatedCallbackFlow {
+ val listener =
+ object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {}
+
+ override fun onDisplayRemoved(displayId: Int) {}
+
+ override fun onDisplayChanged(displayId: Int) {
+ if (
+ displayId == this@ScreenBrightnessDisplayManagerRepository.displayId
+ ) {
+ trySend(Unit)
+ }
+ }
+ }
+ displayManager.registerDisplayListener(
+ listener,
+ null,
+ DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS,
+ )
+
+ awaitClose { displayManager.unregisterDisplayListener(listener) }
+ }
+ .onStart { emit(Unit) }
+ .map { brightnessInfoValue() }
+ .flowOn(backgroundContext)
+ .stateIn(
+ applicationScope,
+ SharingStarted.WhileSubscribed(replayExpirationMillis = 0L),
+ null,
+ )
+
+ private suspend fun brightnessInfoValue(): BrightnessInfo? {
+ return withContext(backgroundContext) {
+ displayManager.getDisplay(displayId).brightnessInfo
+ }
+ }
+
+ override val minLinearBrightness =
+ brightnessInfo
+ .filterNotNull()
+ .map { LinearBrightness(it.brightnessMinimum) }
+ .shareIn(applicationScope, SharingStarted.WhileSubscribed())
+
+ override val maxLinearBrightness =
+ brightnessInfo
+ .filterNotNull()
+ .map { LinearBrightness(it.brightnessMaximum) }
+ .shareIn(applicationScope, SharingStarted.WhileSubscribed())
+
+ override suspend fun getMinMaxLinearBrightness(): Pair<LinearBrightness, LinearBrightness> {
+ val brightnessInfo = brightnessInfo.value ?: brightnessInfoValue()
+ val min = brightnessInfo?.brightnessMinimum ?: 0f
+ val max = brightnessInfo?.brightnessMaximum ?: 1f
+ return LinearBrightness(min) to LinearBrightness(max)
+ }
+
+ override val linearBrightness =
+ brightnessInfo
+ .filterNotNull()
+ .map { LinearBrightness(it.brightness) }
+ .shareIn(applicationScope, SharingStarted.WhileSubscribed())
+
+ override fun setTemporaryBrightness(value: LinearBrightness) {
+ apiQueue.trySend(SetBrightnessMethod.Temporary(value))
+ }
+
+ override fun setBrightness(value: LinearBrightness) {
+ apiQueue.trySend(SetBrightnessMethod.Permanent(value))
+ }
+
+ private sealed interface SetBrightnessMethod {
+ val value: LinearBrightness
+ @JvmInline
+ value class Temporary(override val value: LinearBrightness) : SetBrightnessMethod
+ @JvmInline
+ value class Permanent(override val value: LinearBrightness) : SetBrightnessMethod
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractor.kt b/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractor.kt
new file mode 100644
index 0000000..fb00edf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractor.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import com.android.settingslib.RestrictedLockUtils
+import com.android.systemui.brightness.data.repository.BrightnessPolicyRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.utils.PolicyRestriction
+import javax.inject.Inject
+
+/** Interactor for enforcing the policy that may disallow brightness changing. */
+@SysUISingleton
+class BrightnessPolicyEnforcementInteractor
+@Inject
+constructor(
+ brightnessPolicyRepository: BrightnessPolicyRepository,
+ private val activityStarter: ActivityStarter,
+) {
+
+ /** Brightness policy restriction for the current user. */
+ val brightnessPolicyRestriction = brightnessPolicyRepository.restrictionPolicy
+
+ /**
+ * Starts the dialog with details about the current restriction for changing brightness. Should
+ * be triggered when a restricted user tries to change the brightness.
+ */
+ fun startAdminSupportDetailsDialog(restriction: PolicyRestriction.Restricted) {
+ val intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(restriction.admin)
+ activityStarter.postStartActivityDismissingKeyguard(intent, 0)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractor.kt b/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractor.kt
new file mode 100644
index 0000000..799a0a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import com.android.settingslib.display.BrightnessUtils
+import com.android.systemui.brightness.data.model.LinearBrightness
+import com.android.systemui.brightness.data.repository.ScreenBrightnessRepository
+import com.android.systemui.brightness.shared.GammaBrightness
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.combine
+
+/**
+ * Converts between [GammaBrightness] and [LinearBrightness].
+ *
+ * @see BrightnessUtils
+ */
+@SysUISingleton
+class ScreenBrightnessInteractor
+@Inject
+constructor(
+ private val screenBrightnessRepository: ScreenBrightnessRepository,
+) {
+ /** Maximum value in the Gamma space for brightness */
+ val maxGammaBrightness = GammaBrightness(BrightnessUtils.GAMMA_SPACE_MAX)
+
+ /** Minimum value in the Gamma space for brightness */
+ val minGammaBrightness = GammaBrightness(BrightnessUtils.GAMMA_SPACE_MIN)
+
+ /**
+ * Brightness in the Gamma space for the current display. It will always represent a value
+ * between [minGammaBrightness] and [maxGammaBrightness]
+ */
+ val gammaBrightness =
+ with(screenBrightnessRepository) {
+ combine(
+ linearBrightness,
+ minLinearBrightness,
+ maxLinearBrightness,
+ ) { brightness, min, max ->
+ brightness.toGammaBrightness(min, max)
+ }
+ }
+
+ /** Sets the brightness temporarily, while the user is changing it. */
+ suspend fun setTemporaryBrightness(gammaBrightness: GammaBrightness) {
+ screenBrightnessRepository.setTemporaryBrightness(
+ gammaBrightness.clamp().toLinearBrightness()
+ )
+ }
+
+ /** Sets the brightness definitely. */
+ suspend fun setBrightness(gammaBrightness: GammaBrightness) {
+ screenBrightnessRepository.setBrightness(gammaBrightness.clamp().toLinearBrightness())
+ }
+
+ private suspend fun GammaBrightness.toLinearBrightness(): LinearBrightness {
+ val bounds = screenBrightnessRepository.getMinMaxLinearBrightness()
+ return LinearBrightness(
+ BrightnessUtils.convertGammaToLinearFloat(
+ value,
+ bounds.first.floatValue,
+ bounds.second.floatValue
+ )
+ )
+ }
+
+ private fun GammaBrightness.clamp(): GammaBrightness {
+ return GammaBrightness(value.coerceIn(minGammaBrightness.value, maxGammaBrightness.value))
+ }
+
+ private fun LinearBrightness.toGammaBrightness(
+ min: LinearBrightness,
+ max: LinearBrightness,
+ ): GammaBrightness {
+ return GammaBrightness(
+ BrightnessUtils.convertLinearToGammaFloat(floatValue, min.floatValue, max.floatValue)
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/shared/GammaBrightness.kt b/packages/SystemUI/src/com/android/systemui/brightness/shared/GammaBrightness.kt
new file mode 100644
index 0000000..e20d003
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/shared/GammaBrightness.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.brightness.shared
+
+import androidx.annotation.IntRange
+import com.android.settingslib.display.BrightnessUtils
+
+@JvmInline
+value class GammaBrightness(
+ @IntRange(
+ from = BrightnessUtils.GAMMA_SPACE_MIN.toLong(),
+ to = BrightnessUtils.GAMMA_SPACE_MAX.toLong()
+ )
+ val value: Int
+)
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
new file mode 100644
index 0000000..c1be37a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2024 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.brightness.ui.compose
+
+import androidx.compose.animation.core.animateIntAsState
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.compose.PlatformSlider
+import com.android.systemui.brightness.shared.GammaBrightness
+import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
+import com.android.systemui.brightness.ui.viewmodel.Drag
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.utils.PolicyRestriction
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+@Composable
+private fun BrightnessSlider(
+ gammaValue: Int,
+ valueRange: IntRange,
+ label: Text.Resource,
+ icon: Icon,
+ restriction: PolicyRestriction,
+ onRestrictedClick: (PolicyRestriction.Restricted) -> Unit,
+ onDrag: (Int) -> Unit,
+ onStop: (Int) -> Unit,
+ modifier: Modifier = Modifier,
+ formatter: (Int) -> String = { "$it" },
+) {
+ var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
+ val animatedValue by
+ animateIntAsState(targetValue = value, label = "BrightnessSliderAnimatedValue")
+ val floatValueRange = valueRange.first.toFloat()..valueRange.last.toFloat()
+ val isRestricted = restriction is PolicyRestriction.Restricted
+
+ PlatformSlider(
+ value = animatedValue.toFloat(),
+ valueRange = floatValueRange,
+ enabled = !isRestricted,
+ onValueChange = {
+ if (!isRestricted) {
+ value = it.toInt()
+ onDrag(value)
+ }
+ },
+ onValueChangeFinished = {
+ if (!isRestricted) {
+ onStop(value)
+ }
+ },
+ modifier =
+ modifier.clickable(
+ enabled = isRestricted,
+ ) {
+ if (restriction is PolicyRestriction.Restricted) {
+ onRestrictedClick(restriction)
+ }
+ },
+ icon = { isDragging ->
+ if (isDragging) {
+ Text(text = formatter(value))
+ } else {
+ Icon(modifier = Modifier.size(24.dp), icon = icon)
+ }
+ },
+ label = {
+ Text(
+ text = stringResource(id = label.res),
+ style = MaterialTheme.typography.titleMedium,
+ maxLines = 1,
+ )
+ },
+ )
+}
+
+@Composable
+fun BrightnessSliderContainer(
+ viewModel: BrightnessSliderViewModel,
+ modifier: Modifier = Modifier,
+) {
+ val gamma: Int by viewModel.currentBrightness.map { it.value }.collectAsState(initial = 0)
+ val coroutineScope = rememberCoroutineScope()
+ val restriction by
+ viewModel.policyRestriction.collectAsState(initial = PolicyRestriction.NoRestriction)
+
+ BrightnessSlider(
+ gammaValue = gamma,
+ valueRange = viewModel.minBrightness.value..viewModel.maxBrightness.value,
+ label = viewModel.label,
+ icon = viewModel.icon,
+ restriction = restriction,
+ onRestrictedClick = viewModel::showPolicyRestrictionDialog,
+ onDrag = { coroutineScope.launch { viewModel.onDrag(Drag.Dragging(GammaBrightness(it))) } },
+ onStop = { coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) } },
+ modifier = modifier.fillMaxWidth(),
+ formatter = viewModel::formatValue,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
new file mode 100644
index 0000000..f0988ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 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.brightness.ui.viewmodel
+
+import com.android.systemui.brightness.domain.interactor.BrightnessPolicyEnforcementInteractor
+import com.android.systemui.brightness.domain.interactor.ScreenBrightnessInteractor
+import com.android.systemui.brightness.shared.GammaBrightness
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
+import com.android.systemui.utils.PolicyRestriction
+import javax.inject.Inject
+
+@SysUISingleton
+class BrightnessSliderViewModel
+@Inject
+constructor(
+ private val screenBrightnessInteractor: ScreenBrightnessInteractor,
+ private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
+) {
+ val currentBrightness = screenBrightnessInteractor.gammaBrightness
+
+ val maxBrightness = screenBrightnessInteractor.maxGammaBrightness
+ val minBrightness = screenBrightnessInteractor.minGammaBrightness
+
+ val label = Text.Resource(R.string.quick_settings_brightness_dialog_title)
+
+ val icon = Icon.Resource(R.drawable.ic_brightness_full, ContentDescription.Resource(label.res))
+
+ val policyRestriction = brightnessPolicyEnforcementInteractor.brightnessPolicyRestriction
+
+ fun showPolicyRestrictionDialog(restriction: PolicyRestriction.Restricted) {
+ brightnessPolicyEnforcementInteractor.startAdminSupportDetailsDialog(restriction)
+ }
+
+ /**
+ * As a brightness slider is dragged, the corresponding events should be sent using this method.
+ */
+ suspend fun onDrag(drag: Drag) {
+ when (drag) {
+ is Drag.Dragging -> screenBrightnessInteractor.setTemporaryBrightness(drag.brightness)
+ is Drag.Stopped -> screenBrightnessInteractor.setBrightness(drag.brightness)
+ }
+ }
+
+ /**
+ * Format the current value of brightness as a percentage between the minimum and maximum gamma.
+ */
+ fun formatValue(value: Int): String {
+ val min = minBrightness.value
+ val max = maxBrightness.value
+ val coercedValue = value.coerceIn(min, max)
+ val percentage = (coercedValue - min) * 100 / (max - min)
+ // This is not finalized UI so using fixed string
+ return "$percentage%"
+ }
+}
+
+/** Represents a drag event in a brightness slider. */
+sealed interface Drag {
+ val brightness: GammaBrightness
+ @JvmInline value class Dragging(override val brightness: GammaBrightness) : Drag
+ @JvmInline value class Stopped(override val brightness: GammaBrightness) : Drag
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1ed4b50..7d86e06 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -43,6 +43,7 @@
import com.android.systemui.bouncer.data.repository.BouncerRepositoryModule;
import com.android.systemui.bouncer.domain.interactor.BouncerInteractorModule;
import com.android.systemui.bouncer.ui.BouncerViewModule;
+import com.android.systemui.brightness.dagger.ScreenBrightnessModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
import com.android.systemui.common.data.CommonDataLayerModule;
@@ -229,6 +230,7 @@
RecordIssueModule.class,
ReferenceModule.class,
RetailModeModule.class,
+ ScreenBrightnessModule.class,
ScreenshotModule.class,
SensorModule.class,
SecurityRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 926f7f1..75c50fd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -19,6 +19,7 @@
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_START_REGION;
+import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -81,6 +82,7 @@
private final LockPatternUtils mLockPatternUtils;
private final UserTracker mUserTracker;
private final float mBouncerZoneScreenPercentage;
+ private final float mMinBouncerZoneScreenPercentage;
private final ScrimManager mScrimManager;
private ScrimController mCurrentScrimController;
@@ -222,6 +224,7 @@
@Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
FlingAnimationUtils flingAnimationUtilsClosing,
@Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage,
+ @Named(MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE) float minRegionPercentage,
UiEventLogger uiEventLogger) {
mCentralSurfaces = centralSurfaces;
mScrimManager = scrimManager;
@@ -229,6 +232,7 @@
mLockPatternUtils = lockPatternUtils;
mUserTracker = userTracker;
mBouncerZoneScreenPercentage = swipeRegionPercentage;
+ mMinBouncerZoneScreenPercentage = minRegionPercentage;
mFlingAnimationUtils = flingAnimationUtils;
mFlingAnimationUtilsClosing = flingAnimationUtilsClosing;
mValueAnimatorCreator = valueAnimatorCreator;
@@ -237,24 +241,27 @@
}
@Override
- public void getTouchInitiationRegion(Rect bounds, Region region) {
+ public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
final int width = bounds.width();
final int height = bounds.height();
+ final float minBouncerHeight = height * mMinBouncerZoneScreenPercentage;
+ final int minAllowableBottom = Math.round(height * (1 - mMinBouncerZoneScreenPercentage));
- if (mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) {
- region.op(new Rect(0, 0, width,
- Math.round(
- height * mBouncerZoneScreenPercentage)),
- Region.Op.UNION);
- } else {
- region.op(new Rect(0,
- Math.round(height * (1 - mBouncerZoneScreenPercentage)),
- width,
- height),
- Region.Op.UNION);
+ final boolean isBouncerShowing =
+ mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false);
+ final Rect normalRegion = isBouncerShowing
+ ? new Rect(0, 0, width, Math.round(height * mBouncerZoneScreenPercentage))
+ : new Rect(0, Math.round(height * (1 - mBouncerZoneScreenPercentage)),
+ width, height);
+
+ if (!isBouncerShowing && exclusionRect != null) {
+ int lowestBottom = Math.min(Math.max(0, exclusionRect.bottom), minAllowableBottom);
+ normalRegion.top = Math.max(normalRegion.top, lowestBottom);
}
+ region.union(normalRegion);
}
+
@Override
public void onSessionStart(TouchSession session) {
mVelocityTracker = mVelocityTrackerFactory.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java
index e5c705f..13588c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java
@@ -87,7 +87,7 @@
}
@Override
- public void getTouchInitiationRegion(Rect bounds, Region region) {
+ public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
final Rect outBounds = new Rect(bounds);
outBounds.inset(outBounds.width() - mInitiationWidth, 0, 0, 0);
region.op(outBounds, Region.Op.UNION);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
index 55a9c0c..3b22b31 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
@@ -18,9 +18,15 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static com.android.systemui.shared.Flags.bouncerAreaExclusion;
+
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.GestureDetector;
+import android.view.ISystemGestureExclusionListener;
+import android.view.IWindowManager;
import android.view.InputEvent;
import android.view.MotionEvent;
@@ -31,6 +37,8 @@
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.touch.dagger.InputSessionComponent;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -58,8 +66,23 @@
public class DreamOverlayTouchMonitor {
// This executor is used to protect {@code mActiveTouchSessions} from being modified
// concurrently. Any operation that adds or removes values should use this executor.
- private final Executor mExecutor;
+ public String TAG = "DreamOverlayTouchMonitor";
+ private final Executor mMainExecutor;
+ private final Executor mBackgroundExecutor;
private final Lifecycle mLifecycle;
+ private Rect mExclusionRect = null;
+
+ private ISystemGestureExclusionListener mGestureExclusionListener =
+ new ISystemGestureExclusionListener.Stub() {
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId,
+ Region systemGestureExclusion,
+ Region systemGestureExclusionUnrestricted) {
+ mExclusionRect = systemGestureExclusion.getBounds();
+ }
+ };
+
+
/**
* Adds a new {@link TouchSessionImpl} to participate in receiving future touches and gestures.
@@ -67,7 +90,7 @@
private ListenableFuture<DreamTouchHandler.TouchSession> push(
TouchSessionImpl touchSessionImpl) {
return CallbackToFutureAdapter.getFuture(completer -> {
- mExecutor.execute(() -> {
+ mMainExecutor.execute(() -> {
if (!mActiveTouchSessions.remove(touchSessionImpl)) {
completer.set(null);
return;
@@ -90,7 +113,7 @@
private ListenableFuture<DreamTouchHandler.TouchSession> pop(
TouchSessionImpl touchSessionImpl) {
return CallbackToFutureAdapter.getFuture(completer -> {
- mExecutor.execute(() -> {
+ mMainExecutor.execute(() -> {
if (mActiveTouchSessions.remove(touchSessionImpl)) {
touchSessionImpl.onRemoved();
@@ -240,6 +263,17 @@
*/
private void startMonitoring() {
stopMonitoring(true);
+ if (bouncerAreaExclusion()) {
+ mBackgroundExecutor.execute(() -> {
+ try {
+ mWindowManagerService.registerSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ } catch (RemoteException e) {
+ // Handle the exception
+ Log.e(TAG, "Failed to register gesture exclusion listener", e);
+ }
+ });
+ }
mCurrentInputSession = mInputSessionFactory.create(
"dreamOverlay",
mInputEventListener,
@@ -252,6 +286,18 @@
* Destroys any active {@link InputSession}.
*/
private void stopMonitoring(boolean force) {
+ mExclusionRect = null;
+ if (bouncerAreaExclusion()) {
+ mBackgroundExecutor.execute(() -> {
+ try {
+ mWindowManagerService.unregisterSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ } catch (RemoteException e) {
+ // Handle the exception
+ Log.e(TAG, "unregisterSystemGestureExclusionListener: failed", e);
+ }
+ });
+ }
if (mCurrentInputSession == null) {
return;
}
@@ -263,7 +309,7 @@
// When we stop monitoring touches, we must ensure that all active touch sessions and
// descendants informed of the removal so any cleanup for active tracking can proceed.
- mExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
+ mMainExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
while (touchSession != null) {
touchSession.onRemoved();
touchSession = touchSession.getPredecessor();
@@ -295,11 +341,15 @@
if (!handler.isEnabled()) {
continue;
}
- final Rect maxBounds = mDisplayHelper.getMaxBounds(ev.getDisplayId(),
- TYPE_APPLICATION_OVERLAY);
-
- final Region initiationRegion = Region.obtain();
- handler.getTouchInitiationRegion(maxBounds, initiationRegion);
+ final Rect maxBounds = mDisplayHelper.getMaxBounds(ev.getDisplayId(),
+ TYPE_APPLICATION_OVERLAY);
+ final Region initiationRegion = Region.obtain();
+ Rect exclusionRect = null;
+ if (bouncerAreaExclusion()) {
+ exclusionRect = getCurrentExclusionRect();
+ }
+ handler.getTouchInitiationRegion(
+ maxBounds, initiationRegion, exclusionRect);
if (!initiationRegion.isEmpty()) {
// Initiation regions require a motion event to determine pointer location
@@ -335,6 +385,9 @@
.flatMap(Collection::stream)
.forEach(inputEventListener -> inputEventListener.onInputEvent(ev));
}
+ private Rect getCurrentExclusionRect() {
+ return mExclusionRect;
+ }
};
/**
@@ -416,6 +469,9 @@
private InputSessionComponent.Factory mInputSessionFactory;
private InputSession mCurrentInputSession;
+ private final int mDisplayId;
+ private final IWindowManager mWindowManagerService;
+
/**
* Designated constructor for {@link DreamOverlayTouchMonitor}
@@ -432,15 +488,21 @@
@Inject
public DreamOverlayTouchMonitor(
@Main Executor executor,
+ @Background Executor backgroundExecutor,
Lifecycle lifecycle,
InputSessionComponent.Factory inputSessionFactory,
DisplayHelper displayHelper,
- Set<DreamTouchHandler> handlers) {
+ Set<DreamTouchHandler> handlers,
+ IWindowManager windowManagerService,
+ @DisplayId int displayId) {
+ mDisplayId = displayId;
mHandlers = handlers;
mInputSessionFactory = inputSessionFactory;
- mExecutor = executor;
+ mMainExecutor = executor;
+ mBackgroundExecutor = backgroundExecutor;
mLifecycle = lifecycle;
mDisplayHelper = displayHelper;
+ mWindowManagerService = windowManagerService;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
index 72ad45d..1ec0008 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
@@ -104,7 +104,7 @@
* indicating the entire screen should be considered.
* @param region A {@link Region} that is passed in to the target entry touch region.
*/
- default void getTouchInitiationRegion(Rect bounds, Region region) {
+ default void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
index 6f05e83..e0bf52e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
@@ -82,7 +82,7 @@
}
@Override
- public void getTouchInitiationRegion(Rect bounds, Region region) {
+ public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
final Rect outBounds = new Rect(bounds);
outBounds.inset(0, 0, 0, outBounds.height() - mInitiationHeight);
region.op(outBounds, Region.Op.UNION);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
index 8cf11a9..a5db2ff 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
@@ -21,10 +21,10 @@
import android.util.TypedValue;
import android.view.VelocityTracker;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.touch.BouncerSwipeTouchHandler;
import com.android.systemui.dreams.touch.DreamTouchHandler;
+import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeViewController;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -46,6 +46,9 @@
*/
public static final String SWIPE_TO_BOUNCER_START_REGION = "swipe_to_bouncer_start_region";
+ public static final String MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE =
+ "min_bouncer_zone_screen_percentage";
+
/**
* The {@link android.view.animation.AnimationUtils} for animating the bouncer closing.
*/
@@ -110,6 +113,18 @@
}
/**
+ * Provides the minimum region to start wipe gestures from.
+ */
+ @Provides
+ @Named(MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE)
+ public static float providesMinBouncerZoneScreenPercentage(@Main Resources resources) {
+ TypedValue typedValue = new TypedValue();
+ resources.getValue(R.dimen.dream_overlay_bouncer_min_region_screen_percentage,
+ typedValue, true);
+ return typedValue.getFloat();
+ }
+
+ /**
* Provides the default {@link BouncerSwipeTouchHandler.ValueAnimatorCreator}, which is simply
* a wrapper around {@link ValueAnimator}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fb0d225..654610e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2153,13 +2153,6 @@
mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
synchronized (KeyguardViewMediator.this) {
- if (mHiding && isOccluded) {
- // We're in the process of going away but WindowManager wants to show a
- // SHOW_WHEN_LOCKED activity instead.
- // TODO(bc-unlock): Migrate to remote animation.
- startKeyguardExitAnimation(0, 0);
- }
-
mPowerGestureIntercepted =
isOccluded && mUpdateMonitor.isSecureCameraLaunchedOverKeyguard();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index e017129..bf1f074 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -26,6 +26,9 @@
import com.android.systemui.keyguard.data.repository.BiometricType
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -33,6 +36,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
@@ -48,6 +52,8 @@
@Application private val applicationScope: CoroutineScope,
@Application private val context: Context,
deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val sceneContainerFlags: SceneContainerFlags,
+ private val sceneInteractor: SceneInteractor,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
@@ -65,16 +71,35 @@
}
}
+ private val isSideFpsIndicatorOnPrimaryBouncerEnabled: Boolean
+ get() = context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
+
+ private val isBouncerSceneActive: Flow<Boolean> =
+ if (sceneContainerFlags.isEnabled()) {
+ sceneInteractor.currentScene.map { it == Scenes.Bouncer }.distinctUntilChanged()
+ } else {
+ flowOf(false)
+ }
+
private val showIndicatorForPrimaryBouncer: Flow<Boolean> =
merge(
+ // Legacy bouncer visibility changes.
primaryBouncerInteractor.isShowing,
primaryBouncerInteractor.startingToHide,
primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
+ // Bouncer scene visibility changes.
+ isBouncerSceneActive,
deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }
)
- .map { shouldShowIndicatorForPrimaryBouncer() }
+ .map {
+ isBouncerActive() &&
+ isSideFpsIndicatorOnPrimaryBouncerEnabled &&
+ keyguardUpdateMonitor.isFingerprintDetectionRunning &&
+ keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
+ }
private val showIndicatorForAlternateBouncer: Flow<Boolean> =
+ // Note: this interactor internally verifies that SideFPS is enabled and running.
alternateBouncerInteractor.isVisible
/**
@@ -89,16 +114,11 @@
}
.distinctUntilChanged()
- private fun shouldShowIndicatorForPrimaryBouncer(): Boolean {
- val sfpsEnabled: Boolean =
- context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
- val sfpsDetectionRunning = keyguardUpdateMonitor.isFingerprintDetectionRunning
- val isUnlockingWithFpAllowed = keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
-
+ private fun isBouncerActive(): Boolean {
+ if (sceneContainerFlags.isEnabled()) {
+ return sceneInteractor.currentScene.value == Scenes.Bouncer
+ }
return primaryBouncerInteractor.isBouncerShowing() &&
- sfpsEnabled &&
- sfpsDetectionRunning &&
- isUnlockingWithFpAllowed &&
!primaryBouncerInteractor.isAnimatingAway()
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index da9e00d..e861ddf 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -16,8 +16,11 @@
package com.android.systemui.mediaprojection.permission;
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT;
import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT;
+import static android.media.projection.MediaProjectionManager.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -26,11 +29,13 @@
import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AlertDialog;
import android.app.StatusBarManager;
+import android.app.compat.CompatChanges;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -108,6 +113,7 @@
}
@Override
+ @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE})
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -235,6 +241,10 @@
// the correct screen width when in split screen.
Context dialogContext = getApplicationContext();
if (isPartialScreenSharingEnabled()) {
+ final boolean overrideDisableSingleAppOption =
+ CompatChanges.isChangeEnabled(
+ OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION,
+ mPackageName, getHostUserHandle());
MediaProjectionPermissionDialogDelegate delegate =
new MediaProjectionPermissionDialogDelegate(
dialogContext,
@@ -246,6 +256,7 @@
},
() -> finish(RECORD_CANCEL, /* projection= */ null),
appName,
+ overrideDisableSingleAppOption,
mUid,
mMediaProjectionMetricsLogger);
mDialog =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
index 0f54e93..8858041a 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
@@ -30,11 +30,12 @@
private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
private val onCancelClicked: Runnable,
private val appName: String?,
+ private val forceShowPartialScreenshare: Boolean,
hostUid: Int,
mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
- createOptionList(context, appName, mediaProjectionConfig),
+ createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare),
appName,
hostUid,
mediaProjectionMetricsLogger
@@ -65,7 +66,8 @@
private fun createOptionList(
context: Context,
appName: String?,
- mediaProjectionConfig: MediaProjectionConfig?
+ mediaProjectionConfig: MediaProjectionConfig?,
+ overrideDisableSingleAppOption: Boolean = false,
): List<ScreenShareOption> {
val singleAppWarningText =
if (appName == null) {
@@ -80,8 +82,13 @@
R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
}
+ // The single app option should only be disabled if there is an app name provided,
+ // the client has setup a MediaProjection with
+ // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by
+ // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override.
val singleAppOptionDisabled =
appName != null &&
+ !overrideDisableSingleAppOption &&
mediaProjectionConfig?.regionToCapture ==
MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY
diff --git a/packages/SystemUI/src/com/android/systemui/qs/flags/NewQsUI.kt b/packages/SystemUI/src/com/android/systemui/qs/flags/NewQsUI.kt
new file mode 100644
index 0000000..8af5665
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/flags/NewQsUI.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.qs.flags
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the notification avalanche suppression flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NewQsUI {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_QS_UI_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.qsUiRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
new file mode 100644
index 0000000..a3c2cbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.qs.ui.viewmodel
+
+import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+@SysUISingleton
+class QuickSettingsContainerViewModel
+@Inject
+constructor(
+ val brightnessSliderViewModel: BrightnessSliderViewModel,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
new file mode 100644
index 0000000..0344b32
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the heads-up cycling flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationHeadsUpCycling {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_HEADS_UP_CYCLING
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the heads-up cycling animation enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationContentAlphaOptimization()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index afd2415..5f26702 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -662,7 +662,12 @@
* show if any subsequent events are to be handled.
*/
if (beginShowingBouncer(event)) {
- mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
+ if (SceneContainerFlag.isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Bouncer, "StatusBarKeyguardViewManager.onPanelExpansionChanged");
+ } else {
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
+ }
}
if (!primaryBouncerIsOrWillBeShowing()) {
@@ -716,7 +721,12 @@
// The keyguard might be showing (already). So we need to hide it.
if (!primaryBouncerIsShowing()) {
mCentralSurfaces.hideKeyguard();
- mPrimaryBouncerInteractor.show(true);
+ if (SceneContainerFlag.isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Bouncer, "StatusBarKeyguardViewManager.showBouncerOrKeyguard");
+ } else {
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
+ }
} else {
Log.e(TAG, "Attempted to show the sim bouncer when it is already showing.");
}
@@ -778,7 +788,12 @@
public void showPrimaryBouncer(boolean scrimmed) {
hideAlternateBouncer(false);
if (mKeyguardStateController.isShowing() && !isBouncerShowing()) {
- mPrimaryBouncerInteractor.show(scrimmed);
+ if (SceneContainerFlag.isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Bouncer, "StatusBarKeyguardViewManager.showPrimaryBouncer");
+ } else {
+ mPrimaryBouncerInteractor.show(scrimmed);
+ }
}
updateStates();
}
@@ -873,13 +888,23 @@
if (afterKeyguardGone) {
// we'll handle the dismiss action after keyguard is gone, so just show the
// bouncer
- mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
+ if (SceneContainerFlag.isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Bouncer, "StatusBarKeyguardViewManager.dismissWithAction");
+ } else {
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
+ }
} else {
// after authentication success, run dismiss action with the option to defer
// hiding the keyguard based on the return value of the OnDismissAction
mPrimaryBouncerInteractor.setDismissAction(
mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
- mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
+ if (SceneContainerFlag.isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Bouncer, "StatusBarKeyguardViewManager.dismissWithAction");
+ } else {
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
+ }
// bouncer will handle the dismiss action, so we no longer need to track it here
mAfterKeyguardGoneAction = null;
mKeyguardGoneCancelAction = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 55a0f59..9cdecef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -17,9 +17,12 @@
import android.util.Log
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
+import java.io.PrintWriter
import javax.inject.Inject
/*
@@ -27,7 +30,9 @@
* succession, by delaying visual listener side effects and removal handling from BaseHeadsUpManager
*/
@SysUISingleton
-class AvalancheController @Inject constructor() {
+class AvalancheController @Inject constructor(
+ dumpManager: DumpManager,
+) : Dumpable {
private val tag = "AvalancheController"
private val debug = false
@@ -54,22 +59,26 @@
// For debugging only
@VisibleForTesting var debugDropSet: MutableSet<HeadsUpEntry> = HashSet()
- /**
- * Run or delay Runnable for given HeadsUpEntry
- */
- fun update(entry: HeadsUpEntry, runnable: Runnable, label: String) {
+ init {
+ dumpManager.registerNormalDumpable(tag, /* module */ this)
+ }
+
+ /** Run or delay Runnable for given HeadsUpEntry */
+ fun update(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
if (!NotificationThrottleHun.isEnabled) {
runnable.run()
return
}
val fn = "[$label] => AvalancheController.update ${getKey(entry)}"
-
+ if (entry == null) {
+ log { "Entry is NULL, stop update." }
+ return;
+ }
if (debug) {
debugRunnableLabelMap[runnable] = label
}
-
if (isShowing(entry)) {
- log {"$fn => [update showing]" }
+ log { "$fn => [update showing]" }
runnable.run()
} else if (entry in nextMap) {
log { "$fn => [update next]" }
@@ -164,9 +173,7 @@
}
}
- /**
- * Return true if entry is waiting to show.
- */
+ /** Return true if entry is waiting to show. */
fun isWaiting(key: String): Boolean {
if (!NotificationThrottleHun.isEnabled) {
return false
@@ -179,9 +186,7 @@
return false
}
- /**
- * Return list of keys for huns waiting
- */
+ /** Return list of keys for huns waiting */
fun getWaitingKeys(): MutableList<String> {
if (!NotificationThrottleHun.isEnabled) {
return mutableListOf()
@@ -254,12 +259,15 @@
}
}
- // TODO(b/315362456) expose as dumpable for bugreports
+ private fun getStateStr(): String {
+ return "SHOWING: ${getKey(headsUpEntryShowing)}" +
+ "\tNEXT LIST: $nextListStr\tMAP: $nextMapStr" +
+ "\tDROP: $dropSetStr"
+ }
+
private fun logState(reason: String) {
- log { "state $reason" }
- log { "showing: " + getKey(headsUpEntryShowing) }
- log { "next list: $nextListStr map: $nextMapStr" }
- log { "drop: $dropSetStr" }
+ log { "REASON $reason" }
+ log { getStateStr() }
}
private val dropSetStr: String
@@ -298,4 +306,8 @@
}
return entry.mEntry!!.key
}
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("AvalancheController: ${getStateStr()}")
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
index 7a57027..988564a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar.policy
+import android.os.UserManager
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tileimpl.QSTileImpl
@@ -47,6 +48,7 @@
import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
import com.android.systemui.qs.tiles.impl.work.ui.WorkModeTileMapper
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTilePolicy
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
import com.android.systemui.res.R
@@ -120,6 +122,13 @@
labelRes = R.string.quick_settings_location_label,
),
instanceId = uiEventLogger.getNewInstanceId(),
+ policy =
+ QSTilePolicy.Restricted(
+ listOf(
+ UserManager.DISALLOW_SHARE_LOCATION,
+ UserManager.DISALLOW_CONFIG_LOCATION
+ )
+ )
)
/** Inject LocationTile into tileViewModelMap in QSModule */
diff --git a/packages/SystemUI/src/com/android/systemui/utils/PolicyRestriction.kt b/packages/SystemUI/src/com/android/systemui/utils/PolicyRestriction.kt
new file mode 100644
index 0000000..38c6d7f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/utils/PolicyRestriction.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.utils
+
+import com.android.settingslib.RestrictedLockUtils
+
+/**
+ * Models a possible policy restriction.
+ *
+ * @see RestrictedLockUtils.checkIfRestrictionEnforced
+ */
+sealed interface PolicyRestriction {
+ data object NoRestriction : PolicyRestriction
+
+ data class Restricted(val admin: RestrictedLockUtils.EnforcedAdmin) : PolicyRestriction
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
index b0c8a4a..dc73344 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
@@ -23,7 +23,7 @@
import com.android.settingslib.volume.data.repository.MediaControllerRepository
import com.android.settingslib.volume.data.repository.stateChanges
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
index ea4c082..eebb6fb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
@@ -21,7 +21,7 @@
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.media.dialog.MediaOutputDialogManager
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlayback
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
@@ -33,10 +33,10 @@
private val mediaOutputDialogManager: MediaOutputDialogManager,
) {
- fun onBarClick(session: MediaDeviceSession, isPlaybackActive: Boolean, expandable: Expandable) {
- if (isPlaybackActive) {
+ fun onBarClick(sessionWithPlayback: SessionWithPlayback?, expandable: Expandable) {
+ if (sessionWithPlayback?.playback?.isActive == true) {
mediaOutputDialogManager.createAndShowWithController(
- session.packageName,
+ sessionWithPlayback.session.packageName,
false,
expandable.dialogController()
)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index e60139e..41ad035 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -25,8 +25,8 @@
import com.android.settingslib.volume.data.repository.MediaControllerRepository
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt
index ddc0784..22c160d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt
@@ -16,6 +16,8 @@
package com.android.systemui.volume.panel.component.mediaoutput.domain.model
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
+
/** Models a pair of local and remote [MediaDeviceSession]s. */
data class MediaDeviceSessions(
val local: MediaDeviceSession?,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/MediaDeviceSession.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt
rename to packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/MediaDeviceSession.kt
index 2a2ce79..eca3315 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/MediaDeviceSession.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.volume.panel.component.mediaoutput.domain.model
+package com.android.systemui.volume.panel.component.mediaoutput.shared.model
import android.media.session.MediaSession
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/SessionWithPlayback.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/SessionWithPlayback.kt
new file mode 100644
index 0000000..c4476fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/shared/model/SessionWithPlayback.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.mediaoutput.shared.model
+
+import android.media.session.PlaybackState
+
+data class SessionWithPlayback(
+ val session: MediaDeviceSession,
+ val playback: PlaybackState,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
index 2530a3a..fc9602e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
@@ -17,7 +17,6 @@
package com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel
import android.content.Context
-import android.media.session.PlaybackState
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Color
import com.android.systemui.common.shared.model.Icon
@@ -25,9 +24,8 @@
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputActionsInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlayback
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
-import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -47,7 +45,6 @@
constructor(
private val context: Context,
@VolumePanelScope private val coroutineScope: CoroutineScope,
- private val volumePanelViewModel: VolumePanelViewModel,
private val actionsInteractor: MediaOutputActionsInteractor,
private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
interactor: MediaOutputInteractor,
@@ -129,14 +126,6 @@
)
fun onBarClick(expandable: Expandable) {
- sessionWithPlayback.value?.let {
- actionsInteractor.onBarClick(it.session, it.playback.isActive, expandable)
- }
- volumePanelViewModel.dismissPanel()
+ actionsInteractor.onBarClick(sessionWithPlayback.value, expandable)
}
-
- private data class SessionWithPlayback(
- val session: MediaDeviceSession,
- val playback: PlaybackState,
- )
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
index 73c8bbf..8d8fa17 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
@@ -21,7 +21,7 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
index 4e9a456..09e56c1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -20,8 +20,8 @@
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.isTheSameSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.shared.model.isTheSameSession
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
index d4a0c8f..30c5e6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -77,6 +77,8 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.phone.dozeServiceHost
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -85,7 +87,6 @@
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import java.util.Optional
@@ -238,6 +239,8 @@
testScope.backgroundScope,
mContext,
deviceEntryFingerprintAuthRepository,
+ kosmos.fakeSceneContainerFlags,
+ kosmos.sceneInteractor,
primaryBouncerInteractor,
alternateBouncerInteractor,
keyguardUpdateMonitor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
index ae20c70..1acb203 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -75,6 +75,8 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.phone.dozeServiceHost
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -233,6 +235,8 @@
testScope.backgroundScope,
mContext,
deviceEntryFingerprintAuthRepository,
+ kosmos.fakeSceneContainerFlags,
+ kosmos.sceneInteractor,
primaryBouncerInteractor,
alternateBouncerInteractor,
keyguardUpdateMonitor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
index 1c6f251..a127631 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
@@ -32,6 +32,7 @@
import android.testing.AndroidTestingRunner;
import android.util.Pair;
import android.view.GestureDetector;
+import android.view.IWindowManager;
import android.view.InputEvent;
import android.view.MotionEvent;
@@ -83,11 +84,14 @@
private final GestureDetector.OnGestureListener mGestureListener;
private final DisplayHelper mDisplayHelper;
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ private final FakeExecutor mBackgroundExecutor = new FakeExecutor(new FakeSystemClock());
private final Rect mDisplayBounds = Mockito.mock(Rect.class);
+ private final IWindowManager mIWindowManager;
Environment(Set<DreamTouchHandler> handlers) {
mLifecycle = Mockito.mock(Lifecycle.class);
mLifecycleOwner = Mockito.mock(LifecycleOwner.class);
+ mIWindowManager = Mockito.mock(IWindowManager.class);
mInputFactory = Mockito.mock(InputSessionComponent.Factory.class);
final InputSessionComponent inputComponent = Mockito.mock(InputSessionComponent.class);
@@ -100,8 +104,8 @@
mDisplayHelper = Mockito.mock(DisplayHelper.class);
when(mDisplayHelper.getMaxBounds(anyInt(), anyInt()))
.thenReturn(mDisplayBounds);
- mMonitor = new DreamOverlayTouchMonitor(mExecutor, mLifecycle, mInputFactory,
- mDisplayHelper, handlers);
+ mMonitor = new DreamOverlayTouchMonitor(mExecutor, mBackgroundExecutor,
+ mLifecycle, mInputFactory, mDisplayHelper, handlers, mIWindowManager, 0);
mMonitor.init();
final ArgumentCaptor<LifecycleObserver> lifecycleObserverCaptor =
@@ -163,7 +167,8 @@
environment.publishInputEvent(initialEvent);
// Verify display bounds passed into TouchHandler#getTouchInitiationRegion
- verify(touchHandler).getTouchInitiationRegion(eq(environment.getDisplayBounds()), any());
+ verify(touchHandler).getTouchInitiationRegion(
+ eq(environment.getDisplayBounds()), any(), any());
final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor =
ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class);
verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture());
@@ -182,7 +187,7 @@
final Region region = (Region) invocation.getArguments()[1];
region.set(touchArea);
return null;
- }).when(touchHandler).getTouchInitiationRegion(any(), any());
+ }).when(touchHandler).getTouchInitiationRegion(any(), any(), any());
final Environment environment = new Environment(Stream.of(touchHandler)
.collect(Collectors.toCollection(HashSet::new)));
@@ -211,7 +216,7 @@
final Region region = (Region) invocation.getArguments()[1];
region.set(touchArea);
return null;
- }).when(touchHandler).getTouchInitiationRegion(any(), any());
+ }).when(touchHandler).getTouchInitiationRegion(any(), any(), any());
final Environment environment = new Environment(Stream.of(touchHandler, unzonedTouchHandler)
.collect(Collectors.toCollection(HashSet::new)));
@@ -264,7 +269,7 @@
// Make sure there is no active session.
verify(touchHandler, never()).onSessionStart(any());
- verify(touchHandler, never()).getTouchInitiationRegion(any(), any());
+ verify(touchHandler, never()).getTouchInitiationRegion(any(), any(), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
index 3b4f683..9266af4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -36,16 +36,20 @@
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -69,6 +73,8 @@
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
private val bouncerRepository = FakeKeyguardBouncerRepository()
private val biometricSettingsRepository = FakeBiometricSettingsRepository()
private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
@@ -78,11 +84,11 @@
private lateinit var underTest: DeviceEntrySideFpsOverlayInteractor
- private val testScope = TestScope(StandardTestDispatcher())
-
@Before
fun setup() {
mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+ kosmos.fakeSceneContainerFlags.enabled = false
+
primaryBouncerInteractor =
PrimaryBouncerInteractor(
bouncerRepository,
@@ -100,6 +106,7 @@
mSelectedUserInteractor,
faceAuthInteractor
)
+
alternateBouncerInteractor =
AlternateBouncerInteractor(
mock(StatusBarStateController::class.java),
@@ -114,11 +121,14 @@
{ mock(KeyguardTransitionInteractor::class.java) },
testScope.backgroundScope,
)
+
underTest =
DeviceEntrySideFpsOverlayInteractor(
testScope.backgroundScope,
mContext,
deviceEntryFingerprintAuthRepository,
+ kosmos.fakeSceneContainerFlags,
+ kosmos.sceneInteractor,
primaryBouncerInteractor,
alternateBouncerInteractor,
keyguardUpdateMonitor
@@ -138,7 +148,7 @@
fpsDetectionRunning = true,
isUnlockingWithFpAllowed = true
)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+ assertThat(showIndicatorForDeviceEntry).isTrue()
}
@Test
@@ -154,7 +164,63 @@
fpsDetectionRunning = true,
isUnlockingWithFpAllowed = true
)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ assertThat(showIndicatorForDeviceEntry).isFalse()
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onBouncerSceneActive() =
+ testScope.runTest {
+ kosmos.fakeSceneContainerFlags.enabled = true
+ underTest =
+ DeviceEntrySideFpsOverlayInteractor(
+ testScope.backgroundScope,
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ kosmos.fakeSceneContainerFlags,
+ kosmos.sceneInteractor,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updateBouncerScene(
+ isActive = true,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isTrue()
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onBouncerSceneInactive() =
+ testScope.runTest {
+ kosmos.fakeSceneContainerFlags.enabled = true
+ underTest =
+ DeviceEntrySideFpsOverlayInteractor(
+ testScope.backgroundScope,
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ kosmos.fakeSceneContainerFlags,
+ kosmos.sceneInteractor,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updateBouncerScene(
+ isActive = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isFalse()
}
@Test
@@ -170,7 +236,7 @@
fpsDetectionRunning = false,
isUnlockingWithFpAllowed = true
)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ assertThat(showIndicatorForDeviceEntry).isFalse()
}
}
@@ -187,7 +253,39 @@
fpsDetectionRunning = true,
isUnlockingWithFpAllowed = false
)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ assertThat(showIndicatorForDeviceEntry).isFalse()
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromBouncerScene_whenFpsDetectionNotRunning() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updateBouncerScene(
+ isActive = true,
+ fpsDetectionRunning = false,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isFalse()
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromBouncerScene_onUnlockingWithFpDisallowed() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updateBouncerScene(
+ isActive = true,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = false
+ )
+ assertThat(showIndicatorForDeviceEntry).isFalse()
}
}
@@ -204,7 +302,7 @@
fpsDetectionRunning = true,
isUnlockingWithFpAllowed = true
)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ assertThat(showIndicatorForDeviceEntry).isFalse()
}
}
@@ -216,10 +314,10 @@
runCurrent()
bouncerRepository.setAlternateVisible(true)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+ assertThat(showIndicatorForDeviceEntry).isTrue()
bouncerRepository.setAlternateVisible(false)
- assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ assertThat(showIndicatorForDeviceEntry).isFalse()
}
@Test
@@ -266,4 +364,25 @@
true
)
}
+
+ private fun TestScope.updateBouncerScene(
+ isActive: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ kosmos.sceneInteractor.changeScene(
+ if (isActive) Scenes.Bouncer else Scenes.Lockscreen,
+ "reason"
+ )
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ runCurrent()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
new file mode 100644
index 0000000..e044eec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 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.mediaprojection.permission
+
+import android.app.AlertDialog
+import android.media.projection.MediaProjectionConfig
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.WindowManager
+import android.widget.Spinner
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.AlertDialogWithDelegate
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.mockito.mock
+import junit.framework.Assert.assertEquals
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class MediaProjectionPermissionDialogDelegateTest : SysuiTestCase() {
+
+ private lateinit var dialog: AlertDialog
+
+ private val flags = mock<FeatureFlagsClassic>()
+ private val onStartRecordingClicked = mock<Runnable>()
+ private val mediaProjectionMetricsLogger = mock<MediaProjectionMetricsLogger>()
+
+ private val mediaProjectionConfig: MediaProjectionConfig =
+ MediaProjectionConfig.createConfigForDefaultDisplay()
+ private val appName: String = "testApp"
+ private val hostUid: Int = 12345
+
+ private val resIdSingleApp = R.string.screen_share_permission_dialog_option_single_app
+ private val resIdFullScreen = R.string.screen_share_permission_dialog_option_entire_screen
+ private val resIdSingleAppDisabled =
+ R.string.media_projection_entry_app_permission_dialog_single_app_disabled
+
+ @Before
+ fun setUp() {
+ whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
+ }
+
+ @After
+ fun teardown() {
+ if (::dialog.isInitialized) {
+ dialog.dismiss()
+ }
+ }
+
+ @Test
+ fun showDialog_forceShowPartialScreenShareFalse() {
+ // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
+ // overrideDisableSingleAppOption = false
+ val overrideDisableSingleAppOption = false
+ setUpAndShowDialog(overrideDisableSingleAppOption)
+
+ val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
+ val secondOptionText =
+ spinner.adapter
+ .getDropDownView(1, null, spinner)
+ .findViewById<TextView>(android.R.id.text2)
+ ?.text
+
+ // check that the first option is full screen and enabled
+ assertEquals(context.getString(resIdFullScreen), spinner.selectedItem)
+
+ // check that the second option is single app and disabled
+ assertEquals(context.getString(resIdSingleAppDisabled, appName), secondOptionText)
+ }
+
+ @Test
+ fun showDialog_forceShowPartialScreenShareTrue() {
+ // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
+ // overrideDisableSingleAppOption = true
+ val overrideDisableSingleAppOption = true
+ setUpAndShowDialog(overrideDisableSingleAppOption)
+
+ val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
+ val secondOptionText =
+ spinner.adapter
+ .getDropDownView(1, null, spinner)
+ .findViewById<TextView>(android.R.id.text1)
+ ?.text
+
+ // check that the first option is single app and enabled
+ assertEquals(context.getString(resIdSingleApp), spinner.selectedItem)
+
+ // check that the second option is full screen and enabled
+ assertEquals(context.getString(resIdFullScreen), secondOptionText)
+ }
+
+ private fun setUpAndShowDialog(overrideDisableSingleAppOption: Boolean) {
+ val delegate =
+ MediaProjectionPermissionDialogDelegate(
+ context,
+ mediaProjectionConfig,
+ {},
+ onStartRecordingClicked,
+ appName,
+ overrideDisableSingleAppOption,
+ hostUid,
+ mediaProjectionMetricsLogger
+ )
+
+ dialog = AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate)
+ SystemUIDialog.applyFlags(dialog)
+ SystemUIDialog.setDialogSize(dialog)
+
+ dialog.window?.addSystemFlags(
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+ )
+
+ delegate.onCreate(dialog, savedInstanceState = null)
+ dialog.show()
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryKosmos.kt
new file mode 100644
index 0000000..2e5ddc7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/BrightnessPolicyRepositoryKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeBrightnessPolicyRepository by Kosmos.Fixture { FakeBrightnessPolicyRepository() }
+
+var Kosmos.brightnessPolicyRepository: BrightnessPolicyRepository by
+ Kosmos.Fixture { fakeBrightnessPolicyRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt
new file mode 100644
index 0000000..d3ceb15
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeBrightnessPolicyRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import com.android.settingslib.RestrictedLockUtils
+import com.android.systemui.utils.PolicyRestriction
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBrightnessPolicyRepository : BrightnessPolicyRepository {
+ private val _restrictionPolicy: MutableStateFlow<PolicyRestriction> =
+ MutableStateFlow(PolicyRestriction.NoRestriction)
+ override val restrictionPolicy = _restrictionPolicy.asStateFlow()
+
+ fun setCurrentUserUnrestricted() {
+ _restrictionPolicy.value = PolicyRestriction.NoRestriction
+ }
+
+ fun setCurrentUserRestricted() {
+ _restrictionPolicy.value =
+ PolicyRestriction.Restricted(
+ RestrictedLockUtils.EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(
+ BrightnessPolicyRepository.RESTRICTION
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeScreenBrightnessRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeScreenBrightnessRepository.kt
new file mode 100644
index 0000000..a05b5e6
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/FakeScreenBrightnessRepository.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import android.hardware.display.BrightnessInfo
+import android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE
+import android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF
+import com.android.systemui.brightness.data.model.LinearBrightness
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeScreenBrightnessRepository(
+ initialBrightnessInfo: BrightnessInfo =
+ BrightnessInfo(0f, 0f, 1f, HIGH_BRIGHTNESS_MODE_OFF, 1f, BRIGHTNESS_MAX_REASON_NONE)
+) : ScreenBrightnessRepository {
+
+ private val brightnessInfo = MutableStateFlow(initialBrightnessInfo)
+ private val _temporaryBrightness =
+ MutableStateFlow(LinearBrightness(initialBrightnessInfo.brightness))
+ val temporaryBrightness = _temporaryBrightness.asStateFlow()
+ override val linearBrightness = brightnessInfo.map { LinearBrightness(it.brightness) }
+ override val minLinearBrightness = brightnessInfo.map { LinearBrightness(it.brightnessMinimum) }
+ override val maxLinearBrightness = brightnessInfo.map { LinearBrightness(it.brightnessMaximum) }
+
+ override suspend fun getMinMaxLinearBrightness(): Pair<LinearBrightness, LinearBrightness> {
+ return minMaxLinearBrightness()
+ }
+
+ private fun minMaxLinearBrightness(): Pair<LinearBrightness, LinearBrightness> {
+ return with(brightnessInfo.value) {
+ LinearBrightness(brightnessMinimum) to LinearBrightness(brightnessMaximum)
+ }
+ }
+
+ override fun setTemporaryBrightness(value: LinearBrightness) {
+ val bounds = minMaxLinearBrightness()
+ val clampedValue = value.clamp(bounds.first, bounds.second)
+ _temporaryBrightness.value = clampedValue
+ }
+
+ override fun setBrightness(value: LinearBrightness) {
+ val bounds = minMaxLinearBrightness()
+ val clampedValue = value.clamp(bounds.first, bounds.second)
+ _temporaryBrightness.value = clampedValue
+ brightnessInfo.value =
+ with(brightnessInfo.value) {
+ BrightnessInfo(
+ clampedValue.floatValue,
+ brightnessMinimum,
+ brightnessMaximum,
+ highBrightnessMode,
+ highBrightnessTransitionPoint,
+ brightnessMaxReason,
+ )
+ }
+ }
+
+ fun setMinMaxBrightness(min: LinearBrightness, max: LinearBrightness) {
+ check(min.floatValue <= max.floatValue)
+ val clampedBrightness = LinearBrightness(brightnessInfo.value.brightness).clamp(min, max)
+ _temporaryBrightness.value = clampedBrightness
+ brightnessInfo.value =
+ with(brightnessInfo.value) {
+ BrightnessInfo(
+ clampedBrightness.floatValue,
+ min.floatValue,
+ max.floatValue,
+ highBrightnessMode,
+ highBrightnessTransitionPoint,
+ brightnessMaxReason
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepositoryKosmos.kt
new file mode 100644
index 0000000..c5b0eb2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepositoryKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.brightness.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeScreenBrightnessRepository: FakeScreenBrightnessRepository by
+ Kosmos.Fixture { FakeScreenBrightnessRepository() }
+
+var Kosmos.screenBrightnessRepository: ScreenBrightnessRepository by
+ Kosmos.Fixture { fakeScreenBrightnessRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorKosmos.kt
new file mode 100644
index 0000000..9d3c8d2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/BrightnessPolicyEnforcementInteractorKosmos.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import com.android.systemui.brightness.data.repository.brightnessPolicyRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.activityStarter
+
+val Kosmos.brightnessPolicyEnforcementInteractor by
+ Kosmos.Fixture {
+ BrightnessPolicyEnforcementInteractor(brightnessPolicyRepository, activityStarter)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt
new file mode 100644
index 0000000..22784e4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.brightness.domain.interactor
+
+import com.android.systemui.brightness.data.repository.screenBrightnessRepository
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.screenBrightnessInteractor by
+ Kosmos.Fixture { ScreenBrightnessInteractor(screenBrightnessRepository) }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 8ac1eb9..4dae6d5 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -103,10 +103,10 @@
import com.android.server.companion.datatransfer.contextsync.CrossDeviceCall;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback;
-import com.android.server.companion.presence.CompanionAppBinder;
-import com.android.server.companion.presence.DevicePresenceProcessor;
-import com.android.server.companion.presence.ObservableUuid;
-import com.android.server.companion.presence.ObservableUuidStore;
+import com.android.server.companion.devicepresence.CompanionAppBinder;
+import com.android.server.companion.devicepresence.DevicePresenceProcessor;
+import com.android.server.companion.devicepresence.ObservableUuid;
+import com.android.server.companion.devicepresence.ObservableUuidStore;
import com.android.server.companion.transport.CompanionTransportManager;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index daa8fdb..9cfb535 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -36,8 +36,8 @@
import com.android.server.companion.datatransfer.SystemDataTransferProcessor;
import com.android.server.companion.datatransfer.contextsync.BitmapUtils;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
-import com.android.server.companion.presence.DevicePresenceProcessor;
-import com.android.server.companion.presence.ObservableUuid;
+import com.android.server.companion.devicepresence.DevicePresenceProcessor;
+import com.android.server.companion.devicepresence.ObservableUuid;
import com.android.server.companion.transport.CompanionTransportManager;
import java.io.PrintWriter;
diff --git a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
index acf683d..8c1116b 100644
--- a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
@@ -37,8 +37,8 @@
import android.util.Slog;
import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
-import com.android.server.companion.presence.CompanionAppBinder;
-import com.android.server.companion.presence.DevicePresenceProcessor;
+import com.android.server.companion.devicepresence.CompanionAppBinder;
+import com.android.server.companion.devicepresence.DevicePresenceProcessor;
import com.android.server.companion.transport.CompanionTransportManager;
/**
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java
similarity index 61%
rename from services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
rename to services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java
index 407b9da..6cdc02e 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java
@@ -15,27 +15,15 @@
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import static android.bluetooth.BluetoothAdapter.ACTION_BLE_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
-import static android.bluetooth.BluetoothAdapter.EXTRA_PREVIOUS_STATE;
-import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
-import static android.bluetooth.BluetoothAdapter.nameForState;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_ALREADY_STARTED;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES;
-import static android.bluetooth.le.ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_FIRST_MATCH;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_MATCH_LOST;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
-import static com.android.server.companion.presence.DevicePresenceProcessor.DEBUG;
-import static com.android.server.companion.utils.Utils.btDeviceToString;
-
import static java.util.Objects.requireNonNull;
import android.annotation.MainThread;
@@ -56,21 +44,19 @@
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
-import android.util.Log;
import android.util.Slog;
import com.android.server.companion.association.AssociationStore;
import com.android.server.companion.association.AssociationStore.ChangeType;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@SuppressLint("LongLogTag")
-class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener {
- private static final String TAG = "CDM_BleCompanionDeviceScanner";
+class BleDeviceProcessor implements AssociationStore.OnChangeListener {
+ private static final String TAG = "CDM_BleDeviceProcessor";
interface Callback {
void onBleCompanionDeviceFound(int associationId, int userId);
@@ -78,26 +64,27 @@
void onBleCompanionDeviceLost(int associationId, int userId);
}
- private final @NonNull AssociationStore mAssociationStore;
- private final @NonNull Callback mCallback;
+ @NonNull
+ private final AssociationStore mAssociationStore;
+ @NonNull
+ private final Callback mCallback;
// Non-null after init().
- private @Nullable BluetoothAdapter mBtAdapter;
+ @Nullable
+ private BluetoothAdapter mBtAdapter;
// Non-null after init() and when BLE is available. Otherwise - null.
- private @Nullable BluetoothLeScanner mBleScanner;
+ @Nullable
+ private BluetoothLeScanner mBleScanner;
// Only accessed from the Main thread.
private boolean mScanning = false;
- BleCompanionDeviceScanner(
- @NonNull AssociationStore associationStore, @NonNull Callback callback) {
+ BleDeviceProcessor(@NonNull AssociationStore associationStore, @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
}
@MainThread
void init(@NonNull Context context, @NonNull BluetoothAdapter btAdapter) {
- if (DEBUG) Log.i(TAG, "init()");
-
if (mBtAdapter != null) {
throw new IllegalStateException(getClass().getSimpleName() + " is already initialized");
}
@@ -113,9 +100,7 @@
final void restartScan() {
enforceInitialized();
- if (DEBUG) Log.i(TAG , "restartScan()");
if (mBleScanner == null) {
- if (DEBUG) Log.d(TAG, " > BLE is not available");
return;
}
@@ -138,12 +123,8 @@
enforceInitialized();
final boolean bleAvailable = mBtAdapter.isLeEnabled();
- if (DEBUG) {
- Log.i(TAG, "checkBleState() bleAvailable=" + bleAvailable);
- }
if ((bleAvailable && mBleScanner != null) || (!bleAvailable && mBleScanner == null)) {
// Nothing changed.
- if (DEBUG) Log.i(TAG, " > BLE status did not change");
return;
}
@@ -153,12 +134,9 @@
// Oops, that's a race condition. Can return.
return;
}
- if (DEBUG) Log.i(TAG, " > BLE is now available");
startScan();
} else {
- if (DEBUG) Log.i(TAG, " > BLE is now unavailable");
-
stopScanIfNeeded();
mBleScanner = null;
}
@@ -194,13 +172,7 @@
}
}
if (macAddresses.isEmpty()) {
- if (DEBUG) Log.i(TAG, " > there are no (associated) devices to Scan for.");
return;
- } else {
- if (DEBUG) {
- Log.d(TAG, " > addresses=(n=" + macAddresses.size() + ")"
- + "[" + String.join(", ", macAddresses) + "]");
- }
}
final List<ScanFilter> filters = new ArrayList<>(macAddresses.size());
@@ -230,7 +202,6 @@
Slog.i(TAG, "stopBleScan()");
if (!mScanning) {
- if (DEBUG) Log.d(TAG, " > not scanning.");
return;
}
// mScanCallback is non-null here - it cannot be null when mScanning is true.
@@ -252,26 +223,16 @@
@MainThread
private void notifyDeviceFound(@NonNull BluetoothDevice device) {
- if (DEBUG) Log.i(TAG, "notifyDevice_Found()" + btDeviceToString(device));
-
- final List<AssociationInfo> associations =
- mAssociationStore.getActiveAssociationsByAddress(device.getAddress());
- if (DEBUG) Log.d(TAG, " > associations=" + Arrays.toString(associations.toArray()));
-
- for (AssociationInfo association : associations) {
+ for (AssociationInfo association : mAssociationStore.getActiveAssociationsByAddress(
+ device.getAddress())) {
mCallback.onBleCompanionDeviceFound(association.getId(), association.getUserId());
}
}
@MainThread
private void notifyDeviceLost(@NonNull BluetoothDevice device) {
- if (DEBUG) Log.i(TAG, "notifyDevice_Lost()" + btDeviceToString(device));
-
- final List<AssociationInfo> associations =
- mAssociationStore.getActiveAssociationsByAddress(device.getAddress());
- if (DEBUG) Log.d(TAG, " > associations=" + Arrays.toString(associations.toArray()));
-
- for (AssociationInfo association : associations) {
+ for (AssociationInfo association : mAssociationStore.getActiveAssociationsByAddress(
+ device.getAddress())) {
mCallback.onBleCompanionDeviceLost(association.getId(), association.getUserId());
}
}
@@ -280,17 +241,6 @@
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_STATE, -1);
- final int state = intent.getIntExtra(EXTRA_STATE, -1);
-
- if (DEBUG) {
- // The action is either STATE_CHANGED or BLE_STATE_CHANGED.
- final String action =
- intent.getAction().replace("android.bluetooth.adapter.", "bt.");
- Log.d(TAG, "on(Broadcast)Receive() " + action + ": "
- + nameForBtState(prevState) + "->" + nameForBtState(state));
- }
-
checkBleState();
}
};
@@ -313,16 +263,6 @@
public void onScanResult(int callbackType, ScanResult result) {
final BluetoothDevice device = result.getDevice();
- if (DEBUG) {
- Log.d(TAG, "onScanResult() " + nameForBleScanCallbackType(callbackType)
- + " device=" + btDeviceToString(device));
- Log.v(TAG, " > scanResult=" + result);
-
- final List<AssociationInfo> associations =
- mAssociationStore.getActiveAssociationsByAddress(device.getAddress());
- Log.v(TAG, " > associations=" + Arrays.toString(associations.toArray()));
- }
-
switch (callbackType) {
case CALLBACK_TYPE_FIRST_MATCH:
notifyDeviceFound(device);
@@ -342,60 +282,20 @@
@MainThread
@Override
public void onScanFailed(int errorCode) {
- if (DEBUG) Log.w(TAG, "onScanFailed() " + nameForBleScanErrorCode(errorCode));
mScanning = false;
}
};
- private static String nameForBtState(int state) {
- return nameForState(state) + "(" + state + ")";
- }
-
private static String nameForBleScanCallbackType(int callbackType) {
- final String name;
- switch (callbackType) {
- case CALLBACK_TYPE_ALL_MATCHES:
- name = "ALL_MATCHES";
- break;
- case CALLBACK_TYPE_FIRST_MATCH:
- name = "FIRST_MATCH";
- break;
- case CALLBACK_TYPE_MATCH_LOST:
- name = "MATCH_LOST";
- break;
- default:
- name = "Unknown";
- }
+ final String name = switch (callbackType) {
+ case CALLBACK_TYPE_ALL_MATCHES -> "ALL_MATCHES";
+ case CALLBACK_TYPE_FIRST_MATCH -> "FIRST_MATCH";
+ case CALLBACK_TYPE_MATCH_LOST -> "MATCH_LOST";
+ default -> "Unknown";
+ };
return name + "(" + callbackType + ")";
}
- private static String nameForBleScanErrorCode(int errorCode) {
- final String name;
- switch (errorCode) {
- case SCAN_FAILED_ALREADY_STARTED:
- name = "ALREADY_STARTED";
- break;
- case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
- name = "APPLICATION_REGISTRATION_FAILED";
- break;
- case SCAN_FAILED_INTERNAL_ERROR:
- name = "INTERNAL_ERROR";
- break;
- case SCAN_FAILED_FEATURE_UNSUPPORTED:
- name = "FEATURE_UNSUPPORTED";
- break;
- case SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES:
- name = "OUT_OF_HARDWARE_RESOURCES";
- break;
- case SCAN_FAILED_SCANNING_TOO_FREQUENTLY:
- name = "SCANNING_TOO_FREQUENTLY";
- break;
- default:
- name = "Unknown";
- }
- return name + "(" + errorCode + ")";
- }
-
private static final ScanSettings SCAN_SETTINGS = new ScanSettings.Builder()
.setCallbackType(CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST)
.setScanMode(SCAN_MODE_LOW_POWER)
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/devicepresence/BluetoothDeviceProcessor.java
similarity index 62%
rename from services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
rename to services/companion/java/com/android/server/companion/devicepresence/BluetoothDeviceProcessor.java
index e1a8db4..612c156 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/BluetoothDeviceProcessor.java
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import static android.companion.DevicePresenceEvent.EVENT_BT_CONNECTED;
import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
-import static com.android.server.companion.presence.DevicePresenceProcessor.DEBUG;
-import static com.android.server.companion.utils.Utils.btDeviceToString;
-
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
@@ -32,8 +29,6 @@
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
import com.android.internal.util.ArrayUtils;
import com.android.server.companion.association.AssociationStore;
@@ -45,10 +40,10 @@
import java.util.Map;
@SuppressLint("LongLogTag")
-public class BluetoothCompanionDeviceConnectionListener
+public class BluetoothDeviceProcessor
extends BluetoothAdapter.BluetoothConnectionCallback
implements AssociationStore.OnChangeListener {
- private static final String TAG = "CDM_BluetoothCompanionDeviceConnectionListener";
+ private static final String TAG = "CDM_BluetoothDeviceProcessor";
interface Callback {
void onBluetoothCompanionDeviceConnected(int associationId, int userId);
@@ -58,24 +53,25 @@
void onDevicePresenceEventByUuid(ObservableUuid uuid, int event);
}
- private final @NonNull AssociationStore mAssociationStore;
- private final @NonNull Callback mCallback;
+ @NonNull
+ private final AssociationStore mAssociationStore;
+ @NonNull
+ private final ObservableUuidStore mObservableUuidStore;
+ @NonNull
+ private final Callback mCallback;
+
/** A set of ALL connected BT device (not only companion.) */
- private final @NonNull Map<MacAddress, BluetoothDevice> mAllConnectedDevices = new HashMap<>();
+ @NonNull
+ private final Map<MacAddress, BluetoothDevice> mAllConnectedDevices = new HashMap<>();
- private final @NonNull ObservableUuidStore mObservableUuidStore;
-
- BluetoothCompanionDeviceConnectionListener(UserManager userManager,
- @NonNull AssociationStore associationStore,
+ BluetoothDeviceProcessor(@NonNull AssociationStore associationStore,
@NonNull ObservableUuidStore observableUuidStore, @NonNull Callback callback) {
mAssociationStore = associationStore;
mObservableUuidStore = observableUuidStore;
mCallback = callback;
}
- public void init(@NonNull BluetoothAdapter btAdapter) {
- if (DEBUG) Log.i(TAG, "init()");
-
+ void init(@NonNull BluetoothAdapter btAdapter) {
btAdapter.registerBluetoothConnectionCallback(
new HandlerExecutor(Handler.getMain()), /* callback */this);
mAssociationStore.registerLocalListener(this);
@@ -87,13 +83,9 @@
*/
@Override
public void onDeviceConnected(@NonNull BluetoothDevice device) {
- if (DEBUG) Log.i(TAG, "onDevice_Connected() " + btDeviceToString(device));
-
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
- final int userId = UserHandle.myUserId();
if (mAllConnectedDevices.put(macAddress, device) != null) {
- if (DEBUG) Log.w(TAG, "Device " + btDeviceToString(device) + " is already connected.");
return;
}
@@ -108,18 +100,9 @@
@Override
public void onDeviceDisconnected(@NonNull BluetoothDevice device,
int reason) {
- if (DEBUG) {
- Log.i(TAG, "onDevice_Disconnected() " + btDeviceToString(device));
- Log.d(TAG, " reason=" + disconnectReasonToString(reason));
- }
-
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
- final int userId = UserHandle.myUserId();
if (mAllConnectedDevices.remove(macAddress) == null) {
- if (DEBUG) {
- Log.w(TAG, "The device wasn't tracked as connected " + btDeviceToString(device));
- }
return;
}
@@ -130,22 +113,6 @@
int userId = UserHandle.myUserId();
final List<AssociationInfo> associations =
mAssociationStore.getActiveAssociationsByAddress(device.getAddress());
- final List<ObservableUuid> observableUuids =
- mObservableUuidStore.getObservableUuidsForUser(userId);
- final ParcelUuid[] bluetoothDeviceUuids = device.getUuids();
-
- final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
- ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
-
- if (DEBUG) {
- Log.d(TAG, "onDevice_ConnectivityChanged() " + btDeviceToString(device)
- + " connected=" + connected);
- if (associations.isEmpty()) {
- Log.d(TAG, " > No CDM associations");
- } else {
- Log.d(TAG, " > associations=" + Arrays.toString(associations.toArray()));
- }
- }
for (AssociationInfo association : associations) {
if (!association.isNotifyOnDeviceNearby()) continue;
@@ -157,44 +124,25 @@
}
}
+ final List<ObservableUuid> observableUuids =
+ mObservableUuidStore.getObservableUuidsForUser(userId);
+ final ParcelUuid[] bluetoothDeviceUuids = device.getUuids();
+ final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
+ ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
+
for (ObservableUuid uuid : observableUuids) {
if (deviceUuids.contains(uuid.getUuid())) {
mCallback.onDevicePresenceEventByUuid(uuid, connected ? EVENT_BT_CONNECTED
- : EVENT_BT_DISCONNECTED);
+ : EVENT_BT_DISCONNECTED);
}
}
}
@Override
public void onAssociationAdded(AssociationInfo association) {
- if (DEBUG) Log.d(TAG, "onAssociation_Added() " + association);
-
if (mAllConnectedDevices.containsKey(association.getDeviceMacAddress())) {
mCallback.onBluetoothCompanionDeviceConnected(
association.getId(), association.getUserId());
}
}
-
- @Override
- public void onAssociationRemoved(AssociationInfo association) {
- // Intentionally do nothing: CompanionDevicePresenceMonitor will do all the bookkeeping
- // required.
- }
-
- @Override
- public void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {
- if (DEBUG) {
- Log.d(TAG, "onAssociation_Updated() addrChange=" + addressChanged
- + " " + association);
- }
-
- if (!addressChanged) {
- // Don't need to do anything.
- return;
- }
-
- // At the moment CDM does allow changing association addresses, so we will never come here.
- // This will be implemented when CDM support updating addresses.
- throw new IllegalArgumentException("Address changes are not supported.");
- }
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java b/services/companion/java/com/android/server/companion/devicepresence/CompanionAppBinder.java
similarity index 99%
rename from services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java
rename to services/companion/java/com/android/server/companion/devicepresence/CompanionAppBinder.java
index b6348ea..60f4688 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/CompanionAppBinder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java b/services/companion/java/com/android/server/companion/devicepresence/CompanionServiceConnector.java
similarity index 99%
rename from services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java
rename to services/companion/java/com/android/server/companion/devicepresence/CompanionServiceConnector.java
index c01c319..5923e70c 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/CompanionServiceConnector.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE;
diff --git a/services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
similarity index 96%
rename from services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java
rename to services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
index 092886c..cfb7f337 100644
--- a/services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
@@ -24,6 +24,7 @@
import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_APPEARED;
import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_DISAPPEARED;
import static android.companion.DevicePresenceEvent.NO_ASSOCIATION;
+import static android.content.Context.BLUETOOTH_SERVICE;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
@@ -35,6 +36,7 @@
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
import android.companion.AssociationInfo;
import android.companion.DeviceNotAssociatedException;
import android.companion.DevicePresenceEvent;
@@ -49,7 +51,6 @@
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.UserManager;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -80,8 +81,7 @@
*/
@SuppressLint("LongLogTag")
public class DevicePresenceProcessor implements AssociationStore.OnChangeListener,
- BluetoothCompanionDeviceConnectionListener.Callback, BleCompanionDeviceScanner.Callback {
- static final boolean DEBUG = false;
+ BluetoothDeviceProcessor.Callback, BleDeviceProcessor.Callback {
private static final String TAG = "CDM_DevicePresenceProcessor";
@NonNull
@@ -93,9 +93,9 @@
@NonNull
private final ObservableUuidStore mObservableUuidStore;
@NonNull
- private final BluetoothCompanionDeviceConnectionListener mBtConnectionListener;
+ private final BluetoothDeviceProcessor mBluetoothDeviceProcessor;
@NonNull
- private final BleCompanionDeviceScanner mBleScanner;
+ private final BleDeviceProcessor mBleDeviceProcessor;
@NonNull
private final PowerManagerInternal mPowerManagerInternal;
@NonNull
@@ -142,7 +142,7 @@
public DevicePresenceProcessor(@NonNull Context context,
@NonNull CompanionAppBinder companionAppBinder,
- UserManager userManager,
+ @NonNull UserManager userManager,
@NonNull AssociationStore associationStore,
@NonNull ObservableUuidStore observableUuidStore,
@NonNull PowerManagerInternal powerManagerInternal) {
@@ -151,25 +151,27 @@
mAssociationStore = associationStore;
mObservableUuidStore = observableUuidStore;
mUserManager = userManager;
- mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(userManager,
- associationStore, mObservableUuidStore,
- /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
- mBleScanner = new BleCompanionDeviceScanner(associationStore,
- /* BleCompanionDeviceScanner.Callback */ this);
+ mBluetoothDeviceProcessor = new BluetoothDeviceProcessor(associationStore,
+ mObservableUuidStore, this);
+ mBleDeviceProcessor = new BleDeviceProcessor(associationStore, this);
mPowerManagerInternal = powerManagerInternal;
}
/** Initialize {@link DevicePresenceProcessor} */
public void init(Context context) {
- if (DEBUG) Slog.i(TAG, "init()");
-
- final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
- if (btAdapter != null) {
- mBtConnectionListener.init(btAdapter);
- mBleScanner.init(context, btAdapter);
- } else {
- Slog.w(TAG, "BluetoothAdapter is NOT available.");
+ BluetoothManager bm = (BluetoothManager) context.getSystemService(BLUETOOTH_SERVICE);
+ if (bm == null) {
+ Slog.w(TAG, "BluetoothManager is not available.");
+ return;
}
+ final BluetoothAdapter btAdapter = bm.getAdapter();
+ if (btAdapter == null) {
+ Slog.w(TAG, "BluetoothAdapter is NOT available.");
+ return;
+ }
+
+ mBluetoothDeviceProcessor.init(btAdapter);
+ mBleDeviceProcessor.init(context, btAdapter);
mAssociationStore.registerLocalListener(this);
}
@@ -280,7 +282,7 @@
* For legacy device presence below Android V.
*
* @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int)}
*/
@Deprecated
public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -310,7 +312,7 @@
* For legacy device presence below Android V.
*
* @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int)}
*/
@Deprecated
public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -496,7 +498,7 @@
// Stop the BLE scan if all devices report BT connected status and BLE was present.
if (canStopBleScan()) {
- mBleScanner.stopScanIfNeeded();
+ mBleDeviceProcessor.stopScanIfNeeded();
}
}
@@ -513,7 +515,7 @@
}
// Start BLE scanning when the device is disconnected.
- mBleScanner.startScan();
+ mBleDeviceProcessor.startScan();
onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED);
// If current device is BLE present but BT is disconnected , means it will be
@@ -724,7 +726,7 @@
final ParcelUuid parcelUuid = uuid.getUuid();
final int userId = uuid.getUserId();
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- onDeviceLocked(/* associationId */ -1, userId, eventType, parcelUuid);
+ onDeviceLocked(NO_ASSOCIATION, userId, eventType, parcelUuid);
return;
}
@@ -930,10 +932,6 @@
@Override
public void onAssociationRemoved(@NonNull AssociationInfo association) {
final int id = association.getId();
- if (DEBUG) {
- Log.i(TAG, "onAssociationRemoved() id=" + id);
- Log.d(TAG, " > association=" + association);
- }
mConnectedBtDevices.remove(id);
mNearbyBleDevices.remove(id);
@@ -1004,8 +1002,8 @@
if (deviceEvents != null) {
deviceEvents.removeIf(deviceEvent ->
deviceEvent.getEvent() == EVENT_BLE_APPEARED
- && Objects.equals(deviceEvent.getUuid(), uuid)
- && deviceEvent.getAssociationId() == associationId);
+ && Objects.equals(deviceEvent.getUuid(), uuid)
+ && deviceEvent.getAssociationId() == associationId);
}
}
}
@@ -1018,8 +1016,8 @@
if (deviceEvents != null) {
deviceEvents.removeIf(deviceEvent ->
deviceEvent.getEvent() == EVENT_BT_CONNECTED
- && Objects.equals(deviceEvent.getUuid(), uuid)
- && deviceEvent.getAssociationId() == associationId);
+ && Objects.equals(deviceEvent.getUuid(), uuid)
+ && deviceEvent.getAssociationId() == associationId);
}
}
}
@@ -1054,7 +1052,7 @@
return;
}
- switch(event) {
+ switch (event) {
case EVENT_BLE_APPEARED:
onBleCompanionDeviceFound(
associationInfo.getId(), associationInfo.getUserId());
diff --git a/services/companion/java/com/android/server/companion/presence/ObservableUuid.java b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuid.java
similarity index 96%
rename from services/companion/java/com/android/server/companion/presence/ObservableUuid.java
rename to services/companion/java/com/android/server/companion/devicepresence/ObservableUuid.java
index 9cfa270..c9f60ca 100644
--- a/services/companion/java/com/android/server/companion/presence/ObservableUuid.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuid.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
diff --git a/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
similarity index 99%
rename from services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
rename to services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
index fa0f6bd..4678a16 100644
--- a/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion.presence;
+package com.android.server.companion.devicepresence;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
diff --git a/services/core/java/com/android/server/devicestate/OWNERS b/services/core/java/com/android/server/devicestate/OWNERS
index ae79fc0..43f3f0c 100644
--- a/services/core/java/com/android/server/devicestate/OWNERS
+++ b/services/core/java/com/android/server/devicestate/OWNERS
@@ -1,3 +1,4 @@
ogunwale@google.com
akulian@google.com
-darryljohnson@google.com
+lihongyu@google.com
+kennethford@google.com
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 4aab9d2..06dc7f5 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -55,6 +55,7 @@
import com.android.server.EventLogTags;
import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.clamper.BrightnessClamperController;
+import com.android.server.display.config.HysteresisLevels;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -673,14 +674,10 @@
}
pw.println();
- pw.println(" mAmbientBrightnessThresholds=");
- mAmbientBrightnessThresholds.dump(pw);
- pw.println(" mScreenBrightnessThresholds=");
- mScreenBrightnessThresholds.dump(pw);
- pw.println(" mScreenBrightnessThresholdsIdle=");
- mScreenBrightnessThresholdsIdle.dump(pw);
- pw.println(" mAmbientBrightnessThresholdsIdle=");
- mAmbientBrightnessThresholdsIdle.dump(pw);
+ pw.println(" mAmbientBrightnessThresholds=" + mAmbientBrightnessThresholds);
+ pw.println(" mAmbientBrightnessThresholdsIdle=" + mAmbientBrightnessThresholdsIdle);
+ pw.println(" mScreenBrightnessThresholds=" + mScreenBrightnessThresholds);
+ pw.println(" mScreenBrightnessThresholdsIdle=" + mScreenBrightnessThresholdsIdle);
}
public float[] getLastSensorValues() {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 09094ff..4bbddae 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -162,8 +162,8 @@
DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
var width = displayDeviceInfo.width;
var height = displayDeviceInfo.height;
- if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.yDpi > 0
- && displayDeviceInfo.xDpi > 0) {
+ if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL
+ && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) {
if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) {
height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5);
} else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 70668cb..85a231f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -33,7 +33,6 @@
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.MathUtils;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Spline;
@@ -46,7 +45,6 @@
import com.android.server.display.config.AutoBrightness;
import com.android.server.display.config.BlockingZoneConfig;
import com.android.server.display.config.BrightnessLimitMap;
-import com.android.server.display.config.BrightnessThresholds;
import com.android.server.display.config.BrightnessThrottlingMap;
import com.android.server.display.config.BrightnessThrottlingPoint;
import com.android.server.display.config.Density;
@@ -58,6 +56,7 @@
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HdrBrightnessData;
import com.android.server.display.config.HighBrightnessMode;
+import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.IdleScreenRefreshRateTimeout;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholds;
@@ -80,7 +79,6 @@
import com.android.server.display.config.SensorData;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.ThermalThrottling;
-import com.android.server.display.config.ThresholdPoint;
import com.android.server.display.config.UsiVersion;
import com.android.server.display.config.XmlParser;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -625,13 +623,6 @@
private static final int DEFAULT_HIGH_REFRESH_RATE = 0;
private static final float[] DEFAULT_BRIGHTNESS_THRESHOLDS = new float[]{};
- private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f};
- private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f};
- private static final float[] DEFAULT_AMBIENT_DARKENING_THRESHOLDS = new float[]{200f};
- private static final float[] DEFAULT_SCREEN_THRESHOLD_LEVELS = new float[]{0f};
- private static final float[] DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS = new float[]{100f};
- private static final float[] DEFAULT_SCREEN_DARKENING_THRESHOLDS = new float[]{200f};
-
private static final int INTERPOLATION_DEFAULT = 0;
private static final int INTERPOLATION_LINEAR = 1;
@@ -713,38 +704,16 @@
private long mBrightnessRampIncreaseMaxIdleMillis = 0;
private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS;
- private float mScreenBrighteningMinThreshold = 0.0f; // Retain behaviour as though there is
- private float mScreenBrighteningMinThresholdIdle = 0.0f; // no minimum threshold for change in
- private float mScreenDarkeningMinThreshold = 0.0f; // screen brightness or ambient
- private float mScreenDarkeningMinThresholdIdle = 0.0f; // brightness.
- private float mAmbientLuxBrighteningMinThreshold = 0.0f;
- private float mAmbientLuxBrighteningMinThresholdIdle = 0.0f;
- private float mAmbientLuxDarkeningMinThreshold = 0.0f;
- private float mAmbientLuxDarkeningMinThresholdIdle = 0.0f;
- // Screen brightness thresholds levels & percentages
- private float[] mScreenBrighteningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
- private float[] mScreenBrighteningPercentages = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
- private float[] mScreenDarkeningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
- private float[] mScreenDarkeningPercentages = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
-
- // Screen brightness thresholds levels & percentages for idle mode
- private float[] mScreenBrighteningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
- private float[] mScreenBrighteningPercentagesIdle = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
- private float[] mScreenDarkeningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
- private float[] mScreenDarkeningPercentagesIdle = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
-
- // Ambient brightness thresholds levels & percentages
- private float[] mAmbientBrighteningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
- private float[] mAmbientBrighteningPercentages = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
- private float[] mAmbientDarkeningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
- private float[] mAmbientDarkeningPercentages = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
-
- // Ambient brightness thresholds levels & percentages for idle mode
- private float[] mAmbientBrighteningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
- private float[] mAmbientBrighteningPercentagesIdle = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
- private float[] mAmbientDarkeningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
- private float[] mAmbientDarkeningPercentagesIdle = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
+ // Hysteresis levels for screen/ambient brightness for normal/idle modes
+ private HysteresisLevels mScreenBrightnessHysteresis =
+ HysteresisLevels.loadDisplayBrightnessConfig(null, null);
+ private HysteresisLevels mScreenBrightnessIdleHysteresis =
+ HysteresisLevels.loadDisplayBrightnessIdleConfig(null, null);
+ private HysteresisLevels mAmbientBrightnessHysteresis =
+ HysteresisLevels.loadAmbientBrightnessConfig(null, null);
+ private HysteresisLevels mAmbientBrightnessIdleHysteresis =
+ HysteresisLevels.loadAmbientBrightnessIdleConfig(null, null);
// A mapping between screen off sensor values and lux values
private int[] mScreenOffBrightnessSensorValueToLux;
@@ -1302,324 +1271,20 @@
return mAmbientHorizonShort;
}
- /**
- * The minimum value for the screen brightness increase to actually occur.
- * @return float value in brightness scale of 0 - 1.
- */
- public float getScreenBrighteningMinThreshold() {
- return mScreenBrighteningMinThreshold;
+ public HysteresisLevels getAmbientBrightnessHysteresis() {
+ return mAmbientBrightnessHysteresis;
}
- /**
- * The minimum value for the screen brightness decrease to actually occur.
- * @return float value in brightness scale of 0 - 1.
- */
- public float getScreenDarkeningMinThreshold() {
- return mScreenDarkeningMinThreshold;
+ public HysteresisLevels getAmbientBrightnessIdleHysteresis() {
+ return mAmbientBrightnessIdleHysteresis;
}
- /**
- * The minimum value for the screen brightness increase to actually occur while in idle screen
- * brightness mode.
- * @return float value in brightness scale of 0 - 1.
- */
- public float getScreenBrighteningMinThresholdIdle() {
- return mScreenBrighteningMinThresholdIdle;
+ public HysteresisLevels getScreenBrightnessHysteresis() {
+ return mScreenBrightnessHysteresis;
}
- /**
- * The minimum value for the screen brightness decrease to actually occur while in idle screen
- * brightness mode.
- * @return float value in brightness scale of 0 - 1.
- */
- public float getScreenDarkeningMinThresholdIdle() {
- return mScreenDarkeningMinThresholdIdle;
- }
-
- /**
- * The minimum value for the ambient lux increase for a screen brightness change to actually
- * occur.
- * @return float value in lux.
- */
- public float getAmbientLuxBrighteningMinThreshold() {
- return mAmbientLuxBrighteningMinThreshold;
- }
-
- /**
- * The minimum value for the ambient lux decrease for a screen brightness change to actually
- * occur.
- * @return float value in lux.
- */
- public float getAmbientLuxDarkeningMinThreshold() {
- return mAmbientLuxDarkeningMinThreshold;
- }
-
- /**
- * The minimum value for the ambient lux increase for a screen brightness change to actually
- * occur while in idle screen brightness mode.
- * @return float value in lux.
- */
- public float getAmbientLuxBrighteningMinThresholdIdle() {
- return mAmbientLuxBrighteningMinThresholdIdle;
- }
-
- /**
- * The minimum value for the ambient lux decrease for a screen brightness change to actually
- * occur while in idle screen brightness mode.
- * @return float value in lux.
- */
- public float getAmbientLuxDarkeningMinThresholdIdle() {
- return mAmbientLuxDarkeningMinThresholdIdle;
- }
-
- /**
- * The array that describes the range of screen brightness that each threshold percentage
- * applies within.
- *
- * The (zero-based) index is calculated as follows
- * value = current screen brightness value
- * level = mScreenBrighteningLevels
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mScreenBrighteningPercentages[n]
- * level[MAX] <= value = mScreenBrighteningPercentages[MAX]
- *
- * @return the screen brightness levels between 0.0 and 1.0 for which each
- * mScreenBrighteningPercentages applies
- */
- public float[] getScreenBrighteningLevels() {
- return mScreenBrighteningLevels;
- }
-
- /**
- * The array that describes the screen brightening threshold percentage change at each screen
- * brightness level described in mScreenBrighteningLevels.
- *
- * @return the percentages between 0 and 100 of brightness increase required in order for the
- * screen brightness to change
- */
- public float[] getScreenBrighteningPercentages() {
- return mScreenBrighteningPercentages;
- }
-
- /**
- * The array that describes the range of screen brightness that each threshold percentage
- * applies within.
- *
- * The (zero-based) index is calculated as follows
- * value = current screen brightness value
- * level = mScreenDarkeningLevels
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mScreenDarkeningPercentages[n]
- * level[MAX] <= value = mScreenDarkeningPercentages[MAX]
- *
- * @return the screen brightness levels between 0.0 and 1.0 for which each
- * mScreenDarkeningPercentages applies
- */
- public float[] getScreenDarkeningLevels() {
- return mScreenDarkeningLevels;
- }
-
- /**
- * The array that describes the screen darkening threshold percentage change at each screen
- * brightness level described in mScreenDarkeningLevels.
- *
- * @return the percentages between 0 and 100 of brightness decrease required in order for the
- * screen brightness to change
- */
- public float[] getScreenDarkeningPercentages() {
- return mScreenDarkeningPercentages;
- }
-
- /**
- * The array that describes the range of ambient brightness that each threshold
- * percentage applies within.
- *
- * The (zero-based) index is calculated as follows
- * value = current ambient brightness value
- * level = mAmbientBrighteningLevels
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mAmbientBrighteningPercentages[n]
- * level[MAX] <= value = mAmbientBrighteningPercentages[MAX]
- *
- * @return the ambient brightness levels from 0 lux upwards for which each
- * mAmbientBrighteningPercentages applies
- */
- public float[] getAmbientBrighteningLevels() {
- return mAmbientBrighteningLevels;
- }
-
- /**
- * The array that describes the ambient brightening threshold percentage change at each ambient
- * brightness level described in mAmbientBrighteningLevels.
- *
- * @return the percentages between 0 and 100 of brightness increase required in order for the
- * screen brightness to change
- */
- public float[] getAmbientBrighteningPercentages() {
- return mAmbientBrighteningPercentages;
- }
-
- /**
- * The array that describes the range of ambient brightness that each threshold percentage
- * applies within.
- *
- * The (zero-based) index is calculated as follows
- * value = current ambient brightness value
- * level = mAmbientDarkeningLevels
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mAmbientDarkeningPercentages[n]
- * level[MAX] <= value = mAmbientDarkeningPercentages[MAX]
- *
- * @return the ambient brightness levels from 0 lux upwards for which each
- * mAmbientDarkeningPercentages applies
- */
- public float[] getAmbientDarkeningLevels() {
- return mAmbientDarkeningLevels;
- }
-
- /**
- * The array that describes the ambient darkening threshold percentage change at each ambient
- * brightness level described in mAmbientDarkeningLevels.
- *
- * @return the percentages between 0 and 100 of brightness decrease required in order for the
- * screen brightness to change
- */
- public float[] getAmbientDarkeningPercentages() {
- return mAmbientDarkeningPercentages;
- }
-
- /**
- * The array that describes the range of screen brightness that each threshold percentage
- * applies within whilst in idle screen brightness mode.
- *
- * The (zero-based) index is calculated as follows
- * value = current screen brightness value
- * level = mScreenBrighteningLevelsIdle
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mScreenBrighteningPercentagesIdle[n]
- * level[MAX] <= value = mScreenBrighteningPercentagesIdle[MAX]
- *
- * @return the screen brightness levels between 0.0 and 1.0 for which each
- * mScreenBrighteningPercentagesIdle applies
- */
- public float[] getScreenBrighteningLevelsIdle() {
- return mScreenBrighteningLevelsIdle;
- }
-
- /**
- * The array that describes the screen brightening threshold percentage change at each screen
- * brightness level described in mScreenBrighteningLevelsIdle.
- *
- * @return the percentages between 0 and 100 of brightness increase required in order for the
- * screen brightness to change while in idle mode.
- */
- public float[] getScreenBrighteningPercentagesIdle() {
- return mScreenBrighteningPercentagesIdle;
- }
-
- /**
- * The array that describes the range of screen brightness that each threshold percentage
- * applies within whilst in idle screen brightness mode.
- *
- * The (zero-based) index is calculated as follows
- * value = current screen brightness value
- * level = mScreenDarkeningLevelsIdle
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mScreenDarkeningPercentagesIdle[n]
- * level[MAX] <= value = mScreenDarkeningPercentagesIdle[MAX]
- *
- * @return the screen brightness levels between 0.0 and 1.0 for which each
- * mScreenDarkeningPercentagesIdle applies
- */
- public float[] getScreenDarkeningLevelsIdle() {
- return mScreenDarkeningLevelsIdle;
- }
-
- /**
- * The array that describes the screen darkening threshold percentage change at each screen
- * brightness level described in mScreenDarkeningLevelsIdle.
- *
- * @return the percentages between 0 and 100 of brightness decrease required in order for the
- * screen brightness to change while in idle mode.
- */
- public float[] getScreenDarkeningPercentagesIdle() {
- return mScreenDarkeningPercentagesIdle;
- }
-
- /**
- * The array that describes the range of ambient brightness that each threshold percentage
- * applies within whilst in idle screen brightness mode.
- *
- * The (zero-based) index is calculated as follows
- * value = current ambient brightness value
- * level = mAmbientBrighteningLevelsIdle
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mAmbientBrighteningPercentagesIdle[n]
- * level[MAX] <= value = mAmbientBrighteningPercentagesIdle[MAX]
- *
- * @return the ambient brightness levels from 0 lux upwards for which each
- * mAmbientBrighteningPercentagesIdle applies
- */
- public float[] getAmbientBrighteningLevelsIdle() {
- return mAmbientBrighteningLevelsIdle;
- }
-
- /**
- * The array that describes the ambient brightness threshold percentage change whilst in
- * idle screen brightness mode at each ambient brightness level described in
- * mAmbientBrighteningLevelsIdle.
- *
- * @return the percentages between 0 and 100 of ambient brightness increase required in order
- * for the screen brightness to change
- */
- public float[] getAmbientBrighteningPercentagesIdle() {
- return mAmbientBrighteningPercentagesIdle;
- }
-
- /**
- * The array that describes the range of ambient brightness that each threshold percentage
- * applies within whilst in idle screen brightness mode.
- *
- * The (zero-based) index is calculated as follows
- * value = current ambient brightness value
- * level = mAmbientDarkeningLevelsIdle
- *
- * condition return
- * value < level[0] = 0.0f
- * level[n] <= value < level[n+1] = mAmbientDarkeningPercentagesIdle[n]
- * level[MAX] <= value = mAmbientDarkeningPercentagesIdle[MAX]
- *
- * @return the ambient brightness levels from 0 lux upwards for which each
- * mAmbientDarkeningPercentagesIdle applies
- */
- public float[] getAmbientDarkeningLevelsIdle() {
- return mAmbientDarkeningLevelsIdle;
- }
-
- /**
- * The array that describes the ambient brightness threshold percentage change whilst in
- * idle screen brightness mode at each ambient brightness level described in
- * mAmbientDarkeningLevelsIdle.
- *
- * @return the percentages between 0 and 100 of ambient brightness decrease required in order
- * for the screen brightness to change
- */
- public float[] getAmbientDarkeningPercentagesIdle() {
- return mAmbientDarkeningPercentagesIdle;
+ public HysteresisLevels getScreenBrightnessIdleHysteresis() {
+ return mScreenBrightnessIdleHysteresis;
}
public SensorData getAmbientLightSensor() {
@@ -1985,49 +1650,13 @@
+ "mAmbientHorizonLong=" + mAmbientHorizonLong
+ ", mAmbientHorizonShort=" + mAmbientHorizonShort
+ "\n"
- + "mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
- + ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
- + ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
- + ", mScreenBrighteningMinThresholdIdle=" + mScreenBrighteningMinThresholdIdle
- + ", mAmbientLuxDarkeningMinThreshold=" + mAmbientLuxDarkeningMinThreshold
- + ", mAmbientLuxDarkeningMinThresholdIdle=" + mAmbientLuxDarkeningMinThresholdIdle
- + ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold
- + ", mAmbientLuxBrighteningMinThresholdIdle="
- + mAmbientLuxBrighteningMinThresholdIdle
+ + "mAmbientBrightnessHysteresis=" + mAmbientBrightnessHysteresis
+ "\n"
- + "mScreenBrighteningLevels=" + Arrays.toString(
- mScreenBrighteningLevels)
- + ", mScreenBrighteningPercentages=" + Arrays.toString(
- mScreenBrighteningPercentages)
- + ", mScreenDarkeningLevels=" + Arrays.toString(
- mScreenDarkeningLevels)
- + ", mScreenDarkeningPercentages=" + Arrays.toString(
- mScreenDarkeningPercentages)
- + ", mAmbientBrighteningLevels=" + Arrays.toString(
- mAmbientBrighteningLevels)
- + ", mAmbientBrighteningPercentages=" + Arrays.toString(
- mAmbientBrighteningPercentages)
- + ", mAmbientDarkeningLevels=" + Arrays.toString(
- mAmbientDarkeningLevels)
- + ", mAmbientDarkeningPercentages=" + Arrays.toString(
- mAmbientDarkeningPercentages)
+ + "mAmbientIdleHysteresis=" + mAmbientBrightnessIdleHysteresis
+ "\n"
- + "mAmbientBrighteningLevelsIdle=" + Arrays.toString(
- mAmbientBrighteningLevelsIdle)
- + ", mAmbientBrighteningPercentagesIdle=" + Arrays.toString(
- mAmbientBrighteningPercentagesIdle)
- + ", mAmbientDarkeningLevelsIdle=" + Arrays.toString(
- mAmbientDarkeningLevelsIdle)
- + ", mAmbientDarkeningPercentagesIdle=" + Arrays.toString(
- mAmbientDarkeningPercentagesIdle)
- + ", mScreenBrighteningLevelsIdle=" + Arrays.toString(
- mScreenBrighteningLevelsIdle)
- + ", mScreenBrighteningPercentagesIdle=" + Arrays.toString(
- mScreenBrighteningPercentagesIdle)
- + ", mScreenDarkeningLevelsIdle=" + Arrays.toString(
- mScreenDarkeningLevelsIdle)
- + ", mScreenDarkeningPercentagesIdle=" + Arrays.toString(
- mScreenDarkeningPercentagesIdle)
+ + "mScreenBrightnessHysteresis=" + mScreenBrightnessHysteresis
+ + "\n"
+ + "mScreenBrightnessIdleHysteresis=" + mScreenBrightnessIdleHysteresis
+ "\n"
+ "mAmbientLightSensor=" + mAmbientLightSensor
+ ", mScreenOffBrightnessSensor=" + mScreenOffBrightnessSensor
@@ -3137,281 +2766,15 @@
}
private void loadBrightnessChangeThresholds(DisplayConfiguration config) {
- loadDisplayBrightnessThresholds(config);
- loadAmbientBrightnessThresholds(config);
- loadDisplayBrightnessThresholdsIdle(config);
- loadAmbientBrightnessThresholdsIdle(config);
- }
-
- private void loadDisplayBrightnessThresholds(DisplayConfiguration config) {
- BrightnessThresholds brighteningScreen = null;
- BrightnessThresholds darkeningScreen = null;
- if (config != null && config.getDisplayBrightnessChangeThresholds() != null) {
- brighteningScreen =
- config.getDisplayBrightnessChangeThresholds().getBrighteningThresholds();
- darkeningScreen =
- config.getDisplayBrightnessChangeThresholds().getDarkeningThresholds();
-
- }
-
- // Screen bright/darkening threshold levels for active mode
- Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
- brighteningScreen,
- com.android.internal.R.array.config_screenThresholdLevels,
- com.android.internal.R.array.config_screenBrighteningThresholds,
- DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
- /* potentialOldBrightnessScale= */ true);
-
- mScreenBrighteningLevels = screenBrighteningPair.first;
- mScreenBrighteningPercentages = screenBrighteningPair.second;
-
- Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
- darkeningScreen,
- com.android.internal.R.array.config_screenThresholdLevels,
- com.android.internal.R.array.config_screenDarkeningThresholds,
- DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
- /* potentialOldBrightnessScale= */ true);
- mScreenDarkeningLevels = screenDarkeningPair.first;
- mScreenDarkeningPercentages = screenDarkeningPair.second;
-
- // Screen bright/darkening threshold minimums for active mode
- if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
- mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
- }
- if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
- mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
- }
- }
-
- private void loadAmbientBrightnessThresholds(DisplayConfiguration config) {
- // Ambient Brightness Threshold Levels
- BrightnessThresholds brighteningAmbientLux = null;
- BrightnessThresholds darkeningAmbientLux = null;
- if (config != null && config.getAmbientBrightnessChangeThresholds() != null) {
- brighteningAmbientLux =
- config.getAmbientBrightnessChangeThresholds().getBrighteningThresholds();
- darkeningAmbientLux =
- config.getAmbientBrightnessChangeThresholds().getDarkeningThresholds();
- }
-
- // Ambient bright/darkening threshold levels for active mode
- Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
- brighteningAmbientLux,
- com.android.internal.R.array.config_ambientThresholdLevels,
- com.android.internal.R.array.config_ambientBrighteningThresholds,
- DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
- mAmbientBrighteningLevels = ambientBrighteningPair.first;
- mAmbientBrighteningPercentages = ambientBrighteningPair.second;
-
- Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
- darkeningAmbientLux,
- com.android.internal.R.array.config_ambientThresholdLevels,
- com.android.internal.R.array.config_ambientDarkeningThresholds,
- DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
- mAmbientDarkeningLevels = ambientDarkeningPair.first;
- mAmbientDarkeningPercentages = ambientDarkeningPair.second;
-
- // Ambient bright/darkening threshold minimums for active/idle mode
- if (brighteningAmbientLux != null && brighteningAmbientLux.getMinimum() != null) {
- mAmbientLuxBrighteningMinThreshold =
- brighteningAmbientLux.getMinimum().floatValue();
- }
-
- if (darkeningAmbientLux != null && darkeningAmbientLux.getMinimum() != null) {
- mAmbientLuxDarkeningMinThreshold = darkeningAmbientLux.getMinimum().floatValue();
- }
- }
-
- private void loadDisplayBrightnessThresholdsIdle(DisplayConfiguration config) {
- BrightnessThresholds brighteningScreenIdle = null;
- BrightnessThresholds darkeningScreenIdle = null;
- if (config != null && config.getDisplayBrightnessChangeThresholdsIdle() != null) {
- brighteningScreenIdle =
- config.getDisplayBrightnessChangeThresholdsIdle().getBrighteningThresholds();
- darkeningScreenIdle =
- config.getDisplayBrightnessChangeThresholdsIdle().getDarkeningThresholds();
- }
-
- Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
- brighteningScreenIdle,
- com.android.internal.R.array.config_screenThresholdLevels,
- com.android.internal.R.array.config_screenBrighteningThresholds,
- DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
- /* potentialOldBrightnessScale= */ true);
- mScreenBrighteningLevelsIdle = screenBrighteningPair.first;
- mScreenBrighteningPercentagesIdle = screenBrighteningPair.second;
-
- Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
- darkeningScreenIdle,
- com.android.internal.R.array.config_screenThresholdLevels,
- com.android.internal.R.array.config_screenDarkeningThresholds,
- DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
- /* potentialOldBrightnessScale= */ true);
- mScreenDarkeningLevelsIdle = screenDarkeningPair.first;
- mScreenDarkeningPercentagesIdle = screenDarkeningPair.second;
-
- if (brighteningScreenIdle != null
- && brighteningScreenIdle.getMinimum() != null) {
- mScreenBrighteningMinThresholdIdle =
- brighteningScreenIdle.getMinimum().floatValue();
- }
- if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
- mScreenDarkeningMinThresholdIdle =
- darkeningScreenIdle.getMinimum().floatValue();
- }
- }
-
- private void loadAmbientBrightnessThresholdsIdle(DisplayConfiguration config) {
- BrightnessThresholds brighteningAmbientLuxIdle = null;
- BrightnessThresholds darkeningAmbientLuxIdle = null;
- if (config != null && config.getAmbientBrightnessChangeThresholdsIdle() != null) {
- brighteningAmbientLuxIdle =
- config.getAmbientBrightnessChangeThresholdsIdle().getBrighteningThresholds();
- darkeningAmbientLuxIdle =
- config.getAmbientBrightnessChangeThresholdsIdle().getDarkeningThresholds();
- }
-
- Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
- brighteningAmbientLuxIdle,
- com.android.internal.R.array.config_ambientThresholdLevels,
- com.android.internal.R.array.config_ambientBrighteningThresholds,
- DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
- mAmbientBrighteningLevelsIdle = ambientBrighteningPair.first;
- mAmbientBrighteningPercentagesIdle = ambientBrighteningPair.second;
-
- Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
- darkeningAmbientLuxIdle,
- com.android.internal.R.array.config_ambientThresholdLevels,
- com.android.internal.R.array.config_ambientDarkeningThresholds,
- DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
- mAmbientDarkeningLevelsIdle = ambientDarkeningPair.first;
- mAmbientDarkeningPercentagesIdle = ambientDarkeningPair.second;
-
- if (brighteningAmbientLuxIdle != null
- && brighteningAmbientLuxIdle.getMinimum() != null) {
- mAmbientLuxBrighteningMinThresholdIdle =
- brighteningAmbientLuxIdle.getMinimum().floatValue();
- }
-
- if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
- mAmbientLuxDarkeningMinThresholdIdle =
- darkeningAmbientLuxIdle.getMinimum().floatValue();
- }
- }
-
- private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
- int configFallbackThreshold, int configFallbackPercentage, float[] defaultLevels,
- float[] defaultPercentage) {
- return getBrightnessLevelAndPercentage(thresholds, configFallbackThreshold,
- configFallbackPercentage, defaultLevels, defaultPercentage, false);
- }
-
- // Returns two float arrays, one of the brightness levels and one of the corresponding threshold
- // percentages for brightness levels at or above the lux value.
- // Historically, config.xml would have an array for brightness levels that was 1 shorter than
- // the levels array. Now we prepend a 0 to this array so they can be treated the same in the
- // rest of the framework. Values were also defined in different units (permille vs percent).
- private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
- int configFallbackThreshold, int configFallbackPermille,
- float[] defaultLevels, float[] defaultPercentage,
- boolean potentialOldBrightnessScale) {
- if (thresholds != null
- && thresholds.getBrightnessThresholdPoints() != null
- && thresholds.getBrightnessThresholdPoints()
- .getBrightnessThresholdPoint().size() != 0) {
-
- // The level and percentages arrays are equal length in the ddc (new system)
- List<ThresholdPoint> points =
- thresholds.getBrightnessThresholdPoints().getBrightnessThresholdPoint();
- final int size = points.size();
-
- float[] thresholdLevels = new float[size];
- float[] thresholdPercentages = new float[size];
-
- int i = 0;
- for (ThresholdPoint point : points) {
- thresholdLevels[i] = point.getThreshold().floatValue();
- thresholdPercentages[i] = point.getPercentage().floatValue();
- i++;
- }
- return new Pair<>(thresholdLevels, thresholdPercentages);
- } else {
- // The level and percentages arrays are unequal length in config.xml (old system)
- // We prefix the array with a 0 value to ensure they can be handled consistently
- // with the new system.
-
- // Load levels array
- int[] configThresholdArray = mContext.getResources().getIntArray(
- configFallbackThreshold);
- int configThresholdsSize;
- if (configThresholdArray == null || configThresholdArray.length == 0) {
- configThresholdsSize = 1;
- } else {
- configThresholdsSize = configThresholdArray.length + 1;
- }
-
-
- // Load percentage array
- int[] configPermille = mContext.getResources().getIntArray(
- configFallbackPermille);
-
- // Ensure lengths match up
- boolean emptyArray = configPermille == null || configPermille.length == 0;
- if (emptyArray && configThresholdsSize == 1) {
- return new Pair<>(defaultLevels, defaultPercentage);
- }
- if (emptyArray || configPermille.length != configThresholdsSize) {
- throw new IllegalArgumentException(
- "Brightness threshold arrays do not align in length");
- }
-
- // Calculate levels array
- float[] configThresholdWithZeroPrefixed = new float[configThresholdsSize];
- // Start at 1, so that 0 index value is 0.0f (default)
- for (int i = 1; i < configThresholdsSize; i++) {
- configThresholdWithZeroPrefixed[i] = (float) configThresholdArray[i - 1];
- }
- if (potentialOldBrightnessScale) {
- configThresholdWithZeroPrefixed =
- constraintInRangeIfNeeded(configThresholdWithZeroPrefixed);
- }
-
- // Calculate percentages array
- float[] configPercentage = new float[configThresholdsSize];
- for (int i = 0; i < configPermille.length; i++) {
- configPercentage[i] = configPermille[i] / 10.0f;
- } return new Pair<>(configThresholdWithZeroPrefixed, configPercentage);
- }
- }
-
- /**
- * This check is due to historical reasons, where screen thresholdLevels used to be
- * integer values in the range of [0-255], but then was changed to be float values from [0,1].
- * To accommodate both the possibilities, we first check if all the thresholdLevels are in
- * [0,1], and if not, we divide all the levels with 255 to bring them down to the same scale.
- */
- private float[] constraintInRangeIfNeeded(float[] thresholdLevels) {
- if (isAllInRange(thresholdLevels, /* minValueInclusive= */ 0.0f,
- /* maxValueInclusive= */ 1.0f)) {
- return thresholdLevels;
- }
-
- Slog.w(TAG, "Detected screen thresholdLevels on a deprecated brightness scale");
- float[] thresholdLevelsScaled = new float[thresholdLevels.length];
- for (int index = 0; thresholdLevels.length > index; ++index) {
- thresholdLevelsScaled[index] = thresholdLevels[index] / 255.0f;
- }
- return thresholdLevelsScaled;
- }
-
- private boolean isAllInRange(float[] configArray, float minValueInclusive,
- float maxValueInclusive) {
- for (float v : configArray) {
- if (v < minValueInclusive || v > maxValueInclusive) {
- return false;
- }
- }
- return true;
+ Resources res = mContext.getResources();
+ mScreenBrightnessHysteresis =
+ HysteresisLevels.loadDisplayBrightnessConfig(config, res);
+ mScreenBrightnessIdleHysteresis =
+ HysteresisLevels.loadDisplayBrightnessIdleConfig(config, res);
+ mAmbientBrightnessHysteresis =
+ HysteresisLevels.loadAmbientBrightnessConfig(config, res);
+ mAmbientBrightnessIdleHysteresis =
+ HysteresisLevels.loadAmbientBrightnessIdleConfig(config, res);
}
private boolean thermalStatusIsValid(ThermalStatus value) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b21a89a..404c3ad 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -86,6 +86,7 @@
import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
+import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.Layout;
import com.android.server.display.state.DisplayStateController;
@@ -1050,76 +1051,20 @@
if (defaultModeBrightnessMapper != null) {
// Ambient Lux - Active Mode Brightness Thresholds
- float[] ambientBrighteningThresholds =
- mDisplayDeviceConfig.getAmbientBrighteningPercentages();
- float[] ambientDarkeningThresholds =
- mDisplayDeviceConfig.getAmbientDarkeningPercentages();
- float[] ambientBrighteningLevels =
- mDisplayDeviceConfig.getAmbientBrighteningLevels();
- float[] ambientDarkeningLevels =
- mDisplayDeviceConfig.getAmbientDarkeningLevels();
- float ambientDarkeningMinThreshold =
- mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold();
- float ambientBrighteningMinThreshold =
- mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold();
- HysteresisLevels ambientBrightnessThresholds = mInjector.getHysteresisLevels(
- ambientBrighteningThresholds, ambientDarkeningThresholds,
- ambientBrighteningLevels, ambientDarkeningLevels, ambientDarkeningMinThreshold,
- ambientBrighteningMinThreshold);
+ HysteresisLevels ambientBrightnessThresholds =
+ mDisplayDeviceConfig.getAmbientBrightnessHysteresis();
// Display - Active Mode Brightness Thresholds
- float[] screenBrighteningThresholds =
- mDisplayDeviceConfig.getScreenBrighteningPercentages();
- float[] screenDarkeningThresholds =
- mDisplayDeviceConfig.getScreenDarkeningPercentages();
- float[] screenBrighteningLevels =
- mDisplayDeviceConfig.getScreenBrighteningLevels();
- float[] screenDarkeningLevels =
- mDisplayDeviceConfig.getScreenDarkeningLevels();
- float screenDarkeningMinThreshold =
- mDisplayDeviceConfig.getScreenDarkeningMinThreshold();
- float screenBrighteningMinThreshold =
- mDisplayDeviceConfig.getScreenBrighteningMinThreshold();
- HysteresisLevels screenBrightnessThresholds = mInjector.getHysteresisLevels(
- screenBrighteningThresholds, screenDarkeningThresholds,
- screenBrighteningLevels, screenDarkeningLevels, screenDarkeningMinThreshold,
- screenBrighteningMinThreshold, true);
+ HysteresisLevels screenBrightnessThresholds =
+ mDisplayDeviceConfig.getScreenBrightnessHysteresis();
// Ambient Lux - Idle Screen Brightness Thresholds
- float ambientDarkeningMinThresholdIdle =
- mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle();
- float ambientBrighteningMinThresholdIdle =
- mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle();
- float[] ambientBrighteningThresholdsIdle =
- mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle();
- float[] ambientDarkeningThresholdsIdle =
- mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle();
- float[] ambientBrighteningLevelsIdle =
- mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle();
- float[] ambientDarkeningLevelsIdle =
- mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle();
- HysteresisLevels ambientBrightnessThresholdsIdle = mInjector.getHysteresisLevels(
- ambientBrighteningThresholdsIdle, ambientDarkeningThresholdsIdle,
- ambientBrighteningLevelsIdle, ambientDarkeningLevelsIdle,
- ambientDarkeningMinThresholdIdle, ambientBrighteningMinThresholdIdle);
+ HysteresisLevels ambientBrightnessThresholdsIdle =
+ mDisplayDeviceConfig.getAmbientBrightnessIdleHysteresis();
// Display - Idle Screen Brightness Thresholds
- float screenDarkeningMinThresholdIdle =
- mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle();
- float screenBrighteningMinThresholdIdle =
- mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle();
- float[] screenBrighteningThresholdsIdle =
- mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle();
- float[] screenDarkeningThresholdsIdle =
- mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle();
- float[] screenBrighteningLevelsIdle =
- mDisplayDeviceConfig.getScreenBrighteningLevelsIdle();
- float[] screenDarkeningLevelsIdle =
- mDisplayDeviceConfig.getScreenDarkeningLevelsIdle();
- HysteresisLevels screenBrightnessThresholdsIdle = mInjector.getHysteresisLevels(
- screenBrighteningThresholdsIdle, screenDarkeningThresholdsIdle,
- screenBrighteningLevelsIdle, screenDarkeningLevelsIdle,
- screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle);
+ HysteresisLevels screenBrightnessThresholdsIdle =
+ mDisplayDeviceConfig.getScreenBrightnessIdleHysteresis();
long brighteningLightDebounce = mDisplayDeviceConfig
.getAutoBrightnessBrighteningLightDebounce();
@@ -3208,25 +3153,6 @@
AUTO_BRIGHTNESS_MODE_DEFAULT, displayWhiteBalanceController);
}
- HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels,
- float[] darkeningThresholdLevels, float minDarkeningThreshold,
- float minBrighteningThreshold) {
- return new HysteresisLevels(brighteningThresholdsPercentages,
- darkeningThresholdsPercentages, brighteningThresholdLevels,
- darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold);
- }
-
- HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels,
- float[] darkeningThresholdLevels, float minDarkeningThreshold,
- float minBrighteningThreshold, boolean potentialOldBrightnessRange) {
- return new HysteresisLevels(brighteningThresholdsPercentages,
- darkeningThresholdsPercentages, brighteningThresholdLevels,
- darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold,
- potentialOldBrightnessRange);
- }
-
ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
SensorManager sensorManager,
Sensor lightSensor,
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
deleted file mode 100644
index 0521b8a..0000000
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display;
-
-import android.util.Slog;
-
-import com.android.server.display.utils.DebugUtils;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-
-/**
- * A helper class for handling access to illuminance hysteresis level values.
- */
-public class HysteresisLevels {
- private static final String TAG = "HysteresisLevels";
-
- // To enable these logs, run:
- // 'adb shell setprop persist.log.tag.HysteresisLevels DEBUG && adb reboot'
- private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
-
- private final float[] mBrighteningThresholdsPercentages;
- private final float[] mDarkeningThresholdsPercentages;
- private final float[] mBrighteningThresholdLevels;
- private final float[] mDarkeningThresholdLevels;
- private final float mMinDarkening;
- private final float mMinBrightening;
-
- /**
- * Creates a {@code HysteresisLevels} object with the given equal-length
- * float arrays.
- * @param brighteningThresholdsPercentages 0-100 of thresholds
- * @param darkeningThresholdsPercentages 0-100 of thresholds
- * @param brighteningThresholdLevels float array of brightness values in the relevant units
- * @param minBrighteningThreshold the minimum value for which the brightening value needs to
- * return.
- * @param minDarkeningThreshold the minimum value for which the darkening value needs to return.
- * @param potentialOldBrightnessRange whether or not the values used could be from the old
- * screen brightness range ie, between 1-255.
- */
- HysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages,
- float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
- float minDarkeningThreshold, float minBrighteningThreshold,
- boolean potentialOldBrightnessRange) {
- if (brighteningThresholdsPercentages.length != brighteningThresholdLevels.length
- || darkeningThresholdsPercentages.length != darkeningThresholdLevels.length) {
- throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
- }
- mBrighteningThresholdsPercentages =
- setArrayFormat(brighteningThresholdsPercentages, 100.0f);
- mDarkeningThresholdsPercentages =
- setArrayFormat(darkeningThresholdsPercentages, 100.0f);
- mBrighteningThresholdLevels = setArrayFormat(brighteningThresholdLevels, 1.0f);
- mDarkeningThresholdLevels = setArrayFormat(darkeningThresholdLevels, 1.0f);
- mMinDarkening = minDarkeningThreshold;
- mMinBrightening = minBrighteningThreshold;
- }
-
- HysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages,
- float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
- float minDarkeningThreshold, float minBrighteningThreshold) {
- this(brighteningThresholdsPercentages, darkeningThresholdsPercentages,
- brighteningThresholdLevels, darkeningThresholdLevels, minDarkeningThreshold,
- minBrighteningThreshold, false);
- }
-
- /**
- * Return the brightening hysteresis threshold for the given value level.
- */
- public float getBrighteningThreshold(float value) {
- final float brightConstant = getReferenceLevel(value,
- mBrighteningThresholdLevels, mBrighteningThresholdsPercentages);
-
- float brightThreshold = value * (1.0f + brightConstant);
- if (DEBUG) {
- Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold="
- + brightThreshold + ", value=" + value);
- }
-
- brightThreshold = Math.max(brightThreshold, value + mMinBrightening);
- return brightThreshold;
- }
-
- /**
- * Return the darkening hysteresis threshold for the given value level.
- */
- public float getDarkeningThreshold(float value) {
- final float darkConstant = getReferenceLevel(value,
- mDarkeningThresholdLevels, mDarkeningThresholdsPercentages);
- float darkThreshold = value * (1.0f - darkConstant);
- if (DEBUG) {
- Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
- + darkThreshold + ", value=" + value);
- }
- darkThreshold = Math.min(darkThreshold, value - mMinDarkening);
- return Math.max(darkThreshold, 0.0f);
- }
-
- /**
- * Return the hysteresis constant for the closest threshold value from the given array.
- */
- private float getReferenceLevel(float value, float[] thresholdLevels,
- float[] thresholdPercentages) {
- if (thresholdLevels == null || thresholdLevels.length == 0 || value < thresholdLevels[0]) {
- return 0.0f;
- }
- int index = 0;
- while (index < thresholdLevels.length - 1 && value >= thresholdLevels[index + 1]) {
- index++;
- }
- return thresholdPercentages[index];
- }
-
- /**
- * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
- */
- private float[] setArrayFormat(float[] configArray, float divideFactor) {
- float[] levelArray = new float[configArray.length];
- for (int index = 0; levelArray.length > index; ++index) {
- levelArray[index] = configArray[index] / divideFactor;
- }
- return levelArray;
- }
-
- void dump(PrintWriter pw) {
- pw.println("HysteresisLevels");
- pw.println(" mBrighteningThresholdLevels=" + Arrays.toString(mBrighteningThresholdLevels));
- pw.println(" mBrighteningThresholdsPercentages="
- + Arrays.toString(mBrighteningThresholdsPercentages));
- pw.println(" mMinBrightening=" + mMinBrightening);
- pw.println(" mDarkeningThresholdLevels=" + Arrays.toString(mDarkeningThresholdLevels));
- pw.println(" mDarkeningThresholdsPercentages="
- + Arrays.toString(mDarkeningThresholdsPercentages));
- pw.println(" mMinDarkening=" + mMinDarkening);
- }
-}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 22e4bc5..189e366 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -482,7 +482,8 @@
int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;
- if (mIsAnisotropyCorrectionEnabled && deviceInfo.xDpi > 0 && deviceInfo.yDpi > 0) {
+ if (mIsAnisotropyCorrectionEnabled && deviceInfo.type == Display.TYPE_EXTERNAL
+ && deviceInfo.xDpi > 0 && deviceInfo.yDpi > 0) {
if (deviceInfo.xDpi > deviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) {
maskedHeight = (int) (maskedHeight * deviceInfo.xDpi / deviceInfo.yDpi + 0.5);
} else if (deviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY < deviceInfo.yDpi) {
@@ -711,8 +712,8 @@
var displayLogicalWidth = displayInfo.logicalWidth;
var displayLogicalHeight = displayInfo.logicalHeight;
- if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.xDpi > 0
- && displayDeviceInfo.yDpi > 0) {
+ if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL
+ && displayDeviceInfo.xDpi > 0 && displayDeviceInfo.yDpi > 0) {
if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) {
var scalingFactor = displayDeviceInfo.yDpi / displayDeviceInfo.xDpi;
if (rotated) {
diff --git a/services/core/java/com/android/server/display/config/HysteresisLevels.java b/services/core/java/com/android/server/display/config/HysteresisLevels.java
new file mode 100644
index 0000000..e659d88
--- /dev/null
+++ b/services/core/java/com/android/server/display/config/HysteresisLevels.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.config;
+
+import android.annotation.ArrayRes;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.utils.DebugUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A helper class for handling access to illuminance hysteresis level values.
+ */
+public class HysteresisLevels {
+ private static final String TAG = "HysteresisLevels";
+
+ private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f};
+ private static final float[] DEFAULT_AMBIENT_DARKENING_THRESHOLDS = new float[]{200f};
+ private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f};
+ private static final float[] DEFAULT_SCREEN_THRESHOLD_LEVELS = new float[]{0f};
+ private static final float[] DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS = new float[]{100f};
+ private static final float[] DEFAULT_SCREEN_DARKENING_THRESHOLDS = new float[]{200f};
+
+ // To enable these logs, run:
+ // 'adb shell setprop persist.log.tag.HysteresisLevels DEBUG && adb reboot'
+ private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
+
+ /**
+ * The array that describes the brightness threshold percentage change
+ * at each brightness level described in mBrighteningThresholdLevels.
+ */
+ private final float[] mBrighteningThresholdsPercentages;
+
+ /**
+ * The array that describes the brightness threshold percentage change
+ * at each brightness level described in mDarkeningThresholdLevels.
+ */
+ private final float[] mDarkeningThresholdsPercentages;
+
+ /**
+ * The array that describes the range of brightness that each threshold percentage applies to
+ *
+ * The (zero-based) index is calculated as follows
+ * value = current brightness value
+ * level = mBrighteningThresholdLevels
+ *
+ * condition return
+ * value < mBrighteningThresholdLevels[0] = 0.0f
+ * level[n] <= value < level[n+1] = mBrighteningThresholdsPercentages[n]
+ * level[MAX] <= value = mBrighteningThresholdsPercentages[MAX]
+ */
+ private final float[] mBrighteningThresholdLevels;
+
+ /**
+ * The array that describes the range of brightness that each threshold percentage applies to
+ *
+ * The (zero-based) index is calculated as follows
+ * value = current brightness value
+ * level = mDarkeningThresholdLevels
+ *
+ * condition return
+ * value < level[0] = 0.0f
+ * level[n] <= value < level[n+1] = mDarkeningThresholdsPercentages[n]
+ * level[MAX] <= value = mDarkeningThresholdsPercentages[MAX]
+ */
+ private final float[] mDarkeningThresholdLevels;
+
+ /**
+ * The minimum value decrease for darkening event
+ */
+ private final float mMinDarkening;
+
+ /**
+ * The minimum value increase for brightening event.
+ */
+ private final float mMinBrightening;
+
+ /**
+ * Creates a {@code HysteresisLevels} object with the given equal-length
+ * float arrays.
+ *
+ * @param brighteningThresholdsPercentages 0-100 of thresholds
+ * @param darkeningThresholdsPercentages 0-100 of thresholds
+ * @param brighteningThresholdLevels float array of brightness values in the relevant
+ * units
+ * @param minBrighteningThreshold the minimum value for which the brightening value
+ * needs to
+ * return.
+ * @param minDarkeningThreshold the minimum value for which the darkening value needs
+ * to return.
+ */
+ @VisibleForTesting
+ public HysteresisLevels(float[] brighteningThresholdsPercentages,
+ float[] darkeningThresholdsPercentages,
+ float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
+ float minDarkeningThreshold, float minBrighteningThreshold) {
+ if (brighteningThresholdsPercentages.length != brighteningThresholdLevels.length
+ || darkeningThresholdsPercentages.length != darkeningThresholdLevels.length) {
+ throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
+ }
+ mBrighteningThresholdsPercentages =
+ setArrayFormat(brighteningThresholdsPercentages, 100.0f);
+ mDarkeningThresholdsPercentages =
+ setArrayFormat(darkeningThresholdsPercentages, 100.0f);
+ mBrighteningThresholdLevels = setArrayFormat(brighteningThresholdLevels, 1.0f);
+ mDarkeningThresholdLevels = setArrayFormat(darkeningThresholdLevels, 1.0f);
+ mMinDarkening = minDarkeningThreshold;
+ mMinBrightening = minBrighteningThreshold;
+ }
+
+ /**
+ * Return the brightening hysteresis threshold for the given value level.
+ */
+ public float getBrighteningThreshold(float value) {
+ final float brightConstant = getReferenceLevel(value,
+ mBrighteningThresholdLevels, mBrighteningThresholdsPercentages);
+
+ float brightThreshold = value * (1.0f + brightConstant);
+ if (DEBUG) {
+ Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold="
+ + brightThreshold + ", value=" + value);
+ }
+
+ brightThreshold = Math.max(brightThreshold, value + mMinBrightening);
+ return brightThreshold;
+ }
+
+ /**
+ * Return the darkening hysteresis threshold for the given value level.
+ */
+ public float getDarkeningThreshold(float value) {
+ final float darkConstant = getReferenceLevel(value,
+ mDarkeningThresholdLevels, mDarkeningThresholdsPercentages);
+ float darkThreshold = value * (1.0f - darkConstant);
+ if (DEBUG) {
+ Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
+ + darkThreshold + ", value=" + value);
+ }
+ darkThreshold = Math.min(darkThreshold, value - mMinDarkening);
+ return Math.max(darkThreshold, 0.0f);
+ }
+
+ @VisibleForTesting
+ public float[] getBrighteningThresholdsPercentages() {
+ return mBrighteningThresholdsPercentages;
+ }
+
+ @VisibleForTesting
+ public float[] getDarkeningThresholdsPercentages() {
+ return mDarkeningThresholdsPercentages;
+ }
+
+ @VisibleForTesting
+ public float[] getBrighteningThresholdLevels() {
+ return mBrighteningThresholdLevels;
+ }
+
+ @VisibleForTesting
+ public float[] getDarkeningThresholdLevels() {
+ return mDarkeningThresholdLevels;
+ }
+
+ @VisibleForTesting
+ public float getMinDarkening() {
+ return mMinDarkening;
+ }
+
+ @VisibleForTesting
+ public float getMinBrightening() {
+ return mMinBrightening;
+ }
+
+ /**
+ * Return the hysteresis constant for the closest threshold value from the given array.
+ */
+ private float getReferenceLevel(float value, float[] thresholdLevels,
+ float[] thresholdPercentages) {
+ if (thresholdLevels == null || thresholdLevels.length == 0 || value < thresholdLevels[0]) {
+ return 0.0f;
+ }
+ int index = 0;
+ while (index < thresholdLevels.length - 1 && value >= thresholdLevels[index + 1]) {
+ index++;
+ }
+ return thresholdPercentages[index];
+ }
+
+ /**
+ * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
+ */
+ private float[] setArrayFormat(float[] configArray, float divideFactor) {
+ float[] levelArray = new float[configArray.length];
+ for (int index = 0; levelArray.length > index; ++index) {
+ levelArray[index] = configArray[index] / divideFactor;
+ }
+ return levelArray;
+ }
+
+ @Override
+ public String toString() {
+ return "HysteresisLevels {"
+ + "\n"
+ + " mBrighteningThresholdLevels=" + Arrays.toString(mBrighteningThresholdLevels)
+ + ",\n"
+ + " mBrighteningThresholdsPercentages="
+ + Arrays.toString(mBrighteningThresholdsPercentages)
+ + ",\n"
+ + " mMinBrightening=" + mMinBrightening
+ + ",\n"
+ + " mDarkeningThresholdLevels=" + Arrays.toString(mDarkeningThresholdLevels)
+ + ",\n"
+ + " mDarkeningThresholdsPercentages="
+ + Arrays.toString(mDarkeningThresholdsPercentages)
+ + ",\n"
+ + " mMinDarkening=" + mMinDarkening
+ + "\n"
+ + "}";
+ }
+
+ /**
+ * Creates hysteresis levels for Active Ambient Lux
+ */
+ public static HysteresisLevels loadAmbientBrightnessConfig(
+ @Nullable DisplayConfiguration config, @Nullable Resources resources) {
+ return createHysteresisLevels(
+ config == null ? null : config.getAmbientBrightnessChangeThresholds(),
+ com.android.internal.R.array.config_ambientThresholdLevels,
+ com.android.internal.R.array.config_ambientBrighteningThresholds,
+ com.android.internal.R.array.config_ambientDarkeningThresholds,
+ DEFAULT_AMBIENT_THRESHOLD_LEVELS,
+ DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS,
+ DEFAULT_AMBIENT_DARKENING_THRESHOLDS,
+ resources, /* potentialOldBrightnessScale= */ false);
+ }
+
+ /**
+ * Creates hysteresis levels for Active Screen Brightness
+ */
+ public static HysteresisLevels loadDisplayBrightnessConfig(
+ @Nullable DisplayConfiguration config, @Nullable Resources resources) {
+ return createHysteresisLevels(
+ config == null ? null : config.getDisplayBrightnessChangeThresholds(),
+ com.android.internal.R.array.config_screenThresholdLevels,
+ com.android.internal.R.array.config_screenBrighteningThresholds,
+ com.android.internal.R.array.config_screenDarkeningThresholds,
+ DEFAULT_SCREEN_THRESHOLD_LEVELS,
+ DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
+ DEFAULT_SCREEN_DARKENING_THRESHOLDS,
+ resources, /* potentialOldBrightnessScale= */ true);
+ }
+
+ /**
+ * Creates hysteresis levels for Idle Ambient Lux
+ */
+ public static HysteresisLevels loadAmbientBrightnessIdleConfig(
+ @Nullable DisplayConfiguration config, @Nullable Resources resources) {
+ return createHysteresisLevels(
+ config == null ? null : config.getAmbientBrightnessChangeThresholdsIdle(),
+ com.android.internal.R.array.config_ambientThresholdLevels,
+ com.android.internal.R.array.config_ambientBrighteningThresholds,
+ com.android.internal.R.array.config_ambientDarkeningThresholds,
+ DEFAULT_AMBIENT_THRESHOLD_LEVELS,
+ DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS,
+ DEFAULT_AMBIENT_DARKENING_THRESHOLDS,
+ resources, /* potentialOldBrightnessScale= */ false);
+ }
+
+ /**
+ * Creates hysteresis levels for Idle Screen Brightness
+ */
+ public static HysteresisLevels loadDisplayBrightnessIdleConfig(
+ @Nullable DisplayConfiguration config, @Nullable Resources resources) {
+ return createHysteresisLevels(
+ config == null ? null : config.getDisplayBrightnessChangeThresholdsIdle(),
+ com.android.internal.R.array.config_screenThresholdLevels,
+ com.android.internal.R.array.config_screenBrighteningThresholds,
+ com.android.internal.R.array.config_screenDarkeningThresholds,
+ DEFAULT_SCREEN_THRESHOLD_LEVELS,
+ DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
+ DEFAULT_SCREEN_DARKENING_THRESHOLDS,
+ resources, /* potentialOldBrightnessScale= */ true);
+ }
+
+
+ private static HysteresisLevels createHysteresisLevels(
+ @Nullable Thresholds thresholds,
+ @ArrayRes int configLevels,
+ @ArrayRes int configBrighteningThresholds,
+ @ArrayRes int configDarkeningThresholds,
+ float[] defaultLevels,
+ float[] defaultBrighteningThresholds,
+ float[] defaultDarkeningThresholds,
+ @Nullable Resources resources,
+ boolean potentialOldBrightnessScale
+ ) {
+ BrightnessThresholds brighteningThresholds =
+ thresholds == null ? null : thresholds.getBrighteningThresholds();
+ BrightnessThresholds darkeningThresholds =
+ thresholds == null ? null : thresholds.getDarkeningThresholds();
+
+ Pair<float[], float[]> brighteningPair = getBrightnessLevelAndPercentage(
+ brighteningThresholds,
+ configLevels, configBrighteningThresholds,
+ defaultLevels, defaultBrighteningThresholds,
+ potentialOldBrightnessScale, resources);
+
+ Pair<float[], float[]> darkeningPair = getBrightnessLevelAndPercentage(
+ darkeningThresholds,
+ configLevels, configDarkeningThresholds,
+ defaultLevels, defaultDarkeningThresholds,
+ potentialOldBrightnessScale, resources);
+
+ float brighteningMinThreshold =
+ brighteningThresholds != null && brighteningThresholds.getMinimum() != null
+ ? brighteningThresholds.getMinimum().floatValue() : 0f;
+ float darkeningMinThreshold =
+ darkeningThresholds != null && darkeningThresholds.getMinimum() != null
+ ? darkeningThresholds.getMinimum().floatValue() : 0f;
+
+ return new HysteresisLevels(
+ brighteningPair.second,
+ darkeningPair.second,
+ brighteningPair.first,
+ darkeningPair.first,
+ darkeningMinThreshold,
+ brighteningMinThreshold
+ );
+ }
+
+ // Returns two float arrays, one of the brightness levels and one of the corresponding threshold
+ // percentages for brightness levels at or above the lux value.
+ // Historically, config.xml would have an array for brightness levels that was 1 shorter than
+ // the levels array. Now we prepend a 0 to this array so they can be treated the same in the
+ // rest of the framework. Values were also defined in different units (permille vs percent).
+ private static Pair<float[], float[]> getBrightnessLevelAndPercentage(
+ @Nullable BrightnessThresholds thresholds,
+ int configFallbackThreshold, int configFallbackPermille,
+ float[] defaultLevels, float[] defaultPercentage, boolean potentialOldBrightnessScale,
+ @Nullable Resources resources) {
+ if (thresholds != null
+ && thresholds.getBrightnessThresholdPoints() != null
+ && !thresholds.getBrightnessThresholdPoints().getBrightnessThresholdPoint()
+ .isEmpty()) {
+
+ // The level and percentages arrays are equal length in the ddc (new system)
+ List<ThresholdPoint> points =
+ thresholds.getBrightnessThresholdPoints().getBrightnessThresholdPoint();
+ final int size = points.size();
+
+ float[] thresholdLevels = new float[size];
+ float[] thresholdPercentages = new float[size];
+
+ int i = 0;
+ for (ThresholdPoint point : points) {
+ thresholdLevels[i] = point.getThreshold().floatValue();
+ thresholdPercentages[i] = point.getPercentage().floatValue();
+ i++;
+ }
+ return new Pair<>(thresholdLevels, thresholdPercentages);
+ } else if (resources != null) {
+ // The level and percentages arrays are unequal length in config.xml (old system)
+ // We prefix the array with a 0 value to ensure they can be handled consistently
+ // with the new system.
+
+ // Load levels array
+ int[] configThresholdArray = resources.getIntArray(configFallbackThreshold);
+ int configThresholdsSize;
+ // null check is not needed here, however it test we are mocking resources that might
+ // return null
+ if (configThresholdArray == null || configThresholdArray.length == 0) {
+ configThresholdsSize = 1;
+ } else {
+ configThresholdsSize = configThresholdArray.length + 1;
+ }
+
+ // Load percentage array
+ int[] configPermille = resources.getIntArray(configFallbackPermille);
+
+ // Ensure lengths match up
+ // null check is not needed here, however it test we are mocking resources that might
+ // return null
+ boolean emptyArray = configPermille == null || configPermille.length == 0;
+ if (emptyArray && configThresholdsSize == 1) {
+ return new Pair<>(defaultLevels, defaultPercentage);
+ }
+ if (emptyArray || configPermille.length != configThresholdsSize) {
+ throw new IllegalArgumentException(
+ "Brightness threshold arrays do not align in length");
+ }
+
+ // Calculate levels array
+ float[] configThresholdWithZeroPrefixed = new float[configThresholdsSize];
+ // Start at 1, so that 0 index value is 0.0f (default)
+ for (int i = 1; i < configThresholdsSize; i++) {
+ configThresholdWithZeroPrefixed[i] = (float) configThresholdArray[i - 1];
+ }
+ if (potentialOldBrightnessScale) {
+ configThresholdWithZeroPrefixed =
+ constraintInRangeIfNeeded(configThresholdWithZeroPrefixed);
+ }
+
+ // Calculate percentages array
+ float[] configPercentage = new float[configThresholdsSize];
+ for (int i = 0; i < configPermille.length; i++) {
+ configPercentage[i] = configPermille[i] / 10.0f;
+ }
+ return new Pair<>(configThresholdWithZeroPrefixed, configPercentage);
+ } else {
+ return new Pair<>(defaultLevels, defaultPercentage);
+ }
+ }
+
+ /**
+ * This check is due to historical reasons, where screen thresholdLevels used to be
+ * integer values in the range of [0-255], but then was changed to be float values from [0,1].
+ * To accommodate both the possibilities, we first check if all the thresholdLevels are in
+ * [0,1], and if not, we divide all the levels with 255 to bring them down to the same scale.
+ */
+ private static float[] constraintInRangeIfNeeded(float[] thresholdLevels) {
+ if (isAllInRange(thresholdLevels, /* minValueInclusive= */ 0.0f,
+ /* maxValueInclusive= */ 1.0f)) {
+ return thresholdLevels;
+ }
+
+ Slog.w(TAG, "Detected screen thresholdLevels on a deprecated brightness scale");
+ float[] thresholdLevelsScaled = new float[thresholdLevels.length];
+ for (int index = 0; thresholdLevels.length > index; ++index) {
+ thresholdLevelsScaled[index] = thresholdLevels[index] / 255.0f;
+ }
+ return thresholdLevelsScaled;
+ }
+
+ private static boolean isAllInRange(float[] configArray, float minValueInclusive,
+ float maxValueInclusive) {
+ for (float v : configArray) {
+ if (v < minValueInclusive || v > maxValueInclusive) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7f9c1cf..33b5a70 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -327,7 +327,8 @@
UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT)
.setProfileApiVisibility(
UserProperties.PROFILE_API_VISIBILITY_HIDDEN)
- .setItemsRestrictedOnHomeScreen(true));
+ .setItemsRestrictedOnHomeScreen(true)
+ .setUpdateCrossProfileIntentFiltersOnOTA(true));
}
/**
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 54de64e..64253e1 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -53,6 +53,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.display.brightness.clamper.BrightnessClamperController;
+import com.android.server.display.config.HysteresisLevels;
import com.android.server.testutils.OffsettableClock;
import org.junit.After;
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 494a667..b80d44f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -55,6 +55,7 @@
import com.android.internal.R;
import com.android.server.display.config.HdrBrightnessData;
+import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -169,53 +170,57 @@
assertArrayEquals(mDisplayDeviceConfig.getBacklight(), BRIGHTNESS, ZERO_DELTA);
// Test thresholds
- assertEquals(10, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(),
- ZERO_DELTA);
- assertEquals(20, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle(),
- ZERO_DELTA);
- assertEquals(30, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(), ZERO_DELTA);
- assertEquals(40, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle(), ZERO_DELTA);
+ HysteresisLevels ambientHysteresis = mDisplayDeviceConfig.getAmbientBrightnessHysteresis();
+ HysteresisLevels ambientIdleHysteresis =
+ mDisplayDeviceConfig.getAmbientBrightnessIdleHysteresis();
+ HysteresisLevels screenHysteresis = mDisplayDeviceConfig.getScreenBrightnessHysteresis();
+ HysteresisLevels screenIdleHysteresis =
+ mDisplayDeviceConfig.getScreenBrightnessIdleHysteresis();
+ assertEquals(10, ambientHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(20, ambientIdleHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(30, ambientHysteresis.getMinDarkening(), ZERO_DELTA);
+ assertEquals(40, ambientIdleHysteresis.getMinDarkening(), ZERO_DELTA);
- assertEquals(0.1f, mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), ZERO_DELTA);
- assertEquals(0.2f, mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle(), ZERO_DELTA);
- assertEquals(0.3f, mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), ZERO_DELTA);
- assertEquals(0.4f, mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle(), ZERO_DELTA);
+ assertEquals(0.1f, screenHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0.2f, screenIdleHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0.3f, screenHysteresis.getMinDarkening(), ZERO_DELTA);
+ assertEquals(0.4f, screenIdleHysteresis.getMinDarkening(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 0.10f, 0.20f},
- mDisplayDeviceConfig.getScreenBrighteningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{9, 10, 11},
- mDisplayDeviceConfig.getScreenBrighteningPercentages(), ZERO_DELTA);
+ screenHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.09f, 0.10f, 0.11f},
+ screenHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 0.11f, 0.21f},
- mDisplayDeviceConfig.getScreenDarkeningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{11, 12, 13},
- mDisplayDeviceConfig.getScreenDarkeningPercentages(), ZERO_DELTA);
+ screenHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.11f, 0.12f, 0.13f},
+ screenHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 100, 200},
- mDisplayDeviceConfig.getAmbientBrighteningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{13, 14, 15},
- mDisplayDeviceConfig.getAmbientBrighteningPercentages(), ZERO_DELTA);
+ ambientHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.13f, 0.14f, 0.15f},
+ ambientHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 300, 400},
- mDisplayDeviceConfig.getAmbientDarkeningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{15, 16, 17},
- mDisplayDeviceConfig.getAmbientDarkeningPercentages(), ZERO_DELTA);
+ ambientHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.15f, 0.16f, 0.17f},
+ ambientHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 0.12f, 0.22f},
- mDisplayDeviceConfig.getScreenBrighteningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{17, 18, 19},
- mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle(), ZERO_DELTA);
+ screenIdleHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.17f, 0.18f, 0.19f},
+ screenIdleHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 0.13f, 0.23f},
- mDisplayDeviceConfig.getScreenDarkeningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{19, 20, 21},
- mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle(), ZERO_DELTA);
+ screenIdleHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.19f, 0.20f, 0.21f},
+ screenIdleHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 500, 600},
- mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{21, 22, 23},
- mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle(), ZERO_DELTA);
+ ambientIdleHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.21f, 0.22f, 0.23f},
+ ambientIdleHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 700, 800},
- mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{23, 24, 25},
- mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
+ ambientIdleHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.23f, 0.24f, 0.25f},
+ ambientIdleHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertEquals(75, mDisplayDeviceConfig.getDefaultLowBlockingZoneRefreshRate());
assertEquals(90, mDisplayDeviceConfig.getDefaultHighBlockingZoneRefreshRate());
@@ -686,55 +691,60 @@
new float[]{brightnessIntToFloat(50), brightnessIntToFloat(100),
brightnessIntToFloat(150)}, SMALL_DELTA);
+ HysteresisLevels ambientHysteresis = mDisplayDeviceConfig.getAmbientBrightnessHysteresis();
+ HysteresisLevels ambientIdleHysteresis =
+ mDisplayDeviceConfig.getAmbientBrightnessIdleHysteresis();
+ HysteresisLevels screenHysteresis = mDisplayDeviceConfig.getScreenBrightnessHysteresis();
+ HysteresisLevels screenIdleHysteresis =
+ mDisplayDeviceConfig.getScreenBrightnessIdleHysteresis();
// Test thresholds
- assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle(),
- ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle(), ZERO_DELTA);
+ assertEquals(0, ambientHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0, ambientIdleHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0, ambientHysteresis.getMinDarkening(), ZERO_DELTA);
+ assertEquals(0, ambientIdleHysteresis.getMinDarkening(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), ZERO_DELTA);
- assertEquals(0, mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle(), ZERO_DELTA);
+ assertEquals(0, screenHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0, screenIdleHysteresis.getMinBrightening(), ZERO_DELTA);
+ assertEquals(0, screenHysteresis.getMinDarkening(), ZERO_DELTA);
+ assertEquals(0, screenIdleHysteresis.getMinDarkening(), ZERO_DELTA);
// screen levels will be considered "old screen brightness scale"
// and therefore will divide by 255
assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
- mDisplayDeviceConfig.getScreenBrighteningLevels(), SMALL_DELTA);
- assertArrayEquals(new float[]{35, 36, 37},
- mDisplayDeviceConfig.getScreenBrighteningPercentages(), ZERO_DELTA);
+ screenHysteresis.getBrighteningThresholdLevels(), SMALL_DELTA);
+ assertArrayEquals(new float[]{0.35f, 0.36f, 0.37f},
+ screenHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
- mDisplayDeviceConfig.getScreenDarkeningLevels(), SMALL_DELTA);
- assertArrayEquals(new float[]{37, 38, 39},
- mDisplayDeviceConfig.getScreenDarkeningPercentages(), ZERO_DELTA);
+ screenHysteresis.getDarkeningThresholdLevels(), SMALL_DELTA);
+ assertArrayEquals(new float[]{0.37f, 0.38f, 0.39f},
+ screenHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 30, 31},
- mDisplayDeviceConfig.getAmbientBrighteningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{27, 28, 29},
- mDisplayDeviceConfig.getAmbientBrighteningPercentages(), ZERO_DELTA);
+ ambientHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.27f, 0.28f, 0.29f},
+ ambientHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 30, 31},
- mDisplayDeviceConfig.getAmbientDarkeningLevels(), ZERO_DELTA);
- assertArrayEquals(new float[]{29, 30, 31},
- mDisplayDeviceConfig.getAmbientDarkeningPercentages(), ZERO_DELTA);
+ ambientHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.29f, 0.30f, 0.31f},
+ ambientHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
- mDisplayDeviceConfig.getScreenBrighteningLevelsIdle(), SMALL_DELTA);
- assertArrayEquals(new float[]{35, 36, 37},
- mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle(), ZERO_DELTA);
+ screenIdleHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.35f, 0.36f, 0.37f},
+ screenIdleHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
- mDisplayDeviceConfig.getScreenDarkeningLevelsIdle(), SMALL_DELTA);
- assertArrayEquals(new float[]{37, 38, 39},
- mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle(), ZERO_DELTA);
+ screenIdleHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.37f, 0.38f, 0.39f},
+ screenIdleHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 30, 31},
- mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{27, 28, 29},
- mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle(), ZERO_DELTA);
+ ambientIdleHysteresis.getBrighteningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.27f, 0.28f, 0.29f},
+ ambientIdleHysteresis.getBrighteningThresholdsPercentages(), ZERO_DELTA);
assertArrayEquals(new float[]{0, 30, 31},
- mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA);
- assertArrayEquals(new float[]{29, 30, 31},
- mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
+ ambientIdleHysteresis.getDarkeningThresholdLevels(), ZERO_DELTA);
+ assertArrayEquals(new float[]{0.29f, 0.30f, 0.31f},
+ ambientIdleHysteresis.getDarkeningThresholdsPercentages(), ZERO_DELTA);
assertEquals(mDisplayDeviceConfig.getDefaultLowBlockingZoneRefreshRate(),
DEFAULT_LOW_BLOCKING_ZONE_REFRESH_RATE);
assertEquals(mDisplayDeviceConfig.getDefaultHighBlockingZoneRefreshRate(),
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
index 1c71abc..0029674 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
@@ -26,6 +26,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.Display;
import android.view.SurfaceControl;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -72,6 +73,7 @@
@Test
public void testGetDisplaySurfaceDefaultSizeLocked_notRotated_anisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
@@ -81,6 +83,16 @@
}
@Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_notRotated_noAnisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_INTERNAL;
+ mDisplayDeviceInfo.xDpi = 0.5f;
+ mDisplayDeviceInfo.yDpi = 1.0f;
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+ mMockDisplayAdapter, /*isAnisotropyCorrectionEnabled=*/ true);
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+ }
+
+ @Test
public void testGetDisplaySurfaceDefaultSizeLocked_notRotated() {
DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
mMockDisplayAdapter);
@@ -97,6 +109,7 @@
@Test
public void testGetDisplaySurfaceDefaultSizeLocked_rotation90_anisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
@@ -107,6 +120,17 @@
}
@Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_rotation90_noAnisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_INTERNAL;
+ mDisplayDeviceInfo.xDpi = 0.5f;
+ mDisplayDeviceInfo.yDpi = 1.0f;
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+ mMockDisplayAdapter, /*isAnisotropyCorrectionEnabled=*/ true);
+ displayDevice.setProjectionLocked(mMockTransaction, ROTATION_90, new Rect(), new Rect());
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
+ }
+
+ @Test
public void testGetDisplaySurfaceDefaultSizeLocked_rotation90() {
DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
mMockDisplayAdapter);
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 afb87d1..de93914 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -82,6 +82,7 @@
import com.android.server.display.brightness.clamper.BrightnessClamperController;
import com.android.server.display.brightness.clamper.HdrClamper;
import com.android.server.display.color.ColorDisplayService;
+import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.feature.flags.Flags;
@@ -1954,6 +1955,14 @@
.thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE);
when(displayDeviceConfigMock.getBrightnessRampDecreaseMaxIdleMillis())
.thenReturn(BRIGHTNESS_RAMP_DECREASE_MAX_IDLE);
+
+ final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class);
+ when(displayDeviceConfigMock.getAmbientBrightnessHysteresis()).thenReturn(hysteresisLevels);
+ when(displayDeviceConfigMock.getAmbientBrightnessIdleHysteresis()).thenReturn(
+ hysteresisLevels);
+ when(displayDeviceConfigMock.getScreenBrightnessHysteresis()).thenReturn(hysteresisLevels);
+ when(displayDeviceConfigMock.getScreenBrightnessIdleHysteresis()).thenReturn(
+ hysteresisLevels);
}
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
@@ -1995,7 +2004,7 @@
TestInjector injector = spy(new TestInjector(displayPowerState, animator,
automaticBrightnessController, wakelockController, brightnessMappingStrategy,
- hysteresisLevels, screenOffBrightnessSensorController,
+ screenOffBrightnessSensorController,
hbmController, normalBrightnessModeController, hdrClamper,
clamperController, mDisplayManagerFlagsMock));
@@ -2005,6 +2014,11 @@
final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class);
final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class);
+ when(config.getAmbientBrightnessHysteresis()).thenReturn(hysteresisLevels);
+ when(config.getAmbientBrightnessIdleHysteresis()).thenReturn(hysteresisLevels);
+ when(config.getScreenBrightnessHysteresis()).thenReturn(hysteresisLevels);
+ when(config.getScreenBrightnessIdleHysteresis()).thenReturn(hysteresisLevels);
+
setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
when(config.isAutoBrightnessAvailable()).thenReturn(isAutoBrightnessAvailable);
@@ -2080,7 +2094,6 @@
private final AutomaticBrightnessController mAutomaticBrightnessController;
private final WakelockController mWakelockController;
private final BrightnessMappingStrategy mBrightnessMappingStrategy;
- private final HysteresisLevels mHysteresisLevels;
private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
private final HighBrightnessModeController mHighBrightnessModeController;
@@ -2096,7 +2109,6 @@
AutomaticBrightnessController automaticBrightnessController,
WakelockController wakelockController,
BrightnessMappingStrategy brightnessMappingStrategy,
- HysteresisLevels hysteresisLevels,
ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
HighBrightnessModeController highBrightnessModeController,
NormalBrightnessModeController normalBrightnessModeController,
@@ -2108,7 +2120,6 @@
mAutomaticBrightnessController = automaticBrightnessController;
mWakelockController = wakelockController;
mBrightnessMappingStrategy = brightnessMappingStrategy;
- mHysteresisLevels = hysteresisLevels;
mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
mHighBrightnessModeController = highBrightnessModeController;
mNormalBrightnessModeController = normalBrightnessModeController;
@@ -2186,22 +2197,6 @@
}
@Override
- HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels,
- float[] darkeningThresholdLevels, float minDarkeningThreshold,
- float minBrighteningThreshold) {
- return mHysteresisLevels;
- }
-
- @Override
- HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
- float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels,
- float[] darkeningThresholdLevels, float minDarkeningThreshold,
- float minBrighteningThreshold, boolean potentialOldBrightnessRange) {
- return mHysteresisLevels;
- }
-
- @Override
ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
SensorManager sensorManager, Sensor lightSensor, Handler handler,
ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index e798aa2..779445e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -142,8 +142,39 @@
assertEquals(new Point(0, DISPLAY_HEIGHT / 4), mLogicalDisplay.getDisplayPosition());
}
+
+ @Test
+ public void testNoLetterbox_noAnisotropyCorrectionForInternalDisplay() {
+ mDisplayDeviceInfo.type = Display.TYPE_INTERNAL;
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+
+ // In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
+ // to using the whole screen. This is because display will rescale it back to fill the
+ // screen (in case the display menu setting is set to stretch the pixels across the display)
+ mDisplayDeviceInfo.xDpi = 0.5f;
+ mDisplayDeviceInfo.yDpi = 1.0f;
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ var originalDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
+ // Content width not scaled
+ assertEquals(DISPLAY_WIDTH, originalDisplayInfo.logicalWidth);
+ assertEquals(DISPLAY_HEIGHT, originalDisplayInfo.logicalHeight);
+
+ SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+
+ // Applications need to think that they are shown on a display with square pixels.
+ // as applications can be displayed on multiple displays simultaneously (mirrored).
+ // Content is too wide, should have become letterboxed - but it won't because of anisotropy
+ // correction
+ assertEquals(new Point(0, 0), mLogicalDisplay.getDisplayPosition());
+ }
+
@Test
public void testNoLetterbox_anisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
@@ -172,6 +203,7 @@
@Test
public void testLetterbox_anisotropyCorrectionYDpi() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
@@ -229,6 +261,7 @@
@Test
public void testPillarbox_anisotropyCorrection() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
@@ -257,6 +290,7 @@
@Test
public void testNoPillarbox_anisotropyCorrectionYDpi() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
@@ -318,6 +352,7 @@
@Test
public void testGetDisplayPositionAlwaysRotateDisplayEnabled() {
+ mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
diff --git a/services/tests/selinux/Android.bp b/services/tests/selinux/Android.bp
index 3f2aec7..f387238 100644
--- a/services/tests/selinux/Android.bp
+++ b/services/tests/selinux/Android.bp
@@ -34,7 +34,7 @@
}
android_test {
- name: "SelinuxFrameworkTests",
+ name: "SelinuxFrameworksTests",
srcs: [
"src/**/*.java",
],
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
index dae8f93..0946229 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
@@ -1,23 +1,6 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.contentcapture"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ],
- "postsubmit": [
- {
- // b/331020193, Move to presubmit early april 2024
"name": "FrameworksServicesTests_contentcapture"
}
]
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
index 32729a8..1ad7baa 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
@@ -1,23 +1,6 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.contentprotection"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ],
- "postsubmit": [
- {
- // b/331020193, Move to presubmit early april 2024
"name": "FrameworksServicesTests_contentprotection"
}
]
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
index dc8f934..58f5bb3 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
@@ -1,29 +1,11 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.location.contexthub."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_contexthub_presubmit"
}
],
"postsubmit": [
{
- // b/331020193, Move to presubmit early april 2024
- "name": "FrameworksServicesTests_contexthub_presubmit"
- },
- {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 41c4383..944c1df 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.om."
- }
- ]
+ "name": "FrameworksServicesTests_om"
},
{
"name": "PackageManagerServiceHostTests",
@@ -16,11 +11,5 @@
}
]
}
- ],
- "postsubmit": [
- {
- // b/331020193, Move to presubmit early april 2024
- "name": "FrameworksServicesTests_om"
- }
]
}
diff --git a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
index 06e7002..2138da9 100644
--- a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
@@ -1,17 +1,6 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.os."
- }
- ]
- }
- ],
- "postsubmit": [
- {
- // b/331020193, Move to presubmit early april 2024
"name": "FrameworksServicesTests_os"
}
]
diff --git a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
index f4e724f..861562d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
@@ -21,7 +21,7 @@
"postsubmit": [
{
// Presubmit is intentional here while testing with SLO checker.
- // b/331020193, Move to presubmit early april 2024
+ // Tests are flaky, waiting to bypass.
"name": "FrameworksServicesTests_pm_presubmit"
},
{
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
index 7e7393c..eb7453d 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
@@ -1,21 +1,7 @@
{
- "presubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.recoverysystem."
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ],
- "postsubmit": [
- {
- // b/331020193, Move to presubmit early april 2024
- "name": "FrameworksServicesTests_recoverysystem"
- }
- ]
-}
\ No newline at end of file
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests_recoverysystem"
+ }
+ ]
+}
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index a63db88..7b5b07c 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.util;
import static android.telephony.Annotation.DataState;
+import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE;
+import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -37,6 +39,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.ITelephony;
@@ -48,6 +51,8 @@
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This class provides various util functions
@@ -342,4 +347,31 @@
return false;
}
+
+ /**
+ * @param plmn target plmn for validation.
+ * @return {@code true} if the target plmn is valid {@code false} otherwise.
+ */
+ public static boolean isValidPlmn(@Nullable String plmn) {
+ if (TextUtils.isEmpty(plmn)) {
+ return false;
+ }
+ Pattern pattern = Pattern.compile("^(?:[0-9]{3})(?:[0-9]{2}|[0-9]{3})$");
+ Matcher matcher = pattern.matcher(plmn);
+ if (!matcher.matches()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param serviceType target serviceType for validation.
+ * @return {@code true} if the target serviceType is valid {@code false} otherwise.
+ */
+ public static boolean isValidService(int serviceType) {
+ if (serviceType < FIRST_SERVICE_TYPE || serviceType > LAST_SERVICE_TYPE) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
index a62103e..7558332 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
@@ -16,10 +16,16 @@
package com.android.internal.telephony.tests;
+import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE;
+import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -72,6 +78,22 @@
// getSubscriptionUserHandle should be called if subID is active.
verify(mSubscriptionManager, times(1)).getSubscriptionUserHandle(eq(activeSubId));
}
+
+ @Test
+ public void testIsValidPlmn() {
+ assertTrue(TelephonyUtils.isValidPlmn("310260"));
+ assertTrue(TelephonyUtils.isValidPlmn("45006"));
+ assertFalse(TelephonyUtils.isValidPlmn("1234567"));
+ assertFalse(TelephonyUtils.isValidPlmn("1234"));
+ }
+
+ @Test
+ public void testIsValidService() {
+ assertTrue(TelephonyUtils.isValidService(FIRST_SERVICE_TYPE));
+ assertTrue(TelephonyUtils.isValidService(LAST_SERVICE_TYPE));
+ assertFalse(TelephonyUtils.isValidService(FIRST_SERVICE_TYPE - 1));
+ assertFalse(TelephonyUtils.isValidService(LAST_SERVICE_TYPE + 1));
+ }
}