summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/StatusBarManager.java4
-rw-r--r--core/java/com/android/internal/statusbar/DisableStates.aidl19
-rw-r--r--core/java/com/android/internal/statusbar/DisableStates.java95
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl2
-rw-r--r--core/tests/coretests/src/com/android/internal/statusbar/DisableStatesTest.java64
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java43
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java91
-rw-r--r--services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java74
9 files changed, 409 insertions, 15 deletions
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 01868cc601fe..927d46999284 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -58,8 +58,10 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.IUndoMediaTransferCallback;
import com.android.internal.statusbar.NotificationVisibility;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -119,6 +121,7 @@ public class StatusBarManager {
| DISABLE_SEARCH | DISABLE_ONGOING_CALL_CHIP;
/** @hide */
+ @Target(ElementType.TYPE_USE)
@IntDef(flag = true, prefix = {"DISABLE_"}, value = {
DISABLE_NONE,
DISABLE_EXPAND,
@@ -161,6 +164,7 @@ public class StatusBarManager {
| DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS;
/** @hide */
+ @Target(ElementType.TYPE_USE)
@IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
DISABLE2_NONE,
DISABLE2_MASK,
diff --git a/core/java/com/android/internal/statusbar/DisableStates.aidl b/core/java/com/android/internal/statusbar/DisableStates.aidl
new file mode 100644
index 000000000000..fd9882f0f7c2
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/DisableStates.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2025 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.internal.statusbar;
+
+parcelable DisableStates;
diff --git a/core/java/com/android/internal/statusbar/DisableStates.java b/core/java/com/android/internal/statusbar/DisableStates.java
new file mode 100644
index 000000000000..ca2fd6c03558
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/DisableStates.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2025 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.internal.statusbar;
+
+import android.app.StatusBarManager.Disable2Flags;
+import android.app.StatusBarManager.DisableFlags;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Holds display ids with their disable flags.
+ */
+public class DisableStates implements Parcelable {
+
+ /**
+ * A map of display IDs (integers) with corresponding disable flags.
+ */
+ public Map<Integer, Pair<@DisableFlags Integer, @Disable2Flags Integer>> displaysWithStates;
+
+ /**
+ * Whether the disable state change should be animated.
+ */
+ public boolean animate;
+
+ public DisableStates(
+ Map<Integer, Pair<@DisableFlags Integer, @Disable2Flags Integer>> displaysWithStates,
+ boolean animate) {
+ this.displaysWithStates = displaysWithStates;
+ this.animate = animate;
+ }
+
+ public DisableStates(
+ Map<Integer, Pair<@DisableFlags Integer, @Disable2Flags Integer>> displaysWithStates) {
+ this(displaysWithStates, true);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(displaysWithStates.size()); // Write the size of the map
+ for (Map.Entry<Integer, Pair<Integer, Integer>> entry : displaysWithStates.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeInt(entry.getValue().first);
+ dest.writeInt(entry.getValue().second);
+ }
+ dest.writeBoolean(animate);
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<DisableStates> CREATOR = new Parcelable.Creator<>() {
+ @Override
+ public DisableStates createFromParcel(Parcel source) {
+ int size = source.readInt(); // Read the size of the map
+ Map<Integer, Pair<Integer, Integer>> displaysWithStates = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ int key = source.readInt();
+ int first = source.readInt();
+ int second = source.readInt();
+ displaysWithStates.put(key, new Pair<>(first, second));
+ }
+ final boolean animate = source.readBoolean();
+ return new DisableStates(displaysWithStates, animate);
+ }
+
+ @Override
+ public DisableStates[] newArray(int size) {
+ return new DisableStates[size];
+ }
+ };
+}
+
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5a180d7358dd..ce9b036f2fd7 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -32,6 +32,7 @@ import android.os.UserHandle;
import android.view.KeyEvent;
import android.service.notification.StatusBarNotification;
+import com.android.internal.statusbar.DisableStates;
import com.android.internal.statusbar.IAddTileResultCallback;
import com.android.internal.statusbar.IUndoMediaTransferCallback;
import com.android.internal.statusbar.LetterboxDetails;
@@ -44,6 +45,7 @@ oneway interface IStatusBar
void setIcon(String slot, in StatusBarIcon icon);
void removeIcon(String slot);
void disable(int displayId, int state1, int state2);
+ void disableForAllDisplays(in DisableStates disableStates);
void animateExpandNotificationsPanel();
void animateExpandSettingsPanel(String subPanel);
void animateCollapsePanels();
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/DisableStatesTest.java b/core/tests/coretests/src/com/android/internal/statusbar/DisableStatesTest.java
new file mode 100644
index 000000000000..5b82696b81c3
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/statusbar/DisableStatesTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025 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.internal.statusbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Parcel;
+import android.util.Pair;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DisableStatesTest {
+
+ @Test
+ public void testParcelable() {
+ Map<Integer, Pair<Integer, Integer>> displaysWithStates = new HashMap<>();
+ displaysWithStates.put(1, new Pair<>(10, 20));
+ displaysWithStates.put(2, new Pair<>(30, 40));
+ boolean animate = true;
+ DisableStates original = new DisableStates(displaysWithStates, animate);
+
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ DisableStates restored = DisableStates.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(restored);
+ assertEquals(original.displaysWithStates.size(), restored.displaysWithStates.size());
+ for (Map.Entry<Integer, Pair<Integer, Integer>> entry :
+ original.displaysWithStates.entrySet()) {
+ int displayId = entry.getKey();
+ Pair<Integer, Integer> originalDisplayStates = entry.getValue();
+ Pair<Integer, Integer> restoredDisplayStates = restored.displaysWithStates.get(
+ displayId);
+ assertEquals(originalDisplayStates.first, restoredDisplayStates.first);
+ assertEquals(originalDisplayStates.second, restoredDisplayStates.second);
+ }
+ assertEquals(original.animate, restored.animate);
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 70df82d95008..c26f18f5ab6d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -36,7 +36,9 @@ import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
import android.os.Bundle;
+import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
+import android.util.Pair;
import android.view.KeyEvent;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
@@ -46,6 +48,7 @@ import android.view.WindowInsetsController.Behavior;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.statusbar.DisableStates;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
@@ -58,11 +61,14 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.HashMap;
+import java.util.Map;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class CommandQueueTest extends SysuiTestCase {
- private static final LetterboxDetails[] TEST_LETTERBOX_DETAILS = new LetterboxDetails[] {
+ private static final LetterboxDetails[] TEST_LETTERBOX_DETAILS = new LetterboxDetails[]{
new LetterboxDetails(
/* letterboxInnerBounds= */ new Rect(100, 0, 200, 500),
/* letterboxFullBounds= */ new Rect(0, 0, 500, 100),
@@ -119,6 +125,27 @@ public class CommandQueueTest extends SysuiTestCase {
}
@Test
+ public void testDisableForAllDisplays() throws RemoteException {
+ int state1 = 14;
+ int state2 = 42;
+ int secondaryDisplayState1 = 16;
+ int secondaryDisplayState2 = 44;
+ Map<Integer, Pair<Integer, Integer>> displaysWithStates = new HashMap<>();
+ displaysWithStates.put(DEFAULT_DISPLAY, new Pair<>(state1, state2)); // Example values
+ displaysWithStates.put(SECONDARY_DISPLAY,
+ new Pair<>(secondaryDisplayState1, secondaryDisplayState2)); // Example values
+ DisableStates expectedDisableStates = new DisableStates(displaysWithStates, true);
+
+ mCommandQueue.disableForAllDisplays(expectedDisableStates);
+ waitForIdleSync();
+
+ verify(mCallbacks).disable(eq(DEFAULT_DISPLAY), eq(state1), eq(state2), eq(true));
+ verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(secondaryDisplayState1),
+ eq(secondaryDisplayState2), eq(true));
+ }
+
+
+ @Test
public void testExpandNotifications() {
mCommandQueue.animateExpandNotificationsPanel();
waitForIdleSync();
@@ -475,7 +502,8 @@ public class CommandQueueTest extends SysuiTestCase {
final long requestId = 10;
mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
- credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId);
+ credentialAllowed, requireConfirmation, userId, operationId, packageName,
+ requestId);
waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index e44701dba87c..4daf61a895c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -64,6 +64,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.annotations.KeepForWeakReference;
import com.android.internal.os.SomeArgs;
+import com.android.internal.statusbar.DisableStates;
import com.android.internal.statusbar.IAddTileResultCallback;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IUndoMediaTransferCallback;
@@ -85,6 +86,7 @@ import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Map;
/**
* This class takes the functions from IStatusBar that come in on
@@ -184,6 +186,8 @@ public class CommandQueue extends IStatusBar.Stub implements
private static final int MSG_TOGGLE_QUICK_SETTINGS_PANEL = 82 << MSG_SHIFT;
private static final int MSG_WALLET_ACTION_LAUNCH_GESTURE = 83 << MSG_SHIFT;
private static final int MSG_DISPLAY_REMOVE_SYSTEM_DECORATIONS = 85 << MSG_SHIFT;
+ private static final int MSG_DISABLE_ALL = 86 << MSG_SHIFT;
+
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
@@ -654,7 +658,8 @@ public class CommandQueue extends IStatusBar.Stub implements
/**
* Called to notify that disable flags are updated.
- * @see Callbacks#disable(int, int, int, boolean).
+ * @see Callbacks#disable(int, int, int, boolean)
+ * @see Callbacks#disableForAllDisplays(DisableStates)
*/
public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
boolean animate) {
@@ -682,6 +687,27 @@ public class CommandQueue extends IStatusBar.Stub implements
disable(displayId, state1, state2, true);
}
+ @Override
+ public void disableForAllDisplays(DisableStates disableStates) throws RemoteException {
+ synchronized (mLock) {
+ for (Map.Entry<Integer, Pair<Integer, Integer>> displaysWithStates :
+ disableStates.displaysWithStates.entrySet()) {
+ int displayId = displaysWithStates.getKey();
+ Pair<Integer, Integer> states = displaysWithStates.getValue();
+ setDisabled(displayId, states.first, states.second);
+ }
+ mHandler.removeMessages(MSG_DISABLE_ALL);
+ Message msg = mHandler.obtainMessage(MSG_DISABLE_ALL, disableStates);
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ // If its the right looper execute immediately so hides can be handled quickly.
+ mHandler.handleMessage(msg);
+ msg.recycle();
+ } else {
+ msg.sendToTarget();
+ }
+ }
+ }
+
/**
* Apply current disable flags by {@link CommandQueue#disable(int, int, int, boolean)}.
*
@@ -1552,6 +1578,21 @@ public class CommandQueue extends IStatusBar.Stub implements
args.argi4 != 0 /* animate */);
}
break;
+ case MSG_DISABLE_ALL:
+ DisableStates disableStates = (DisableStates) msg.obj;
+ boolean animate = disableStates.animate;
+ Map<Integer, Pair<Integer, Integer>> displaysWithDisableStates =
+ disableStates.displaysWithStates;
+ for (Map.Entry<Integer, Pair<Integer, Integer>> displayWithDisableStates :
+ displaysWithDisableStates.entrySet()) {
+ int displayId = displayWithDisableStates.getKey();
+ Pair<Integer, Integer> states = displayWithDisableStates.getValue();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).disable(displayId, states.first, states.second,
+ animate);
+ }
+ }
+ break;
case MSG_EXPAND_NOTIFICATIONS:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).animateExpandNotificationsPanel();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 798c794edaf5..0f6cc24f1fc9 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -87,6 +87,7 @@ import android.service.quicksettings.TileService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
+import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -102,6 +103,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.logging.InstanceId;
import com.android.internal.os.TransferPipe;
+import com.android.internal.statusbar.DisableStates;
import com.android.internal.statusbar.IAddTileResultCallback;
import com.android.internal.statusbar.ISessionListener;
import com.android.internal.statusbar.IStatusBar;
@@ -124,6 +126,7 @@ import com.android.server.policy.GlobalActionsProvider;
import com.android.server.power.ShutdownCheckPoints;
import com.android.server.power.ShutdownThread;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.systemui.shared.Flags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1344,48 +1347,76 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
return mTracingEnabled;
}
- // TODO(b/117478341): make it aware of multi-display if needed.
+ /**
+ * Disable status bar features. Pass the bitwise-or of the {@code #DISABLE_*} flags.
+ * To re-enable everything, pass {@code #DISABLE_NONE}.
+ *
+ * Warning: Only pass {@code #DISABLE_*} flags into this function, do not use
+ * {@code #DISABLE2_*} flags.
+ */
@Override
public void disable(int what, IBinder token, String pkg) {
disableForUser(what, token, pkg, mCurrentUserId);
}
- // TODO(b/117478341): make it aware of multi-display if needed.
+ /**
+ * Disable status bar features for a given user. Pass the bitwise-or of the
+ * {@code #DISABLE_*} flags. To re-enable everything, pass {@code #DISABLE_NONE}.
+ *
+ * Warning: Only pass {@code #DISABLE_*} flags into this function, do not use
+ * {@code #DISABLE2_*} flags.
+ */
@Override
public void disableForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
enforceValidCallingUser();
synchronized (mLock) {
- disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1);
+ if (Flags.statusBarConnectedDisplays()) {
+ IntArray displayIds = new IntArray();
+ for (int i = 0; i < mDisplayUiState.size(); i++) {
+ displayIds.add(mDisplayUiState.keyAt(i));
+ }
+ disableAllDisplaysLocked(displayIds, userId, what, token, pkg, /* whichFlag= */ 1);
+ } else {
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, /* whichFlag= */ 1);
+ }
}
}
- // TODO(b/117478341): make it aware of multi-display if needed.
/**
- * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
- * To re-enable everything, pass {@link #DISABLE2_NONE}.
+ * Disable additional status bar features. Pass the bitwise-or of the {@code #DISABLE2_*} flags.
+ * To re-enable everything, pass {@code #DISABLE2_NONE}.
*
- * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
+ * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use
+ * {@code #DISABLE_*} flags.
*/
@Override
public void disable2(int what, IBinder token, String pkg) {
disable2ForUser(what, token, pkg, mCurrentUserId);
}
- // TODO(b/117478341): make it aware of multi-display if needed.
/**
- * Disable additional status bar features for a given user. Pass the bitwise-or of the
- * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
+ * Disable additional status bar features for a given user. Pass the bitwise-or
+ * of the {@code #DISABLE2_*} flags. To re-enable everything, pass {@code #DISABLE2_NONE}.
*
- * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
+ * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use
+ * {@code #DISABLE_*} flags.
*/
@Override
public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
synchronized (mLock) {
- disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2);
+ if (Flags.statusBarConnectedDisplays()) {
+ IntArray displayIds = new IntArray();
+ for (int i = 0; i < mDisplayUiState.size(); i++) {
+ displayIds.add(mDisplayUiState.keyAt(i));
+ }
+ disableAllDisplaysLocked(displayIds, userId, what, token, pkg, /* whichFlag= */ 2);
+ } else {
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, /* whichFlag= */ 2);
+ }
}
}
@@ -1414,6 +1445,42 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
}
+ // This method batches disable state across all displays into a single remote call
+ // (IStatusBar#disableForAllDisplays) for efficiency and calls
+ // NotificationDelegate#onSetDisabled only if any display's disable state changes.
+ private void disableAllDisplaysLocked(IntArray displayIds, int userId, int what, IBinder token,
+ String pkg, int whichFlag) {
+ // It's important that the the callback and the call to mBar get done
+ // in the same order when multiple threads are calling this function
+ // so they are paired correctly. The messages on the handler will be
+ // handled in the order they were enqueued, but will be outside the lock.
+ manageDisableListLocked(userId, what, token, pkg, whichFlag);
+
+ // Ensure state for the current user is applied, even if passed a non-current user.
+ final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1);
+ final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2);
+
+ IStatusBar bar = mBar;
+ Map<Integer, Pair<Integer, Integer>> displaysWithNewDisableStates = new HashMap<>();
+ for (int displayId : displayIds.toArray()) {
+ final UiState state = getUiState(displayId);
+ if (!state.disableEquals(net1, net2)) {
+ state.setDisabled(net1, net2);
+ displaysWithNewDisableStates.put(displayId, new Pair(net1, net2));
+ }
+ }
+ if (bar != null) {
+ try {
+ bar.disableForAllDisplays(new DisableStates(displaysWithNewDisableStates));
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to disable Status bar.", ex);
+ }
+ }
+ if (!displaysWithNewDisableStates.isEmpty()) {
+ mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
+ }
+ }
+
/**
* Get the currently applied disable flags, in the form of one Pair<Integer, Integer>.
*
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index 148c96850d34..6d682ccef98d 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -36,6 +36,7 @@ import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
@@ -69,16 +70,20 @@ import android.os.Binder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.service.quicksettings.TileService;
import android.testing.TestableContext;
+import android.util.Pair;
import androidx.test.InstrumentationRegistry;
+import com.android.internal.statusbar.DisableStates;
import com.android.internal.statusbar.IAddTileResultCallback;
import com.android.internal.statusbar.IStatusBar;
import com.android.server.LocalServices;
import com.android.server.policy.GlobalActionsProvider;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.systemui.shared.Flags;
import libcore.junit.util.compat.CoreCompatChangeRule;
@@ -105,6 +110,7 @@ public class StatusBarManagerServiceTest {
TEST_SERVICE);
private static final CharSequence APP_NAME = "AppName";
private static final CharSequence TILE_LABEL = "Tile label";
+ private static final int SECONDARY_DISPLAY_ID = 2;
@Rule
public final TestableContext mContext =
@@ -749,6 +755,40 @@ public class StatusBarManagerServiceTest {
}
@Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
+ public void testDisableForAllDisplays() throws Exception {
+ int user1Id = 0;
+ mockUidCheck();
+ mockCurrentUserCheck(user1Id);
+
+ mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID);
+
+ int expectedFlags = DISABLE_MASK & DISABLE_BACK;
+ String pkg = mContext.getPackageName();
+
+ // before disabling
+ assertEquals(DISABLE_NONE,
+ mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]);
+
+ // disable
+ mStatusBarManagerService.disable(expectedFlags, mMockStatusBar, pkg);
+
+ ArgumentCaptor<DisableStates> disableStatesCaptor = ArgumentCaptor.forClass(
+ DisableStates.class);
+ verify(mMockStatusBar).disableForAllDisplays(disableStatesCaptor.capture());
+ DisableStates capturedDisableStates = disableStatesCaptor.getValue();
+ assertTrue(capturedDisableStates.animate);
+ assertEquals(capturedDisableStates.displaysWithStates.size(), 2);
+ Pair<Integer, Integer> display0States = capturedDisableStates.displaysWithStates.get(0);
+ assertEquals((int) display0States.first, expectedFlags);
+ assertEquals((int) display0States.second, 0);
+ Pair<Integer, Integer> display2States = capturedDisableStates.displaysWithStates.get(
+ SECONDARY_DISPLAY_ID);
+ assertEquals((int) display2States.first, expectedFlags);
+ assertEquals((int) display2States.second, 0);
+ }
+
+ @Test
public void testSetHomeDisabled() throws Exception {
int expectedFlags = DISABLE_MASK & DISABLE_HOME;
String pkg = mContext.getPackageName();
@@ -851,6 +891,40 @@ public class StatusBarManagerServiceTest {
}
@Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
+ public void testDisable2ForAllDisplays() throws Exception {
+ int user1Id = 0;
+ mockUidCheck();
+ mockCurrentUserCheck(user1Id);
+
+ mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID);
+
+ int expectedFlags = DISABLE2_MASK & DISABLE2_NOTIFICATION_SHADE;
+ String pkg = mContext.getPackageName();
+
+ // before disabling
+ assertEquals(DISABLE_NONE,
+ mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]);
+
+ // disable
+ mStatusBarManagerService.disable2(expectedFlags, mMockStatusBar, pkg);
+
+ ArgumentCaptor<DisableStates> disableStatesCaptor = ArgumentCaptor.forClass(
+ DisableStates.class);
+ verify(mMockStatusBar).disableForAllDisplays(disableStatesCaptor.capture());
+ DisableStates capturedDisableStates = disableStatesCaptor.getValue();
+ assertTrue(capturedDisableStates.animate);
+ assertEquals(capturedDisableStates.displaysWithStates.size(), 2);
+ Pair<Integer, Integer> display0States = capturedDisableStates.displaysWithStates.get(0);
+ assertEquals((int) display0States.first, 0);
+ assertEquals((int) display0States.second, expectedFlags);
+ Pair<Integer, Integer> display2States = capturedDisableStates.displaysWithStates.get(
+ SECONDARY_DISPLAY_ID);
+ assertEquals((int) display2States.first, 0);
+ assertEquals((int) display2States.second, expectedFlags);
+ }
+
+ @Test
public void testSetQuickSettingsDisabled2() throws Exception {
int expectedFlags = DISABLE2_MASK & DISABLE2_QUICK_SETTINGS;
String pkg = mContext.getPackageName();