Merge "Remove WindowConfiguration.setBounds and getBounds annotations" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 26b0263..2137f47 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -309,6 +309,7 @@
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
+ field public static final String REPORT_USAGE_STATS = "android.permission.REPORT_USAGE_STATS";
field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fbb97ff..cbbf4e0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -868,10 +868,6 @@
@Override
public VirtualDeviceManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- if (!ctx.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_COMPANION_DEVICE_SETUP)) {
- return null;
- }
if (!ctx.getResources().getBoolean(R.bool.config_enableVirtualDeviceManager)) {
return null;
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index ecf16439..2a10ed1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1106,6 +1106,7 @@
* <p><em>This method is only for use by the system</em>
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.REPORT_USAGE_STATS)
public void reportUserInteraction(@NonNull String packageName, int userId) {
try {
mService.reportUserInteraction(packageName, userId);
@@ -1396,6 +1397,7 @@
* {@link UsageEvents}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.REPORT_USAGE_STATS)
public void reportChooserSelection(String packageName, int userId, String contentType,
String[] annotations, String action) {
try {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3194b4..dd1a499 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6099,6 +6099,10 @@
android:protectionLevel="signature|privileged|development|appop|retailDemo" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <!-- @SystemApi @hide Allows trusted system components to report events to UsageStatsManager -->
+ <permission android:name="android.permission.REPORT_USAGE_STATS"
+ android:protectionLevel="signature|module" />
+
<!-- Allows an application to query broadcast response stats (see
{@link android.app.usage.BroadcastResponseStats}).
@SystemApi
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index 0f467b9..8b56336 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -15,7 +15,7 @@
#
[versions]
-agp = "8.1.0"
+agp = "8.1.1"
compose-compiler = "1.5.1"
dexmaker-mockito = "2.28.3"
kotlin = "1.9.0"
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
index c1962a7..033e24c 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index 5b0ac44..da04f42 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -16,6 +16,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/packages/SettingsLib/Spa/gradlew b/packages/SettingsLib/Spa/gradlew
index aeb74cb..fcb6fca 100755
--- a/packages/SettingsLib/Spa/gradlew
+++ b/packages/SettingsLib/Spa/gradlew
@@ -130,10 +130,13 @@
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 84198de..b810511 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -63,7 +63,7 @@
api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
api("androidx.lifecycle:lifecycle-livedata-ktx")
api("androidx.lifecycle:lifecycle-runtime-compose")
- api("androidx.navigation:navigation-compose:2.7.0-rc01")
+ api("androidx.navigation:navigation-compose:2.7.1")
api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha")
api("com.google.android.material:material:1.7.0-alpha03")
debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
index 97d8de3..0d489e8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -147,19 +147,20 @@
return create(entryName, owner).setLink(toPage = owner)
}
- fun create(owner: SettingsPage, entryName: String, label: String? = null):
- SettingsEntryBuilder {
- return SettingsEntryBuilder(entryName, owner).setLabel(label ?: entryName)
- }
+ fun create(
+ owner: SettingsPage,
+ entryName: String,
+ label: String = entryName,
+ ): SettingsEntryBuilder = SettingsEntryBuilder(entryName, owner).setLabel(label)
- fun createInject(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
- val label = label ?: "${INJECT_ENTRY_LABEL}_${owner.displayName}"
- return createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
- }
+ fun createInject(
+ owner: SettingsPage,
+ label: String = "${INJECT_ENTRY_LABEL}_${owner.displayName}",
+ ): SettingsEntryBuilder = createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
- fun createRoot(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
- val label = label ?: "${ROOT_ENTRY_LABEL}_${owner.displayName}"
- return createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
- }
+ fun createRoot(
+ owner: SettingsPage,
+ label: String = "${ROOT_ENTRY_LABEL}_${owner.displayName}",
+ ): SettingsEntryBuilder = createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
index b809c0f..3496f02 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
@@ -64,8 +64,8 @@
}
}
- override fun onChanged(slice: Slice?) {
- val uri = slice?.uri ?: return
+ override fun onChanged(value: Slice?) {
+ val uri = value?.uri ?: return
Log.d(TAG, "onChanged: $uri")
context?.contentResolver?.notifyChange(uri, null)
}
@@ -74,4 +74,4 @@
Log.d(TAG, "onCreateSliceProvider")
return true
}
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
index cff1c0c..ee24a09 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
@@ -17,7 +17,7 @@
package com.android.settingslib.spa.slice.presenter
import android.net.Uri
-import androidx.compose.material3.Divider
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
@@ -34,7 +34,7 @@
SliceLiveData.fromUri(context, sliceUri)
}
- Divider()
+ HorizontalDivider()
AndroidView(
factory = { localContext ->
val view = SliceView(localContext)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
index 6135203..6330ddf 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
@@ -24,7 +24,7 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
-import androidx.compose.material3.Divider
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Alignment
@@ -105,7 +105,7 @@
BaseLayout(
title = "Title",
subTitle = {
- Divider(thickness = 10.dp)
+ HorizontalDivider(thickness = 10.dp)
}
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 67f4418..d437e35 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -99,8 +99,8 @@
.fillMaxSize(),
) {
content(
- bottomPadding = paddingValues.calculateBottomPadding(),
- searchQuery = remember {
+ paddingValues.calculateBottomPadding(),
+ remember {
derivedStateOf { if (isSearchMode) viewModel.searchQuery.text else "" }
},
)
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bd3b83e..ffe28a6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -167,6 +167,7 @@
<uses-permission android:name="android.permission.FORCE_BACK" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.REPORT_USAGE_STATS" />
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
index 25269dc..44c4105 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
@@ -78,6 +78,7 @@
modifier = modifier,
enabled = enabled,
content = content,
+ colors = textButtonColors(),
)
}
@@ -85,26 +86,29 @@
@Composable
private fun filledButtonColors(): ButtonColors {
- val colors = LocalAndroidColorScheme.current.deprecated
+ val colors = LocalAndroidColorScheme.current
return ButtonDefaults.buttonColors(
- containerColor = colors.colorAccentPrimary,
- contentColor = colors.textColorOnAccent,
+ containerColor = colors.primary,
+ contentColor = colors.onPrimary,
)
}
@Composable
private fun outlineButtonColors(): ButtonColors {
- val colors = LocalAndroidColorScheme.current.deprecated
return ButtonDefaults.outlinedButtonColors(
- contentColor = colors.textColorPrimary,
+ contentColor = LocalAndroidColorScheme.current.onSurface,
)
}
@Composable
private fun outlineButtonBorder(): BorderStroke {
- val colors = LocalAndroidColorScheme.current.deprecated
return BorderStroke(
width = 1.dp,
- color = colors.colorAccentPrimaryVariant,
+ color = LocalAndroidColorScheme.current.primary,
)
}
+
+@Composable
+private fun textButtonColors(): ButtonColors {
+ return ButtonDefaults.textButtonColors(contentColor = LocalAndroidColorScheme.current.primary)
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
new file mode 100644
index 0000000..48f40e7
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dialog.ui.composable
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ProvideTextStyle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.android.compose.theme.LocalAndroidColorScheme
+
+/**
+ * The content of an AlertDialog which can be used together with
+ * [SystemUIDialogFactory.create][com.android.systemui.statusbar.phone.create] to create an alert
+ * dialog in Compose.
+ *
+ * @see com.android.systemui.statusbar.phone.create
+ */
+@Composable
+fun AlertDialogContent(
+ title: @Composable () -> Unit,
+ content: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ icon: (@Composable () -> Unit)? = null,
+ positiveButton: (@Composable () -> Unit)? = null,
+ negativeButton: (@Composable () -> Unit)? = null,
+ neutralButton: (@Composable () -> Unit)? = null,
+) {
+ Column(
+ modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(DialogPaddings),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ // Icon.
+ if (icon != null) {
+ val defaultSize = 32.dp
+ Box(
+ Modifier.defaultMinSize(minWidth = defaultSize, minHeight = defaultSize),
+ propagateMinConstraints = true,
+ ) {
+ val iconColor = LocalAndroidColorScheme.current.primary
+ CompositionLocalProvider(LocalContentColor provides iconColor) { icon() }
+ }
+
+ Spacer(Modifier.height(16.dp))
+ }
+
+ // Title.
+ val titleColor = LocalAndroidColorScheme.current.onSurface
+ CompositionLocalProvider(LocalContentColor provides titleColor) {
+ ProvideTextStyle(
+ MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center)
+ ) {
+ title()
+ }
+ }
+ Spacer(Modifier.height(16.dp))
+
+ // Content.
+ val contentColor = LocalAndroidColorScheme.current.onSurfaceVariant
+ Box(Modifier.defaultMinSize(minHeight = 48.dp)) {
+ CompositionLocalProvider(LocalContentColor provides contentColor) {
+ ProvideTextStyle(
+ MaterialTheme.typography.bodyMedium.copy(textAlign = TextAlign.Center)
+ ) {
+ content()
+ }
+ }
+ }
+ Spacer(Modifier.height(32.dp))
+
+ // Buttons.
+ // TODO(b/283817398): If there is not enough space, the buttons should automatically stack
+ // as shown in go/sysui-dialog-styling.
+ if (positiveButton != null || negativeButton != null || neutralButton != null) {
+ Row(Modifier.fillMaxWidth()) {
+ if (neutralButton != null) {
+ neutralButton()
+ Spacer(Modifier.width(8.dp))
+ }
+
+ Spacer(Modifier.weight(1f))
+
+ if (negativeButton != null) {
+ negativeButton()
+ }
+
+ if (positiveButton != null) {
+ if (negativeButton != null) {
+ Spacer(Modifier.width(8.dp))
+ }
+
+ positiveButton()
+ }
+ }
+ }
+ }
+}
+
+private val DialogPaddings = PaddingValues(start = 24.dp, end = 24.dp, top = 24.dp, bottom = 18.dp)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
new file mode 100644
index 0000000..5d6dd3b
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.ComposeView
+import com.android.compose.theme.PlatformTheme
+
+/**
+ * Create a [SystemUIDialog] with the given [content].
+ *
+ * Note that the returned dialog will already have a background so the content should not draw an
+ * additional background.
+ *
+ * Example:
+ * ```
+ * val dialog = systemUiDialogFactory.create {
+ * AlertDialogContent(
+ * title = { Text("My title") },
+ * content = { Text("My content") },
+ * )
+ * }
+ *
+ * dialogLaunchAnimator.showFromView(dialog, viewThatWasClicked)
+ * ```
+ *
+ * @param context the [Context] in which the dialog will be constructed.
+ * @param dismissOnDeviceLock whether the dialog should be automatically dismissed when the device
+ * is locked (true by default).
+ */
+fun SystemUIDialogFactory.create(
+ context: Context = this.applicationContext,
+ dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ content: @Composable (SystemUIDialog) -> Unit,
+): ComponentSystemUIDialog {
+ val dialog = create(context, dismissOnDeviceLock)
+
+ // Create the dialog so that it is properly constructed before we set the Compose content.
+ // Otherwise, the ComposeView won't render properly.
+ dialog.create()
+
+ // Set the content. Note that the background of the dialog is drawn on the DecorView of the
+ // dialog directly, which makes it automatically work nicely with DialogLaunchAnimator.
+ dialog.setContentView(
+ ComposeView(context).apply {
+ setContent {
+ PlatformTheme {
+ val defaultContentColor = MaterialTheme.colorScheme.onSurfaceVariant
+ CompositionLocalProvider(LocalContentColor provides defaultContentColor) {
+ content(dialog)
+ }
+ }
+ }
+ }
+ )
+
+ return dialog
+}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2dc1b45..62c4424 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -857,6 +857,8 @@
<dimen name="keyguard_security_container_padding_top">20dp</dimen>
+ <dimen name="keyguard_translate_distance_on_swipe_up">-200dp</dimen>
+
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
<dimen name="lock_icon_margin_bottom">74dp</dimen>
<dimen name="ambient_indication_margin_bottom">71dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 04eae64..579358f 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -212,6 +212,8 @@
<item type="id" name="keyguard_indication_text" />
<item type="id" name="keyguard_indication_text_bottom" />
<item type="id" name="nssl_guideline" />
+ <item type="id" name="nssl_top_barrier" />
+ <item type="id" name="nssl_bottom_barrier" />
<item type="id" name="split_shade_guideline" />
<item type="id" name="lock_icon" />
<item type="id" name="lock_icon_bg" />
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
new file mode 100644
index 0000000..b2bc06f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.common.shared.model
+
+/** Positioning info for the shared notification container */
+data class SharedNotificationContainerPosition(
+ val top: Float = 0f,
+ val bottom: Float = 0f,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index c0d1951..b8de8d8 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -43,6 +43,9 @@
val scaleForResolution: Flow<Float>
fun getResolutionScale(): Float
+
+ /** Convience to context.resources.getDimensionPixelSize() */
+ fun getDimensionPixelSize(id: Int): Int
}
@ExperimentalCoroutinesApi
@@ -115,4 +118,8 @@
}
return 1f
}
+
+ override fun getDimensionPixelSize(id: Int): Int {
+ return context.resources.getDimensionPixelSize(id)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d67c5fc..e9a539f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -223,7 +223,7 @@
// TODO(b/291710220): Tracking bug.
@JvmField
val WALLPAPER_PICKER_PAGE_TRANSITIONS =
- unreleasedFlag("wallpaper_picker_page_transitions")
+ unreleasedFlag("wallpaper_picker_page_transitions", teamfood = true)
/** Add "Apply" button to wall paper picker's grid preview page. */
// TODO(b/294866904): Tracking bug.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 9b323ee..1cd8795 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -51,6 +51,7 @@
import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.statusbar.KeyguardIndicationController
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -90,6 +91,7 @@
private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
private val communalWidgetViewModel: CommunalWidgetViewModel,
private val communalWidgetViewAdapter: CommunalWidgetViewAdapter,
+ private val notificationStackScrollerLayoutController: NotificationStackScrollLayoutController,
) : CoreStartable {
private var rootViewHandle: DisposableHandle? = null
@@ -131,6 +133,7 @@
SharedNotificationContainerBinder.bind(
sharedNotificationContainer,
sharedNotificationContainerViewModel,
+ notificationStackScrollerLayoutController,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ed84884..e13f675 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -19,10 +19,14 @@
import android.app.StatusBarManager
import android.graphics.Point
+import android.util.MathUtils
+import com.android.app.animation.Interpolators
+import com.android.systemui.R
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.Position
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
@@ -38,12 +42,14 @@
import com.android.systemui.keyguard.shared.model.ScreenModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -51,6 +57,7 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
@@ -66,7 +73,11 @@
featureFlags: FeatureFlags,
bouncerRepository: KeyguardBouncerRepository,
configurationRepository: ConfigurationRepository,
+ shadeRepository: ShadeRepository,
) {
+ /** Position information for the shared notification container. */
+ val sharedNotificationContainerPosition =
+ MutableStateFlow(SharedNotificationContainerPosition())
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
* all.
@@ -196,6 +207,22 @@
val keyguardAlpha: Flow<Float> = repository.keyguardAlpha
+ val keyguardTranslationY: Flow<Float> =
+ configurationChange.flatMapLatest {
+ val translationDistance =
+ configurationRepository.getDimensionPixelSize(
+ R.dimen.keyguard_translate_distance_on_swipe_up
+ )
+ shadeRepository.shadeModel.map {
+ // On swipe up, translate the keyguard to reveal the bouncer
+ MathUtils.lerp(
+ translationDistance,
+ 0,
+ Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it.expansionAmount)
+ )
+ }
+ }
+
/** Whether to animate the next doze mode transition. */
val animateDozingTransitions: Flow<Boolean> = repository.animateBottomAreaDozingTransitions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 19f622b..2814732 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -18,6 +18,7 @@
import android.annotation.DrawableRes
import android.view.View
+import android.view.View.OnLayoutChangeListener
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -43,6 +44,9 @@
/** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */
@ExperimentalCoroutinesApi
object KeyguardRootViewBinder {
+
+ private var onLayoutChangeListener: OnLayoutChange? = null
+
@JvmStatic
fun bind(
view: ViewGroup,
@@ -54,8 +58,8 @@
): DisposableHandle {
val disposableHandle =
view.repeatWhenAttached {
- if (featureFlags.isEnabled(Flags.FP_LISTEN_OCCLUDING_APPS)) {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ if (featureFlags.isEnabled(Flags.FP_LISTEN_OCCLUDING_APPS)) {
launch {
occludingAppDeviceEntryMessageViewModel.message.collect {
biometricMessage ->
@@ -72,10 +76,8 @@
}
}
}
- }
- if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
launch {
viewModel.keyguardRootViewVisibilityState.collect { visibilityState ->
view.animate().cancel()
@@ -84,16 +86,21 @@
val isOcclusionTransitionRunning =
visibilityState.occlusionTransitionRunning
if (goingToFullShade) {
- view.animate().alpha(0f).setStartDelay(
- keyguardStateController.keyguardFadingAwayDelay
- ).setDuration(
- keyguardStateController.shortenedFadingAwayDuration
- ).setInterpolator(
- Interpolators.ALPHA_OUT
- ).withEndAction { view.visibility = View.GONE }.start()
+ view
+ .animate()
+ .alpha(0f)
+ .setStartDelay(
+ keyguardStateController.keyguardFadingAwayDelay
+ )
+ .setDuration(
+ keyguardStateController.shortenedFadingAwayDuration
+ )
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .withEndAction { view.visibility = View.GONE }
+ .start()
} else if (
statusBarState == StatusBarState.KEYGUARD ||
- statusBarState == StatusBarState.SHADE_LOCKED
+ statusBarState == StatusBarState.SHADE_LOCKED
) {
view.visibility = View.VISIBLE
if (!isOcclusionTransitionRunning) {
@@ -105,15 +112,30 @@
}
}
+ launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
+ }
+
+ if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
launch {
- viewModel.alpha.collect { alpha ->
- view.alpha = alpha
+ viewModel.translationY.collect {
+ val statusView =
+ view.requireViewById<View>(R.id.keyguard_status_view)
+ statusView.translationY = it
}
}
}
}
}
- return disposableHandle
+
+ onLayoutChangeListener = OnLayoutChange(viewModel)
+ view.addOnLayoutChangeListener(onLayoutChangeListener)
+
+ return object : DisposableHandle {
+ override fun dispose() {
+ disposableHandle.dispose()
+ view.removeOnLayoutChangeListener(onLayoutChangeListener)
+ }
+ }
}
/**
@@ -122,10 +144,10 @@
private fun createChipbarInfo(message: String, @DrawableRes icon: Int): ChipbarInfo {
return ChipbarInfo(
startIcon =
- TintedIcon(
- Icon.Resource(icon, null),
- ChipbarInfo.DEFAULT_ICON_TINT,
- ),
+ TintedIcon(
+ Icon.Resource(icon, null),
+ ChipbarInfo.DEFAULT_ICON_TINT,
+ ),
text = Text.Loaded(message),
endItem = null,
vibrationEffect = null,
@@ -138,5 +160,31 @@
)
}
+ private class OnLayoutChange(private val viewModel: KeyguardRootViewModel) :
+ OnLayoutChangeListener {
+ override fun onLayoutChange(
+ v: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ val ksv = v.findViewById(R.id.keyguard_status_view) as View?
+ val lockIcon = v.findViewById(R.id.lock_icon_view) as View?
+
+ if (ksv != null && lockIcon != null) {
+ // After layout, ensure the notifications are positioned correctly
+ viewModel.onSharedNotificationContainerPositionChanged(
+ ksv!!.top.toFloat() + ksv!!.height,
+ lockIcon!!.y
+ )
+ }
+ }
+ }
+
private const val ID = "occluding_app_device_entry_unlock_msg"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 3f319ba..f1f5973 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -18,20 +18,20 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.Context
-import android.view.ViewGroup
-import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
-import javax.inject.Inject
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import androidx.constraintlayout.widget.ConstraintSet.END
+import com.android.systemui.R
+import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.util.LargeScreenUtils
+import com.android.systemui.util.Utils
+import javax.inject.Inject
-class DefaultStatusViewSection @Inject constructor(private val context: Context) :
- KeyguardSection {
+class DefaultStatusViewSection @Inject constructor(private val context: Context) : KeyguardSection {
private val statusViewId = R.id.keyguard_status_view
override fun apply(constraintSet: ConstraintSet) {
@@ -41,6 +41,15 @@
connect(statusViewId, TOP, PARENT_ID, TOP)
connect(statusViewId, START, PARENT_ID, START)
connect(statusViewId, END, PARENT_ID, END)
+
+ val margin =
+ if (LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)) {
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
+ } else {
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
+ Utils.getStatusBarHeaderHeightKeyguard(context)
+ }
+ setMargin(statusViewId, TOP, margin)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 92b9ee4..c49af4d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
import javax.inject.Inject
@@ -57,6 +58,8 @@
}
}
+ val translationY: Flow<Float> = keyguardInteractor.keyguardTranslationY
+
/**
* Puts this view-model in "preview mode", which means it's being used for UI that is rendering
* the lock screen preview in wallpaper picker / settings and not the real experience on the
@@ -66,4 +69,9 @@
val newPreviewMode = PreviewMode(true)
previewMode.value = newPreviewMode
}
+
+ fun onSharedNotificationContainerPositionChanged(top: Float, bottom: Float) {
+ keyguardInteractor.sharedNotificationContainerPosition.value =
+ SharedNotificationContainerPosition(top, bottom)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 014093d..a41d6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -194,6 +194,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
import com.android.systemui.statusbar.phone.BounceInterpolator;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -606,7 +607,7 @@
private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
private final PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
-
+ private final SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final KeyguardInteractor mKeyguardInteractor;
private final KeyguardViewConfigurator mKeyguardViewConfigurator;
@@ -772,6 +773,7 @@
KeyguardLongPressViewModel keyguardLongPressViewModel,
KeyguardInteractor keyguardInteractor,
ActivityStarter activityStarter,
+ SharedNotificationContainerInteractor sharedNotificationContainerInteractor,
KeyguardViewConfigurator keyguardViewConfigurator,
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
KeyguardRootView keyguardRootView) {
@@ -797,6 +799,7 @@
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mSharedNotificationContainerInteractor = sharedNotificationContainerInteractor;
mKeyguardInteractor = keyguardInteractor;
mKeyguardViewConfigurator = keyguardViewConfigurator;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@@ -1308,15 +1311,17 @@
// Reset any left over overscroll state. It is a rare corner case but can happen.
mQsController.setOverScrollAmount(0);
mScrimController.setNotificationsOverScrollAmount(0);
- mNotificationStackScrollLayoutController.setOverExpansion(0);
- mNotificationStackScrollLayoutController.setOverScrollAmount(0);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mNotificationStackScrollLayoutController.setOverExpansion(0);
+ mNotificationStackScrollLayoutController.setOverScrollAmount(0);
+ }
// when we switch between split shade and regular shade we want to enforce setting qs to
// the default state: expanded for split shade and collapsed otherwise
- if (!isOnKeyguard() && mPanelExpanded) {
+ if (!isKeyguardShowing() && mPanelExpanded) {
mQsController.setExpanded(mSplitShadeEnabled);
}
- if (isOnKeyguard() && mQsController.getExpanded() && mSplitShadeEnabled) {
+ if (isKeyguardShowing() && mQsController.getExpanded() && mSplitShadeEnabled) {
// In single column keyguard - when you swipe from the top - QS is fully expanded and
// StatusBarState is KEYGUARD. That state doesn't make sense for split shade,
// where notifications are always visible and we effectively go to fully expanded
@@ -1327,7 +1332,9 @@
}
updateClockAppearance();
mQsController.updateQsState();
- mNotificationStackScrollLayoutController.updateFooter();
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mNotificationStackScrollLayoutController.updateFooter();
+ }
}
private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) {
@@ -1368,10 +1375,6 @@
attachSplitShadeMediaPlayerContainer(
keyguardStatusView.findViewById(R.id.status_view_media_container));
- } else {
- attachSplitShadeMediaPlayerContainer(
- mKeyguardViewConfigurator.getKeyguardRootView()
- .findViewById(R.id.status_view_media_container));
}
// we need to update KeyguardStatusView constraints after reinflating it
@@ -1400,6 +1403,12 @@
updateViewControllers(userAvatarView, keyguardUserSwitcherView);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ attachSplitShadeMediaPlayerContainer(
+ mKeyguardViewConfigurator.getKeyguardRootView()
+ .findViewById(R.id.status_view_media_container));
+ }
+
if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1481,6 +1490,10 @@
if (SPEW_LOGCAT) Log.d(TAG, "Skipping computeMaxKeyguardNotifications() by request");
}
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ return;
+ }
+
if (isKeyguardShowing() && !mKeyguardBypassController.getBypassEnabled()) {
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
mMaxAllowedKeyguardNotifications);
@@ -1552,7 +1565,7 @@
private void positionClockAndNotifications(boolean forceClockUpdate) {
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
- boolean onKeyguard = isOnKeyguard();
+ boolean onKeyguard = isKeyguardShowing();
if (onKeyguard || forceClockUpdate) {
updateClockAppearance();
@@ -1624,8 +1637,10 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
- mKeyguardStatusViewController.setLockscreenClockY(
- mClockPositionAlgorithm.getExpandedPreferredClockY());
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mKeyguardStatusViewController.setLockscreenClockY(
+ mClockPositionAlgorithm.getExpandedPreferredClockY());
+ }
if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
mKeyguardInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1635,9 +1650,12 @@
}
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
- mKeyguardStatusViewController.updatePosition(
- mClockPositionResult.clockX, mClockPositionResult.clockY,
- mClockPositionResult.clockScale, animateClock);
+
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mKeyguardStatusViewController.updatePosition(
+ mClockPositionResult.clockX, mClockPositionResult.clockY,
+ mClockPositionResult.clockScale, animateClock);
+ }
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.updatePosition(
mClockPositionResult.clockX,
@@ -1867,8 +1885,12 @@
}
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
- mKeyguardStatusViewController
- .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ // TODO (b/296373478) This is for split shade media movement.
+ } else {
+ mKeyguardStatusViewController
+ .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true);
+ }
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setAlpha(alpha);
@@ -1980,7 +2002,7 @@
mQsController.setExpandImmediate(true);
setShowShelfOnly(true);
}
- if (mSplitShadeEnabled && isOnKeyguard()) {
+ if (mSplitShadeEnabled && isKeyguardShowing()) {
// It's a special case as this method is likely to not be initiated by finger movement
// but rather called from adb shell or accessibility service.
// We're using LockscreenShadeTransitionController because on lockscreen that's the
@@ -2024,7 +2046,7 @@
mQsController.setLastShadeFlingWasExpanding(expand);
mHeadsUpTouchHelper.notifyFling(!expand);
mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
- setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
+ setClosingWithAlphaFadeout(!expand && !isKeyguardShowing() && getFadeoutAlpha() == 1.0f);
mNotificationStackScrollLayoutController.setPanelFlinging(true);
if (target == mExpandedHeight && mOverExpansion == 0.0f) {
// We're at the target and didn't fling and there's no overshoot
@@ -2425,9 +2447,14 @@
}
void requestScrollerTopPaddingUpdate(boolean animate) {
- mNotificationStackScrollLayoutController.updateTopPadding(
- mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
- getKeyguardNotificationStaticPadding(), mExpandedFraction), animate);
+ float padding = mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
+ getKeyguardNotificationStaticPadding(), mExpandedFraction);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mSharedNotificationContainerInteractor.setTopPosition(padding);
+ } else {
+ mNotificationStackScrollLayoutController.updateTopPadding(padding, animate);
+ }
+
if (isKeyguardShowing()
&& mKeyguardBypassController.getBypassEnabled()) {
// update the position of the header
@@ -3022,7 +3049,7 @@
mNotificationStackScrollLayoutController
.setExpandingVelocity(getCurrentExpandVelocity());
}
- if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
+ if (mKeyguardBypassController.getBypassEnabled() && isKeyguardShowing()) {
// The expandedHeight is always the full panel Height when bypassing
expandedHeight = getMaxPanelHeight();
}
@@ -3033,7 +3060,7 @@
private void updateStatusBarIcons() {
boolean showIconsWhenExpanded = getExpandedHeight() < getOpeningHeight();
- if (showIconsWhenExpanded && isOnKeyguard()) {
+ if (showIconsWhenExpanded && isKeyguardShowing()) {
showIconsWhenExpanded = false;
}
if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
@@ -3047,10 +3074,6 @@
return mBarState;
}
- private boolean isOnKeyguard() {
- return mBarState == KEYGUARD;
- }
-
/** Called when a HUN is dragged up or down to indicate the starting height for shade motion. */
@VisibleForTesting
void setHeadsUpDraggingStartingHeight(int startHeight) {
@@ -4434,7 +4457,7 @@
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
- if (!isOnKeyguard()) {
+ if (!isKeyguardShowing()) {
mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
entry.getHeadsUpAnimationView(), true);
}
@@ -4447,7 +4470,7 @@
// we need to make sure that an animation happens in this case, otherwise the
// notification
// will stick to the top without any interaction.
- if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) {
+ if (isFullyCollapsed() && entry.isRowHeadsUp() && !isKeyguardShowing()) {
mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
entry.getHeadsUpAnimationView(), false);
entry.setHeadsUpIsVisible();
@@ -4748,7 +4771,7 @@
// we need to ignore it on keyguard as this is a false alarm - transition from unlocked
// to locked will trigger this event and we're not actually in the process of opening
// the shade, lockscreen is just always expanded
- if (mSplitShadeEnabled && !isOnKeyguard()) {
+ if (mSplitShadeEnabled && !isKeyguardShowing()) {
mQsController.setExpandImmediate(true);
}
mOpenCloseListener.onOpenStarted();
@@ -4799,8 +4822,11 @@
private Consumer<Float> setTransitionY(
NotificationStackScrollLayoutController stackScroller) {
return (Float translationY) -> {
- mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false);
- stackScroller.setTranslationY(translationY);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mKeyguardStatusViewController.setTranslationY(translationY,
+ /* excludeMedia= */false);
+ stackScroller.setTranslationY(translationY);
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index ebb9935..5a8be1e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -37,11 +37,18 @@
/** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
val qsExpansion: StateFlow<Float>
+ /** The amount the shade has expanded */
+ val shadeExpansion: StateFlow<Float>
+
/** Amount shade has expanded with regard to the UDFPS location */
val udfpsTransitionToFullShadeProgress: StateFlow<Float>
+ /** The amount QS has expanded without notifications */
fun setQsExpansion(qsExpansion: Float)
fun setUdfpsTransitionToFullShadeProgress(progress: Float)
+
+ /** The amount the shade has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded */
+ fun setShadeExpansion(expansion: Float)
}
/** Business logic for shade interactions */
@@ -69,7 +76,6 @@
val currentState = shadeExpansionStateManager.addExpansionListener(callback)
callback.onPanelExpansionChanged(currentState)
- trySendWithFailureLogging(ShadeModel(), TAG, "initial shade expansion info")
awaitClose { shadeExpansionStateManager.removeExpansionListener(callback) }
}
@@ -78,6 +84,9 @@
private val _qsExpansion = MutableStateFlow(0f)
override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
+ private val _shadeExpansion = MutableStateFlow(0f)
+ override val shadeExpansion: StateFlow<Float> = _shadeExpansion.asStateFlow()
+
private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
_udfpsTransitionToFullShadeProgress.asStateFlow()
@@ -85,6 +94,10 @@
_qsExpansion.value = qsExpansion
}
+ override fun setShadeExpansion(expansion: Float) {
+ _shadeExpansion.value = expansion
+ }
+
override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
_udfpsTransitionToFullShadeProgress.value = progress
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6fde84a..288d32e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -19,6 +19,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -43,6 +45,7 @@
userSetupRepository: UserSetupRepository,
deviceProvisionedController: DeviceProvisionedController,
userInteractor: UserInteractor,
+ repository: ShadeRepository,
) {
/** Emits true if the shade is currently allowed and false otherwise. */
val isShadeEnabled: StateFlow<Boolean> =
@@ -50,6 +53,25 @@
.map { it.isShadeEnabled() }
.stateIn(scope, SharingStarted.Eagerly, initialValue = false)
+ /** The amount [0-1] that the shade has been opened */
+ val shadeExpansion: Flow<Float> =
+ combine(repository.shadeExpansion, keyguardRepository.statusBarState) {
+ shadeExpansion,
+ statusBarState ->
+ // This is required, as shadeExpansion gets reset to 0f even with the shade open
+ if (statusBarState == StatusBarState.SHADE_LOCKED) {
+ 1f
+ } else {
+ shadeExpansion
+ }
+ }
+
+ /**
+ * The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will
+ * report 0f.
+ */
+ val qsExpansion: StateFlow<Float> = repository.qsExpansion
+
/** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
val isExpandToQsEnabled: Flow<Boolean> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 672796a..25bb204 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -424,6 +424,7 @@
if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
fractionToShade =
MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
+ shadeRepository.setShadeExpansion(fractionToShade)
nsslController.setTransitionToFullShadeAmount(fractionToShade)
qsTransitionController.dragDownAmount = value
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index 874450b..4ed31c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -20,19 +20,27 @@
import android.content.Context
import com.android.systemui.R
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
/** Encapsulates business-logic specifically related to the shared notification stack container. */
+@SysUISingleton
class SharedNotificationContainerInteractor
@Inject
constructor(
configurationRepository: ConfigurationRepository,
private val context: Context,
) {
+
+ private val _topPosition = MutableStateFlow(0f)
+ val topPosition = _topPosition.asStateFlow()
+
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
configurationRepository.onAnyConfigurationChange
.onStart { emit(Unit) }
@@ -54,6 +62,11 @@
}
.distinctUntilChanged()
+ /** Top position (without translation) of the shared container. */
+ fun setTopPosition(top: Float) {
+ _topPosition.value = top
+ }
+
data class ConfigurationBasedDimensions(
val useSplitShade: Boolean,
val useLargeScreenHeader: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index fb1d55d..2af7181 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -19,6 +19,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import kotlinx.coroutines.launch
@@ -30,9 +31,10 @@
fun bind(
view: SharedNotificationContainer,
viewModel: SharedNotificationContainerViewModel,
+ controller: NotificationStackScrollLayoutController,
) {
view.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
viewModel.configurationBasedDimensions.collect {
view.updateConstraints(
@@ -42,8 +44,29 @@
marginEnd = it.marginEnd,
marginBottom = it.marginBottom,
)
+
+ controller.setOverExpansion(0f)
+ controller.setOverScrollAmount(0)
+ controller.updateFooter()
}
}
+
+ launch {
+ viewModel.maxNotifications.collect {
+ controller.setMaxDisplayedNotifications(it)
+ }
+ }
+
+ launch {
+ viewModel.position.collect {
+ controller.updateTopPadding(
+ it.top,
+ controller.isAddOrRemoveAnimationPending()
+ )
+ }
+ }
+
+ launch { viewModel.translationY.collect { controller.setTranslationY(it) } }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b2e5ac1..6f4adeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -17,18 +17,35 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
-/** View-model for the shared notification container */
+/** View-model for the shared notification container, used by both the shade and keyguard spaces */
class SharedNotificationContainerViewModel
@Inject
constructor(
interactor: SharedNotificationContainerInteractor,
+ keyguardInteractor: KeyguardInteractor,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ notificationStackSizeCalculator: NotificationStackSizeCalculator,
+ controller: NotificationStackScrollLayoutController,
+ shadeInteractor: ShadeInteractor,
) {
+ private val statesForConstrainedNotifications =
+ setOf(KeyguardState.LOCKSCREEN, KeyguardState.AOD, KeyguardState.DOZING)
+
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
interactor.configurationBasedDimensions
.map {
@@ -43,6 +60,91 @@
}
.distinctUntilChanged()
+ /** If the user is visually on one of the unoccluded lockscreen states. */
+ val isOnLockscreen: Flow<Boolean> =
+ keyguardTransitionInteractor.finishedKeyguardState
+ .map { statesForConstrainedNotifications.contains(it) }
+ .distinctUntilChanged()
+
+ /** Are we purely on the keyguard without the shade/qs? */
+ val isOnLockscreenWithoutShade: Flow<Boolean> =
+ combine(
+ isOnLockscreen,
+ // Shade with notifications
+ shadeInteractor.shadeExpansion.map { it > 0f },
+ // Shade without notifications, quick settings only (pull down from very top on
+ // lockscreen)
+ shadeInteractor.qsExpansion.map { it > 0f },
+ ) { isKeyguard, isShadeVisible, qsExpansion ->
+ isKeyguard && !(isShadeVisible || qsExpansion)
+ }
+ .distinctUntilChanged()
+
+ /**
+ * The container occupies the entire screen, and must be positioned relative to other elements.
+ *
+ * On keyguard, this generally fits below the clock and above the lock icon, or in split shade,
+ * the top of the screen to the lock icon.
+ *
+ * When the shade is expanding, the position is controlled by... the shade.
+ */
+ val position: Flow<SharedNotificationContainerPosition> =
+ isOnLockscreenWithoutShade.flatMapLatest { onLockscreen ->
+ if (onLockscreen) {
+ combine(
+ keyguardInteractor.sharedNotificationContainerPosition,
+ configurationBasedDimensions
+ ) { position, config ->
+ if (config.useSplitShade) {
+ position.copy(top = 0f)
+ } else {
+ position
+ }
+ }
+ } else {
+ interactor.topPosition.map { top ->
+ keyguardInteractor.sharedNotificationContainerPosition.value.copy(top = top)
+ }
+ }
+ }
+
+ /**
+ * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
+ * translated as the keyguard fades out.
+ */
+ val translationY: Flow<Float> =
+ combine(isOnLockscreen, keyguardInteractor.keyguardTranslationY) {
+ isOnLockscreen,
+ translationY ->
+ if (isOnLockscreen) {
+ translationY
+ } else {
+ 0f
+ }
+ }
+
+ /**
+ * When on keyguard, there is limited space to display notifications so calculate how many could
+ * be shown. Otherwise, there is no limit since the vertical space will be scrollable.
+ * TODO: b/296606746 - Need to rerun logic when notifs change
+ */
+ val maxNotifications: Flow<Int> =
+ combine(isOnLockscreen, shadeInteractor.shadeExpansion, position) {
+ onLockscreen,
+ shadeExpansion,
+ positionInfo ->
+ if (onLockscreen && shadeExpansion < 1f) {
+ notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ controller.getView(),
+ positionInfo.bottom - positionInfo.top,
+ 0f, // Vertical space for shelf is already accounted for
+ controller.getShelfHeight().toFloat(),
+ )
+ } else {
+ -1 // No limit
+ }
+ }
+
data class ConfigurationBasedDimensions(
val marginStart: Int,
val marginTop: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 6a3ebe6..4aa8b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2857,7 +2857,9 @@
&& mWakefulnessLifecycle.getLastWakeReason()
== PowerManager.WAKE_REASON_POWER_BUTTON
&& mFingerprintManager.get().isPowerbuttonFps()
- && mFingerprintManager.get().hasEnrolledFingerprints()
+ && mKeyguardUpdateMonitor
+ .getCachedIsUnlockWithFingerprintPossible(
+ mUserTracker.getUserId())
&& !touchToUnlockAnytime;
if (DEBUG_WAKEUP_DELAY) {
Log.d(TAG, "mShouldDelayWakeUpAnimation=" + mShouldDelayWakeUpAnimation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt
new file mode 100644
index 0000000..38a6d39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.annotation.CallSuper
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.savedstate.SavedStateRegistry
+import androidx.savedstate.SavedStateRegistryController
+import androidx.savedstate.SavedStateRegistryOwner
+import androidx.savedstate.setViewTreeSavedStateRegistryOwner
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.model.SysUiState
+
+/**
+ * A [SystemUIDialog] that implements [LifecycleOwner], [SavedStateRegistryOwner] and
+ * [OnBackPressedDispatcherOwner].
+ *
+ * This class was forked from [androidx.activity.ComponentDialog] and can be used to easily create
+ * SystemUI dialogs without the need to subclass [SystemUIDialog]. You should call
+ * [SystemUIDialogFactory.create] to easily instantiate this class.
+ *
+ * Important: [ComponentSystemUIDialog] should be created and shown on the main thread.
+ *
+ * @see SystemUIDialogFactory.create
+ */
+class ComponentSystemUIDialog(
+ context: Context,
+ theme: Int,
+ dismissOnDeviceLock: Boolean,
+ featureFlags: FeatureFlags,
+ dialogManager: SystemUIDialogManager,
+ sysUiState: SysUiState,
+ broadcastDispatcher: BroadcastDispatcher,
+ dialogLaunchAnimator: DialogLaunchAnimator,
+) :
+ SystemUIDialog(
+ context,
+ theme,
+ dismissOnDeviceLock,
+ featureFlags,
+ dialogManager,
+ sysUiState,
+ broadcastDispatcher,
+ dialogLaunchAnimator
+ ),
+ LifecycleOwner,
+ SavedStateRegistryOwner,
+ OnBackPressedDispatcherOwner {
+ private var _lifecycleRegistry: LifecycleRegistry? = null
+ private val lifecycleRegistry: LifecycleRegistry
+ get() = _lifecycleRegistry ?: LifecycleRegistry(this).also { _lifecycleRegistry = it }
+
+ private val savedStateRegistryController: SavedStateRegistryController =
+ SavedStateRegistryController.create(this)
+ override val savedStateRegistry: SavedStateRegistry
+ get() = savedStateRegistryController.savedStateRegistry
+
+ override val lifecycle: Lifecycle
+ get() = lifecycleRegistry
+
+ override fun onSaveInstanceState(): Bundle {
+ val bundle = super.onSaveInstanceState()
+ savedStateRegistryController.performSave(bundle)
+ return bundle
+ }
+
+ @CallSuper
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ onBackPressedDispatcher.setOnBackInvokedDispatcher(onBackInvokedDispatcher)
+ savedStateRegistryController.performRestore(savedInstanceState)
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
+ }
+
+ @CallSuper
+ override fun start() {
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ }
+
+ @CallSuper
+ override fun stop() {
+ // This is the closest thing to onDestroy that a Dialog has
+ // TODO(b/296180426): Make SystemUIDialog.onStop() and onStart() open again (annotated with
+ // @CallSuper) and do this *before* calling super.onStop(), like AndroidX ComponentDialog
+ // does.
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ _lifecycleRegistry = null
+ }
+
+ @Suppress("DEPRECATION")
+ override val onBackPressedDispatcher = OnBackPressedDispatcher { super.onBackPressed() }
+
+ @CallSuper
+ override fun onBackPressed() {
+ onBackPressedDispatcher.onBackPressed()
+ }
+
+ override fun setContentView(layoutResID: Int) {
+ initializeViewTreeOwners()
+ super.setContentView(layoutResID)
+ }
+
+ override fun setContentView(view: View) {
+ initializeViewTreeOwners()
+ super.setContentView(view)
+ }
+
+ override fun setContentView(view: View, params: ViewGroup.LayoutParams?) {
+ initializeViewTreeOwners()
+ super.setContentView(view, params)
+ }
+
+ override fun addContentView(view: View, params: ViewGroup.LayoutParams?) {
+ initializeViewTreeOwners()
+ super.addContentView(view, params)
+ }
+
+ /**
+ * Sets the view tree owners before setting the content view so that the inflation process and
+ * attach listeners will see them already present.
+ */
+ @CallSuper
+ open fun initializeViewTreeOwners() {
+ window!!.decorView.setViewTreeLifecycleOwner(this)
+ window!!.decorView.setViewTreeOnBackPressedDispatcherOwner(this)
+ window!!.decorView.setViewTreeSavedStateRegistryOwner(this)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index baf94fc..69510ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -68,7 +68,7 @@
// TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
private static final String FLAG_TABLET_DIALOG_WIDTH =
"persist.systemui.flag_tablet_dialog_width";
- private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
+ public static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
private final Context mContext;
private final FeatureFlags mFeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
new file mode 100644
index 0000000..3b15065
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.model.SysUiState
+import com.android.systemui.util.Assert
+import javax.inject.Inject
+
+/** A factory to easily instantiate a [ComponentSystemUIDialog]. */
+class SystemUIDialogFactory
+@Inject
+constructor(
+ @Application val applicationContext: Context,
+ private val featureFlags: FeatureFlagsClassic,
+ private val dialogManager: SystemUIDialogManager,
+ private val sysUiState: SysUiState,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+) {
+ /**
+ * Create a new [ComponentSystemUIDialog].
+ *
+ * Important: This should be called on the main thread and the returned dialog should be shown
+ * on the main thread.
+ *
+ * @param context the [Context] in which the dialog will be constructed.
+ * @param dismissOnDeviceLock whether the dialog should be automatically dismissed when the
+ * device is locked (true by default).
+ */
+ fun create(
+ context: Context = this.applicationContext,
+ dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ ): ComponentSystemUIDialog {
+ Assert.isMainThread()
+
+ return ComponentSystemUIDialog(
+ context,
+ SystemUIDialog.DEFAULT_THEME,
+ dismissOnDeviceLock,
+ featureFlags,
+ dialogManager,
+ sysUiState,
+ broadcastDispatcher,
+ dialogLaunchAnimator,
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index b67f280..c91313ad 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -22,13 +22,11 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.ClockAnimations
@@ -38,7 +36,6 @@
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockTickRate
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -47,6 +44,8 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
+import java.util.TimeZone
+import java.util.concurrent.Executor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
@@ -63,10 +62,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import java.util.TimeZone
-import java.util.concurrent.Executor
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -82,7 +79,6 @@
@Mock private lateinit var clock: ClockController
@Mock private lateinit var mainExecutor: DelayableExecutor
@Mock private lateinit var bgExecutor: Executor
- @Mock private lateinit var featureFlags: FeatureFlags
@Mock private lateinit var smallClockController: ClockFaceController
@Mock private lateinit var smallClockView: View
@Mock private lateinit var smallClockViewTreeObserver: ViewTreeObserver
@@ -95,9 +91,7 @@
@Mock private lateinit var largeClockEvents: ClockFaceEvents
@Mock private lateinit var parentView: View
@Mock private lateinit var transitionRepository: KeyguardTransitionRepository
- @Mock private lateinit var commandQueue: CommandQueue
private lateinit var repository: FakeKeyguardRepository
- private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
@Mock private lateinit var smallLogBuffer: LogBuffer
@Mock private lateinit var largeLogBuffer: LogBuffer
private lateinit var underTest: ClockEventController
@@ -123,31 +117,35 @@
.thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE))
repository = FakeKeyguardRepository()
- bouncerRepository = FakeKeyguardBouncerRepository()
- underTest = ClockEventController(
- KeyguardInteractor(
+ val withDeps =
+ KeyguardInteractorFactory.create(
repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = bouncerRepository,
- configurationRepository = FakeConfigurationRepository(),
- ),
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- ).keyguardTransitionInteractor,
- broadcastDispatcher,
- batteryController,
- keyguardUpdateMonitor,
- configurationController,
- context.resources,
- context,
- mainExecutor,
- bgExecutor,
- smallLogBuffer,
- largeLogBuffer,
- featureFlags
- )
+ )
+
+ withDeps.featureFlags.apply {
+ set(Flags.REGION_SAMPLING, false)
+ set(Flags.DOZING_MIGRATION_1, false)
+ }
+ underTest =
+ ClockEventController(
+ withDeps.keyguardInteractor,
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ )
+ .keyguardTransitionInteractor,
+ broadcastDispatcher,
+ batteryController,
+ keyguardUpdateMonitor,
+ configurationController,
+ context.resources,
+ context,
+ mainExecutor,
+ bgExecutor,
+ smallLogBuffer,
+ largeLogBuffer,
+ withDeps.featureFlags
+ )
underTest.clock = clock
runBlocking(IMMEDIATE) {
@@ -171,38 +169,41 @@
}
@Test
- fun themeChanged_verifyClockPaletteUpdated() = runBlocking(IMMEDIATE) {
- verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
- verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
+ fun themeChanged_verifyClockPaletteUpdated() =
+ runBlocking(IMMEDIATE) {
+ verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+ verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
- val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
- verify(configurationController).addCallback(capture(captor))
- captor.value.onThemeChanged()
+ val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+ verify(configurationController).addCallback(capture(captor))
+ captor.value.onThemeChanged()
- verify(events).onColorPaletteChanged(any())
- }
+ verify(events).onColorPaletteChanged(any())
+ }
@Test
- fun fontChanged_verifyFontSizeUpdated() = runBlocking(IMMEDIATE) {
- val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
- verify(configurationController).addCallback(capture(captor))
- captor.value.onDensityOrFontScaleChanged()
+ fun fontChanged_verifyFontSizeUpdated() =
+ runBlocking(IMMEDIATE) {
+ val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+ verify(configurationController).addCallback(capture(captor))
+ captor.value.onDensityOrFontScaleChanged()
- verify(smallClockEvents, times(2)).onFontSettingChanged(anyFloat())
- verify(largeClockEvents, times(2)).onFontSettingChanged(anyFloat())
- }
+ verify(smallClockEvents, times(2)).onFontSettingChanged(anyFloat())
+ verify(largeClockEvents, times(2)).onFontSettingChanged(anyFloat())
+ }
@Test
- fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) {
- val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
- verify(batteryController).addCallback(capture(batteryCaptor))
- val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
- keyguardCaptor.value.onKeyguardVisibilityChanged(true)
- batteryCaptor.value.onBatteryLevelChanged(10, false, true)
+ fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() =
+ runBlocking(IMMEDIATE) {
+ val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+ verify(batteryController).addCallback(capture(batteryCaptor))
+ val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
+ keyguardCaptor.value.onKeyguardVisibilityChanged(true)
+ batteryCaptor.value.onBatteryLevelChanged(10, false, true)
- verify(animations, times(2)).charge()
- }
+ verify(animations, times(2)).charge()
+ }
@Test
fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() =
@@ -219,16 +220,17 @@
}
@Test
- fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) {
- val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
- verify(batteryController).addCallback(capture(batteryCaptor))
- val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
- keyguardCaptor.value.onKeyguardVisibilityChanged(false)
- batteryCaptor.value.onBatteryLevelChanged(10, false, true)
+ fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() =
+ runBlocking(IMMEDIATE) {
+ val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+ verify(batteryController).addCallback(capture(batteryCaptor))
+ val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
+ keyguardCaptor.value.onKeyguardVisibilityChanged(false)
+ batteryCaptor.value.onBatteryLevelChanged(10, false, true)
- verify(animations, never()).charge()
- }
+ verify(animations, never()).charge()
+ }
@Test
fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() =
@@ -244,102 +246,111 @@
}
@Test
- fun localeCallback_verifyClockNotified() = runBlocking(IMMEDIATE) {
- val captor = argumentCaptor<BroadcastReceiver>()
- verify(broadcastDispatcher).registerReceiver(
- capture(captor), any(), eq(null), eq(null), anyInt(), eq(null)
- )
- captor.value.onReceive(context, mock())
+ fun localeCallback_verifyClockNotified() =
+ runBlocking(IMMEDIATE) {
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(broadcastDispatcher)
+ .registerReceiver(capture(captor), any(), eq(null), eq(null), anyInt(), eq(null))
+ captor.value.onReceive(context, mock())
- verify(events).onLocaleChanged(any())
- }
+ verify(events).onLocaleChanged(any())
+ }
@Test
- fun keyguardCallback_visibilityChanged_clockDozeCalled() = runBlocking(IMMEDIATE) {
- val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+ fun keyguardCallback_visibilityChanged_clockDozeCalled() =
+ runBlocking(IMMEDIATE) {
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(captor))
- captor.value.onKeyguardVisibilityChanged(true)
- verify(animations, never()).doze(0f)
+ captor.value.onKeyguardVisibilityChanged(true)
+ verify(animations, never()).doze(0f)
- captor.value.onKeyguardVisibilityChanged(false)
- verify(animations, times(2)).doze(0f)
- }
+ captor.value.onKeyguardVisibilityChanged(false)
+ verify(animations, times(2)).doze(0f)
+ }
@Test
- fun keyguardCallback_timeFormat_clockNotified() = runBlocking(IMMEDIATE) {
- val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(captor))
- captor.value.onTimeFormatChanged("12h")
+ fun keyguardCallback_timeFormat_clockNotified() =
+ runBlocking(IMMEDIATE) {
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+ captor.value.onTimeFormatChanged("12h")
- verify(events).onTimeFormatChanged(false)
- }
+ verify(events).onTimeFormatChanged(false)
+ }
@Test
- fun keyguardCallback_timezoneChanged_clockNotified() = runBlocking(IMMEDIATE) {
- val mockTimeZone = mock<TimeZone>()
- val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(captor))
- captor.value.onTimeZoneChanged(mockTimeZone)
+ fun keyguardCallback_timezoneChanged_clockNotified() =
+ runBlocking(IMMEDIATE) {
+ val mockTimeZone = mock<TimeZone>()
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+ captor.value.onTimeZoneChanged(mockTimeZone)
- verify(events).onTimeZoneChanged(mockTimeZone)
- }
+ verify(events).onTimeZoneChanged(mockTimeZone)
+ }
@Test
- fun keyguardCallback_userSwitched_clockNotified() = runBlocking(IMMEDIATE) {
- val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
- verify(keyguardUpdateMonitor).registerCallback(capture(captor))
- captor.value.onUserSwitchComplete(10)
+ fun keyguardCallback_userSwitched_clockNotified() =
+ runBlocking(IMMEDIATE) {
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+ captor.value.onUserSwitchComplete(10)
- verify(events).onTimeFormatChanged(false)
- }
+ verify(events).onTimeFormatChanged(false)
+ }
@Test
- fun keyguardCallback_verifyKeyguardChanged() = runBlocking(IMMEDIATE) {
- val job = underTest.listenForDozeAmount(this)
- repository.setDozeAmount(0.4f)
+ fun keyguardCallback_verifyKeyguardChanged() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.listenForDozeAmount(this)
+ repository.setDozeAmount(0.4f)
- yield()
+ yield()
- verify(animations, times(2)).doze(0.4f)
+ verify(animations, times(2)).doze(0.4f)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun unregisterListeners_validate() = runBlocking(IMMEDIATE) {
- underTest.unregisterListeners()
- verify(broadcastDispatcher).unregisterReceiver(any())
- verify(configurationController).removeCallback(any())
- verify(batteryController).removeCallback(any())
- verify(keyguardUpdateMonitor).removeCallback(any())
- verify(smallClockController.view)
+ fun unregisterListeners_validate() =
+ runBlocking(IMMEDIATE) {
+ underTest.unregisterListeners()
+ verify(broadcastDispatcher).unregisterReceiver(any())
+ verify(configurationController).removeCallback(any())
+ verify(batteryController).removeCallback(any())
+ verify(keyguardUpdateMonitor).removeCallback(any())
+ verify(smallClockController.view)
.removeOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
- verify(largeClockController.view)
+ verify(largeClockController.view)
.removeOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
- }
+ }
@Test
- fun registerOnAttachStateChangeListener_validate() = runBlocking(IMMEDIATE) {
- verify(smallClockController.view)
- .addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
- verify(largeClockController.view)
- .addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
- }
+ fun registerOnAttachStateChangeListener_validate() =
+ runBlocking(IMMEDIATE) {
+ verify(smallClockController.view)
+ .addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
+ verify(largeClockController.view)
+ .addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
+ }
@Test
- fun registerAndRemoveOnGlobalLayoutListener_correctly() = runBlocking(IMMEDIATE) {
- underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
- verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
- underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(smallClockView)
- verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
- }
+ fun registerAndRemoveOnGlobalLayoutListener_correctly() =
+ runBlocking(IMMEDIATE) {
+ underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
+ verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
+ underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(
+ smallClockView
+ )
+ verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
+ }
@Test
fun registerOnGlobalLayoutListener_RemoveOnAttachStateChangeListener_correctly() =
runBlocking(IMMEDIATE) {
- underTest.smallClockOnAttachStateChangeListener!!
- .onViewAttachedToWindow(smallClockView)
+ underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
underTest.unregisterListeners()
verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index b18137c..b9e3f14 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -47,7 +47,6 @@
import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory;
import com.android.systemui.plugins.FalsingManager;
@@ -92,7 +91,6 @@
protected @Mock ConfigurationController mConfigurationController;
protected @Mock VibratorHelper mVibrator;
protected @Mock AuthRippleController mAuthRippleController;
- protected @Mock KeyguardTransitionRepository mTransitionRepository;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
protected FakeFeatureFlags mFeatureFlags;
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@@ -165,8 +163,8 @@
mAuthRippleController,
mResources,
KeyguardTransitionInteractorFactory.create(
- TestScopeProvider.getTestScope().getBackgroundScope(),
- mTransitionRepository).getKeyguardTransitionInteractor(),
+ TestScopeProvider.getTestScope().getBackgroundScope())
+ .getKeyguardTransitionInteractor(),
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
mFeatureFlags,
mPrimaryBouncerInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index e73d580..36822e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -34,8 +34,6 @@
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
@@ -45,9 +43,8 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer
@@ -58,7 +55,6 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any
@@ -95,7 +91,6 @@
@Mock private lateinit var backgroundHandler: Handler
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
@@ -183,13 +178,10 @@
underTest.interactor =
KeyguardQuickAffordanceInteractor(
keyguardInteractor =
- KeyguardInteractor(
- repository = FakeKeyguardRepository(),
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- configurationRepository = FakeConfigurationRepository(),
- ),
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ )
+ .keyguardInteractor,
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 4b09468..972af4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.test.TestScope
@@ -52,6 +53,7 @@
private lateinit var repository: FakeKeyguardRepository
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var configurationRepository: FakeConfigurationRepository
+ private lateinit var shadeRepository: FakeShadeRepository
@Before
fun setUp() {
@@ -62,6 +64,7 @@
repository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
configurationRepository = FakeConfigurationRepository()
+ shadeRepository = FakeShadeRepository()
underTest =
KeyguardInteractor(
repository,
@@ -69,6 +72,7 @@
featureFlags,
bouncerRepository,
configurationRepository,
+ shadeRepository,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index 1dcb55d..f24ea6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -116,13 +116,13 @@
keyguardUpdateMonitor,
),
fingerprintAuthRepository,
- KeyguardInteractor(
- keyguardRepository,
- commandQueue = mock(),
- featureFlags,
- bouncerRepository,
- configurationRepository,
- ),
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ repository = keyguardRepository,
+ bouncerRepository = bouncerRepository,
+ configurationRepository = configurationRepository,
+ )
+ .keyguardInteractor,
PrimaryBouncerInteractor(
bouncerRepository,
primaryBouncerView = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 981e44b..209dcc1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -145,6 +145,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -322,6 +323,7 @@
@Mock private JavaAdapter mJavaAdapter;
@Mock private CastController mCastController;
@Mock private KeyguardRootView mKeyguardRootView;
+ @Mock private SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
protected final int mMaxUdfpsBurnInOffsetY = 5;
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -650,6 +652,7 @@
mKeyuardLongPressViewModel,
mKeyguardInteractor,
mActivityStarter,
+ mSharedNotificationContainerInteractor,
mKeyguardViewConfigurator,
mKeyguardFaceAuthInteractor,
mKeyguardRootView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index a2c2912..e22e571 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -49,7 +49,7 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.screenrecord.RecordingController;
-import com.android.systemui.shade.data.repository.ShadeRepository;
+import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -147,6 +147,7 @@
protected FakeDisableFlagsRepository mDisableFlagsRepository =
new FakeDisableFlagsRepository();
protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
+ protected FakeShadeRepository mShadeRepository = new FakeShadeRepository();
protected SysuiStatusBarStateController mStatusBarStateController;
protected ShadeInteractor mShadeInteractor;
@@ -174,7 +175,8 @@
mKeyguardRepository,
new FakeUserSetupRepository(),
mDeviceProvisionedController,
- mUserInteractor
+ mUserInteractor,
+ mShadeRepository
);
KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
@@ -249,7 +251,7 @@
mShadeLogger,
mDumpManager,
mock(KeyguardFaceAuthInteractor.class),
- mock(ShadeRepository.class),
+ mShadeRepository,
mShadeInteractor,
new JavaAdapter(mTestScope.getBackgroundScope()),
mCastController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index cdcd1a2..e6e7482 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
@@ -69,6 +70,7 @@
private val userRepository = FakeUserRepository()
private val disableFlagsRepository = FakeDisableFlagsRepository()
private val keyguardRepository = FakeKeyguardRepository()
+ private val shadeRepository = FakeShadeRepository()
@Mock private lateinit var manager: UserManager
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@@ -143,6 +145,7 @@
userSetupRepository,
deviceProvisionedController,
userInteractor,
+ shadeRepository,
)
}
@@ -353,4 +356,29 @@
// THEN expand is enabled
assertThat(actual).isTrue()
}
+
+ @Test
+ fun fullShadeExpansionWhenShadeLocked() =
+ testScope.runTest {
+ val actual by collectLastValue(underTest.shadeExpansion)
+
+ keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ shadeRepository.setShadeExpansion(0.5f)
+
+ assertThat(actual).isEqualTo(1f)
+ }
+
+ @Test
+ fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
+ testScope.runTest {
+ val actual by collectLastValue(underTest.shadeExpansion)
+
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+
+ shadeRepository.setShadeExpansion(0.5f)
+ assertThat(actual).isEqualTo(0.5f)
+
+ shadeRepository.setShadeExpansion(0.8f)
+ assertThat(actual).isEqualTo(0.8f)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index e26a8bd..fdaea22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -58,9 +58,8 @@
MockitoAnnotations.initMocks(this)
underTest = ShadeRepositoryImpl(shadeExpansionStateManager)
- `when`(shadeExpansionStateManager.addExpansionListener(any())).thenReturn(
- ShadeExpansionChangeEvent(0f, false, false, 0f)
- )
+ `when`(shadeExpansionStateManager.addExpansionListener(any()))
+ .thenReturn(ShadeExpansionChangeEvent(0f, false, false, 0f))
}
@Test
@@ -122,6 +121,21 @@
}
@Test
+ fun updateShadeExpansion() =
+ testScope.runTest {
+ assertThat(underTest.shadeExpansion.value).isEqualTo(0f)
+
+ underTest.setShadeExpansion(.5f)
+ assertThat(underTest.shadeExpansion.value).isEqualTo(.5f)
+
+ underTest.setShadeExpansion(.82f)
+ assertThat(underTest.shadeExpansion.value).isEqualTo(.82f)
+
+ underTest.setShadeExpansion(1f)
+ assertThat(underTest.shadeExpansion.value).isEqualTo(1f)
+ }
+
+ @Test
fun updateUdfpsTransitionToFullShadeProgress() =
testScope.runTest {
assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 4a2518a..51e72c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -60,8 +60,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -102,21 +102,24 @@
@Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
private val disableFlagsRepository = FakeDisableFlagsRepository()
private val keyguardRepository = FakeKeyguardRepository()
- private val shadeInteractor = ShadeInteractor(
- testScope.backgroundScope,
- disableFlagsRepository,
- keyguardRepository,
- userSetupRepository = FakeUserSetupRepository(),
- deviceProvisionedController = mock(),
- userInteractor = mock(),
- )
- private val powerInteractor = PowerInteractor(
- FakePowerRepository(),
- keyguardRepository,
- FalsingCollectorFake(),
- screenOffAnimationController = mock(),
- statusBarStateController = mock(),
- )
+ private val shadeInteractor =
+ ShadeInteractor(
+ testScope.backgroundScope,
+ disableFlagsRepository,
+ keyguardRepository,
+ userSetupRepository = FakeUserSetupRepository(),
+ deviceProvisionedController = mock(),
+ userInteractor = mock(),
+ repository = FakeShadeRepository(),
+ )
+ private val powerInteractor =
+ PowerInteractor(
+ FakePowerRepository(),
+ keyguardRepository,
+ FalsingCollectorFake(),
+ screenOffAnimationController = mock(),
+ statusBarStateController = mock(),
+ )
@JvmField @Rule val mockito = MockitoJUnit.rule()
private val configurationController = FakeConfigurationController()
@@ -127,14 +130,13 @@
disableFlagsRepository.disableFlags.value = DisableFlagsModel()
testScope.runCurrent()
- val helper = NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this))
+ val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
row = helper.createRow()
- context.getOrCreateTestableResources()
- .addOverride(R.bool.config_use_split_notification_shade, false)
- context.getOrCreateTestableResources()
+ context
+ .getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, false)
+ context
+ .getOrCreateTestableResources()
.addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
transitionController =
LockscreenShadeTransitionController(
@@ -154,15 +156,20 @@
splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
singleShadeOverScrollerFactory = { singleShadeOverScroller },
scrimTransitionController =
- LockscreenShadeScrimTransitionController(
- scrimController, context, configurationController, dumpManager),
+ LockscreenShadeScrimTransitionController(
+ scrimController,
+ context,
+ configurationController,
+ dumpManager
+ ),
keyguardTransitionControllerFactory = { notificationPanelController ->
LockscreenShadeKeyguardTransitionController(
mediaHierarchyManager,
notificationPanelController,
context,
configurationController,
- dumpManager)
+ dumpManager
+ )
},
qsTransitionControllerFactory = { qsTransitionController },
activityStarter = activityStarter,
@@ -180,8 +187,8 @@
whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(nsslController.isInLockedDownShade).thenReturn(false)
whenever(qS.isFullyCollapsed).thenReturn(true)
- whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
- true)
+ whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt()))
+ .thenReturn(true)
whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
@@ -228,8 +235,10 @@
whenever(statusbarStateController.isDozing).thenReturn(false)
transitionController.goToLockedShade(null)
verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
- assertFalse("Waking to shade locked when not dozing",
- transitionController.isWakingToShadeLocked)
+ assertFalse(
+ "Waking to shade locked when not dozing",
+ transitionController.isWakingToShadeLocked
+ )
}
@Test
@@ -243,9 +252,10 @@
@Test
fun testDontGoWhenShadeDisabled() {
- disableFlagsRepository.disableFlags.value = DisableFlagsModel(
- disable2 = DISABLE2_NOTIFICATION_SHADE,
- )
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NOTIFICATION_SHADE,
+ )
testScope.runCurrent()
transitionController.goToLockedShade(null)
verify(statusbarStateController, never()).setState(anyInt())
@@ -298,8 +308,8 @@
verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat())
verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
- verify(transitionControllerCallback, never()).setTransitionToFullShadeAmount(anyFloat(),
- anyBoolean(), anyLong())
+ verify(transitionControllerCallback, never())
+ .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
verify(qsTransitionController, never()).dragDownAmount = anyFloat()
}
@@ -309,15 +319,16 @@
verify(nsslController).setTransitionToFullShadeAmount(anyFloat())
verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
- verify(transitionControllerCallback).setTransitionToFullShadeAmount(anyFloat(),
- anyBoolean(), anyLong())
+ verify(transitionControllerCallback)
+ .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
verify(qsTransitionController).dragDownAmount = 10f
verify(depthController).transitionToFullShadeProgress = anyFloat()
}
@Test
fun testDragDownAmount_depthDistanceIsZero_setsProgressToZero() {
- context.getOrCreateTestableResources()
+ context
+ .getOrCreateTestableResources()
.addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0)
configurationController.notifyConfigurationChanged()
@@ -328,7 +339,8 @@
@Test
fun testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistance() {
- context.getOrCreateTestableResources()
+ context
+ .getOrCreateTestableResources()
.addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
configurationController.notifyConfigurationChanged()
@@ -346,13 +358,14 @@
@Test
fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
- val alphaDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ val alphaDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
+ )
transitionController.dragDownAmount = 10f
val expectedAlpha = 1 - 10f / alphaDistance
- verify(shadeViewController)
- .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+ verify(shadeViewController).setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
}
@Test
@@ -378,8 +391,7 @@
transitionController.dragDownAmount = 10f
- verify(shadeViewController)
- .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
+ verify(shadeViewController).setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
}
@Test
@@ -392,10 +404,12 @@
val distance =
context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_keyguard_transition_distance)
+ R.dimen.lockscreen_shade_keyguard_transition_distance
+ )
val offset =
context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_keyguard_transition_vertical_offset)
+ R.dimen.lockscreen_shade_keyguard_transition_vertical_offset
+ )
val expectedTranslation = 10f / distance * offset
verify(shadeViewController)
.setKeyguardTransitionProgress(anyFloat(), eq(expectedTranslation.toInt()))
@@ -411,16 +425,19 @@
@Test
fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
val distance = 10
- context.orCreateTestableResources
- .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_scrim_transition_distance,
+ distance
+ )
configurationController.notifyConfigurationChanged()
transitionController.dragDownAmount = 5f
- verify(scrimController).transitionToFullShadeProgress(
+ verify(scrimController)
+ .transitionToFullShadeProgress(
progress = eq(0.5f),
lockScreenNotificationsProgress = anyFloat()
- )
+ )
}
@Test
@@ -428,17 +445,22 @@
val distance = 100
val delay = 10
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+ distance
+ )
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+ delay
+ )
configurationController.notifyConfigurationChanged()
transitionController.dragDownAmount = 20f
- verify(scrimController).transitionToFullShadeProgress(
+ verify(scrimController)
+ .transitionToFullShadeProgress(
progress = anyFloat(),
lockScreenNotificationsProgress = eq(0.1f)
- )
+ )
}
@Test
@@ -446,17 +468,22 @@
val distance = 100
val delay = 50
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+ distance
+ )
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+ delay
+ )
configurationController.notifyConfigurationChanged()
transitionController.dragDownAmount = 20f
- verify(scrimController).transitionToFullShadeProgress(
+ verify(scrimController)
+ .transitionToFullShadeProgress(
progress = anyFloat(),
lockScreenNotificationsProgress = eq(0f)
- )
+ )
}
@Test
@@ -464,17 +491,22 @@
val distance = 100
val delay = 50
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+ distance
+ )
context.orCreateTestableResources.addOverride(
- R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+ delay
+ )
configurationController.notifyConfigurationChanged()
transitionController.dragDownAmount = 999999f
- verify(scrimController).transitionToFullShadeProgress(
+ verify(scrimController)
+ .transitionToFullShadeProgress(
progress = anyFloat(),
lockScreenNotificationsProgress = eq(1f)
- )
+ )
}
@Test
@@ -508,8 +540,10 @@
@Test
fun setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistance() {
- val alphaDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ val alphaDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
+ )
val dragDownAmount = 10f
enableSplitShade()
@@ -549,9 +583,6 @@
progress: Float,
lockScreenNotificationsProgress: Float
) {
- scrimController.setTransitionToFullShadeProgress(
- progress,
- lockScreenNotificationsProgress
- )
+ scrimController.setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index afd9954..55b52dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -21,122 +21,369 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerViewModelTest : SysuiTestCase() {
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ private val disableFlagsRepository = FakeDisableFlagsRepository()
+ private val userSetupRepository = FakeUserSetupRepository()
+ private val shadeRepository = FakeShadeRepository()
+ private val keyguardRepository = FakeKeyguardRepository()
+
private lateinit var configurationRepository: FakeConfigurationRepository
private lateinit var sharedNotificationContainerInteractor:
SharedNotificationContainerInteractor
private lateinit var underTest: SharedNotificationContainerViewModel
+ private lateinit var keyguardInteractor: KeyguardInteractor
+ private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ private lateinit var shadeInteractor: ShadeInteractor
+
+ @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock private lateinit var userInteractor: UserInteractor
+ @Mock
+ private lateinit var notificationStackScrollLayoutController:
+ NotificationStackScrollLayoutController
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
+ whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
+
configurationRepository = FakeConfigurationRepository()
+ KeyguardTransitionInteractorFactory.create(
+ scope = testScope.backgroundScope,
+ )
+ .also {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardTransitionInteractor = it.keyguardTransitionInteractor
+ keyguardTransitionRepository = it.repository
+ }
+
+ shadeInteractor =
+ ShadeInteractor(
+ testScope.backgroundScope,
+ disableFlagsRepository,
+ keyguardRepository,
+ userSetupRepository,
+ deviceProvisionedController,
+ userInteractor,
+ shadeRepository,
+ )
+
sharedNotificationContainerInteractor =
SharedNotificationContainerInteractor(
configurationRepository,
mContext,
)
- underTest = SharedNotificationContainerViewModel(sharedNotificationContainerInteractor)
+ underTest =
+ SharedNotificationContainerViewModel(
+ sharedNotificationContainerInteractor,
+ keyguardInteractor,
+ keyguardTransitionInteractor,
+ notificationStackSizeCalculator,
+ notificationStackScrollLayoutController,
+ shadeInteractor
+ )
}
@Test
- fun validateMarginStartInSplitShade() = runTest {
- overrideResource(R.bool.config_use_split_notification_shade, true)
- overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
+ fun validateMarginStartInSplitShade() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.marginStart).isEqualTo(0)
- }
+ assertThat(dimens!!.marginStart).isEqualTo(0)
+ }
@Test
- fun validateMarginStart() = runTest {
- overrideResource(R.bool.config_use_split_notification_shade, false)
- overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
+ fun validateMarginStart() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.marginStart).isEqualTo(20)
- }
+ assertThat(dimens!!.marginStart).isEqualTo(20)
+ }
@Test
- fun validateMarginEnd() = runTest {
- overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
+ fun validateMarginEnd() =
+ testScope.runTest {
+ overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.marginEnd).isEqualTo(50)
- }
+ assertThat(dimens!!.marginEnd).isEqualTo(50)
+ }
@Test
- fun validateMarginBottom() = runTest {
- overrideResource(R.dimen.notification_panel_margin_bottom, 50)
+ fun validateMarginBottom() =
+ testScope.runTest {
+ overrideResource(R.dimen.notification_panel_margin_bottom, 50)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.marginBottom).isEqualTo(50)
- }
+ assertThat(dimens!!.marginBottom).isEqualTo(50)
+ }
@Test
- fun validateMarginTopWithLargeScreenHeader() = runTest {
- overrideResource(R.bool.config_use_large_screen_shade_header, true)
- overrideResource(R.dimen.large_screen_shade_header_height, 50)
- overrideResource(R.dimen.notification_panel_margin_top, 0)
+ fun validateMarginTopWithLargeScreenHeader() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_large_screen_shade_header, true)
+ overrideResource(R.dimen.large_screen_shade_header_height, 50)
+ overrideResource(R.dimen.notification_panel_margin_top, 0)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.marginTop).isEqualTo(50)
- }
+ assertThat(dimens!!.marginTop).isEqualTo(50)
+ }
@Test
- fun validateMarginTop() = runTest {
- overrideResource(R.bool.config_use_large_screen_shade_header, false)
- overrideResource(R.dimen.large_screen_shade_header_height, 50)
- overrideResource(R.dimen.notification_panel_margin_top, 0)
+ fun validateMarginTop() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_large_screen_shade_header, false)
+ overrideResource(R.dimen.large_screen_shade_header_height, 50)
+ overrideResource(R.dimen.notification_panel_margin_top, 0)
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
+ configurationRepository.onAnyConfigurationChange()
- val lastDimens = dimens()!!
+ assertThat(dimens!!.marginTop).isEqualTo(0)
+ }
- assertThat(lastDimens.marginTop).isEqualTo(0)
+ @Test
+ fun isOnLockscreen() =
+ testScope.runTest {
+ val isOnLockscreen by collectLastValue(underTest.isOnLockscreen)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED)
+ )
+ assertThat(isOnLockscreen).isFalse()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.FINISHED
+ )
+ )
+ assertThat(isOnLockscreen).isTrue()
+ }
+
+ @Test
+ fun isOnLockscreenWithoutShade() =
+ testScope.runTest {
+ val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
+
+ // First on AOD
+ shadeRepository.setShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0f)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.OCCLUDED,
+ transitionState = TransitionState.FINISHED
+ )
+ )
+ assertThat(isOnLockscreenWithoutShade).isFalse()
+
+ // Now move to lockscreen
+ showLockscreen()
+
+ // While state is LOCKSCREEN, validate variations of both shade and qs expansion
+ shadeRepository.setShadeExpansion(0.1f)
+ shadeRepository.setQsExpansion(0f)
+ assertThat(isOnLockscreenWithoutShade).isFalse()
+
+ shadeRepository.setShadeExpansion(0.1f)
+ shadeRepository.setQsExpansion(0.1f)
+ assertThat(isOnLockscreenWithoutShade).isFalse()
+
+ shadeRepository.setShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0.1f)
+ assertThat(isOnLockscreenWithoutShade).isFalse()
+
+ shadeRepository.setShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0f)
+ assertThat(isOnLockscreenWithoutShade).isTrue()
+ }
+
+ @Test
+ fun positionOnLockscreenNotInSplitShade() =
+ testScope.runTest {
+ val position by collectLastValue(underTest.position)
+
+ // Start on lockscreen
+ showLockscreen()
+
+ // When not in split shade
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ configurationRepository.onAnyConfigurationChange()
+
+ keyguardInteractor.sharedNotificationContainerPosition.value =
+ SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+ assertThat(position)
+ .isEqualTo(SharedNotificationContainerPosition(top = 1f, bottom = 2f))
+ }
+
+ @Test
+ fun positionOnLockscreenInSplitShade() =
+ testScope.runTest {
+ val position by collectLastValue(underTest.position)
+
+ // Start on lockscreen
+ showLockscreen()
+
+ // When in split shade
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ configurationRepository.onAnyConfigurationChange()
+
+ keyguardInteractor.sharedNotificationContainerPosition.value =
+ SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ runCurrent()
+
+ // Top should be overridden to 0f
+ assertThat(position)
+ .isEqualTo(SharedNotificationContainerPosition(top = 0f, bottom = 2f))
+ }
+
+ @Test
+ fun positionOnShade() =
+ testScope.runTest {
+ val position by collectLastValue(underTest.position)
+
+ // Start on lockscreen with shade expanded
+ showLockscreenWithShadeExpanded()
+
+ // When not in split shade
+ sharedNotificationContainerInteractor.setTopPosition(10f)
+
+ assertThat(position)
+ .isEqualTo(SharedNotificationContainerPosition(top = 10f, bottom = 0f))
+ }
+
+ @Test
+ fun maxNotificationsOnLockscreen() =
+ testScope.runTest {
+ whenever(
+ notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ )
+ .thenReturn(10)
+
+ val maxNotifications by collectLastValue(underTest.maxNotifications)
+
+ showLockscreen()
+
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ configurationRepository.onAnyConfigurationChange()
+ keyguardInteractor.sharedNotificationContainerPosition.value =
+ SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+ assertThat(maxNotifications).isEqualTo(10)
+ }
+
+ @Test
+ fun maxNotificationsOnShade() =
+ testScope.runTest {
+ whenever(
+ notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ )
+ .thenReturn(10)
+ val maxNotifications by collectLastValue(underTest.maxNotifications)
+
+ // Show lockscreen with shade expanded
+ showLockscreenWithShadeExpanded()
+
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ configurationRepository.onAnyConfigurationChange()
+ keyguardInteractor.sharedNotificationContainerPosition.value =
+ SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+ // -1 means No Limit
+ assertThat(maxNotifications).isEqualTo(-1)
+ }
+
+ private suspend fun showLockscreen() {
+ shadeRepository.setShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0f)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.FINISHED
+ )
+ )
+ }
+
+ private suspend fun showLockscreenWithShadeExpanded() {
+ shadeRepository.setShadeExpansion(1f)
+ shadeRepository.setQsExpansion(0f)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.FINISHED
+ )
+ )
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index b2a1668..72cdbbc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -16,22 +16,21 @@
package com.android.systemui.common.ui.data.repository
-import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.receiveAsFlow
class FakeConfigurationRepository : ConfigurationRepository {
- private val onAnyConfigurationChangeChannel = Channel<Unit>()
- override val onAnyConfigurationChange: Flow<Unit> =
- onAnyConfigurationChangeChannel.receiveAsFlow()
+ private val _onAnyConfigurationChange = MutableSharedFlow<Unit>()
+ override val onAnyConfigurationChange: Flow<Unit> = _onAnyConfigurationChange.asSharedFlow()
private val _scaleForResolution = MutableStateFlow(1f)
override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
suspend fun onAnyConfigurationChange() {
- onAnyConfigurationChangeChannel.send(Unit)
+ _onAnyConfigurationChange.tryEmit(Unit)
}
fun setScaleForResolution(scale: Float) {
@@ -41,4 +40,8 @@
override fun getResolutionScale(): Float {
return _scaleForResolution.value
}
+
+ override fun getDimensionPixelSize(id: Int): Int {
+ throw IllegalStateException("Don't use for tests")
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index f13c98d..8c1ef1d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -23,6 +23,7 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.shade.data.repository.FakeShadeRepository
/**
* Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
@@ -38,6 +39,7 @@
commandQueue: FakeCommandQueue = FakeCommandQueue(),
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
+ shadeRepository: FakeShadeRepository = FakeShadeRepository(),
): WithDependencies {
return WithDependencies(
repository = repository,
@@ -45,12 +47,14 @@
featureFlags = featureFlags,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
+ shadeRepository = shadeRepository,
KeyguardInteractor(
repository = repository,
commandQueue = commandQueue,
featureFlags = featureFlags,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
+ shadeRepository = shadeRepository,
)
)
}
@@ -66,6 +70,7 @@
val featureFlags: FakeFeatureFlags,
val bouncerRepository: FakeKeyguardBouncerRepository,
val configurationRepository: FakeConfigurationRepository,
+ val shadeRepository: FakeShadeRepository,
val keyguardInteractor: KeyguardInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
index 23faaf3..05c63b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.util.mockito.mock
import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
@@ -31,7 +30,7 @@
@JvmStatic
fun create(
scope: CoroutineScope,
- repository: KeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
+ repository: FakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
keyguardInteractor: KeyguardInteractor =
KeyguardInteractorFactory.create().keyguardInteractor,
fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor> = Lazy {
@@ -58,7 +57,7 @@
}
data class WithDependencies(
- val repository: KeyguardTransitionRepository,
+ val repository: FakeKeyguardTransitionRepository,
val keyguardInteractor: KeyguardInteractor,
val fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor>,
val fromPrimaryBouncerTransitionInteractor: Lazy<FromPrimaryBouncerTransitionInteractor>,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index f0e1111..6b40f8e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -41,6 +41,7 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.mockito.mock
@@ -158,7 +159,8 @@
commandQueue = FakeCommandQueue(),
featureFlags = featureFlags,
bouncerRepository = FakeKeyguardBouncerRepository(),
- configurationRepository = FakeConfigurationRepository()
+ configurationRepository = FakeConfigurationRepository(),
+ shadeRepository = FakeShadeRepository(),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 492e542..ccddca2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -33,6 +33,9 @@
private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
+ private val _shadeExpansion = MutableStateFlow(0f)
+ override val shadeExpansion = _shadeExpansion
+
fun setShadeModel(model: ShadeModel) {
_shadeModel.value = model
}
@@ -44,4 +47,8 @@
override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
_udfpsTransitionToFullShadeProgress.value = progress
}
+
+ override fun setShadeExpansion(expansion: Float) {
+ _shadeExpansion.value = expansion
+ }
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index e484a6c..97fb0e7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -4907,6 +4907,18 @@
@GuardedBy(anyOf = {"mService", "mProcLock"})
void updateApplicationInfoLOSP(List<String> packagesToUpdate, int userId,
boolean updateFrameworkRes) {
+ final ArrayMap<String, ApplicationInfo> applicationInfoByPackage = new ArrayMap<>();
+ for (int i = packagesToUpdate.size() - 1; i >= 0; i--) {
+ final String packageName = packagesToUpdate.get(i);
+ final ApplicationInfo ai = mService.getPackageManagerInternal().getApplicationInfo(
+ packageName, STOCK_PM_FLAGS, Process.SYSTEM_UID, userId);
+ if (ai != null) {
+ applicationInfoByPackage.put(packageName, ai);
+ }
+ }
+ mService.mActivityTaskManager.updateActivityApplicationInfo(userId,
+ applicationInfoByPackage);
+
final ArrayList<WindowProcessController> targetProcesses = new ArrayList<>();
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mLruProcesses.get(i);
@@ -4921,8 +4933,7 @@
app.getPkgList().forEachPackage(packageName -> {
if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
try {
- final ApplicationInfo ai = AppGlobals.getPackageManager()
- .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
+ final ApplicationInfo ai = applicationInfoByPackage.get(packageName);
if (ai != null) {
if (ai.packageName.equals(app.info.packageName)) {
app.info = ai;
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index c04c279..39172b8 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -25,6 +25,7 @@
import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.MathUtils;
@@ -33,6 +34,7 @@
import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
@@ -99,6 +101,7 @@
private boolean mIsHdrLayerPresent = false;
// mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping
private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+ private boolean mForceHbmChangeCallback = false;
private boolean mIsBlockedByLowPowerMode = false;
private int mWidth;
private int mHeight;
@@ -484,7 +487,8 @@
private void updateHbmMode() {
int newHbmMode = calculateHighBrightnessMode();
updateHbmStats(newHbmMode);
- if (mHbmMode != newHbmMode) {
+ if (mHbmMode != newHbmMode || mForceHbmChangeCallback) {
+ mForceHbmChangeCallback = false;
mHbmMode = newHbmMode;
mHbmChangeCallback.run();
}
@@ -600,26 +604,32 @@
public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio) {
mHandler.post(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "HBMController#onHdrInfoChanged");
mIsHdrLayerPresent = numberOfHdrLayers > 0
&& (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
* mHbmData.minimumHdrPercentOfScreen);
- final float candidateDesiredHdrSdrRatio =
+ float candidateDesiredHdrSdrRatio =
mIsHdrLayerPresent && mHdrBrightnessCfg != null
? maxDesiredHdrSdrRatio
: DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
- if (candidateDesiredHdrSdrRatio >= 1.0f) {
- mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
- } else {
+ if (candidateDesiredHdrSdrRatio < 1.0f) {
Slog.w(TAG, "Ignoring invalid desired HDR/SDR Ratio: "
+ candidateDesiredHdrSdrRatio);
- mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+ candidateDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+ }
+
+ if (!BrightnessSynchronizer.floatEquals(
+ mMaxDesiredHdrSdrRatio, candidateDesiredHdrSdrRatio)) {
+ mForceHbmChangeCallback = true;
+ mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
}
// Calling the brightness update so that we can recalculate
// brightness with HDR in mind.
onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
});
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7897195..b01a89e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,7 +72,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
@@ -94,6 +93,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
/**
* Manages all permissions and handles permissions related tasks.
@@ -233,11 +233,11 @@
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkPermission(packageName, permissionName,
- deviceId, userId);
+ return mPermissionManagerServiceImpl.checkPermission(
+ packageName, permissionName, userId);
}
- return checkPermissionDelegate.checkPermission(packageName, permissionName,
- deviceId, userId, mPermissionManagerServiceImpl::checkPermission);
+ return checkPermissionDelegate.checkPermission(packageName, permissionName, userId,
+ mPermissionManagerServiceImpl::checkPermission);
}
@Override
@@ -254,10 +254,10 @@
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
+ return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName);
}
return checkPermissionDelegate.checkUidPermission(uid, permissionName,
- deviceId, mPermissionManagerServiceImpl::checkUidPermission);
+ mPermissionManagerServiceImpl::checkUidPermission);
}
@Override
@@ -511,14 +511,14 @@
public int getPermissionFlags(String packageName, String permissionName, int deviceId,
int userId) {
return mPermissionManagerServiceImpl
- .getPermissionFlags(packageName, permissionName, deviceId, userId);
+ .getPermissionFlags(packageName, permissionName, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permissionName, int flagMask,
int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
mPermissionManagerServiceImpl.updatePermissionFlags(packageName, permissionName, flagMask,
- flagValues, checkAdjustPolicyFlagPermission, deviceId, userId);
+ flagValues, checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -560,15 +560,14 @@
@Override
public void grantRuntimePermission(String packageName, String permissionName, int deviceId,
int userId) {
- mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName,
- deviceId, userId);
+ mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName, userId);
}
@Override
public void revokeRuntimePermission(String packageName, String permissionName, int deviceId,
int userId, String reason) {
mPermissionManagerServiceImpl.revokeRuntimePermission(packageName, permissionName,
- deviceId, userId, reason);
+ userId, reason);
}
@Override
@@ -581,14 +580,14 @@
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int deviceId, int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
- permissionName, deviceId, userId);
+ permissionName, userId);
}
@Override
public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
int deviceId, int userId) {
- return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
- permissionName, deviceId, userId);
+ return mPermissionManagerServiceImpl
+ .isPermissionRevokedByPolicy(packageName, permissionName, userId);
}
@Override
@@ -869,7 +868,6 @@
*
* @param packageName the name of the package to be checked
* @param permissionName the name of the permission to be checked
- * @param deviceId The device ID
* @param userId the user ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
@@ -878,21 +876,20 @@
* @see android.content.pm.PackageManager#checkPermission(String, String)
*/
int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- int deviceId, @UserIdInt int userId,
- @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl);
+ @UserIdInt int userId,
+ @NonNull TriFunction<String, String, Integer, Integer> superImpl);
/**
* Check whether the given UID has been granted the specified permission.
*
* @param uid the UID to be checked
* @param permissionName the name of the permission to be checked
- * @param deviceId The device ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
* the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
*/
- int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- TriFunction<Integer, String, Integer, Integer> superImpl);
+ int checkUidPermission(int uid, @NonNull String permissionName,
+ BiFunction<Integer, String, Integer> superImpl);
/**
* @return list of delegated permissions
@@ -921,32 +918,31 @@
@Override
public int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- int deviceId, int userId,
- @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl) {
+ int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
if (mDelegatedPackageName.equals(packageName)
&& isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply("com.android.shell", permissionName, deviceId, userId);
+ return superImpl.apply("com.android.shell", permissionName, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(packageName, permissionName, deviceId, userId);
+ return superImpl.apply(packageName, permissionName, userId);
}
@Override
- public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
+ public int checkUidPermission(int uid, @NonNull String permissionName,
+ @NonNull BiFunction<Integer, String, Integer> superImpl) {
if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
+ return superImpl.apply(Process.SHELL_UID, permissionName);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(uid, permissionName, deviceId);
+ return superImpl.apply(uid, permissionName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 6764e08..4353c57 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -681,7 +681,7 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
final int callingUid = Binder.getCallingUid();
return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
}
@@ -724,7 +724,7 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
final int callingUid = Binder.getCallingUid();
boolean overridePolicy = false;
@@ -908,12 +908,8 @@
}
}
- private int checkPermission(String pkgName, String permName, int userId) {
- return checkPermission(pkgName, permName, Context.DEVICE_ID_DEFAULT, userId);
- }
-
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}
@@ -979,12 +975,8 @@
return true;
}
- private int checkUidPermission(int uid, String permName) {
- return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
- }
-
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName) {
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -1303,8 +1295,7 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, final int userId) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1477,11 +1468,11 @@
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
- checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY, deviceId)
+ checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
== PackageManager.PERMISSION_GRANTED;
revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
@@ -1868,7 +1859,7 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
+ @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
@@ -1931,8 +1922,7 @@
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -2069,8 +2059,8 @@
continue;
}
boolean isSystemOrPolicyFixed = (getPermissionFlags(newPackage.getPackageName(),
- permInfo.name, Context.DEVICE_ID_DEFAULT, userId) & (
- FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_POLICY_FIXED)) != 0;
+ permInfo.name, userId) & (FLAG_PERMISSION_SYSTEM_FIXED
+ | FLAG_PERMISSION_POLICY_FIXED)) != 0;
if (isSystemOrPolicyFixed) {
continue;
}
@@ -2236,8 +2226,7 @@
for (final int userId : userIds) {
final int permissionState = checkPermission(packageName, permName,
userId);
- final int flags = getPermissionFlags(packageName, permName,
- Context.DEVICE_ID_DEFAULT, userId);
+ final int flags = getPermissionFlags(packageName, permName, userId);
final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED
| FLAG_PERMISSION_GRANTED_BY_DEFAULT
@@ -5133,7 +5122,8 @@
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName,
+ @UserIdInt int userId) {
Objects.requireNonNull(packageName, "packageName");
Preconditions.checkArgumentNonNegative(userId, "userId");
return getGrantedPermissionsInternal(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 2d824aa..128f847 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,6 +25,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
@@ -136,16 +137,14 @@
void removePermission(String permName);
/**
- * Gets the permission state flags associated with a permission.
+ * Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
* @param permName the permission for which to get the flags
- * @param deviceId The device for which to get the flags
* @param userId the user for which to get permission flags
* @return the permission flags
*/
- int getPermissionFlags(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ int getPermissionFlags(String packageName, String permName, int userId);
/**
* Updates the flags associated with a permission by replacing the flags in the specified mask
@@ -155,11 +154,10 @@
* @param permName The permission for which to update the flags
* @param flagMask The flags which to replace
* @param flagValues The flags with which to replace
- * @param deviceId The device for which to update the permission flags
* @param userId The user for which to update the permission flags
*/
- void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
- boolean checkAdjustPolicyFlagPermission, int deviceId, @UserIdInt int userId);
+ void updatePermissionFlags(String packageName, String permName, int flagMask,
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
/**
* Update the permission flags for all packages and runtime permissions of a user in order
@@ -293,13 +291,11 @@
*
* @param packageName the package to which to grant the permission
* @param permName the permission name to grant
- * @param deviceId the device for which to grant the permission
* @param userId the user for which to grant the permission
*
- * @see #revokeRuntimePermission(String, String, int, int, String)
+ * @see #revokeRuntimePermission(String, String, android.os.UserHandle, String)
*/
- void grantRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ void grantRuntimePermission(String packageName, String permName, int userId);
/**
* Revoke a runtime permission that was previously granted by
@@ -314,14 +310,13 @@
*
* @param packageName the package from which to revoke the permission
* @param permName the permission name to revoke
- * @param deviceId the device for which to revoke the permission
* @param userId the user for which to revoke the permission
* @param reason the reason for the revoke, or {@code null} for unspecified
*
- * @see #grantRuntimePermission(String, String, int, int)
+ * @see #grantRuntimePermission(String, String, android.os.UserHandle)
*/
- void revokeRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId, String reason);
+ void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason);
/**
* Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE
@@ -338,29 +333,24 @@
* does not clearly communicate to the user what would be the benefit from grating this
* permission.
*
- * @param packageName the package name
* @param permName a permission your app wants to request
- * @param deviceId the device for which to check the permission
- * @param userId the user for which to check the permission
* @return whether you can show permission rationale UI
*/
boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId);
+ @UserIdInt int userId);
/**
- * Checks whether a particular permission has been revoked for a package by policy. Typically,
+ * Checks whether a particular permissions has been revoked for a package by policy. Typically
* the device owner or the profile owner may apply such a policy. The user cannot grant policy
* revoked permissions, hence the only way for an app to get such a permission is by a policy
* change.
*
* @param packageName the name of the package you are checking against
* @param permName the name of the permission you are checking for
- * @param deviceId the device for which you are checking the permission
- * @param userId the device for which you are checking the permission
+ *
* @return whether the permission is restricted by policy
*/
- boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId);
/**
* Get set of permissions that have been split into more granular or dependent permissions.
@@ -383,25 +373,14 @@
List<SplitPermissionInfoParcelable> getSplitPermissions();
/**
- * Check whether a permission is granted or not to a package.
- *
- * @param pkgName package name
- * @param permName permission name
- * @param deviceId device ID
- * @param userId user ID
- * @return permission result {@link PackageManager.PermissionResult}
+ * TODO:theianchen add doc describing this is the old checkPermissionImpl
*/
- int checkPermission(String pkgName, String permName, int deviceId, @UserIdInt int userId);
+ int checkPermission(String pkgName, String permName, int userId);
/**
- * Check whether a permission is granted or not to an UID.
- *
- * @param uid UID
- * @param permName permission name
- * @param deviceId device ID
- * @return permission result {@link PackageManager.PermissionResult}
+ * TODO:theianchen add doc describing this is the old checkUidPermissionImpl
*/
- int checkUidPermission(int uid, String permName, int deviceId);
+ int checkUidPermission(int uid, String permName);
/**
* Get all the package names requesting app op permissions.
@@ -421,11 +400,15 @@
@UserIdInt int userId);
/**
- * Reset the runtime permission state changes for a package for all devices.
+ * Reset the runtime permission state changes for a package.
*
* TODO(zhanghai): Turn this into package change callback?
+ *
+ * @param pkg the package
+ * @param userId the user ID
*/
- void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId);
+ void resetRuntimePermissions(@NonNull AndroidPackage pkg,
+ @UserIdInt int userId);
/**
* Reset the runtime permission state changes for all packages in a user.
@@ -466,8 +449,8 @@
/**
* Get all the permissions granted to a package.
*
- * @param packageName package name
- * @param userId user ID
+ * @param packageName the name of the package
+ * @param userId the user ID
* @return the names of the granted permissions
*/
@NonNull
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index dacb8c6..7f98e21 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -120,21 +120,21 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ return mService.getPermissionFlags(packageName, permName, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
+ permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
+ ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
- + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ + ", userId = " + userId + ")");
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -182,20 +182,18 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ mService.grantRuntimePermission(packageName, permName, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId
- + ", reason = " + reason + ")");
- mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ + permName + ", userId = " + userId + ", reason = " + reason + ")");
+ mService.revokeRuntimePermission(packageName, permName, userId, reason);
}
@Override
@@ -207,20 +205,17 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ int userId) {
Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
- + ", permName = " + permName + ", deviceId = " + deviceId
- + ", userId = " + userId + ")");
- return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
- userId);
+ + ", permName = " + permName + ", userId = " + userId + ")");
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
}
@Override
@@ -230,17 +225,16 @@
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
- + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.checkPermission(pkgName, permName, deviceId, userId);
+ + ", userId = " + userId + ")");
+ return mService.checkPermission(pkgName, permName, userId);
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
- Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
- + ", deviceId = " + deviceId + ")");
- return mService.checkUidPermission(uid, permName, deviceId);
+ public int checkUidPermission(int uid, String permName) {
+ Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName + ")");
+ return mService.checkUidPermission(uid, permName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 35d165b..d4c6d42 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -153,10 +153,9 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
- int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+ public int getPermissionFlags(String packageName, String permName, int userId) {
+ int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, userId);
+ int newVal = mNewImplementation.getPermissionFlags(packageName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("getPermissionFlags");
@@ -166,12 +165,11 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId,
- @UserIdInt int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -236,17 +234,16 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
- mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId, String reason) {
- mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
- mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, userId);
}
@Override
@@ -258,11 +255,11 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
- boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
- permName, deviceId, userId);
- boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
- permName, deviceId, userId);
+ int userId) {
+ boolean oldVal = mOldImplementation
+ .shouldShowRequestPermissionRationale(packageName, permName, userId);
+ boolean newVal = mNewImplementation
+ .shouldShowRequestPermissionRationale(packageName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("shouldShowRequestPermissionRationale");
@@ -271,12 +268,11 @@
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
- deviceId, userId);
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ boolean oldVal = mOldImplementation
+ .isPermissionRevokedByPolicy(packageName, permName, userId);
boolean newVal = mNewImplementation.isPermissionRevokedByPolicy(packageName, permName,
- deviceId, userId);
+ userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("isPermissionRevokedByPolicy");
@@ -296,9 +292,9 @@
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
- int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
- int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
+ public int checkPermission(String pkgName, String permName, int userId) {
+ int oldVal = mOldImplementation.checkPermission(pkgName, permName, userId);
+ int newVal = mNewImplementation.checkPermission(pkgName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkPermission");
@@ -307,9 +303,9 @@
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
- int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
- int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
+ public int checkUidPermission(int uid, String permName) {
+ int oldVal = mOldImplementation.checkUidPermission(uid, permName);
+ int newVal = mNewImplementation.checkUidPermission(uid, permName);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkUidPermission");
@@ -376,7 +372,7 @@
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName, int userId) {
Set<String> oldVal = mOldImplementation.getGrantedPermissions(packageName, userId);
Set<String> newVal = mNewImplementation.getGrantedPermissions(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index cbeede0..4e72fae 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -158,10 +158,10 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
try {
- return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+ return mService.getPermissionFlags(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -169,12 +169,12 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
try {
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -253,24 +253,23 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
try {
- mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+ mService.grantRuntimePermission(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
try {
- mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ mService.revokeRuntimePermission(packageName, permName, userId, reason);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -289,24 +288,22 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
try {
- return mService.shouldShowRequestPermissionRationale(
- packageName, permName, deviceId, userId);
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
try {
- return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+ return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -324,20 +321,20 @@
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
try {
- return mService.checkPermission(pkgName, permName, deviceId, userId);
+ return mService.checkPermission(pkgName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
try {
- return mService.checkUidPermission(uid, permName, deviceId);
+ return mService.checkUidPermission(uid, permName);
} finally {
Trace.traceEnd(TRACE_TAG);
}
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 3b4b20f..fbad762 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -322,11 +322,26 @@
interface Clock {
/** Returns milliseconds since boot, including time spent in sleep. */
long elapsedRealtime();
+
+ /** Returns milliseconds since boot, not counting time spent in deep sleep. */
+ long uptimeMillis();
+ }
+
+ private static class RealClock implements Clock {
+ @Override
+ public long elapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public long uptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
}
public LowPowerStandbyController(Context context, Looper looper) {
- this(context, looper, SystemClock::elapsedRealtime,
- new DeviceConfigWrapper(), () -> ActivityManager.getService(),
+ this(context, looper, new RealClock(), new DeviceConfigWrapper(),
+ () -> ActivityManager.getService(),
new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml"));
}
@@ -572,9 +587,9 @@
@GuardedBy("mLock")
private void updateActiveLocked() {
- final long now = mClock.elapsedRealtime();
+ final long nowElapsed = mClock.elapsedRealtime();
final boolean standbyTimeoutExpired =
- (now - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig;
+ (nowElapsed - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig;
final boolean maintenanceMode = mIdleSinceNonInteractive && !mIsDeviceIdle;
final boolean newActive =
mForceActive || (mIsEnabled && !mIsInteractive && standbyTimeoutExpired
@@ -600,11 +615,11 @@
if (DEBUG) {
Slog.d(TAG, "onNonInteractive");
}
- final long now = mClock.elapsedRealtime();
+ final long nowElapsed = mClock.elapsedRealtime();
synchronized (mLock) {
mIsInteractive = false;
mIsDeviceIdle = false;
- mLastInteractiveTimeElapsed = now;
+ mLastInteractiveTimeElapsed = nowElapsed;
if (mStandbyTimeoutConfig > 0) {
scheduleStandbyTimeoutAlarmLocked();
@@ -630,7 +645,7 @@
@GuardedBy("mLock")
private void scheduleStandbyTimeoutAlarmLocked() {
- final long nextAlarmTime = SystemClock.elapsedRealtime() + mStandbyTimeoutConfig;
+ final long nextAlarmTime = mClock.elapsedRealtime() + mStandbyTimeoutConfig;
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
nextAlarmTime, "LowPowerStandbyController.StandbyTimeout",
mOnStandbyTimeoutExpired, mHandler);
@@ -748,9 +763,8 @@
@GuardedBy("mLock")
private void enqueueNotifyPolicyChangedLocked() {
- final long now = mClock.elapsedRealtime();
final Message msg = mHandler.obtainMessage(MSG_NOTIFY_POLICY_CHANGED, getPolicy());
- mHandler.sendMessageAtTime(msg, now);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
private void notifyPolicyChanged(LowPowerStandbyPolicy policy) {
@@ -775,9 +789,8 @@
@GuardedBy("mLock")
private void enqueueNotifyActiveChangedLocked() {
- final long now = mClock.elapsedRealtime();
final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ACTIVE_CHANGED, mIsActive);
- mHandler.sendMessageAtTime(msg, now);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
/** Notify other system components about the updated Low Power Standby active state */
@@ -1308,7 +1321,6 @@
@GuardedBy("mLock")
private void enqueueNotifyAllowlistChangedLocked() {
- final long now = mClock.elapsedRealtime();
final int[] allowlistUids = getAllowlistUidsLocked();
if (DEBUG) {
@@ -1317,7 +1329,7 @@
}
final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ALLOWLIST_CHANGED, allowlistUids);
- mHandler.sendMessageAtTime(msg, now);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
private void notifyAllowlistChanged(int[] allowlistUids) {
@@ -1334,14 +1346,12 @@
@GuardedBy("mLock")
private void enqueueNotifyStandbyPortsChangedLocked() {
- final long now = mClock.elapsedRealtime();
-
if (DEBUG) {
Slog.d(TAG, "enqueueNotifyStandbyPortsChangedLocked");
}
final Message msg = mHandler.obtainMessage(MSG_NOTIFY_STANDBY_PORTS_CHANGED);
- mHandler.sendMessageAtTime(msg, now);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
private void notifyStandbyPortsChanged() {
@@ -1448,12 +1458,11 @@
public void onForegroundStateChanged(IBinder serviceToken, String packageName,
int userId, boolean isForeground) {
try {
- final long now = mClock.elapsedRealtime();
final int uid = mContext.getPackageManager()
.getPackageUidAsUser(packageName, userId);
final Message message =
mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0);
- mHandler.sendMessageAtTime(message, now);
+ mHandler.sendMessageAtTime(message, mClock.uptimeMillis());
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index aafff2c..d430dda 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -615,7 +615,15 @@
@Override
public int getTaskForActivity(IBinder token, boolean onlyRoot) {
synchronized (mGlobalLock) {
- return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r == null) {
+ return INVALID_TASK_ID;
+ }
+ final Task task = r.getTask();
+ if (onlyRoot) {
+ return task.getRootActivity() == r ? task.mTaskId : INVALID_TASK_ID;
+ }
+ return task.mTaskId;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f776fac..9eec5f8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -584,20 +584,11 @@
// Tracking splash screen status from previous activity
boolean mSplashScreenStyleSolidColor = false;
- Drawable mEnterpriseThumbnailDrawable;
-
boolean mPauseSchedulePendingForPip = false;
// Gets set to indicate that the activity is currently being auto-pipped.
boolean mAutoEnteringPip = false;
- private void updateEnterpriseThumbnailDrawable(Context context) {
- DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
- WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
- () -> context.getDrawable(R.drawable.ic_corp_badge));
- }
-
static final int LAUNCH_SOURCE_TYPE_SYSTEM = 1;
static final int LAUNCH_SOURCE_TYPE_HOME = 2;
static final int LAUNCH_SOURCE_TYPE_SYSTEMUI = 3;
@@ -2212,8 +2203,6 @@
mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
- updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
-
boolean appActivityEmbeddingEnabled = false;
try {
appActivityEmbeddingEnabled = WindowManager.hasWindowExtensionsEnabled()
@@ -3397,7 +3386,7 @@
rootTask.moveToFront(reason, task);
// Report top activity change to tracking services and WM
- if (mRootWindowContainer.getTopResumedActivity() == this) {
+ if (mState == RESUMED && mRootWindowContainer.getTopResumedActivity() == this) {
mAtmService.setLastResumedActivityUncheckLocked(this, reason);
}
return true;
@@ -7122,15 +7111,18 @@
return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
}
+ /**
+ * Returns the task id of the activity token. If onlyRoot=true is specified, it will
+ * return a valid id only if the activity is root or the activity is immediately above
+ * the first non-relinquish-identity activity.
+ * TODO(b/297476786): Clarify the use cases about when should get the bottom activity
+ * or the first non-relinquish-identity activity from bottom.
+ */
static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null || r.getParent() == null) {
return INVALID_TASK_ID;
}
- return getTaskForActivityLocked(r, onlyRoot);
- }
-
- static int getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot) {
final Task task = r.task;
if (onlyRoot && r.compareTo(task.getRootActivity(
false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
@@ -7711,9 +7703,16 @@
return;
}
final Rect frame = win.getRelativeFrame();
- final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
- ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
- : mEnterpriseThumbnailDrawable;
+ final Context context = mAtmService.getUiContext();
+ final Drawable thumbnailDrawable;
+ if (task.mUserId == mWmService.mCurrentUserId) {
+ thumbnailDrawable = context.getDrawable(R.drawable.ic_account_circle);
+ } else {
+ final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+ thumbnailDrawable = dpm.getResources().getDrawable(
+ WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
+ () -> context.getDrawable(R.drawable.ic_corp_badge));
+ }
final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
if (thumbnail == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fb62412..59159bb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4588,6 +4588,20 @@
}
/**
+ * Updates the {@link ApplicationInfo}s of the package activities th that are attached in the
+ * WM hierarchy.
+ */
+ public void updateActivityApplicationInfo(int userId,
+ ArrayMap<String, ApplicationInfo> applicationInfoByPackage) {
+ synchronized (mGlobalLock) {
+ if (mRootWindowContainer != null) {
+ mRootWindowContainer.updateActivityApplicationInfo(userId,
+ applicationInfoByPackage);
+ }
+ }
+ }
+
+ /**
* Update the asset configuration and increase the assets sequence number.
* @param processes the processes that needs to update the asset configuration
*/
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2eec58b..6b4cc25 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3172,6 +3172,20 @@
});
}
+ void updateActivityApplicationInfo(int userId,
+ ArrayMap<String, ApplicationInfo> applicationInfoByPackage) {
+ forAllActivities(r -> {
+ if (r.mUserId != userId) {
+ return;
+ }
+
+ final ApplicationInfo aInfo = applicationInfoByPackage.get(r.packageName);
+ if (aInfo != null) {
+ r.updateApplicationInfo(aInfo);
+ }
+ });
+ }
+
void finishVoiceTask(IVoiceInteractionSession session) {
final IBinder binder = session.asBinder();
forAllLeafTasks(t -> t.finishIfVoiceTask(binder), true /* traverseTopToBottom */);
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 6a349e2..17474fb 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -26,7 +26,6 @@
import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.immutable.IndexedMap
import com.android.server.permission.access.permission.AppIdPermissionPolicy
-import com.android.server.permission.access.permission.DevicePermissionPolicy
import com.android.server.permission.access.util.attributeInt
import com.android.server.permission.access.util.attributeInterned
import com.android.server.permission.access.util.forEachTag
@@ -47,7 +46,6 @@
getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = policy
}
addPolicy(AppIdPermissionPolicy())
- addPolicy(DevicePermissionPolicy())
addPolicy(AppIdAppOpPolicy())
addPolicy(PackageAppOpPolicy())
} as IndexedMap<String, IndexedMap<String, SchemePolicy>>
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 94c878a..4ec32ea 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -329,18 +329,6 @@
private typealias AppIdPermissionFlagsReference =
MutableReference<AppIdPermissionFlags, MutableAppIdPermissionFlags>
-
-typealias DevicePermissionFlags =
- IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias MutableDevicePermissionFlags =
- MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias AppIdDevicePermissionFlags =
- IntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-typealias MutableAppIdDevicePermissionFlags =
- MutableIntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-private typealias AppIdDevicePermissionFlagsReference =
- MutableReference<AppIdDevicePermissionFlags, MutableAppIdDevicePermissionFlags>
-
typealias AppIdAppOpModes =
IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
typealias MutableAppIdAppOpModes =
@@ -358,7 +346,6 @@
sealed class UserState(
internal val packageVersionsReference: PackageVersionsReference,
internal val appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
- internal val appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
internal val appIdAppOpModesReference: AppIdAppOpModesReference,
internal val packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -370,9 +357,6 @@
val appIdPermissionFlags: AppIdPermissionFlags
get() = appIdPermissionFlagsReference.get()
- val appIdDevicePermissionFlags: AppIdDevicePermissionFlags
- get() = appIdDevicePermissionFlagsReference.get()
-
val appIdAppOpModes: AppIdAppOpModes
get() = appIdAppOpModesReference.get()
@@ -391,7 +375,6 @@
class MutableUserState private constructor(
packageVersionsReference: PackageVersionsReference,
appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
- appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
appIdAppOpModesReference: AppIdAppOpModesReference,
packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -399,7 +382,6 @@
) : UserState(
packageVersionsReference,
appIdPermissionFlagsReference,
- appIdDevicePermissionFlagsReference,
appIdAppOpModesReference,
packageAppOpModesReference,
defaultPermissionGrantFingerprint,
@@ -408,7 +390,6 @@
constructor() : this(
PackageVersionsReference(MutableIndexedMap<String, Int>()),
AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
- AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
AppIdAppOpModesReference(MutableAppIdAppOpModes()),
PackageAppOpModesReference(MutablePackageAppOpModes()),
null,
@@ -418,7 +399,6 @@
internal constructor(userState: UserState) : this(
userState.packageVersionsReference.toImmutable(),
userState.appIdPermissionFlagsReference.toImmutable(),
- userState.appIdDevicePermissionFlagsReference.toImmutable(),
userState.appIdAppOpModesReference.toImmutable(),
userState.packageAppOpModesReference.toImmutable(),
userState.defaultPermissionGrantFingerprint,
@@ -430,9 +410,6 @@
fun mutateAppIdPermissionFlags(): MutableAppIdPermissionFlags =
appIdPermissionFlagsReference.mutate()
- fun mutateAppIdDevicePermissionFlags(): MutableAppIdDevicePermissionFlags =
- appIdDevicePermissionFlagsReference.mutate()
-
fun mutateAppIdAppOpModes(): MutableAppIdAppOpModes = appIdAppOpModesReference.mutate()
fun mutatePackageAppOpModes(): MutablePackageAppOpModes = packageAppOpModesReference.mutate()
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index 1d46ca7..d1abc04 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -65,17 +65,6 @@
}
}
-data class DevicePermissionUri(
- val permissionName: String,
- val deviceId: Int
-) : AccessUri(SCHEME) {
- override fun toString(): String = "$scheme:///$permissionName/$deviceId"
-
- companion object {
- const val SCHEME = "device-permission"
- }
-}
-
data class UidUri(
val uid: Int
) : AccessUri(SCHEME) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
deleted file mode 100644
index 37a4a90..0000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionFlags
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutableAppIdDevicePermissionFlags
-import com.android.server.permission.access.MutableDevicePermissionFlags
-import com.android.server.permission.access.WriteMode
-import com.android.server.permission.access.immutable.IndexedMap
-import com.android.server.permission.access.immutable.MutableIndexedMap
-import com.android.server.permission.access.immutable.forEachIndexed
-import com.android.server.permission.access.immutable.forEachReversedIndexed
-import com.android.server.permission.access.immutable.set
-import com.android.server.permission.access.util.andInv
-import com.android.server.permission.access.util.attributeInt
-import com.android.server.permission.access.util.attributeInterned
-import com.android.server.permission.access.util.forEachTag
-import com.android.server.permission.access.util.getAttributeIntOrThrow
-import com.android.server.permission.access.util.getAttributeValueOrThrow
-import com.android.server.permission.access.util.hasBits
-import com.android.server.permission.access.util.tag
-import com.android.server.permission.access.util.tagName
-
-class DevicePermissionPersistence {
- fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
- when (tagName) {
- TAG_APP_ID_DEVICE_PERMISSIONS -> parseAppIdDevicePermissions(state, userId)
- else -> {}
- }
- }
-
- private fun BinaryXmlPullParser.parseAppIdDevicePermissions(
- state: MutableAccessState,
- userId: Int
- ) {
- val userState = state.mutateUserState(userId, WriteMode.NONE)!!
- val appIdDevicePermissionFlags = userState.mutateAppIdDevicePermissionFlags()
- forEachTag {
- when (tagName) {
- TAG_APP_ID -> parseAppId(appIdDevicePermissionFlags)
- else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
-
- appIdDevicePermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ ->
- if (appId !in state.externalState.appIdPackageNames) {
- Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
- appIdDevicePermissionFlags.removeAt(appIdIndex)
- userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
- }
- }
- }
-
- private fun BinaryXmlPullParser.parseAppId(
- appIdPermissionFlags: MutableAppIdDevicePermissionFlags
- ) {
- val appId = getAttributeIntOrThrow(ATTR_ID)
- val devicePermissionFlags = MutableDevicePermissionFlags()
- appIdPermissionFlags[appId] = devicePermissionFlags
- forEachTag {
- when (tagName) {
- TAG_DEVICE -> parseDevice(devicePermissionFlags)
- else -> {
- Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
- }
- }
-
- private fun BinaryXmlPullParser.parseDevice(
- deviceIdPermissionFlags: MutableDevicePermissionFlags
- ) {
- val deviceId = getAttributeValueOrThrow(ATTR_ID)
- val permissionFlags = MutableIndexedMap<String, Int>()
- deviceIdPermissionFlags.put(deviceId, permissionFlags)
- forEachTag {
- when (tagName) {
- TAG_PERMISSION -> parsePermission(permissionFlags)
- else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
- }
-
- private fun BinaryXmlPullParser.parsePermission(
- permissionFlags: MutableIndexedMap<String, Int>
- ) {
- val name = getAttributeValueOrThrow(ATTR_NAME).intern()
- val flags = getAttributeIntOrThrow(ATTR_FLAGS)
- permissionFlags[name] = flags
- }
-
- fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
- val appIdDevicePermissionFlags = state.userStates[userId]!!.appIdDevicePermissionFlags
- tag(TAG_APP_ID_DEVICE_PERMISSIONS) {
- appIdDevicePermissionFlags.forEachIndexed { _, appId, devicePermissionFlags ->
- serializeAppId(appId, devicePermissionFlags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializeAppId(
- appId: Int,
- devicePermissionFlags: DevicePermissionFlags
- ) {
- tag(TAG_APP_ID) {
- attributeInt(ATTR_ID, appId)
- devicePermissionFlags.forEachIndexed { _, deviceId, permissionFlags ->
- serializeDevice(deviceId, permissionFlags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializeDevice(
- deviceId: String,
- permissionFlags: IndexedMap<String, Int>
- ) {
- tag(TAG_DEVICE) {
- attributeInterned(ATTR_ID, deviceId)
- permissionFlags.forEachIndexed { _, name, flags ->
- serializePermission(name, flags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializePermission(name: String, flags: Int) {
- tag(TAG_PERMISSION) {
- attributeInterned(ATTR_NAME, name)
- // Never serialize one-time permissions as granted.
- val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
- flags andInv PermissionFlags.RUNTIME_GRANTED
- } else {
- flags
- }
- attributeInt(ATTR_FLAGS, serializedFlags)
- }
- }
-
- companion object {
- private val LOG_TAG = DevicePermissionPersistence::class.java.simpleName
-
- private const val TAG_APP_ID_DEVICE_PERMISSIONS = "app-id-device-permissions"
- private const val TAG_APP_ID = "app-id"
- private const val TAG_DEVICE = "device"
- private const val TAG_PERMISSION = "permission"
-
- private const val ATTR_ID = "id"
- private const val ATTR_NAME = "name"
- private const val ATTR_FLAGS = "flags"
- }
-}
\ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
deleted file mode 100644
index c0d7546..0000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionUri
-import com.android.server.permission.access.GetStateScope
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutateStateScope
-import com.android.server.permission.access.SchemePolicy
-import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.util.andInv
-import com.android.server.pm.pkg.PackageState
-
-class DevicePermissionPolicy : SchemePolicy() {
- private val persistence = DevicePermissionPersistence()
-
- @Volatile
- private var listeners: IndexedListSet<OnDevicePermissionFlagsChangedListener> =
- MutableIndexedListSet()
- private val listenersLock = Any()
-
- override val subjectScheme: String
- get() = UidUri.SCHEME
-
- override val objectScheme: String
- get() = DevicePermissionUri.SCHEME
-
- override fun GetStateScope.onStateMutated() {
- listeners.forEachIndexed { _, it -> it.onStateMutated() }
- }
-
- override fun MutateStateScope.onAppIdRemoved(appId: Int) {
- newState.userStates.forEachIndexed { userStateIndex, _, userState ->
- if (appId in userState.appIdDevicePermissionFlags) {
- newState.mutateUserStateAt(userStateIndex)
- .mutateAppIdDevicePermissionFlags() -= appId
- }
- }
- }
-
- override fun MutateStateScope.onStorageVolumeMounted(
- volumeUuid: String?,
- packageNames: List<String>,
- isSystemUpdated: Boolean
- ) {
- packageNames.forEachIndexed { _, packageName ->
- val packageState = newState.externalState.packageStates[packageName]!!
- trimPermissionStates(packageState.appId)
- }
- }
-
- override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
- trimPermissionStates(packageState.appId)
- }
-
- override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
- if (appId in newState.externalState.appIdPackageNames) {
- trimPermissionStates(appId)
- }
- }
-
- override fun MutateStateScope.onPackageUninstalled(
- packageName: String,
- appId: Int,
- userId: Int
- ) {
- resetPermissionStates(packageName, userId)
- }
-
- private fun MutateStateScope.resetPermissionStates(packageName: String, userId: Int) {
- // It's okay to skip resetting permissions for packages that are removed,
- // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
- val packageState = newState.externalState.packageStates[packageName] ?: return
- val androidPackage = packageState.androidPackage ?: return
- val appId = packageState.appId
- val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
- androidPackage.requestedPermissions.forEach { permissionName ->
- val isRequestedByOtherPackages = anyPackageInAppId(appId) {
- it.packageName != packageName &&
- permissionName in it.androidPackage!!.requestedPermissions
- }
- if (isRequestedByOtherPackages) {
- return@forEach
- }
- appIdPermissionFlags[appId]?.forEachIndexed { _, deviceId, _ ->
- setPermissionFlags(appId, deviceId, userId, permissionName, 0)
- }
- }
- }
-
- private fun MutateStateScope.trimPermissionStates(appId: Int) {
- val requestedPermissions = MutableIndexedSet<String>()
- forEachPackageInAppId(appId) {
- requestedPermissions += it.androidPackage!!.requestedPermissions
- }
- newState.userStates.forEachIndexed { _, userId, userState ->
- userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed {
- _, deviceId, permissionFlags ->
- permissionFlags.forEachReversedIndexed { _, permissionName, _ ->
- if (permissionName !in requestedPermissions) {
- setPermissionFlags(appId, deviceId, userId, permissionName, 0)
- }
- }
- }
- }
- }
-
- private inline fun MutateStateScope.anyPackageInAppId(
- appId: Int,
- state: AccessState = newState,
- predicate: (PackageState) -> Boolean
- ): Boolean {
- val packageNames = state.externalState.appIdPackageNames[appId]!!
- return packageNames.anyIndexed { _, packageName ->
- val packageState = state.externalState.packageStates[packageName]!!
- packageState.androidPackage != null && predicate(packageState)
- }
- }
-
- private inline fun MutateStateScope.forEachPackageInAppId(
- appId: Int,
- state: AccessState = newState,
- action: (PackageState) -> Unit
- ) {
- val packageNames = state.externalState.appIdPackageNames[appId]!!
- packageNames.forEachIndexed { _, packageName ->
- val packageState = state.externalState.packageStates[packageName]!!
- if (packageState.androidPackage != null) {
- action(packageState)
- }
- }
- }
-
- override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
- with(persistence) { this@parseUserState.parseUserState(state, userId) }
- }
-
- override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
- with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
- }
-
- fun GetStateScope.getPermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String
- ): Int =
- state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId)
- ?.getWithDefault(permissionName, 0) ?: 0
-
- fun MutateStateScope.setPermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String,
- flags: Int
- ): Boolean =
- updatePermissionFlags(
- appId, deviceId, userId, permissionName, PermissionFlags.MASK_ALL, flags
- )
-
- private fun MutateStateScope.updatePermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String,
- flagMask: Int,
- flagValues: Int
- ): Boolean {
- if (!isDeviceAwarePermission(permissionName)) {
- Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
- return false
- }
- val oldFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags[appId]
- ?.get(deviceId).getWithDefault(permissionName, 0)
- val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
- if (oldFlags == newFlags) {
- return false
- }
- val appIdDevicePermissionFlags =
- newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
- val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) {
- MutableIndexedReferenceMap()
- }
- val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() }
- permissionFlags.putWithDefault(permissionName, newFlags, 0)
- if (permissionFlags.isEmpty()) {
- devicePermissionFlags -= deviceId
- if (devicePermissionFlags.isEmpty()) {
- appIdDevicePermissionFlags -= appId
- }
- }
- listeners.forEachIndexed { _, it ->
- it.onDevicePermissionFlagsChanged(
- appId, userId, deviceId, permissionName, oldFlags, newFlags
- )
- }
- return true
- }
-
- fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
- synchronized(listenersLock) {
- listeners = listeners + listener
- }
- }
-
- fun removeOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
- synchronized(listenersLock) {
- listeners = listeners - listener
- }
- }
-
- private fun isDeviceAwarePermission(permissionName: String): Boolean =
- DEVICE_SUPPORTED_PERMISSIONS.contains(permissionName)
-
- companion object {
- private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
-
- /**
- * These permissions are supported for virtual devices.
- */
- private val DEVICE_SUPPORTED_PERMISSIONS = indexedSetOf(
- android.Manifest.permission.CAMERA,
- android.Manifest.permission.RECORD_AUDIO
- )
- }
-
- /**
- * TODO: b/289355341 - implement listener for permission changes
- * Listener for permission flags changes.
- */
- abstract class OnDevicePermissionFlagsChangedListener {
- /**
- * Called when a permission flags change has been made to the upcoming new state.
- *
- * Implementations should keep this method fast to avoid stalling the locked state mutation,
- * and only call external code after [onStateMutated] when the new state has actually become
- * the current state visible to external code.
- */
- abstract fun onDevicePermissionFlagsChanged(
- appId: Int,
- userId: Int,
- deviceId: String,
- permissionName: String,
- oldFlags: Int,
- newFlags: Int
- )
-
- /**
- * Called when the upcoming new state has become the current state.
- *
- * Implementations should keep this method fast to avoid stalling the locked state mutation.
- */
- abstract fun onStateMutated()
- }
-}
\ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index f0705ed..b797492 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -64,11 +64,9 @@
import com.android.server.PermissionThread
import com.android.server.ServiceThread
import com.android.server.SystemConfig
-import com.android.server.companion.virtual.VirtualDeviceManagerInternal
import com.android.server.permission.access.AccessCheckingService
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AppOpUri
-import com.android.server.permission.access.DevicePermissionUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
@@ -112,9 +110,6 @@
private val policy =
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
- private val devicePolicy =
- service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy
-
private val context = service.context
private lateinit var metricsLogger: MetricsLogger
private lateinit var packageManagerInternal: PackageManagerInternal
@@ -135,8 +130,6 @@
@GuardedBy("storageVolumeLock")
private val storageVolumePackageNames = ArrayMap<String?, MutableList<String>>()
- private var virtualDeviceManagerInternal: VirtualDeviceManagerInternal? = null
-
private lateinit var permissionControllerManager: PermissionControllerManager
/**
@@ -159,6 +152,7 @@
systemConfig = SystemConfig.getInstance()
userManagerInternal = LocalServices.getService(UserManagerInternal::class.java)
userManagerService = UserManagerService.getInstance()
+
// The package info cache is the cache for package and permission information.
// Disable the package info and package permission caches locally but leave the
// checkPermission cache active.
@@ -466,7 +460,7 @@
return size
}
- override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
+ override fun checkUidPermission(uid: Int, permissionName: String): Int {
val userId = UserHandle.getUserId(uid)
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
@@ -488,7 +482,7 @@
return PackageManager.PERMISSION_DENIED
}
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName, deviceId)
+ isPermissionGranted(packageState, userId, permissionName)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -521,12 +515,7 @@
return false
}
- override fun checkPermission(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int
- ): Int {
+ override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
}
@@ -535,7 +524,7 @@
.use { it.getPackageState(packageName) } ?: return PackageManager.PERMISSION_DENIED
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName, deviceId)
+ isPermissionGranted(packageState, userId, permissionName)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -553,21 +542,19 @@
private fun GetStateScope.isPermissionGranted(
packageState: PackageState,
userId: Int,
- permissionName: String,
- deviceId: Int
+ permissionName: String
): Boolean {
val appId = packageState.appId
// Note that instant apps can't have shared UIDs, so we only need to check the current
// package state.
val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
- if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
+ if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName)) {
return true
}
val fullerPermissionName = FULLER_PERMISSIONS[permissionName]
if (fullerPermissionName != null &&
- isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName, deviceId)
- ) {
+ isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName)) {
return true
}
@@ -581,10 +568,9 @@
appId: Int,
userId: Int,
isInstantApp: Boolean,
- permissionName: String,
- deviceId: Int,
+ permissionName: String
): Boolean {
- val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (!PermissionFlags.isPermissionGranted(flags)) {
return false
}
@@ -615,8 +601,7 @@
?: return emptySet()
return permissionFlags.mapNotNullIndexedTo(ArraySet()) { _, permissionName, _ ->
- if (isPermissionGranted(
- packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
permissionName
} else {
null
@@ -655,26 +640,18 @@
}
}
- override fun grantRuntimePermission(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int
- ) {
- setRuntimePermissionGranted(
- packageName, userId, permissionName, deviceId, isGranted = true
- )
+ override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
+ setRuntimePermissionGranted(packageName, userId, permissionName, isGranted = true)
}
override fun revokeRuntimePermission(
packageName: String,
permissionName: String,
- deviceId: Int,
userId: Int,
reason: String?
) {
setRuntimePermissionGranted(
- packageName, userId, permissionName, deviceId, isGranted = false, revokeReason = reason
+ packageName, userId, permissionName, isGranted = false, revokeReason = reason
)
}
@@ -683,8 +660,8 @@
userId: Int
) {
setRuntimePermissionGranted(
- packageName, userId, Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT,
- isGranted = false, skipKillUid = true
+ packageName, userId, Manifest.permission.POST_NOTIFICATIONS, isGranted = false,
+ skipKillUid = true
)
}
@@ -696,7 +673,6 @@
packageName: String,
userId: Int,
permissionName: String,
- deviceId: Int,
isGranted: Boolean,
skipKillUid: Boolean = false,
revokeReason: String? = null
@@ -772,7 +748,7 @@
}
setRuntimePermissionGranted(
- packageState, userId, permissionName, deviceId, isGranted, canManageRolePermission,
+ packageState, userId, permissionName, isGranted, canManageRolePermission,
overridePolicyFixed, reportError = true, methodName
)
}
@@ -806,16 +782,14 @@
if (permissionState ==
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
setRuntimePermissionGranted(
- packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT,
- isGranted = true, canManageRolePermission = false,
- overridePolicyFixed = false, reportError = false,
- "setRequestedPermissionStates"
+ packageState, userId, permissionName, isGranted = true,
+ canManageRolePermission = false, overridePolicyFixed = false,
+ reportError = false, "setRequestedPermissionStates"
)
updatePermissionFlags(
packageState.appId, userId, permissionName,
- Context.DEVICE_ID_DEFAULT,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED or
- PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
canUpdateSystemFlags = false,
reportErrorForUnknownPermission = false,
isPermissionRequested = true, "setRequestedPermissionStates",
@@ -842,7 +816,6 @@
packageState: PackageState,
userId: Int,
permissionName: String,
- deviceId: Int,
isGranted: Boolean,
canManageRolePermission: Boolean,
overridePolicyFixed: Boolean,
@@ -898,7 +871,7 @@
}
val appId = packageState.appId
- val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
if (reportError) {
@@ -961,7 +934,7 @@
return
}
- setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+ with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
if (permission.isRuntime) {
val action = if (isGranted) {
@@ -990,12 +963,7 @@
with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
}
- override fun getPermissionFlags(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int,
- ): Int {
+ override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
return 0
@@ -1026,8 +994,7 @@
}
val flags =
- getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+ with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
return PermissionFlags.toApiFlags(flags)
}
}
@@ -1035,7 +1002,6 @@
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,
- deviceId: Int,
userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
@@ -1052,13 +1018,13 @@
.use { it.getPackageState(packageName) } ?: return false
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
return false
}
- val flags =
- getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+ val flags = with(policy) {
+ getPermissionFlags(packageState.appId, userId, permissionName)
+ }
return flags.hasBits(PermissionFlags.POLICY_FIXED)
}
}
@@ -1080,8 +1046,7 @@
override fun shouldShowRequestPermissionRationale(
packageName: String,
permissionName: String,
- deviceId: Int,
- userId: Int,
+ userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "shouldShowRequestPermissionRationale: Unknown user $userId")
@@ -1103,11 +1068,11 @@
val flags: Int
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
return false
}
- flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
}
if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
return false
@@ -1139,7 +1104,6 @@
flagMask: Int,
flagValues: Int,
enforceAdjustPolicyPermission: Boolean,
- deviceId: Int,
userId: Int
) {
val callingUid = Binder.getCallingUid()
@@ -1235,7 +1199,7 @@
val appId = packageState.appId
service.mutateState {
updatePermissionFlags(
- appId, userId, permissionName, deviceId, flagMask, flagValues, canUpdateSystemFlags,
+ appId, userId, permissionName, flagMask, flagValues, canUpdateSystemFlags,
reportErrorForUnknownPermission = true, isPermissionRequested,
"updatePermissionFlags", packageName
)
@@ -1284,9 +1248,8 @@
val androidPackage = packageState.androidPackage ?: return@forEach
androidPackage.requestedPermissions.forEach { permissionName ->
updatePermissionFlags(
- packageState.appId, userId, permissionName, Context.DEVICE_ID_DEFAULT,
- flagMask, flagValues, canUpdateSystemFlags,
- reportErrorForUnknownPermission = false,
+ packageState.appId, userId, permissionName, flagMask, flagValues,
+ canUpdateSystemFlags, reportErrorForUnknownPermission = false,
isPermissionRequested = true, "updatePermissionFlagsForAllApps", packageName
)
}
@@ -1301,7 +1264,6 @@
appId: Int,
userId: Int,
permissionName: String,
- deviceId: Int,
flagMask: Int,
flagValues: Int,
canUpdateSystemFlags: Boolean,
@@ -1336,7 +1298,7 @@
return
}
- val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (!isPermissionRequested && oldFlags == 0) {
Slog.w(
LOG_TAG, "$methodName: Permission $permissionName isn't requested by package" +
@@ -1346,7 +1308,7 @@
}
val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
- setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+ with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
}
override fun getAllowlistedRestrictedPermissions(
@@ -1403,63 +1365,6 @@
)
}
- private fun GetStateScope.getPermissionFlagsWithPolicy(
- appId: Int,
- userId: Int,
- permissionName: String,
- deviceId: Int,
- ): Int {
- return if (deviceId == Context.DEVICE_ID_DEFAULT) {
- with(policy) { getPermissionFlags(appId, userId, permissionName) }
- } else {
- val virtualDeviceManagerInternal = virtualDeviceManagerInternal
- if (virtualDeviceManagerInternal == null) {
- Slog.e(LOG_TAG, "Virtual device manager service is not available.")
- return 0
- }
- val persistentDeviceId =
- virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
- if (persistentDeviceId != null) {
- with(devicePolicy) {
- getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
- }
- } else {
- Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
- 0
- }
- }
- }
-
- private fun MutateStateScope.setPermissionFlagsWithPolicy(
- appId: Int,
- userId: Int,
- permissionName: String,
- deviceId: Int,
- flags: Int
- ): Boolean {
- return if (deviceId == Context.DEVICE_ID_DEFAULT) {
- with(policy) {
- setPermissionFlags(appId, userId, permissionName, flags)
- }
- } else {
- val virtualDeviceManagerInternal = virtualDeviceManagerInternal
- if (virtualDeviceManagerInternal == null) {
- Slog.e(LOG_TAG, "Virtual device manager service is not available.")
- return false
- }
- val persistentDeviceId =
- virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
- if (persistentDeviceId != null) {
- with(devicePolicy) {
- setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
- }
- } else {
- Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
- false
- }
- }
- }
-
/**
* This method does not enforce checks on the caller, should only be called after
* required checks.
@@ -1634,7 +1539,8 @@
) {
service.mutateState {
with(policy) {
- val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState
+ val permissionsFlags =
+ getUidPermissionFlags(appId, userId) ?: return@mutateState
val permissions = getPermissions()
androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
@@ -1755,6 +1661,8 @@
)
}
+
+
override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
requireNotNull(permissionName) { "permissionName cannot be null" }
val packageNames = ArraySet<String>()
@@ -1971,7 +1879,7 @@
println("Permissions:")
withIndent {
userState.appIdPermissionFlags[appId]?.forEachIndexed {
- _, permissionName, flags ->
+ _, permissionName, flags ->
val isGranted = PermissionFlags.isPermissionGranted(flags)
println(
"$permissionName: granted=$isGranted, flags=" +
@@ -1980,20 +1888,6 @@
}
}
- userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
- _, deviceId, devicePermissionFlags ->
- println("Permissions (Device $deviceId):")
- withIndent {
- devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
- val isGranted = PermissionFlags.isPermissionGranted(flags)
- println(
- "$permissionName: granted=$isGranted, flags=" +
- PermissionFlags.toString(flags)
- )
- }
- }
- }
-
println("App ops:")
withIndent {
userState.appIdAppOpModes[appId]?.forEachIndexed {_, appOpName, appOpMode ->
@@ -2109,8 +2003,6 @@
override fun onSystemReady() {
service.onSystemReady()
- virtualDeviceManagerInternal =
- LocalServices.getService(VirtualDeviceManagerInternal::class.java)
permissionControllerManager = PermissionControllerManager(
context, PermissionThread.getHandler()
)
@@ -2520,7 +2412,7 @@
}
private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
- if (checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
+ if (checkUidPermission(uid, Manifest.permission.BACKUP) !=
PackageManager.PERMISSION_GRANTED) {
return false
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 76e6ec7..8e01a11 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -32,8 +32,10 @@
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -390,6 +392,35 @@
assertEquals(Float.POSITIVE_INFINITY, hbmc.getHdrBrightnessValue(), 0.0);
}
+ @Test
+ public void testHdrRespectsChangingDesiredHdrSdrRatio() {
+ final Runnable hbmChangedCallback = mock(Runnable.class);
+ final HighBrightnessModeController hbmc = new TestHbmBuilder()
+ .setClock(new OffsettableClock())
+ .setHdrBrightnessConfig(mHdrBrightnessDeviceConfigMock)
+ .setHbmChangedCallback(hbmChangedCallback)
+ .build();
+
+ // Passthrough return the max desired hdr/sdr ratio
+ when(mHdrBrightnessDeviceConfigMock.getHdrBrightnessFromSdr(anyFloat(), anyFloat()))
+ .thenAnswer(i -> i.getArgument(1));
+
+ hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 2.0f /*maxDesiredHdrSdrRatio*/);
+ advanceTime(0);
+ assertEquals(2.0f, hbmc.getHdrBrightnessValue(), EPSILON);
+ verify(hbmChangedCallback, times(1)).run();
+
+ // Verify that a change in only the desired hdrSdrRatio still results in the changed
+ // callback being invoked
+ hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/,
+ 3.0f /*maxDesiredHdrSdrRatio*/);
+ advanceTime(0);
+ assertEquals(3.0f, hbmc.getHdrBrightnessValue(), 0.0);
+ verify(hbmChangedCallback, times(2)).run();
+ }
+
@Test
public void testHdrTrumpsSunlight() {
@@ -698,6 +729,7 @@
private class TestHbmBuilder {
OffsettableClock mClock;
HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessCfg;
+ Runnable mHdrChangedCallback = () -> {};
TestHbmBuilder setClock(OffsettableClock clock) {
mClock = clock;
@@ -711,6 +743,11 @@
return this;
}
+ TestHbmBuilder setHbmChangedCallback(Runnable runnable) {
+ mHdrChangedCallback = runnable;
+ return this;
+ }
+
HighBrightnessModeController build() {
initHandler(mClock);
if (mHighBrightnessModeMetadata == null) {
@@ -718,8 +755,8 @@
}
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
- DEFAULT_HBM_DATA, mHdrBrightnessCfg, () -> {}, mHighBrightnessModeMetadata,
- mContextSpy);
+ DEFAULT_HBM_DATA, mHdrBrightnessCfg, mHdrChangedCallback,
+ mHighBrightnessModeMetadata, mContextSpy);
}
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
index d3c0e35..8e328ca 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -191,7 +191,17 @@
mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml");
mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(),
- () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
+ new LowPowerStandbyController.Clock() {
+ @Override
+ public long elapsedRealtime() {
+ return mClock.now();
+ }
+
+ @Override
+ public long uptimeMillis() {
+ return mClock.now();
+ }
+ }, mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
mTestPolicyFile);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index bb20244..b44d52e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -296,7 +296,7 @@
.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).build();
final ActivityRecord activity1 = new ActivityBuilder(mAtm)
.setTask(task1).setUid(ActivityBuilder.DEFAULT_FAKE_UID + 1).build();
- task1.setResumedActivity(activity1, "test");
+ activity1.setState(ActivityRecord.State.RESUMED, "test");
final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index f332b69..1dd71e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1093,10 +1093,16 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top of the root one.
- new ActivityBuilder(mAtm).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
task.getBottomMostActivity(), task.getRootActivity());
+ assertEquals("The task id of root activity must be reported.",
+ task.mTaskId, mAtm.mActivityClientController.getTaskForActivity(
+ activity0.token, true /* onlyRoot */));
+ assertEquals("No task must be reported for non root activity if onlyRoot.",
+ INVALID_TASK_ID, mAtm.mActivityClientController.getTaskForActivity(
+ activity1.token, true /* onlyRoot */));
}
/**
@@ -1572,8 +1578,7 @@
}
private Task getTestTask() {
- final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
- return task.getBottomMostTask();
+ return new TaskBuilder(mSupervisor).setCreateActivity(true).build();
}
private void testRootTaskBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e738d29..90b798c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2061,6 +2061,15 @@
return mode == AppOpsManager.MODE_ALLOWED;
}
+ private boolean canReportUsageStats() {
+ if (isCallingUidSystem()) {
+ return true; // System UID can always report UsageStats
+ }
+
+ return getContext().checkCallingPermission(Manifest.permission.REPORT_USAGE_STATS)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
private boolean hasObserverPermission() {
final int callingUid = Binder.getCallingUid();
DevicePolicyManagerInternal dpmInternal = getDpmInternal();
@@ -2541,14 +2550,19 @@
@Override
public void reportChooserSelection(@NonNull String packageName, int userId,
@NonNull String contentType, String[] annotations, @NonNull String action) {
- if (packageName == null) {
- throw new IllegalArgumentException("Package selection must not be null.");
- }
- // A valid contentType and action must be provided for chooser selection events.
- if (contentType == null || contentType.isBlank()
- || action == null || action.isBlank()) {
+ // A valid package name, content type, and action must be provided for these events
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(contentType);
+ Objects.requireNonNull(action);
+ if (contentType.isBlank() || action.isBlank()) {
return;
}
+
+ if (!canReportUsageStats()) {
+ throw new SecurityException("Only the system or holders of the REPORT_USAGE_STATS"
+ + " permission are allowed to call reportChooserSelection");
+ }
+
// Verify if this package exists before reporting an event for it.
if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
Slog.w(TAG, "Event report user selecting an invalid package");
@@ -2566,9 +2580,11 @@
@Override
public void reportUserInteraction(String packageName, int userId) {
Objects.requireNonNull(packageName);
- if (!isCallingUidSystem()) {
- throw new SecurityException("Only system is allowed to call reportUserInteraction");
+ if (!canReportUsageStats()) {
+ throw new SecurityException("Only the system or holders of the REPORT_USAGE_STATS"
+ + " permission are allowed to call reportUserInteraction");
}
+
final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
event.mPackage = packageName;
reportEventOrAddToQueue(userId, event);