Merge "Make IMMS#mImeDrawsImeNavBarRes multi-user aware" into main
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 23e262c..d7952eb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1251,8 +1251,22 @@
* canceled. Only the pilfering window will continue to receive events for the affected pointers
* until the pointer is lifted.
*
- * This method should be used with caution as unexpected pilfering can break fundamental user
- * interactions.
+ * Furthermore, if any new pointers go down within the touchable region of the pilfering window
+ * and are part of the same gesture, those new pointers will be pilfered as well, and will not
+ * be sent to any other windows.
+ *
+ * Pilfering is designed to be used only once per gesture. Once the gesture is complete
+ * (i.e. on {@link MotionEvent#ACTION_UP}, {@link MotionEvent#ACTION_CANCEL},
+ * or {@link MotionEvent#ACTION_HOVER_EXIT}), the system will resume dispatching pointers
+ * to the appropriately touched windows.
+ *
+ * NOTE: This method should be used with caution as unexpected pilfering can break fundamental
+ * user interactions.
+ *
+ * NOTE: Since this method pilfers pointers based on gesture stream that is
+ * currently active for the window, the behavior will depend on the state of the system, and
+ * is inherently racy. For example, a pilfer request on a quick tap may not be successful if
+ * the tap is already complete by the time the pilfer request is received by the system.
*
* @see android.os.InputConfig#SPY
* @hide
diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java
index 2302dc7..ea4abc1 100644
--- a/core/java/android/view/InputMonitor.java
+++ b/core/java/android/view/InputMonitor.java
@@ -50,13 +50,12 @@
private final SurfaceControl mSurface;
/**
- * Takes all of the current pointer events streams that are currently being sent to this
- * monitor and generates appropriate cancellations for the windows that would normally get
- * them.
+ * Pilfer pointers from this input monitor.
*
- * This method should be used with caution as unexpected pilfering can break fundamental user
- * interactions.
+ * @see android.hardware.input.InputManager#pilferPointers(IBinder)
+ * @deprecated
*/
+ @Deprecated
public void pilferPointers() {
try {
mHost.pilferPointers();
@@ -197,10 +196,10 @@
};
@DataClass.Generated(
- time = 1679692514588L,
+ time = 1720819824835L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\nprivate final @android.annotation.NonNull android.view.SurfaceControl mSurface\npublic void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\nprivate final @android.annotation.NonNull android.view.SurfaceControl mSurface\npublic @java.lang.Deprecated void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index cdd8557..61c7a8c 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -393,12 +393,6 @@
<bool name="config_wait_for_device_alignment_in_demo_datagram">false</bool>
<java-symbol type="bool" name="config_wait_for_device_alignment_in_demo_datagram" />
- <!-- Boolean indicating whether to enable MMS to be attempted on IWLAN if possible, even if
- existing cellular networks already supports IWLAN.
- -->
- <bool name="force_iwlan_mms_feature_enabled">false</bool>
- <java-symbol type="bool" name="force_iwlan_mms_feature_enabled" />
-
<!-- The time duration in millis after which Telephony will abort the last message datagram
sending requests. Telephony starts a timer when receiving a last message datagram sending
request in either OFF, IDLE, or NOT_CONNECTED state. In NOT_CONNECTED, the duration of the
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index b949cd5..ac0b9b4 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.drawer;
+import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,7 +26,9 @@
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Icon;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -36,6 +39,8 @@
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
@@ -102,6 +107,9 @@
/** The key used to get the package name of the icon resource for the preference. */
static final String EXTRA_PREFERENCE_ICON_PACKAGE = "com.android.settings.icon_package";
+ /** The key used for the raw byte data of the icon for the preference. */
+ static final String EXTRA_PREFERENCE_ICON_RAW = "com.android.settings.icon_raw";
+
/**
* Name of the meta-data item that should be set in the AndroidManifest.xml
* to specify the key that should be used for the preference.
@@ -518,6 +526,24 @@
}
/**
+ * Retrieves an icon stored in the Bundle as a Parcel with key EXTRA_PREFERENCE_ICON_RAW
+ */
+ @TargetApi(Build.VERSION_CODES.TIRAMISU)
+ @Nullable
+ public static Icon getRawIconFromUri(@NonNull Context context, @Nullable Uri uri,
+ @NonNull Map<String, IContentProvider> providerMap) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ return null;
+ }
+ final Bundle bundle = getBundleFromUri(context, uri, providerMap, null /* bundle */);
+ if (bundle == null) {
+ return null;
+ }
+
+ return bundle.getParcelable(EXTRA_PREFERENCE_ICON_RAW, Icon.class);
+ }
+
+ /**
* Gets text associated with the input key from the content provider.
*
* @param context context
@@ -564,8 +590,9 @@
return getBundleFromUri(context, uri, providerMap, bundle);
}
- private static Bundle getBundleFromUri(Context context, Uri uri,
- Map<String, IContentProvider> providerMap, Bundle bundle) {
+ @Nullable
+ private static Bundle getBundleFromUri(@NonNull Context context, @Nullable Uri uri,
+ @NonNull Map<String, IContentProvider> providerMap, @Nullable Bundle bundle) {
final Pair<String, String> args = getMethodAndKey(uri);
if (args == null) {
return null;
@@ -593,8 +620,9 @@
}
}
- private static IContentProvider getProviderFromUri(Context context, Uri uri,
- Map<String, IContentProvider> providerMap) {
+ @Nullable
+ private static IContentProvider getProviderFromUri(@NonNull Context context, @Nullable Uri uri,
+ @NonNull Map<String, IContentProvider> providerMap) {
if (uri == null) {
return null;
}
@@ -609,7 +637,8 @@
}
/** Returns method and key of the complete uri. */
- private static Pair<String, String> getMethodAndKey(Uri uri) {
+ @Nullable
+ private static Pair<String, String> getMethodAndKey(@Nullable Uri uri) {
if (uri == null) {
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
index 7f6a8ed..7886e85 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
@@ -18,6 +18,9 @@
import android.app.NotificationManager
import android.provider.Settings
+import com.android.settingslib.notification.modes.TestModeBuilder
+import com.android.settingslib.notification.modes.ZenMode
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -32,6 +35,11 @@
override val globalZenMode: StateFlow<Int>
get() = mutableZenMode.asStateFlow()
+ private val mutableModesFlow: MutableStateFlow<List<ZenMode>> =
+ MutableStateFlow(listOf(TestModeBuilder.EXAMPLE))
+ override val modes: Flow<List<ZenMode>>
+ get() = mutableModesFlow.asStateFlow()
+
init {
updateNotificationPolicy()
}
@@ -43,6 +51,20 @@
fun updateZenMode(zenMode: Int) {
mutableZenMode.value = zenMode
}
+
+ fun addMode(id: String, active: Boolean = false) {
+ mutableModesFlow.value += newMode(id, active)
+ }
+
+ fun removeMode(id: String) {
+ mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id }
+ }
+
+ fun deactivateMode(id: String) {
+ val oldMode = mutableModesFlow.value.find { it.id == id } ?: return
+ removeMode(id)
+ mutableModesFlow.value += TestModeBuilder(oldMode).setActive(false).build()
+ }
}
fun FakeZenModeRepository.updateNotificationPolicy(
@@ -61,5 +83,8 @@
suppressedVisualEffects,
state,
priorityConversationSenders,
- )
- )
+ ))
+
+private fun newMode(id: String, active: Boolean = false): ZenMode {
+ return TestModeBuilder().setId(id).setName("Mode $id").setActive(active).build()
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
index 72c3c17..ef94526 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
@@ -18,18 +18,26 @@
import android.app.NotificationManager
import android.content.BroadcastReceiver
+import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.database.ContentObserver
import android.os.Handler
+import android.provider.Settings
import com.android.settingslib.flags.Flags
+import com.android.settingslib.notification.modes.ZenMode
+import com.android.settingslib.notification.modes.ZenModesBackend
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -44,11 +52,16 @@
/** @see NotificationManager.getZenMode */
val globalZenMode: StateFlow<Int?>
+
+ /** A list of all existing priority modes. */
+ val modes: Flow<List<ZenMode>>
}
class ZenModeRepositoryImpl(
private val context: Context,
private val notificationManager: NotificationManager,
+ private val backend: ZenModesBackend,
+ private val contentResolver: ContentResolver,
val scope: CoroutineScope,
val backgroundCoroutineContext: CoroutineContext,
// This is nullable just to simplify testing, since SettingsLib doesn't have a good way
@@ -87,7 +100,6 @@
.let {
if (Flags.volumePanelBroadcastFix()) {
it.flowOn(backgroundCoroutineContext)
- .stateIn(scope, SharingStarted.WhileSubscribed(), null)
} else {
it.shareIn(
started = SharingStarted.WhileSubscribed(),
@@ -121,4 +133,45 @@
.onStart { emit(mapper()) }
.flowOn(backgroundCoroutineContext)
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+ private val zenConfigChanged by lazy {
+ if (android.app.Flags.modesUi()) {
+ callbackFlow {
+ // emit an initial value
+ trySend(Unit)
+
+ val observer =
+ object : ContentObserver(backgroundHandler) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+ /* notifyForDescendants= */ false,
+ observer)
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG),
+ /* notifyForDescendants= */ false,
+ observer)
+
+ awaitClose { contentResolver.unregisterContentObserver(observer) }
+ }
+ .flowOn(backgroundCoroutineContext)
+ } else {
+ flowOf(Unit)
+ }
+ }
+
+ override val modes: Flow<List<ZenMode>> by lazy {
+ if (android.app.Flags.modesUi()) {
+ zenConfigChanged
+ .map { backend.modes }
+ .distinctUntilChanged()
+ .flowOn(backgroundCoroutineContext)
+ } else {
+ flowOf(emptyList())
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
new file mode 100644
index 0000000..7b994d5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.notification.modes;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ZenDeviceEffects;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.Nullable;
+
+import java.util.Random;
+
+public class TestModeBuilder {
+
+ private String mId;
+ private AutomaticZenRule mRule;
+ private ZenModeConfig.ZenRule mConfigZenRule;
+
+ public static final ZenMode EXAMPLE = new TestModeBuilder().build();
+
+ public TestModeBuilder() {
+ // Reasonable defaults
+ int id = new Random().nextInt(1000);
+ mId = "rule_" + id;
+ mRule = new AutomaticZenRule.Builder("Test Rule #" + id, Uri.parse("rule://" + id))
+ .setPackage("some_package")
+ .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().disallowAllSounds().build())
+ .build();
+ mConfigZenRule = new ZenModeConfig.ZenRule();
+ mConfigZenRule.enabled = true;
+ mConfigZenRule.pkg = "some_package";
+ }
+
+ public TestModeBuilder(ZenMode previous) {
+ mId = previous.getId();
+ mRule = previous.getRule();
+
+ mConfigZenRule = new ZenModeConfig.ZenRule();
+ mConfigZenRule.enabled = previous.getRule().isEnabled();
+ mConfigZenRule.pkg = previous.getRule().getPackageName();
+ setActive(previous.isActive());
+ }
+
+ public TestModeBuilder setId(String id) {
+ mId = id;
+ return this;
+ }
+
+ public TestModeBuilder setAzr(AutomaticZenRule rule) {
+ mRule = rule;
+ mConfigZenRule.pkg = rule.getPackageName();
+ mConfigZenRule.conditionId = rule.getConditionId();
+ mConfigZenRule.enabled = rule.isEnabled();
+ return this;
+ }
+
+ public TestModeBuilder setConfigZenRule(ZenModeConfig.ZenRule configZenRule) {
+ mConfigZenRule = configZenRule;
+ return this;
+ }
+
+ public TestModeBuilder setName(String name) {
+ mRule.setName(name);
+ mConfigZenRule.name = name;
+ return this;
+ }
+
+ public TestModeBuilder setPackage(String pkg) {
+ mRule.setPackageName(pkg);
+ mConfigZenRule.pkg = pkg;
+ return this;
+ }
+
+ public TestModeBuilder setOwner(ComponentName owner) {
+ mRule.setOwner(owner);
+ mConfigZenRule.component = owner;
+ return this;
+ }
+
+ public TestModeBuilder setConfigurationActivity(ComponentName configActivity) {
+ mRule.setConfigurationActivity(configActivity);
+ mConfigZenRule.configurationActivity = configActivity;
+ return this;
+ }
+
+ public TestModeBuilder setConditionId(Uri conditionId) {
+ mRule.setConditionId(conditionId);
+ mConfigZenRule.conditionId = conditionId;
+ return this;
+ }
+
+ public TestModeBuilder setType(@AutomaticZenRule.Type int type) {
+ mRule.setType(type);
+ mConfigZenRule.type = type;
+ return this;
+ }
+
+ public TestModeBuilder setInterruptionFilter(
+ @NotificationManager.InterruptionFilter int interruptionFilter) {
+ mRule.setInterruptionFilter(interruptionFilter);
+ mConfigZenRule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
+ interruptionFilter, NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+ return this;
+ }
+
+ public TestModeBuilder setZenPolicy(@Nullable ZenPolicy policy) {
+ mRule.setZenPolicy(policy);
+ mConfigZenRule.zenPolicy = policy;
+ return this;
+ }
+
+ public TestModeBuilder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
+ mRule.setDeviceEffects(deviceEffects);
+ mConfigZenRule.zenDeviceEffects = deviceEffects;
+ return this;
+ }
+
+ public TestModeBuilder setEnabled(boolean enabled) {
+ mRule.setEnabled(enabled);
+ mConfigZenRule.enabled = enabled;
+ return this;
+ }
+
+ public TestModeBuilder setManualInvocationAllowed(boolean allowed) {
+ mRule.setManualInvocationAllowed(allowed);
+ mConfigZenRule.allowManualInvocation = allowed;
+ return this;
+ }
+
+ public TestModeBuilder setTriggerDescription(@Nullable String triggerDescription) {
+ mRule.setTriggerDescription(triggerDescription);
+ mConfigZenRule.triggerDescription = triggerDescription;
+ return this;
+ }
+
+ public TestModeBuilder setIconResId(@DrawableRes int iconResId) {
+ mRule.setIconResId(iconResId);
+ return this;
+ }
+
+ public TestModeBuilder setActive(boolean active) {
+ if (active) {
+ mConfigZenRule.enabled = true;
+ mConfigZenRule.condition = new Condition(mRule.getConditionId(), "...",
+ Condition.STATE_TRUE);
+ } else {
+ mConfigZenRule.condition = null;
+ }
+ return this;
+ }
+
+ public ZenMode build() {
+ return new ZenMode(mId, mRule, mConfigZenRule);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
index 06333b61..6e11e1f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
@@ -18,13 +18,18 @@
import android.app.NotificationManager
import android.content.BroadcastReceiver
+import android.content.ContentResolver
import android.content.Context
import android.content.Intent
+import android.database.ContentObserver
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.provider.Settings.Global
import androidx.test.filters.SmallTest
import com.android.settingslib.flags.Flags
+import com.android.settingslib.notification.modes.TestModeBuilder
+import com.android.settingslib.notification.modes.ZenMode
+import com.android.settingslib.notification.modes.ZenModesBackend
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
@@ -36,6 +41,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.any
@@ -52,8 +58,16 @@
@Mock private lateinit var notificationManager: NotificationManager
+ @Mock private lateinit var zenModesBackend: ZenModesBackend
+
+ @Mock private lateinit var contentResolver: ContentResolver
+
@Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
+ @Captor private lateinit var zenModeObserverCaptor: ArgumentCaptor<ContentObserver>
+
+ @Captor private lateinit var zenConfigObserverCaptor: ArgumentCaptor<ContentObserver>
+
private lateinit var underTest: ZenModeRepository
private val testScope: TestScope = TestScope()
@@ -66,6 +80,8 @@
ZenModeRepositoryImpl(
context,
notificationManager,
+ zenModesBackend,
+ contentResolver,
testScope.backgroundScope,
testScope.testScheduler,
backgroundHandler = null,
@@ -128,11 +144,61 @@
}
}
+ @EnableFlags(android.app.Flags.FLAG_MODES_UI)
+ @Test
+ fun modesListEmitsOnSettingsChange() {
+ testScope.runTest {
+ val values = mutableListOf<List<ZenMode>>()
+ val modes1 = listOf(TestModeBuilder().setId("One").build())
+ `when`(zenModesBackend.modes).thenReturn(modes1)
+ underTest.modes.onEach { values.add(it) }.launchIn(backgroundScope)
+ runCurrent()
+
+ // zen mode change triggers update
+ val modes2 = listOf(TestModeBuilder().setId("Two").build())
+ `when`(zenModesBackend.modes).thenReturn(modes2)
+ triggerZenModeSettingUpdate()
+ runCurrent()
+
+ // zen config change also triggers update
+ val modes3 = listOf(TestModeBuilder().setId("Three").build())
+ `when`(zenModesBackend.modes).thenReturn(modes3)
+ triggerZenConfigSettingUpdate()
+ runCurrent()
+
+ // setting update with no list change doesn't trigger update
+ triggerZenModeSettingUpdate()
+ runCurrent()
+
+ assertThat(values).containsExactly(modes1, modes2, modes3).inOrder()
+ }
+ }
+
private fun triggerIntent(action: String) {
verify(context).registerReceiver(receiverCaptor.capture(), any(), any(), any())
receiverCaptor.value.onReceive(context, Intent(action))
}
+ private fun triggerZenModeSettingUpdate() {
+ verify(contentResolver)
+ .registerContentObserver(
+ eq(Global.getUriFor(Global.ZEN_MODE)),
+ eq(false),
+ zenModeObserverCaptor.capture(),
+ )
+ zenModeObserverCaptor.value.onChange(false)
+ }
+
+ private fun triggerZenConfigSettingUpdate() {
+ verify(contentResolver)
+ .registerContentObserver(
+ eq(Global.getUriFor(Global.ZEN_MODE_CONFIG_ETAG)),
+ eq(false),
+ zenConfigObserverCaptor.capture(),
+ )
+ zenConfigObserverCaptor.value.onChange(false)
+ }
+
private companion object {
val testPolicy1 =
NotificationManager.Policy(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 12ca997..a184cf3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -337,7 +337,7 @@
// expanded, reset scrim offset.
LaunchedEffect(stackHeight, scrimOffset) {
snapshotFlow { stackHeight.intValue < minVisibleScrimHeight() && scrimOffset.value < 0f }
- .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.snapTo(0f) }
+ .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.animateTo(0f, tween()) }
}
// if we receive scroll delta from NSSL, offset the scrim and placeholder accordingly.
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 51c008a..9b725eb 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -17,7 +17,6 @@
import android.app.UserSwitchObserver
import android.content.Context
import android.database.ContentObserver
-import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.UserHandle
import android.provider.Settings
@@ -33,6 +32,7 @@
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
+import com.android.systemui.plugins.clocks.ClockPickerConfig
import com.android.systemui.plugins.clocks.ClockProvider
import com.android.systemui.plugins.clocks.ClockProviderPlugin
import com.android.systemui.plugins.clocks.ClockSettings
@@ -341,6 +341,7 @@
}
private var isClockChanged = AtomicBoolean(false)
+
private fun triggerOnCurrentClockChanged() {
val shouldSchedule = isClockChanged.compareAndSet(false, true)
if (!shouldSchedule) {
@@ -355,6 +356,7 @@
}
private var isClockListChanged = AtomicBoolean(false)
+
private fun triggerOnAvailableClocksChanged() {
val shouldSchedule = isClockListChanged.compareAndSet(false, true)
if (!shouldSchedule) {
@@ -458,6 +460,7 @@
}
private var isQueued = AtomicBoolean(false)
+
fun verifyLoadedProviders() {
val shouldSchedule = isQueued.compareAndSet(false, true)
if (!shouldSchedule) {
@@ -565,8 +568,8 @@
return availableClocks.map { (_, clock) -> clock.metadata }
}
- fun getClockThumbnail(clockId: ClockId): Drawable? =
- availableClocks[clockId]?.provider?.getClockThumbnail(clockId)
+ fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? =
+ availableClocks[clockId]?.provider?.getClockPickerConfig(clockId)
fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 9e0af97..4802e34 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -15,13 +15,13 @@
import android.content.Context
import android.content.res.Resources
-import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
+import com.android.systemui.plugins.clocks.ClockPickerConfig
import com.android.systemui.plugins.clocks.ClockProvider
import com.android.systemui.plugins.clocks.ClockSettings
@@ -60,12 +60,17 @@
)
}
- override fun getClockThumbnail(id: ClockId): Drawable? {
+ override fun getClockPickerConfig(id: ClockId): ClockPickerConfig {
if (id != DEFAULT_CLOCK_ID) {
throw IllegalArgumentException("$id is unsupported by $TAG")
}
- // TODO(b/352049256): Update placeholder to actual resource
- return resources.getDrawable(R.drawable.clock_default_thumbnail, null)
+ return ClockPickerConfig(
+ DEFAULT_CLOCK_ID,
+ resources.getString(R.string.clock_default_name),
+ resources.getString(R.string.clock_default_description),
+ // TODO(b/352049256): Update placeholder to actual resource
+ resources.getDrawable(R.drawable.clock_default_thumbnail, null),
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
index 583c10f..09dca25 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -20,9 +20,6 @@
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
-import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
-import android.provider.Settings.Global.ZEN_MODE_OFF
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.data.repository.FakeZenModeRepository
@@ -65,24 +62,28 @@
@EnableFlags(Flags.FLAG_MODES_UI)
@Test
- fun dataMatchesTheRepository() = runTest {
+ fun isActivatedWhenModesChange() = runTest {
val dataList: List<ModesTileModel> by
collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
runCurrent()
+ assertThat(dataList.map { it.isActivated }).containsExactly(false).inOrder()
- // Enable zen mode
- zenModeRepository.updateZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ // Add active mode
+ zenModeRepository.addMode(id = "One", active = true)
runCurrent()
+ assertThat(dataList.map { it.isActivated }).containsExactly(false, true).inOrder()
- // Change zen mode: it's still enabled, so this shouldn't cause another emission
- zenModeRepository.updateZenMode(ZEN_MODE_NO_INTERRUPTIONS)
+ // Add another mode: state hasn't changed, so this shouldn't cause another emission
+ zenModeRepository.addMode(id = "Two", active = true)
runCurrent()
+ assertThat(dataList.map { it.isActivated }).containsExactly(false, true).inOrder()
- // Disable zen mode
- zenModeRepository.updateZenMode(ZEN_MODE_OFF)
+ // Remove a mode and disable the other
+ zenModeRepository.removeMode("One")
runCurrent()
-
- assertThat(dataList.map { it.isActivated }).containsExactly(false, true, false)
+ zenModeRepository.deactivateMode("Two")
+ runCurrent()
+ assertThat(dataList.map { it.isActivated }).containsExactly(false, true, false).inOrder()
}
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index ba7ddce..f8e6337 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -633,7 +633,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun headsUpAnimationsEnabled_keyguardShowing_false() =
+ fun headsUpAnimationsEnabled_keyguardShowing_true() =
testScope.runTest {
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
@@ -641,6 +641,6 @@
fakeKeyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
runCurrent()
- assertThat(animationsEnabled).isFalse()
+ assertThat(animationsEnabled).isTrue()
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index c7998f0..4812ff0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -50,8 +50,8 @@
/** Initializes and returns the target clock design */
fun createClock(settings: ClockSettings): ClockController
- /** A static thumbnail for rendering in some examples */
- fun getClockThumbnail(id: ClockId): Drawable?
+ /** Settings configuration parameters for the clock */
+ fun getClockPickerConfig(id: ClockId): ClockPickerConfig
}
/** Interface for controlling an active clock */
@@ -133,6 +133,7 @@
// both small and large clock should have a container (RelativeLayout in
// SimpleClockFaceController)
override val views = listOf(view)
+
override fun applyConstraints(constraints: ConstraintSet): ConstraintSet {
if (views.size != 1) {
throw IllegalArgumentException(
@@ -267,6 +268,25 @@
val clockId: ClockId,
)
+data class ClockPickerConfig(
+ val id: String,
+
+ /** Localized name of the clock */
+ val name: String,
+
+ /** Localized accessibility description for the clock */
+ val description: String,
+
+ /* Static & lightweight thumbnail version of the clock */
+ val thumbnail: Drawable,
+
+ /** True if the clock will react to tone changes in the seed color */
+ val isReactiveToTone: Boolean = true,
+
+ /** True if the clock is capable of chagning style in reaction to touches */
+ val isReactiveToTouch: Boolean = false,
+)
+
/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
val id: String,
@@ -280,7 +300,7 @@
/** Transition to AOD should move smartspace like large clock instead of small clock */
val useAlternateSmartspaceAODTransition: Boolean = false,
- /** True if the clock will react to tone changes in the seed color. */
+ @Deprecated("TODO(b/352049256): Remove")
val isReactiveToTone: Boolean = true,
/** True if the clock is large frame clock, which will use weather in compose. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 9e9368d..b482862 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -120,6 +120,7 @@
ShortcutHelperSinglePane(
modifier,
shortcutsUiState.shortcutCategories,
+ shortcutsUiState.defaultSelectedCategory,
onKeyboardSettingsClicked
)
} else {
@@ -146,6 +147,7 @@
private fun ShortcutHelperSinglePane(
modifier: Modifier = Modifier,
categories: List<ShortcutCategory>,
+ defaultSelectedCategory: ShortcutCategoryType,
onKeyboardSettingsClicked: () -> Unit,
) {
Column(
@@ -159,7 +161,7 @@
Spacer(modifier = Modifier.height(6.dp))
ShortcutsSearchBar()
Spacer(modifier = Modifier.height(16.dp))
- CategoriesPanelSinglePane(categories)
+ CategoriesPanelSinglePane(categories, defaultSelectedCategory)
Spacer(modifier = Modifier.weight(1f))
KeyboardSettings(onClick = onKeyboardSettingsClicked)
}
@@ -168,8 +170,10 @@
@Composable
private fun CategoriesPanelSinglePane(
categories: List<ShortcutCategory>,
+ defaultSelectedCategory: ShortcutCategoryType,
) {
- var expandedCategory by remember { mutableStateOf<ShortcutCategory?>(null) }
+ val selectedCategory = categories.firstOrNull { it.type == defaultSelectedCategory }
+ var expandedCategory by remember { mutableStateOf(selectedCategory) }
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
categories.fastForEachIndexed { index, category ->
val isExpanded = expandedCategory == category
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index ad258f4..25574ea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -19,6 +19,9 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -52,7 +55,7 @@
} else {
ShortcutsUiState.Active(
shortcutCategories = it,
- defaultSelectedCategory = it.first().type,
+ defaultSelectedCategory = getDefaultSelectedCategory(it),
)
}
}
@@ -62,6 +65,13 @@
initialValue = ShortcutsUiState.Inactive
)
+ private fun getDefaultSelectedCategory(
+ categories: List<ShortcutCategory>
+ ): ShortcutCategoryType {
+ val currentAppShortcuts = categories.firstOrNull { it.type is CurrentApp }
+ return currentAppShortcuts?.type ?: categories.first().type
+ }
+
fun onViewClosed() {
stateInteractor.onViewClosed()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2f872b6..e46a7cb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -78,7 +78,6 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -151,6 +150,7 @@
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.settings.UserTracker;
@@ -360,6 +360,7 @@
private final SecureSettings mSecureSettings;
private final SystemSettings mSystemSettings;
private final SystemClock mSystemClock;
+ private final ProcessWrapper mProcessWrapper;
private final SystemPropertiesHelper mSystemPropertiesHelper;
/**
@@ -1459,10 +1460,12 @@
Lazy<ActivityTransitionAnimator> activityTransitionAnimator,
Lazy<ScrimController> scrimControllerLazy,
IActivityTaskManager activityTaskManagerService,
+ IStatusBarService statusBarService,
FeatureFlags featureFlags,
SecureSettings secureSettings,
SystemSettings systemSettings,
SystemClock systemClock,
+ ProcessWrapper processWrapper,
@Main CoroutineDispatcher mainDispatcher,
Lazy<DreamViewModel> dreamViewModel,
Lazy<CommunalTransitionViewModel> communalTransitionViewModel,
@@ -1487,9 +1490,9 @@
mSecureSettings = secureSettings;
mSystemSettings = systemSettings;
mSystemClock = systemClock;
+ mProcessWrapper = processWrapper;
mSystemPropertiesHelper = systemPropertiesHelper;
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mStatusBarService = statusBarService;
mKeyguardDisplayManager = keyguardDisplayManager;
mShadeController = shadeControllerLazy;
dumpManager.registerDumpable(this);
@@ -3511,12 +3514,20 @@
// TODO (b/155663717) After restart, status bar will not properly hide home button
// unless disable is called to show un-hide it once first
if (forceClearFlags) {
- try {
- mStatusBarService.disableForUser(flags, mStatusBarDisableToken,
- mContext.getPackageName(),
- mSelectedUserInteractor.getSelectedUserId(true));
- } catch (RemoteException e) {
- Log.d(TAG, "Failed to force clear flags", e);
+ if (UserManager.isVisibleBackgroundUsersEnabled()
+ && !mProcessWrapper.isSystemUser() && !mProcessWrapper.isForegroundUser()) {
+ // TODO: b/341604160 - Support visible background users properly.
+ if (DEBUG) {
+ Log.d(TAG, "Status bar manager is disabled for visible background users");
+ }
+ } else {
+ try {
+ mStatusBarService.disableForUser(flags, mStatusBarDisableToken,
+ mContext.getPackageName(),
+ mSelectedUserInteractor.getSelectedUserId(true));
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to force clear flags", e);
+ }
}
}
@@ -3540,6 +3551,14 @@
}
if (!SceneContainerFlag.isEnabled()) {
+ if (UserManager.isVisibleBackgroundUsersEnabled()
+ && !mProcessWrapper.isSystemUser() && !mProcessWrapper.isForegroundUser()) {
+ // TODO: b/341604160 - Support visible background users properly.
+ if (DEBUG) {
+ Log.d(TAG, "Status bar manager is disabled for visible background users");
+ }
+ return;
+ }
try {
mStatusBarService.disableForUser(flags, mStatusBarDisableToken,
mContext.getPackageName(),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 15dac09..a43bfd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -23,6 +23,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -64,6 +65,7 @@
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransitionModule;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -158,10 +160,12 @@
Lazy<ActivityTransitionAnimator> activityTransitionAnimator,
Lazy<ScrimController> scrimControllerLazy,
IActivityTaskManager activityTaskManagerService,
+ IStatusBarService statusBarService,
FeatureFlags featureFlags,
SecureSettings secureSettings,
SystemSettings systemSettings,
SystemClock systemClock,
+ ProcessWrapper processWrapper,
@Main CoroutineDispatcher mainDispatcher,
Lazy<DreamViewModel> dreamViewModel,
Lazy<CommunalTransitionViewModel> communalTransitionViewModel,
@@ -206,10 +210,12 @@
activityTransitionAnimator,
scrimControllerLazy,
activityTaskManagerService,
+ statusBarService,
featureFlags,
secureSettings,
systemSettings,
systemClock,
+ processWrapper,
mainDispatcher,
dreamViewModel,
communalTransitionViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java b/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
index d848b43..e8ded03 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.os.RemoteException;
+import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -36,6 +37,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
@@ -63,6 +65,7 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardStateController mKeyguardStateController;
private final UiEventLogger mUiEventLogger;
+ private final ProcessWrapper mProcessWrapper;
private final Map<Integer, InstanceId> mSessionToInstanceId = new HashMap<>();
private boolean mKeyguardSessionStarted;
@@ -73,13 +76,15 @@
AuthController authController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardStateController keyguardStateController,
- UiEventLogger uiEventLogger
+ UiEventLogger uiEventLogger,
+ ProcessWrapper processWrapper
) {
mStatusBarManagerService = statusBarService;
mAuthController = authController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardStateController = keyguardStateController;
mUiEventLogger = uiEventLogger;
+ mProcessWrapper = processWrapper;
}
@Override
@@ -109,6 +114,16 @@
final InstanceId instanceId = mInstanceIdGenerator.newInstanceId();
mSessionToInstanceId.put(type, instanceId);
+
+ if (UserManager.isVisibleBackgroundUsersEnabled() && !mProcessWrapper.isSystemUser()
+ && !mProcessWrapper.isForegroundUser()) {
+ // TODO: b/341604160 - Support visible background users properly.
+ if (DEBUG) {
+ Log.d(TAG, "Status bar manager is disabled for visible background users");
+ }
+ return;
+ }
+
try {
if (DEBUG) {
Log.d(TAG, "Session start for [" + getString(type) + "] id=" + instanceId);
@@ -139,6 +154,14 @@
if (endSessionUiEvent != null) {
mUiEventLogger.log(endSessionUiEvent, instanceId);
}
+ if (UserManager.isVisibleBackgroundUsersEnabled() && !mProcessWrapper.isSystemUser()
+ && !mProcessWrapper.isForegroundUser()) {
+ // TODO: b/341604160 - Support visible background users properly.
+ if (DEBUG) {
+ Log.d(TAG, "Status bar manager is disabled for visible background users");
+ }
+ return;
+ }
mStatusBarManagerService.onSessionEnded(type, instanceId);
} catch (RemoteException e) {
Log.e(TAG, "Unable to send onSessionEnded for session="
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index bda0069..e7c2a45 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,7 +17,6 @@
package com.android.systemui.media;
import android.annotation.Nullable;
-import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -124,13 +123,9 @@
boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
throws RemoteException {
if (LOGD) {
- Log.d(TAG, "play(token=" + token + ", uri=" + uri
- + ", uid=" + Binder.getCallingUid()
- + ") uriUserId=" + ContentProvider.getUserIdFromUri(uri)
- + " callingUserId=" + Binder.getCallingUserHandle().getIdentifier());
+ Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ + Binder.getCallingUid() + ")");
}
- enforceUriUserId(uri);
-
Client client;
synchronized (mClients) {
client = mClients.get(token);
@@ -212,7 +207,6 @@
@Override
public String getTitle(Uri uri) {
- enforceUriUserId(uri);
final UserHandle user = Binder.getCallingUserHandle();
return Ringtone.getTitle(getContextForUser(user), uri,
false /*followSettingsUri*/, false /*allowRemote*/);
@@ -245,25 +239,6 @@
}
throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
}
-
- /**
- * Must be called from the Binder calling thread.
- * Ensures caller is from the same userId as the content they're trying to access.
- * @param uri the URI to check
- * @throws SecurityException when non-system call or userId in uri differs from the
- * caller's userId
- */
- private void enforceUriUserId(Uri uri) throws SecurityException {
- final int uriUserId = ContentProvider.getUserIdFromUri(uri);
- final int callerUserId = Binder.getCallingUserHandle().getIdentifier();
- // for a non-system call, verify the URI to play belongs to the same user as the caller
- if (UserHandle.isApp(Binder.getCallingUid()) && uriUserId != callerUserId) {
- throw new SecurityException("Illegal access to uri=" + uri
- + " content associated with user=" + uriUserId
- + ", request originates from user=" + callerUserId);
- }
- }
-
};
private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
index b4cc196..294d0c7 100644
--- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
@@ -16,6 +16,7 @@
package com.android.systemui.process;
+import android.app.ActivityManager;
import android.os.Process;
import android.os.UserHandle;
@@ -37,6 +38,13 @@
}
/**
+ * Returns {@code true} if the foreground user is running the current process.
+ */
+ public boolean isForegroundUser() {
+ return ActivityManager.getCurrentUser() == myUserHandle().getIdentifier();
+ }
+
+ /**
* Returns {@link UserHandle} as returned statically by {@link Process#myUserHandle()}.
*
* This should not be used to get the "current" user. This information only applies to the
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index da4d2f1..930109a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -18,7 +18,6 @@
import android.app.Flags
import android.os.UserHandle
-import android.provider.Settings.Global.ZEN_MODE_OFF
import com.android.settingslib.notification.data.repository.ZenModeRepository
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
@@ -31,9 +30,10 @@
class ModesTileDataInteractor @Inject constructor(val zenModeRepository: ZenModeRepository) :
QSTileDataInteractor<ModesTileModel> {
- // TODO(b/346519570): This should be checking for any enabled modes.
private val zenModeActive =
- zenModeRepository.globalZenMode.map { it != ZEN_MODE_OFF }.distinctUntilChanged()
+ zenModeRepository.modes
+ .map { modes -> modes.any { mode -> mode.isActive } }
+ .distinctUntilChanged()
override fun tileData(
user: UserHandle,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index b63ee4c..ca5f49d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -25,6 +25,7 @@
import com.android.settingslib.notification.data.repository.ZenModeRepository;
import com.android.settingslib.notification.data.repository.ZenModeRepositoryImpl;
import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
@@ -288,6 +289,7 @@
@Background Handler handler
) {
return new ZenModeRepositoryImpl(context, notificationManager,
+ ZenModesBackend.getInstance(context), context.getContentResolver(),
coroutineScope, coroutineContext, handler);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index b54f9c4..5fba615 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -275,13 +275,7 @@
if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
- combine(
- notificationStackInteractor.isShowingOnLockscreen,
- shadeInteractor.isShadeFullyCollapsed
- ) { (isKeyguardShowing, isShadeFullyCollapsed) ->
- !isKeyguardShowing && isShadeFullyCollapsed
- }
- .dumpWhileCollecting("headsUpAnimationsEnabled")
+ flowOf(true).dumpWhileCollecting("headsUpAnimationsEnabled")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index 4fba7e3..c9c39b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -189,6 +189,15 @@
listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
)
+ private val standardPackageName1 = "standard.app.group1"
+
+ private val standardAppGroup1 =
+ KeyboardShortcutGroup(
+ "Standard app group 1",
+ listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+ )
+ .apply { packageName = standardPackageName1 }
+
private val standardSubCategory1 =
ShortcutSubCategory(
standardGroup1.label!!.toString(),
@@ -230,6 +239,9 @@
)
)
+ val currentAppGroups = listOf(standardAppGroup1)
+ val currentAppPackageName = standardPackageName1
+
val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
val systemCategory =
ShortcutCategory(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 07feaa1..69fc463 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperInputShortcutsSource
@@ -52,6 +53,7 @@
private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
+ private val fakeCurrentAppsSource = FakeKeyboardShortcutGroupsSource()
private val kosmos =
Kosmos().also {
@@ -61,7 +63,7 @@
it.shortcutHelperMultiTaskingShortcutsSource = fakeMultiTaskingSource
it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
- it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperCurrentAppShortcutsSource = fakeCurrentAppsSource
}
private val testScope = kosmos.testScope
@@ -216,4 +218,17 @@
assertThat(activeUiState.defaultSelectedCategory)
.isEqualTo(activeUiState.shortcutCategories.first().type)
}
+
+ @Test
+ fun shortcutsUiState_featureActive_emitsActiveWithCurrentAppsCategorySelectedWhenPresent() =
+ testScope.runTest {
+ fakeCurrentAppsSource.setGroups(TestShortcuts.currentAppGroups)
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+ testHelper.showFromActivity()
+
+ val activeUiState = uiState as ShortcutsUiState.Active
+ assertThat(activeUiState.defaultSelectedCategory)
+ .isEqualTo(CurrentApp(TestShortcuts.currentAppPackageName))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 03afcb7..e68a4a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -77,6 +77,7 @@
import com.android.internal.foldables.FoldGracePeriodProvider;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardSecurityView;
@@ -101,6 +102,7 @@
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.scene.FakeWindowRootViewComponent;
import com.android.systemui.scene.ui.view.WindowRootView;
import com.android.systemui.settings.UserTracker;
@@ -188,6 +190,7 @@
private @Mock ActivityTransitionAnimator mActivityTransitionAnimator;
private @Mock ScrimController mScrimController;
private @Mock IActivityTaskManager mActivityTaskManagerService;
+ private @Mock IStatusBarService mStatusBarService;
private @Mock SysuiColorExtractor mColorExtractor;
private @Mock AuthController mAuthController;
private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
@@ -211,6 +214,7 @@
private @Mock SystemSettings mSystemSettings;
private @Mock SecureSettings mSecureSettings;
private @Mock AlarmManager mAlarmManager;
+ private @Mock ProcessWrapper mProcessWrapper;
private FakeSystemClock mSystemClock;
private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
@@ -247,6 +251,7 @@
.thenReturn(mock(Flow.class));
when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(mDefaultUserId);
when(mSelectedUserInteractor.getSelectedUserId(anyBoolean())).thenReturn(mDefaultUserId);
+ when(mProcessWrapper.isSystemUser()).thenReturn(true);
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
mContext,
new FakeWindowRootViewComponent.Factory(mock(WindowRootView.class)),
@@ -1225,10 +1230,12 @@
() -> mActivityTransitionAnimator,
() -> mScrimController,
mActivityTaskManagerService,
+ mStatusBarService,
mFeatureFlags,
mSecureSettings,
mSystemSettings,
mSystemClock,
+ mProcessWrapper,
mDispatcher,
() -> mDreamViewModel,
() -> mCommunalTransitionViewModel,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java
index fbeb6d8..732bef1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java
@@ -44,6 +44,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -68,6 +69,8 @@
private KeyguardStateController mKeyguardStateController;
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private ProcessWrapper mProcessWrapper;
@Captor
ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@@ -86,13 +89,15 @@
@Before
public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
+ when(mProcessWrapper.isSystemUser()).thenReturn(true);
mSessionTracker = new SessionTracker(
mStatusBarService,
mAuthController,
mKeyguardUpdateMonitor,
mKeyguardStateController,
- mUiEventLogger
+ mUiEventLogger,
+ mProcessWrapper
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 2f52248..150f53d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
+import com.android.systemui.plugins.clocks.ClockPickerConfig
import com.android.systemui.plugins.clocks.ClockProviderPlugin
import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.plugins.PluginLifecycleManager
@@ -74,6 +75,7 @@
private lateinit var fakeDefaultProvider: FakeClockPlugin
private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
private lateinit var registry: ClockRegistry
+ private lateinit var pickerConfig: ClockPickerConfig
private val featureFlags = FakeFeatureFlags()
companion object {
@@ -82,9 +84,9 @@
return null!!
}
- private fun failThumbnail(clockId: ClockId): Drawable? {
- fail("Unexpected call to getThumbnail: $clockId")
- return null
+ private fun failPickerConfig(clockId: ClockId): ClockPickerConfig {
+ fail("Unexpected call to getClockPickerConfig: $clockId")
+ return null!!
}
}
@@ -123,22 +125,31 @@
private class FakeClockPlugin : ClockProviderPlugin {
private val metadata = mutableListOf<ClockMetadata>()
private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>()
- private val thumbnailCallbacks = mutableMapOf<ClockId, (ClockId) -> Drawable?>()
+ private val pickerConfigs = mutableMapOf<ClockId, (ClockId) -> ClockPickerConfig>()
override fun getClocks() = metadata
- override fun createClock(settings: ClockSettings): ClockController =
- createCallbacks[settings.clockId!!]!!(settings.clockId!!)
- override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!(id)
+
+ override fun createClock(settings: ClockSettings): ClockController {
+ val clockId = settings.clockId ?: throw IllegalArgumentException("No clockId specified")
+ return createCallbacks[clockId]?.invoke(clockId)
+ ?: throw NotImplementedError("No callback for '$clockId'")
+ }
+
+ override fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig {
+ return pickerConfigs[clockId]?.invoke(clockId)
+ ?: throw NotImplementedError("No picker config for '$clockId'")
+ }
+
override fun initialize(buffers: ClockMessageBuffers?) { }
fun addClock(
id: ClockId,
create: (ClockId) -> ClockController = ::failFactory,
- getThumbnail: (ClockId) -> Drawable? = ::failThumbnail
+ getPickerConfig: (ClockId) -> ClockPickerConfig = ::failPickerConfig
): FakeClockPlugin {
metadata.add(ClockMetadata(id))
createCallbacks[id] = create
- thumbnailCallbacks[id] = getThumbnail
+ pickerConfigs[id] = getPickerConfig
return this
}
}
@@ -148,9 +159,10 @@
scheduler = TestCoroutineScheduler()
dispatcher = StandardTestDispatcher(scheduler)
scope = TestScope(dispatcher)
+ pickerConfig = ClockPickerConfig("CLOCK_ID", "NAME", "DESC", mockThumbnail)
fakeDefaultProvider = FakeClockPlugin()
- .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail })
+ .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { pickerConfig })
whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
@@ -215,8 +227,8 @@
@Test
fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
val plugin1 = FakeClockPlugin()
- .addClock("clock_1", { mockClock }, { mockThumbnail })
- .addClock("clock_2", { mockClock }, { mockThumbnail })
+ .addClock("clock_1", { mockClock }, { pickerConfig })
+ .addClock("clock_2", { mockClock }, { pickerConfig })
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
val plugin2 = FakeClockPlugin()
@@ -238,8 +250,8 @@
assertEquals(registry.createExampleClock("clock_1"), mockClock)
assertEquals(registry.createExampleClock("clock_2"), mockClock)
- assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail)
- assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail)
+ assertEquals(registry.getClockPickerConfig("clock_1"), pickerConfig)
+ assertEquals(registry.getClockPickerConfig("clock_2"), pickerConfig)
verify(lifecycle1, never()).unloadPlugin()
verify(lifecycle2, times(2)).unloadPlugin()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 2522ed7..bbe03f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -72,6 +72,10 @@
.thenReturn(mockSmallClockView)
whenever(layoutInflater.inflate(eq(R.layout.clock_default_large), any(), anyBoolean()))
.thenReturn(mockLargeClockView)
+ whenever(resources.getString(R.string.clock_default_name))
+ .thenReturn("DEFAULT_CLOCK_NAME")
+ whenever(resources.getString(R.string.clock_default_description))
+ .thenReturn("DEFAULT_CLOCK_DESC")
whenever(resources.getDrawable(R.drawable.clock_default_thumbnail, null))
.thenReturn(mockClockThumbnail)
whenever(mockSmallClockView.getLayoutParams()).thenReturn(FrameLayout.LayoutParams(10, 10))
@@ -85,7 +89,7 @@
// All providers need to provide clocks & thumbnails for exposed clocks
for (metadata in provider.getClocks()) {
assertNotNull(provider.createClock(metadata.clockId))
- assertNotNull(provider.getClockThumbnail(metadata.clockId))
+ assertNotNull(provider.getClockPickerConfig(metadata.clockId))
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt
index 3e09b23..6ca5cd8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt
@@ -41,6 +41,7 @@
}
private var imeShortcuts: List<KeyboardShortcutGroup> = emptyList()
+ private var currentAppsShortcuts: List<KeyboardShortcutGroup> = emptyList()
init {
whenever(windowManager.requestImeKeyboardShortcuts(any(), any())).thenAnswer {
@@ -48,6 +49,11 @@
keyboardShortcutReceiver.onKeyboardShortcutsReceived(imeShortcuts)
return@thenAnswer Unit
}
+ whenever(windowManager.requestAppKeyboardShortcuts(any(), any())).thenAnswer {
+ val keyboardShortcutReceiver = it.getArgument<KeyboardShortcutsReceiver>(0)
+ keyboardShortcutReceiver.onKeyboardShortcutsReceived(currentAppsShortcuts)
+ return@thenAnswer Unit
+ }
repo.start()
}
@@ -59,6 +65,14 @@
this.imeShortcuts = imeShortcuts
}
+ /**
+ * Use this method to set what current app shortcuts should be returned from windowManager in
+ * tests. By default [WindowManager.requestAppKeyboardShortcuts] will return emptyList.
+ */
+ fun setCurrentAppsShortcuts(currentAppShortcuts: List<KeyboardShortcutGroup>) {
+ this.currentAppsShortcuts = currentAppShortcuts
+ }
+
fun hideThroughCloseSystemDialogs() {
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
diff --git a/services/Android.bp b/services/Android.bp
index cd974c5..dce6aa7 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -186,7 +186,15 @@
// merge all required services into one jar
// ============================================================
-java_library {
+soong_config_module_type {
+ name: "system_java_library",
+ module_type: "java_library",
+ config_namespace: "system_services",
+ bool_variables: ["without_vibrator"],
+ properties: ["vintf_fragments"],
+}
+
+system_java_library {
name: "services",
defaults: [
"services_java_defaults",
@@ -248,9 +256,19 @@
"service-sdksandbox.stubs.system_server",
],
- vintf_fragments: [
- "manifest_services.xml",
- ],
+ soong_config_variables: {
+ without_vibrator: {
+ vintf_fragments: [
+ "manifest_services.xml",
+ ],
+ conditions_default: {
+ vintf_fragments: [
+ "manifest_services.xml",
+ "manifest_services_android.frameworks.vibrator.xml",
+ ],
+ },
+ },
+ },
required: [
"libukey2_jni_shared",
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 00183ac..67985ef 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -76,6 +76,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.os.WakeLockStats;
import android.os.WorkSource;
@@ -158,6 +159,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1107,6 +1109,13 @@
FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET,
null, // use default PullAtomMetadata values
DIRECT_EXECUTOR, pullAtomCallback);
+ if (Flags.addBatteryUsageStatsSliceAtom()) {
+ statsManager.setPullAtomCallback(
+ FrameworkStatsLog.BATTERY_USAGE_STATS_PER_UID,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ pullAtomCallback);
+ }
}
/** StatsPullAtomCallback for pulling BatteryUsageStats data. */
@@ -1115,7 +1124,7 @@
public int onPullAtom(int atomTag, List<StatsEvent> data) {
final BatteryUsageStats bus;
switch (atomTag) {
- case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET:
+ case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET: {
@SuppressLint("MissingPermission")
final double minConsumedPowerThreshold =
DeviceConfig.getFloat(DEVICE_CONFIG_NAMESPACE,
@@ -1130,6 +1139,7 @@
.build();
bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
break;
+ }
case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL:
final BatteryUsageStatsQuery queryPowerProfile =
new BatteryUsageStatsQuery.Builder()
@@ -1141,7 +1151,7 @@
.build();
bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
break;
- case FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET:
+ case FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET: {
final long sessionStart =
getLastBatteryUsageStatsBeforeResetAtomPullTimestamp();
final long sessionEnd;
@@ -1158,6 +1168,31 @@
bus = getBatteryUsageStats(List.of(queryBeforeReset)).get(0);
setLastBatteryUsageStatsBeforeResetAtomPullTimestamp(sessionEnd);
break;
+ }
+ case FrameworkStatsLog.BATTERY_USAGE_STATS_PER_UID: {
+ if (!Flags.addBatteryUsageStatsSliceAtom()) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ @SuppressLint("MissingPermission")
+ final double minConsumedPowerThreshold =
+ DeviceConfig.getFloat(
+ DEVICE_CONFIG_NAMESPACE,
+ MIN_CONSUMED_POWER_THRESHOLD_KEY,
+ 0);
+ final long sessionStart = 0;
+ final long sessionEnd = System.currentTimeMillis();
+ final BatteryUsageStatsQuery query =
+ new BatteryUsageStatsQuery.Builder()
+ .setMaxStatsAgeMs(0)
+ .includeProcessStateData()
+ .includeVirtualUids()
+ .aggregateSnapshots(sessionStart, sessionEnd)
+ .setMinConsumedPowerThreshold(minConsumedPowerThreshold)
+ .build();
+ bus = getBatteryUsageStats(List.of(query)).get(0);
+ return StatsPerUidLogger.logStats(bus, data);
+ }
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -1169,6 +1204,262 @@
}
}
+ private static class StatsPerUidLogger {
+
+ private static final int STATSD_METRIC_MAX_DIMENSIONS_COUNT = 3000;
+
+ private static final int[] UID_PROCESS_STATES = {
+ BatteryConsumer.PROCESS_STATE_UNSPECIFIED,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE,
+ BatteryConsumer.PROCESS_STATE_CACHED
+ };
+
+ public record SessionInfo(
+ long startTs,
+ long endTs,
+ long duration,
+ int dischargePercentage,
+ long dischargeDuration) {}
+ ;
+
+ static int logStats(BatteryUsageStats bus, List<StatsEvent> data) {
+ final SessionInfo sessionInfo =
+ new SessionInfo(
+ bus.getStatsStartTimestamp(),
+ bus.getStatsEndTimestamp(),
+ bus.getStatsDuration(),
+ bus.getDischargePercentage(),
+ bus.getDischargeDurationMs());
+
+ if (DBG) {
+ Slog.d(TAG, "BatteryUsageStats dump = " + bus);
+ }
+ final BatteryConsumer deviceConsumer =
+ bus.getAggregateBatteryConsumer(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+
+ final float totalDeviceConsumedPowerMah = (float) deviceConsumer.getConsumedPower();
+
+ for (@BatteryConsumer.PowerComponent int componentId = 0;
+ componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+ componentId++) {
+
+ for (@BatteryConsumer.ProcessState int processState : UID_PROCESS_STATES) {
+
+ if (!addStatsForPredefinedComponent(
+ data,
+ sessionInfo,
+ Process.INVALID_UID,
+ processState,
+ totalDeviceConsumedPowerMah,
+ deviceConsumer,
+ componentId)) {
+ return StatsManager.PULL_SUCCESS;
+ }
+ }
+ }
+
+ final int customPowerComponentCount = deviceConsumer.getCustomPowerComponentCount();
+ for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+ componentId
+ < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ + customPowerComponentCount;
+ componentId++) {
+
+ if (!addStatsForCustomComponent(
+ data,
+ sessionInfo,
+ Process.INVALID_UID,
+ BatteryConsumer.PROCESS_STATE_UNSPECIFIED,
+ 0,
+ totalDeviceConsumedPowerMah,
+ deviceConsumer,
+ componentId)) {
+ return StatsManager.PULL_SUCCESS;
+ }
+ }
+
+ final List<UidBatteryConsumer> uidConsumers = bus.getUidBatteryConsumers();
+ uidConsumers.sort(
+ Comparator.<BatteryConsumer>comparingDouble(BatteryConsumer::getConsumedPower)
+ .reversed());
+
+ // Log single atom for BatteryUsageStats per uid/process_state/component/etc.
+ for (UidBatteryConsumer uidConsumer : uidConsumers) {
+ final int uid = uidConsumer.getUid();
+ final float totalConsumedPowerMah = (float) uidConsumer.getConsumedPower();
+
+ for (@BatteryConsumer.PowerComponent int componentId = 0;
+ componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+ componentId++) {
+
+ for (@BatteryConsumer.ProcessState int processState : UID_PROCESS_STATES) {
+
+ if (!addStatsForPredefinedComponent(
+ data,
+ sessionInfo,
+ uid,
+ processState,
+ totalConsumedPowerMah,
+ uidConsumer,
+ componentId)) {
+ return StatsManager.PULL_SUCCESS;
+ }
+ }
+ }
+
+ // looping over custom components
+ for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+ componentId
+ < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ + customPowerComponentCount;
+ componentId++) {
+ for (@BatteryConsumer.ProcessState int processState : UID_PROCESS_STATES) {
+ final long timeInStateMillis =
+ uidConsumer.getTimeInProcessStateMs(processState);
+ if (timeInStateMillis <= 0) {
+ continue;
+ }
+
+ if (!addStatsForCustomComponent(
+ data,
+ sessionInfo,
+ uid,
+ processState,
+ timeInStateMillis,
+ totalConsumedPowerMah,
+ uidConsumer,
+ componentId)) {
+ return StatsManager.PULL_SUCCESS;
+ }
+ }
+ }
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ private static boolean addStatsForPredefinedComponent(
+ List<StatsEvent> data,
+ SessionInfo sessionInfo,
+ int uid,
+ @BatteryConsumer.ProcessState int processState,
+ float totalConsumedPowerMah,
+ BatteryConsumer batteryConsumer,
+ @BatteryConsumer.PowerComponent int componentId) {
+ final BatteryConsumer.Key key = batteryConsumer.getKey(componentId, processState);
+ if (key == null) {
+ return true;
+ }
+
+ final String powerComponentName = BatteryConsumer.powerComponentIdToString(componentId);
+ final float powerMah = (float) batteryConsumer.getConsumedPower(key);
+ final long powerComponentDurationMillis = batteryConsumer.getUsageDurationMillis(key);
+
+ if (powerMah == 0 && powerComponentDurationMillis == 0) {
+ return true;
+ }
+
+ long timeInState = 0;
+ if (batteryConsumer instanceof UidBatteryConsumer) {
+ timeInState =
+ ((UidBatteryConsumer) batteryConsumer)
+ .getTimeInProcessStateMs(processState);
+ }
+
+ return addStatsAtom(
+ data,
+ sessionInfo,
+ uid,
+ processState,
+ timeInState,
+ powerComponentName,
+ totalConsumedPowerMah,
+ powerMah,
+ powerComponentDurationMillis);
+ }
+
+ private static boolean addStatsForCustomComponent(
+ List<StatsEvent> data,
+ SessionInfo sessionInfo,
+ int uid,
+ @BatteryConsumer.ProcessState int processState,
+ long timeInStateMillis,
+ float totalConsumedPowerMah,
+ BatteryConsumer batteryConsumer,
+ int componentId) {
+
+ if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+ throw new IllegalArgumentException("Invalid custom component id: " + componentId);
+ }
+
+ final float powerMah =
+ (float) batteryConsumer.getConsumedPowerForCustomComponent(componentId);
+ if (powerMah == 0) {
+ return true;
+ }
+
+ final String powerComponentName =
+ batteryConsumer.getCustomPowerComponentName(componentId);
+
+ final long powerComponentDurationMillis =
+ batteryConsumer.getUsageDurationForCustomComponentMillis(componentId);
+
+ return addStatsAtom(
+ data,
+ sessionInfo,
+ uid,
+ processState,
+ timeInStateMillis,
+ powerComponentName,
+ totalConsumedPowerMah,
+ powerMah,
+ powerComponentDurationMillis);
+ }
+
+ /**
+ * Returns true on success and false if reached max atoms capacity and no more atoms should
+ * be added
+ */
+ private static boolean addStatsAtom(
+ List<StatsEvent> data,
+ SessionInfo sessionInfo,
+ int uid,
+ int processState,
+ long timeInStateMillis,
+ String powerComponentName,
+ float totalConsumedPowerMah,
+ float powerComponentMah,
+ long powerComponentDurationMillis) {
+ data.add(
+ FrameworkStatsLog.buildStatsEvent(
+ FrameworkStatsLog.BATTERY_USAGE_STATS_PER_UID,
+ sessionInfo.startTs(),
+ sessionInfo.endTs(),
+ sessionInfo.duration(),
+ sessionInfo.dischargePercentage(),
+ sessionInfo.dischargeDuration(),
+ uid,
+ processState,
+ timeInStateMillis,
+ powerComponentName,
+ totalConsumedPowerMah,
+ powerComponentMah,
+ powerComponentDurationMillis));
+
+ // Early termination due to statsd dimensions guardrail
+ if (data.size() == STATSD_METRIC_MAX_DIMENSIONS_COUNT) {
+ Slog.w(
+ TAG,
+ "BATTERY_USAGE_STATS_PER_UID is complete reaching"
+ + " dimension guardrail");
+ return false;
+ }
+ return true;
+ }
+ }
+
@Override
@RequiresNoPermission
public boolean isCharging() {
@@ -2824,9 +3115,11 @@
pw.println(" --checkin: generate output for a checkin report; will write (and clear) the");
pw.println(" last old completed stats when they had been reset.");
pw.println(" -c: write the current stats in checkin format.");
- pw.println(" --proto: write the current aggregate stats (without history) in proto format.");
+ pw.println(
+ " --proto: write the current aggregate stats (without history) in proto format.");
pw.println(" --history: show only history data.");
- pw.println(" --history-start <num>: show only history data starting at given time offset.");
+ pw.println(
+ " --history-start <num>: show only history data starting at given time offset.");
pw.println(" --history-create-events <num>: create <num> of battery history events.");
pw.println(" --charged: only output data since last charged.");
pw.println(" --daily: only output full daily data.");
@@ -2850,12 +3143,15 @@
pw.println(" -h: print this help text.");
pw.println("Battery stats (batterystats) commands:");
pw.println(" enable|disable <option>");
- pw.println(" Enable or disable a running option. Option state is not saved across boots.");
+ pw.println(
+ " Enable or disable a running option. Option state is not saved across boots.");
pw.println(" Options are:");
pw.println(" full-history: include additional detailed events in battery history:");
pw.println(" wake_lock_in, alarms and proc events");
pw.println(" no-auto-reset: don't automatically reset stats when unplugged");
- pw.println(" pretend-screen-off: pretend the screen is off, even if screen state changes");
+ pw.println(
+ " pretend-screen-off: pretend the screen is off, even if screen state"
+ + " changes");
}
private void dumpSettings(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java b/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
index 058c1c8..e1b1416 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
@@ -16,10 +16,12 @@
package com.android.server.location.contexthub;
+import android.chre.flags.Flags;
import android.hardware.location.NanoAppMessage;
import android.util.Log;
import java.util.Collection;
+import java.util.Optional;
/**
* A class to log events and useful metrics within the Context Hub service.
@@ -149,10 +151,20 @@
*/
public final NanoAppMessage message;
+ /**
+ * the error code for the message
+ */
+ public Optional<Byte> errorCode;
+
public NanoappMessageEvent(long mTimeStampInMs, int mContextHubId,
NanoAppMessage mMessage, boolean mSuccess) {
super(mTimeStampInMs, mContextHubId, 0, mSuccess);
message = mMessage;
+ errorCode = Optional.empty();
+ }
+
+ public void setErrorCode(byte errorCode) {
+ this.errorCode = Optional.of(errorCode);
}
@Override
@@ -165,6 +177,8 @@
sb.append(message.toString());
sb.append(", success = ");
sb.append(success ? "true" : "false");
+ sb.append(", errorCode = ");
+ sb.append(errorCode.isPresent() ? errorCode.get() : "null");
sb.append(']');
return sb.toString();
}
@@ -312,6 +326,28 @@
}
/**
+ * Logs the status of a reliable message
+ *
+ * @param messageSequenceNumber the message sequence number
+ * @param errorCode the error code
+ */
+ public synchronized void logReliableMessageToNanoappStatus(
+ int messageSequenceNumber, byte errorCode) {
+ if (!Flags.reliableMessage()) {
+ return;
+ }
+
+ for (NanoappMessageEvent event : mMessageToNanoappQueue) {
+ if (event.message.isReliable()
+ && event.message.getMessageSequenceNumber()
+ == messageSequenceNumber) {
+ event.setErrorCode(errorCode);
+ break;
+ }
+ }
+ }
+
+ /**
* Logs a context hub restart event
*
* @param contextHubId the ID of the context hub
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index a0aad52..ed451ff 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1087,6 +1087,8 @@
* @param messageDeliveryStatus The message delivery status to deliver.
*/
private void handleMessageDeliveryStatusCallback(MessageDeliveryStatus messageDeliveryStatus) {
+ ContextHubEventLogger.getInstance().logReliableMessageToNanoappStatus(
+ messageDeliveryStatus.messageSequenceNumber, messageDeliveryStatus.errorCode);
mTransactionManager.onMessageDeliveryResponse(messageDeliveryStatus.messageSequenceNumber,
messageDeliveryStatus.errorCode == ErrorCode.OK);
}
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index c5e2bb8..8410cff 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -34,6 +34,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -370,8 +371,13 @@
}
private void enforceUid(int callingUid) {
- if (callingUid != mAllowedUid && callingUid != UserHandle.AID_ROOT) {
- throw new SecurityException("uid " + callingUid + " not allowed to access PDB");
+ enforceUid(callingUid, /* allowShell= */ false);
+ }
+
+ private void enforceUid(int callingUid, boolean allowShell) {
+ if (callingUid != mAllowedUid && callingUid != UserHandle.AID_ROOT
+ && (callingUid != Process.SHELL_UID || !allowShell)) {
+ throw new SecurityException("Uid " + callingUid + " not allowed to access PDB");
}
}
@@ -864,7 +870,8 @@
private final IBinder mService = new IPersistentDataBlockService.Stub() {
private int printFrpStatus(PrintWriter pw, boolean printSecrets) {
- enforceUid(Binder.getCallingUid());
+ // Only allow SHELL_UID to print the status if printing the secrets is disabled
+ enforceUid(Binder.getCallingUid(), /* allowShell= */ !printSecrets);
pw.println("FRP state");
pw.println("=========");
@@ -872,8 +879,14 @@
pw.println("FRP state: " + mFrpActive);
printFrpDataFilesContents(pw, printSecrets);
printFrpSecret(pw, printSecrets);
- pw.println("OEM unlock state: " + getOemUnlockEnabled());
- pw.println("Bootloader lock state: " + getFlashLockState());
+
+ // Do not print OEM unlock state and flash lock state if the caller is a non-root
+ // shell - it likely won't have permissions anyways.
+ if (Binder.getCallingUid() != Process.SHELL_UID) {
+ pw.println("OEM unlock state: " + getOemUnlockEnabled());
+ pw.println("Bootloader lock state: " + getFlashLockState());
+ }
+
pw.println("Verified boot state: " + getVerifiedBootState());
pw.println("Has FRP credential handle: " + hasFrpCredentialHandle());
pw.println("FRP challenge block size: " + getDataBlockSize());
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index 6a5a7ac..d34498a 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -47,3 +47,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "add_battery_usage_stats_slice_atom"
+ namespace: "backstage_power"
+ description: "Adds battery_usage_stats_slice atom"
+ bug: "324602949"
+}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 228eb76..390e34c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -98,6 +98,7 @@
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
+import static com.android.input.flags.Flags.removeInputChannelFromWindowstate;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -633,6 +634,9 @@
// Input channel and input window handle used by the input dispatcher.
final InputWindowHandleWrapper mInputWindowHandle;
+ /**
+ * Only populated if flag REMOVE_INPUT_CHANNEL_FROM_WINDOWSTATE is disabled.
+ */
InputChannel mInputChannel;
/**
@@ -1877,6 +1881,10 @@
* Input Manager uses when discarding windows from input consideration.
*/
boolean isPotentialDragTarget(boolean targetInterceptsGlobalDrag) {
+ if (removeInputChannelFromWindowstate()) {
+ return (targetInterceptsGlobalDrag || isVisibleNow()) && !mRemoved
+ && mInputChannelToken != null && mInputWindowHandle != null;
+ }
return (targetInterceptsGlobalDrag || isVisibleNow()) && !mRemoved
&& mInputChannel != null && mInputWindowHandle != null;
}
@@ -2626,6 +2634,19 @@
}
void openInputChannel(@NonNull InputChannel outInputChannel) {
+ if (mInputChannelToken != null) {
+ throw new IllegalStateException("Window already has an input channel token.");
+ }
+ if (removeInputChannelFromWindowstate()) {
+ String name = getName();
+ InputChannel channel = mWmService.mInputManager.createInputChannel(name);
+ mInputChannelToken = channel.getToken();
+ mInputWindowHandle.setToken(mInputChannelToken);
+ mWmService.mInputToWindowMap.put(mInputChannelToken, this);
+ channel.copyTo(outInputChannel);
+ channel.dispose();
+ return;
+ }
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
@@ -2657,9 +2678,11 @@
mInputChannelToken = null;
}
- if (mInputChannel != null) {
- mInputChannel.dispose();
- mInputChannel = null;
+ if (!removeInputChannelFromWindowstate()) {
+ if (mInputChannel != null) {
+ mInputChannel.dispose();
+ mInputChannel = null;
+ }
}
mInputWindowHandle.setToken(null);
}
diff --git a/services/manifest_services.xml b/services/manifest_services.xml
index 8ff1a7d..114fe32 100644
--- a/services/manifest_services.xml
+++ b/services/manifest_services.xml
@@ -4,9 +4,4 @@
<version>2</version>
<fqname>IAltitudeService/default</fqname>
</hal>
- <hal format="aidl">
- <name>android.frameworks.vibrator</name>
- <version>1</version>
- <fqname>IVibratorControlService/default</fqname>
- </hal>
</manifest>
diff --git a/services/manifest_services_android.frameworks.vibrator.xml b/services/manifest_services_android.frameworks.vibrator.xml
new file mode 100644
index 0000000..c287643
--- /dev/null
+++ b/services/manifest_services_android.frameworks.vibrator.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="framework">
+ <hal format="aidl">
+ <name>android.frameworks.vibrator</name>
+ <version>1</version>
+ <fqname>IVibratorControlService/default</fqname>
+ </hal>
+</manifest>
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 3d40f64..927146d 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -21,6 +21,7 @@
":services.net-sources",
],
static_libs: [
+ "modules-utils-build_system",
"netd-client",
"networkstack-client",
"net-utils-services-common",
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java
index 8863d27..41cb6fd 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java
@@ -18,11 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import android.chre.flags.Flags;
import android.hardware.location.NanoAppMessage;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,6 +37,8 @@
public class ContextHubEventLoggerTest {
private static final ContextHubEventLogger sInstance = ContextHubEventLogger.getInstance();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Test
public void testLogNanoappLoad() {
ContextHubEventLogger.NanoappLoadEvent[] events =
@@ -46,10 +52,10 @@
sInstance.clear();
sInstance.logNanoappLoad(-1, 42, -34, 100, false);
sInstance.logNanoappLoad(0, 123, 321, 001, true);
- String sInstanceDump = sInstance.toString();
+ String instanceDump = sInstance.toString();
for (String eventString: eventStrings) {
assertThat(eventString.length() > 0).isTrue();
- assertThat(sInstanceDump.contains(eventString)).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
}
}
@@ -66,10 +72,10 @@
sInstance.clear();
sInstance.logNanoappUnload(-1, 47, false);
sInstance.logNanoappUnload(1, 0xFFFFFFFF, true);
- String sInstanceDump = sInstance.toString();
+ String instanceDump = sInstance.toString();
for (String eventString: eventStrings) {
assertThat(eventString.length() > 0).isTrue();
- assertThat(sInstanceDump.contains(eventString)).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
}
}
@@ -90,10 +96,10 @@
sInstance.clear();
sInstance.logMessageFromNanoapp(-123, message1, false);
sInstance.logMessageFromNanoapp(321, message2, true);
- String sInstanceDump = sInstance.toString();
+ String instanceDump = sInstance.toString();
for (String eventString: eventStrings) {
assertThat(eventString.length() > 0).isTrue();
- assertThat(sInstanceDump.contains(eventString)).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
}
}
@@ -114,10 +120,54 @@
sInstance.clear();
sInstance.logMessageToNanoapp(888, message1, true);
sInstance.logMessageToNanoapp(999, message2, false);
- String sInstanceDump = sInstance.toString();
+ String instanceDump = sInstance.toString();
for (String eventString: eventStrings) {
assertThat(eventString.length() > 0).isTrue();
- assertThat(sInstanceDump.contains(eventString)).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
+ }
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_RELIABLE_MESSAGE,
+ Flags.FLAG_RELIABLE_MESSAGE_IMPLEMENTATION})
+ public void testLogReliableMessageToNanoappStatus() {
+ NanoAppMessage message1 = NanoAppMessage.createMessageToNanoApp(1, 0,
+ new byte[] {0x00, 0x11, 0x22, 0x33});
+ NanoAppMessage message2 = NanoAppMessage.createMessageToNanoApp(0, 1,
+ new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
+ message1.setIsReliable(true);
+ message2.setIsReliable(true);
+ message1.setMessageSequenceNumber(0);
+ message2.setMessageSequenceNumber(1);
+
+ ContextHubEventLogger.NanoappMessageEvent[] events =
+ new ContextHubEventLogger.NanoappMessageEvent[] {
+ new ContextHubEventLogger.NanoappMessageEvent(23, 888, message1, true),
+ new ContextHubEventLogger.NanoappMessageEvent(34, 999, message2, false)
+ };
+ String[] eventStrings = generateEventDumpStrings(events);
+
+ // log events and test sInstance.toString() contains event details
+ sInstance.clear();
+ sInstance.logMessageToNanoapp(888, message1, true);
+ sInstance.logMessageToNanoapp(999, message2, false);
+ String instanceDump = sInstance.toString();
+ for (String eventString: eventStrings) {
+ assertThat(eventString.length() > 0).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
+ }
+
+ // set the error codes for the events and verify
+ sInstance.logReliableMessageToNanoappStatus(0, (byte) 0x02);
+ sInstance.logReliableMessageToNanoappStatus(1, (byte) 0x03);
+ events[0].setErrorCode((byte) 0x02);
+ events[1].setErrorCode((byte) 0x03);
+ eventStrings = generateEventDumpStrings(events);
+
+ instanceDump = sInstance.toString();
+ for (String eventString: eventStrings) {
+ assertThat(eventString.length() > 0).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
}
}
@@ -134,10 +184,10 @@
sInstance.clear();
sInstance.logContextHubRestart(1);
sInstance.logContextHubRestart(2);
- String sInstanceDump = sInstance.toString();
+ String instanceDump = sInstance.toString();
for (String eventString: eventStrings) {
assertThat(eventString.length() > 0).isTrue();
- assertThat(sInstanceDump.contains(eventString)).isTrue();
+ assertThat(instanceDump.contains(eventString)).isTrue();
}
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index cbf2c2f..382b088 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -198,6 +198,7 @@
android::DiagMessage(el->line_number)
<< "Cannot find symbol for android:configChanges with min sdk: "
<< context->GetMinSdkVersion());
+ return false;
}
std::stringstream new_value;