Merge "Update the java doc of getCallCapablePhoneAccountsAcrossProfiles" into main
diff --git a/MEMORY_OWNERS b/MEMORY_OWNERS
new file mode 100644
index 0000000..89ce5140
--- /dev/null
+++ b/MEMORY_OWNERS
@@ -0,0 +1,6 @@
+surenb@google.com
+tjmercier@google.com
+kaleshsingh@google.com
+jyescas@google.com
+carlosgalo@google.com
+jji@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 3e10261..a3775b0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -45225,13 +45225,13 @@
method @FlaggedApi("com.android.internal.telephony.flags.enforce_subscription_user_filter") @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public android.telephony.SubscriptionManager createForAllUserProfiles();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
- method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
+ method @Nullable public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
method public static int getActiveDataSubscriptionId();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount();
method public int getActiveSubscriptionInfoCountMax();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public java.util.List<android.telephony.SubscriptionInfo> getAllSubscriptionInfoList();
method @NonNull public java.util.List<android.telephony.SubscriptionInfo> getCompleteActiveSubscriptionInfoList();
method public static int getDefaultDataSubscriptionId();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d0fdf69..50764b2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -14590,7 +14590,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubscriptionIdList();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public byte[] getAllSimSpecificSettingsForBackup();
- method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
+ method @Nullable public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int);
method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int);
@@ -14844,7 +14844,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
- method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(android.Manifest.permission.DUMP) public void persistEmergencyCallDiagnosticData(@NonNull String, @NonNull android.telephony.TelephonyManager.EmergencyCallDiagnosticParams);
+ method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(android.Manifest.permission.DUMP) public void persistEmergencyCallDiagnosticData(@NonNull String, @NonNull android.telephony.TelephonyManager.EmergencyCallDiagnosticData);
method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
@@ -15023,19 +15023,19 @@
method public default void onCarrierServiceChanged(@Nullable String, int);
}
- @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") public static final class TelephonyManager.EmergencyCallDiagnosticParams {
+ @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") public static final class TelephonyManager.EmergencyCallDiagnosticData {
method public long getLogcatCollectionStartTimeMillis();
method public boolean isLogcatCollectionEnabled();
- method public boolean isTelecomDumpSysCollectionEnabled();
- method public boolean isTelephonyDumpSysCollectionEnabled();
+ method public boolean isTelecomDumpsysCollectionEnabled();
+ method public boolean isTelephonyDumpsysCollectionEnabled();
}
- public static final class TelephonyManager.EmergencyCallDiagnosticParams.Builder {
- ctor public TelephonyManager.EmergencyCallDiagnosticParams.Builder();
- method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams build();
- method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setLogcatCollectionStartTimeMillis(long);
- method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setTelecomDumpSysCollectionEnabled(boolean);
- method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setTelephonyDumpSysCollectionEnabled(boolean);
+ public static final class TelephonyManager.EmergencyCallDiagnosticData.Builder {
+ ctor public TelephonyManager.EmergencyCallDiagnosticData.Builder();
+ method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticData build();
+ method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticData.Builder setLogcatCollectionStartTimeMillis(long);
+ method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticData.Builder setTelecomDumpsysCollectionEnabled(boolean);
+ method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticData.Builder setTelephonyDumpsysCollectionEnabled(boolean);
}
public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 77add41..850f149 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1745,6 +1745,7 @@
method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptorsForInputDevice(@NonNull android.view.InputDevice);
method @NonNull public String getKeyboardLayoutTypeForLayoutDescriptor(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public java.util.Map<java.lang.Integer,java.lang.Integer> getModifierKeyRemapping();
+ method public int getMousePointerSpeed();
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
method public void removeUniqueIdAssociation(@NonNull String);
@@ -1754,6 +1755,7 @@
public class InputSettings {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setMaximumObscuringOpacityForTouch(@NonNull android.content.Context, @FloatRange(from=0, to=1) float);
+ field public static final int DEFAULT_POINTER_SPEED = 0; // 0x0
}
}
@@ -2882,6 +2884,10 @@
field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
}
+ public static final class Settings.System extends android.provider.Settings.NameValueTable {
+ field public static final String POINTER_SPEED = "pointer_speed";
+ }
+
public static final class Telephony.Sms.Intents {
field public static final String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
}
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index 074ce9b..5e8bdb5 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -5,4 +5,25 @@
namespace: "machine_learning"
description: "This flag enables the WearableSensingManager#STATUS_UNSUPPORTED_OPERATION status code API."
bug: "301427767"
+}
+
+flag {
+ name: "enable_data_request_observer_api"
+ namespace: "machine_learning"
+ description: "This flag enables the API to register a data request observer on WearableSensingManager."
+ bug: "301427767"
+}
+
+flag {
+ name: "enable_provide_wearable_connection_api"
+ namespace: "machine_learning"
+ description: "This flag enables the WearableSensingManager#provideWearableConnection API."
+ bug: "301427767"
+}
+
+flag {
+ name: "enable_hotword_wearable_sensing_api"
+ namespace: "machine_learning"
+ description: "This flag enables the APIs related to hotword in WearableSensingManager and WearableSensingService."
+ bug: "310055381"
}
\ No newline at end of file
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index 53dd3bf..fb95608895 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -10,3 +10,4 @@
per-file UserInfo* = file:/MULTIUSER_OWNERS
per-file *UserProperties* = file:/MULTIUSER_OWNERS
per-file *multiuser* = file:/MULTIUSER_OWNERS
+per-file IBackgroundInstallControlService.aidl = file:/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 7bea9ae..1f54959 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -67,6 +67,9 @@
KeyCharacterMap getKeyCharacterMap(String layoutDescriptor);
+ // Returns the mouse pointer speed.
+ int getMousePointerSpeed();
+
// Temporarily changes the pointer speed.
void tryPointerSpeed(int speed);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index db992cd..744dfae9 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -28,6 +28,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
@@ -857,6 +858,28 @@
}
/**
+ * Returns the mouse pointer speed.
+ *
+ * <p>The pointer speed is a value between {@link InputSettings#MIN_POINTER_SPEED} and
+ * {@link InputSettings#MAX_POINTER_SPEED}, the default value being
+ * {@link InputSettings#DEFAULT_POINTER_SPEED}.
+ *
+ * <p> Note that while setting the mouse pointer speed, it's possible that the input reader has
+ * only received this value and has not yet completed reconfiguring itself with this value.
+ *
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi") // TestApi without associated feature.
+ @TestApi
+ public int getMousePointerSpeed() {
+ try {
+ return mIm.getMousePointerSpeed();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Changes the mouse pointer speed temporarily, but does not save the setting.
* <p>
* Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 89fa5fb..54e34ec 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -54,8 +54,8 @@
/**
* Pointer Speed: The default pointer speed (0).
- * @hide
*/
+ @SuppressLint("UnflaggedApi") // TestApi without associated feature.
public static final int DEFAULT_POINTER_SPEED = 0;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 524b733..76fda06 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6015,8 +6015,10 @@
* +7 = fastest
* @hide
*/
+ @SuppressLint({"NoSettingsProvider", "UnflaggedApi"}) // TestApi without associated feature.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Readable
+ @TestApi
public static final String POINTER_SPEED = "pointer_speed";
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index efc3e25..6534354 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -12258,12 +12258,19 @@
try {
if (mLastPreferredFrameRateCategory != frameRateCategory) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(
+ Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory "
+ + frameRateCategory);
+ }
mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
frameRateCategory, false).applyAsyncUnsafe();
mLastPreferredFrameRateCategory = frameRateCategory;
}
} catch (Exception e) {
Log.e(mTag, "Unable to set frame rate category", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
@@ -12282,12 +12289,19 @@
try {
if (mLastPreferredFrameRate != preferredFrameRate) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(
+ Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
+ + preferredFrameRate);
+ }
mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
Surface.FRAME_RATE_COMPATIBILITY_DEFAULT).applyAsyncUnsafe();
mLastPreferredFrameRate = preferredFrameRate;
}
} catch (Exception e) {
Log.e(mTag, "Unable to set frame rate", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 1de77f6..82067de 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -66,3 +66,14 @@
bug: "314952133"
is_fixed_read_only: true
}
+
+flag {
+ name: "app_compat_refactoring"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Whether the changes about app compat refactoring are enabled./n"
+ "The goal is to simplify code readability unblocking the implementation of /n"
+ "app compat feature like reachability, animations and others related to/n"
+ "freeform windowing mode."
+ bug: "309593314"
+ is_fixed_read_only: true
+}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 627e877..e591327 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -171,11 +171,11 @@
* Register a LockSettingsStateListener
* @param listener The listener to be registered
*/
- public abstract void registerLockSettingsStateListener(ILockSettingsStateListener listener);
+ public abstract void registerLockSettingsStateListener(LockSettingsStateListener listener);
/**
* Unregister a LockSettingsStateListener
* @param listener The listener to be unregistered
*/
- public abstract void unregisterLockSettingsStateListener(ILockSettingsStateListener listener);
+ public abstract void unregisterLockSettingsStateListener(LockSettingsStateListener listener);
}
diff --git a/core/java/com/android/internal/widget/ILockSettingsStateListener.aidl b/core/java/com/android/internal/widget/LockSettingsStateListener.java
similarity index 91%
rename from core/java/com/android/internal/widget/ILockSettingsStateListener.aidl
rename to core/java/com/android/internal/widget/LockSettingsStateListener.java
index 25e3003..869e676 100644
--- a/core/java/com/android/internal/widget/ILockSettingsStateListener.aidl
+++ b/core/java/com/android/internal/widget/LockSettingsStateListener.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -21,7 +21,7 @@
* state of primary authentication (i.e. PIN/pattern/password).
* @hide
*/
-oneway interface ILockSettingsStateListener {
+public interface LockSettingsStateListener {
/**
* Defines behavior in response to a successful authentication
* @param userId The user Id for the requested authentication
@@ -33,4 +33,4 @@
* @param userId The user Id for the requested authentication
*/
void onAuthenticationFailed(int userId);
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/OWNERS b/core/java/com/android/internal/widget/remotecompose/OWNERS
new file mode 100644
index 0000000..61724ec
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/OWNERS
@@ -0,0 +1,6 @@
+nicolasroard@google.com
+hoford@google.com
+jnichol@google.com
+sihua@google.com
+sunnygoyal@google.com
+oscarad@google.com
diff --git a/core/tests/coretests/src/android/os/HandlerThreadTest.java b/core/tests/coretests/src/android/os/HandlerThreadTest.java
index 1ad71da..3237812 100644
--- a/core/tests/coretests/src/android/os/HandlerThreadTest.java
+++ b/core/tests/coretests/src/android/os/HandlerThreadTest.java
@@ -126,7 +126,7 @@
public void testUncaughtExceptionFails() throws Exception {
// For the moment we can only test Ravenwood; on a physical device uncaught exceptions
// are detected, but reported as test failures at a higher level where we can't inspect
- Assume.assumeTrue(RavenwoodRule.isOnRavenwood());
+ Assume.assumeTrue(false); // TODO: re-enable
mThrown.expect(IllegalStateException.class);
final HandlerThread thread = new HandlerThread("HandlerThreadTest");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index f82212d..7c8fcbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -248,6 +248,12 @@
// Check if count changed
if (prevCount != newCount) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: visibleTaskCount has changed from %d to %d",
+ prevCount,
+ newCount
+ )
notifyVisibleTaskListeners(displayId, newCount)
}
}
@@ -262,6 +268,11 @@
* Get number of tasks that are marked as visible on given [displayId]
*/
fun getVisibleTaskCount(displayId: Int): Int {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: visibleTaskCount= %d",
+ displayData[displayId]?.visibleTasks?.size ?: 0
+ )
return displayData[displayId]?.visibleTasks?.size ?: 0
}
@@ -290,6 +301,10 @@
taskId
)
freeformTasksInZOrder.remove(taskId)
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: remaining freeform tasks: " + freeformTasksInZOrder.toDumpString()
+ )
}
/**
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index fd2f9bd..bab6781 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -7,3 +7,13 @@
bug: "314812750"
}
+flag {
+ name: "enable_cached_bluetooth_device_dedup"
+ namespace: "bluetooth"
+ description: "Enable dedup in CachedBluetoothDevice"
+ bug: "319197962"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index c97445f..647fcb9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -16,6 +16,8 @@
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.flags.Flags.enableCachedBluetoothDeviceDedup;
+
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothCsipSetCoordinator;
@@ -377,6 +379,10 @@
cachedDevice = mDeviceManager.addDevice(device);
}
+ if (enableCachedBluetoothDeviceDedup() && bondState == BluetoothDevice.BOND_BONDED) {
+ mDeviceManager.removeDuplicateInstanceForIdentityAddress(device);
+ }
+
for (BluetoothCallback callback : mCallbacks) {
callback.onDeviceBondStateChanged(cachedDevice, bondState);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 89fe268..32eec7e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -340,6 +340,20 @@
}
}
+ synchronized void removeDuplicateInstanceForIdentityAddress(BluetoothDevice device) {
+ String identityAddress = device.getIdentityAddress();
+ if (identityAddress == null || identityAddress.equals(device.getAddress())) {
+ return;
+ }
+ mCachedDevices.removeIf(d -> {
+ boolean shouldRemove = d.getDevice().getAddress().equals(identityAddress);
+ if (shouldRemove) {
+ Log.d(TAG, "Remove instance for identity address " + d);
+ }
+ return shouldRemove;
+ });
+ }
+
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
cachedDevice, int state, int profileId) {
if (profileId == BluetoothProfile.HEARING_AID) {
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index 13ee196..9a34d6f 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -27,6 +27,8 @@
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.scene.shared.model.Scene
@@ -112,6 +114,12 @@
dialogFactory: BouncerDialogFactory,
): View = throwComposeUnavailableError()
+ override fun createLockscreen(
+ context: Context,
+ viewModel: LockscreenContentViewModel,
+ blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
+ ): View = throwComposeUnavailableError()
+
private fun throwComposeUnavailableError(): Nothing {
error(
"Compose is not available. Make sure to check isComposeAvailable() before calling any" +
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
index 725aef2..fc3912e 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -16,6 +16,16 @@
package com.android.systemui.scene
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
import dagger.Module
+import dagger.Provides
-@Module interface LockscreenSceneModule
+@Module
+interface LockscreenSceneModule {
+ companion object {
+ @Provides
+ fun providesLockscreenBlueprints(): Set<LockscreenSceneBlueprint> {
+ return emptySet()
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index f05c7f3..4cc7332 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -22,6 +22,8 @@
import android.view.WindowInsets
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -40,6 +42,10 @@
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.keyboard.stickykeys.ui.view.createStickyKeyIndicatorView
import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
+import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.people.ui.compose.PeopleScreen
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.compose.FooterActions
@@ -211,4 +217,19 @@
setContent { PlatformTheme { BouncerContent(viewModel, dialogFactory) } }
}
}
+
+ override fun createLockscreen(
+ context: Context,
+ viewModel: LockscreenContentViewModel,
+ blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
+ ): View {
+ val sceneBlueprints =
+ blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
+ return ComposeView(context).apply {
+ setContent {
+ LockscreenContent(viewModel = viewModel, blueprints = sceneBlueprints)
+ .Content(modifier = Modifier.fillMaxSize())
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
index cbf2496..f5dc154 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -20,8 +20,10 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewConfigurator
import com.android.systemui.keyguard.qualifiers.KeyguardRootView
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.composable.LockscreenScene
import com.android.systemui.keyguard.ui.composable.LockscreenSceneBlueprintModule
+import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.scene.shared.model.Scene
import dagger.Binds
import dagger.Module
@@ -51,5 +53,12 @@
): () -> View {
return { configurator.get().getKeyguardRootView() }
}
+
+ @Provides
+ fun providesLockscreenBlueprints(
+ blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>
+ ): Set<LockscreenSceneBlueprint> {
+ return blueprints
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 2cb0034..b5499b7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -25,7 +25,7 @@
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.transitions
-import com.android.systemui.keyguard.ui.composable.blueprint.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import javax.inject.Inject
@@ -39,10 +39,10 @@
@Inject
constructor(
private val viewModel: LockscreenContentViewModel,
- private val blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
+ private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
) {
- private val sceneKeyByBlueprint: Map<LockscreenSceneBlueprint, SceneKey> by lazy {
+ private val sceneKeyByBlueprint: Map<ComposableLockscreenSceneBlueprint, SceneKey> by lazy {
blueprints.associateWith { blueprint -> SceneKey(blueprint.id) }
}
private val sceneKeyByBlueprintId: Map<String, SceneKey> by lazy {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
index 86124c6..6b210af 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
@@ -36,7 +36,7 @@
@Inject
constructor(
private val viewModel: LockscreenContentViewModel,
-) : LockscreenSceneBlueprint {
+) : ComposableLockscreenSceneBlueprint {
override val id: String = "communal"
@@ -59,5 +59,5 @@
@Module
interface CommunalBlueprintModule {
- @Binds @IntoSet fun blueprint(blueprint: CommunalBlueprint): LockscreenSceneBlueprint
+ @Binds @IntoSet fun blueprint(blueprint: CommunalBlueprint): ComposableLockscreenSceneBlueprint
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
similarity index 87%
rename from packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt
rename to packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
index 6d9cba4..cb73983 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
@@ -19,13 +19,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
/** Defines interface for classes that can render the content for a specific blueprint/layout. */
-interface LockscreenSceneBlueprint {
-
- /** The ID that uniquely identifies this blueprint across all other blueprints. */
- val id: String
-
+interface ComposableLockscreenSceneBlueprint : LockscreenSceneBlueprint {
/** Renders the content of this blueprint. */
@Composable fun SceneScope.Content(modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index bf02d8a..a07ab4a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -20,10 +20,12 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
@@ -38,6 +40,7 @@
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -61,7 +64,7 @@
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
private val clockInteractor: KeyguardClockInteractor,
-) : LockscreenSceneBlueprint {
+) : ComposableLockscreenSceneBlueprint {
override val id: String = "default"
@@ -84,6 +87,7 @@
with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
with(clockSection) {
SmallClock(
+ burnInParams = burnIn.parameters,
onTopChanged = burnIn.onSmallClockTopChanged,
modifier = Modifier.fillMaxWidth(),
)
@@ -95,7 +99,13 @@
modifier =
Modifier.fillMaxWidth()
.padding(
- top = { viewModel.getSmartSpacePaddingTop(resources) }
+ top = { viewModel.getSmartSpacePaddingTop(resources) },
+ )
+ .padding(
+ bottom =
+ dimensionResource(
+ R.dimen.keyguard_status_view_bottom_margin
+ ),
),
)
}
@@ -214,5 +224,5 @@
@Module
interface DefaultBlueprintModule {
- @Binds @IntoSet fun blueprint(blueprint: DefaultBlueprint): LockscreenSceneBlueprint
+ @Binds @IntoSet fun blueprint(blueprint: DefaultBlueprint): ComposableLockscreenSceneBlueprint
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index d0aa444..b035e42 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -20,10 +20,12 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
@@ -38,6 +40,7 @@
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -61,7 +64,7 @@
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
private val clockInteractor: KeyguardClockInteractor,
-) : LockscreenSceneBlueprint {
+) : ComposableLockscreenSceneBlueprint {
override val id: String = "shortcuts-besides-udfps"
@@ -86,6 +89,7 @@
SmallClock(
onTopChanged = burnIn.onSmallClockTopChanged,
modifier = Modifier.fillMaxWidth(),
+ burnInParams = burnIn.parameters,
)
}
with(smartSpaceSection) {
@@ -96,6 +100,12 @@
Modifier.fillMaxWidth()
.padding(
top = { viewModel.getSmartSpacePaddingTop(resources) }
+ )
+ .padding(
+ bottom =
+ dimensionResource(
+ R.dimen.keyguard_status_view_bottom_margin
+ )
),
)
}
@@ -222,5 +232,5 @@
interface ShortcutsBesideUdfpsBlueprintModule {
@Binds
@IntoSet
- fun blueprint(blueprint: ShortcutsBesideUdfpsBlueprint): LockscreenSceneBlueprint
+ fun blueprint(blueprint: ShortcutsBesideUdfpsBlueprint): ComposableLockscreenSceneBlueprint
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
index 616a7b4..660fc5a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
@@ -72,7 +72,7 @@
private val settingsMenuSection: SettingsMenuSection,
private val clockInteractor: KeyguardClockInteractor,
private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
-) : LockscreenSceneBlueprint {
+) : ComposableLockscreenSceneBlueprint {
override val id: String = "split-shade"
@@ -109,7 +109,14 @@
.padding(
top = {
viewModel.getSmartSpacePaddingTop(resources)
- }
+ },
+ )
+ .padding(
+ bottom =
+ dimensionResource(
+ R.dimen
+ .keyguard_status_view_bottom_margin
+ )
),
)
}
@@ -237,5 +244,7 @@
@Module
interface SplitShadeBlueprintModule {
- @Binds @IntoSet fun blueprint(blueprint: SplitShadeBlueprint): LockscreenSceneBlueprint
+ @Binds
+ @IntoSet
+ fun blueprint(blueprint: SplitShadeBlueprint): ComposableLockscreenSceneBlueprint
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt
index 8f21879..fa07baf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt
@@ -33,7 +33,10 @@
import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import javax.inject.Inject
@@ -42,10 +45,12 @@
constructor(
private val viewModel: KeyguardClockViewModel,
private val clockInteractor: KeyguardClockInteractor,
+ private val aodBurnInViewModel: AodBurnInViewModel,
) {
@Composable
fun SceneScope.SmallClock(
+ burnInParams: BurnInParameters,
onTopChanged: (top: Float?) -> Unit,
modifier: Modifier = Modifier,
) {
@@ -89,7 +94,11 @@
dimensionResource(customizationR.dimen.clock_padding_start)
)
.padding(top = { viewModel.getSmallClockTopMargin(view.context) })
- .onTopPlacementChanged(onTopChanged),
+ .onTopPlacementChanged(onTopChanged)
+ .burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ ),
update = {
val newClockView = checkNotNull(currentClock).smallClock.view
it.removeAllViews()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 5e27d82..6a8da10 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -19,6 +19,11 @@
import android.content.Context
import android.view.ViewGroup
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
@@ -40,56 +45,82 @@
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.DisposableHandle
@SysUISingleton
class NotificationSection
@Inject
constructor(
- @Application context: Context,
+ @Application private val context: Context,
private val viewModel: NotificationsPlaceholderViewModel,
- controller: NotificationStackScrollLayoutController,
- sceneContainerFlags: SceneContainerFlags,
- sharedNotificationContainer: SharedNotificationContainer,
- sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
- stackScrollLayout: NotificationStackScrollLayout,
- notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
- ambientState: AmbientState,
- notificationStackSizeCalculator: NotificationStackSizeCalculator,
- @Main mainDispatcher: CoroutineDispatcher,
+ private val controller: NotificationStackScrollLayoutController,
+ private val sceneContainerFlags: SceneContainerFlags,
+ private val sharedNotificationContainer: SharedNotificationContainer,
+ private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+ private val stackScrollLayout: NotificationStackScrollLayout,
+ private val notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
+ private val ambientState: AmbientState,
+ private val notificationStackSizeCalculator: NotificationStackSizeCalculator,
+ @Main private val mainDispatcher: CoroutineDispatcher,
) {
- init {
- if (!KeyguardShadeMigrationNssl.isUnexpectedlyInLegacyMode()) {
- // This scene container section moves the NSSL to the SharedNotificationContainer. This
- // also requires that SharedNotificationContainer gets moved to the SceneWindowRootView
- // by the SceneWindowRootViewBinder.
- // Prior to Scene Container, but when the KeyguardShadeMigrationNssl flag is enabled,
- // NSSL is moved into this container by the NotificationStackScrollLayoutSection.
- (stackScrollLayout.parent as? ViewGroup)?.removeView(stackScrollLayout)
- sharedNotificationContainer.addNotificationStackScrollLayout(stackScrollLayout)
+ @Composable
+ fun SceneScope.Notifications(modifier: Modifier = Modifier) {
+ if (KeyguardShadeMigrationNssl.isUnexpectedlyInLegacyMode()) {
+ // This scene container section moves the NSSL to the SharedNotificationContainer.
+ // This also requires that SharedNotificationContainer gets moved to the
+ // SceneWindowRootView by the SceneWindowRootViewBinder. Prior to Scene Container,
+ // but when the KeyguardShadeMigrationNssl flag is enabled, NSSL is moved into this
+ // container by the NotificationStackScrollLayoutSection.
+ return
+ }
- SharedNotificationContainerBinder.bind(
- sharedNotificationContainer,
- sharedNotificationContainerViewModel,
- sceneContainerFlags,
- controller,
- notificationStackSizeCalculator,
- mainDispatcher,
+ var isBound by remember { mutableStateOf(false) }
+
+ DisposableEffect(Unit) {
+ val disposableHandles: MutableList<DisposableHandle> = mutableListOf()
+
+ // Ensure stackScrollLayout is a child of sharedNotificationContainer.
+ if (stackScrollLayout.parent != sharedNotificationContainer) {
+ (stackScrollLayout.parent as? ViewGroup)?.removeView(stackScrollLayout)
+ sharedNotificationContainer.addNotificationStackScrollLayout(stackScrollLayout)
+ }
+
+ disposableHandles.add(
+ SharedNotificationContainerBinder.bind(
+ sharedNotificationContainer,
+ sharedNotificationContainerViewModel,
+ sceneContainerFlags,
+ controller,
+ notificationStackSizeCalculator,
+ mainDispatcher,
+ )
)
if (sceneContainerFlags.flexiNotifsEnabled()) {
- NotificationStackAppearanceViewBinder.bind(
- context,
- sharedNotificationContainer,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
+ disposableHandles.add(
+ NotificationStackAppearanceViewBinder.bind(
+ context,
+ sharedNotificationContainer,
+ notificationStackAppearanceViewModel,
+ ambientState,
+ controller,
+ )
)
}
- }
- }
- @Composable
- fun SceneScope.Notifications(modifier: Modifier = Modifier) {
+ isBound = true
+
+ onDispose {
+ disposableHandles.forEach { it.dispose() }
+ disposableHandles.clear()
+ isBound = false
+ }
+ }
+
+ if (!isBound) {
+ return
+ }
+
NotificationStack(
viewModel = viewModel,
modifier = modifier,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
new file mode 100644
index 0000000..693de55
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.NotificationContainerBounds
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationsPlaceholderViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val underTest = kosmos.notificationsPlaceholderViewModel
+ @Test
+ fun onBoundsChanged_setsNotificationContainerBounds() {
+ underTest.onBoundsChanged(left = 5f, top = 5f, right = 5f, bottom = 5f)
+ assertThat(kosmos.keyguardInteractor.notificationContainerBounds.value)
+ .isEqualTo(NotificationContainerBounds(left = 5f, top = 5f, right = 5f, bottom = 5f))
+ assertThat(kosmos.notificationStackAppearanceInteractor.stackBounds.value)
+ .isEqualTo(NotificationContainerBounds(left = 5f, top = 5f, right = 5f, bottom = 5f))
+ }
+ @Test
+ fun onContentTopChanged_setsContentTop() {
+ underTest.onContentTopChanged(padding = 5f)
+ assertThat(kosmos.notificationStackAppearanceInteractor.contentTop.value).isEqualTo(5f)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 8df7e8b..9a4dfdd 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -27,6 +27,8 @@
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.scene.shared.model.Scene
@@ -115,4 +117,11 @@
/** Creates a container that hosts the communal UI and handles gesture transitions. */
fun createCommunalContainer(context: Context, viewModel: BaseCommunalViewModel): View
+
+ /** Creates a [View] that represents the Lockscreen. */
+ fun createLockscreen(
+ context: Context,
+ viewModel: LockscreenContentViewModel,
+ blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
+ ): View
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 7f43fac..abe49ee 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -20,6 +20,12 @@
import android.content.Context
import android.view.LayoutInflater
import android.view.View
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.internal.jank.InteractionJankMonitor
import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.KeyguardStatusViewController
@@ -29,10 +35,13 @@
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.compose.ComposeFacade
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.keyguard.shared.ComposeLockscreen
+import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
@@ -44,6 +53,7 @@
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
@@ -88,6 +98,8 @@
private val falsingManager: FalsingManager,
private val aodAlphaViewModel: AodAlphaViewModel,
private val keyguardClockViewModel: KeyguardClockViewModel,
+ private val lockscreenContentViewModel: LockscreenContentViewModel,
+ private val lockscreenSceneBlueprintsLazy: Lazy<Set<LockscreenSceneBlueprint>>,
) : CoreStartable {
private var rootViewHandle: DisposableHandle? = null
@@ -115,11 +127,28 @@
initializeViews()
if (!SceneContainerFlag.isEnabled) {
- KeyguardBlueprintViewBinder.bind(
- keyguardRootView,
- keyguardBlueprintViewModel,
- keyguardClockViewModel
- )
+ if (ComposeLockscreen.isEnabled) {
+ val composeView =
+ ComposeFacade.createLockscreen(
+ context = context,
+ viewModel = lockscreenContentViewModel,
+ blueprints = lockscreenSceneBlueprintsLazy.get(),
+ )
+ composeView.id = View.generateViewId()
+ val cs = ConstraintSet()
+ cs.clone(keyguardRootView)
+ cs.connect(composeView.id, START, PARENT_ID, START)
+ cs.connect(composeView.id, END, PARENT_ID, END)
+ cs.connect(composeView.id, TOP, PARENT_ID, TOP)
+ cs.connect(composeView.id, BOTTOM, PARENT_ID, BOTTOM)
+ keyguardRootView.addView(composeView)
+ } else {
+ KeyguardBlueprintViewBinder.bind(
+ keyguardRootView,
+ keyguardBlueprintViewModel,
+ keyguardClockViewModel,
+ )
+ }
}
keyguardBlueprintCommandListener.start()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/LockscreenSceneBlueprint.kt
similarity index 60%
copy from packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt
copy to packages/SystemUI/src/com/android/systemui/keyguard/shared/model/LockscreenSceneBlueprint.kt
index 6d9cba4..2eafb83 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/LockscreenSceneBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/LockscreenSceneBlueprint.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -14,18 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.ui.composable.blueprint
+package com.android.systemui.keyguard.shared.model
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
-
-/** Defines interface for classes that can render the content for a specific blueprint/layout. */
+/**
+ * Defines interface for classes that can render the content for a specific blueprint/layout.
+ *
+ * The actual rendering is done by a compose-aware sub-interface.
+ */
interface LockscreenSceneBlueprint {
-
/** The ID that uniquely identifies this blueprint across all other blueprints. */
val id: String
-
- /** Renders the content of this blueprint. */
- @Composable fun SceneScope.Content(modifier: Modifier)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
index a651c10..52d94a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
@@ -57,7 +57,7 @@
private val mainDispatcher: CoroutineDispatcher,
) : KeyguardSection() {
private val placeHolderId = R.id.nssl_placeholder
- private var disposableHandle: DisposableHandle? = null
+ private val disposableHandles: MutableList<DisposableHandle> = mutableListOf()
/**
* Align the notification placeholder bottom to the top of either the lock icon or the ambient
@@ -102,8 +102,9 @@
if (!KeyguardShadeMigrationNssl.isEnabled) {
return
}
- disposableHandle?.dispose()
- disposableHandle =
+
+ disposeHandles()
+ disposableHandles.add(
SharedNotificationContainerBinder.bind(
sharedNotificationContainer,
sharedNotificationContainerViewModel,
@@ -112,19 +113,28 @@
notificationStackSizeCalculator,
mainDispatcher,
)
+ )
+
if (sceneContainerFlags.flexiNotifsEnabled()) {
- NotificationStackAppearanceViewBinder.bind(
- context,
- sharedNotificationContainer,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
+ disposableHandles.add(
+ NotificationStackAppearanceViewBinder.bind(
+ context,
+ sharedNotificationContainer,
+ notificationStackAppearanceViewModel,
+ ambientState,
+ controller,
+ )
)
}
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- disposableHandle?.dispose()
+ disposeHandles()
constraintLayout.removeView(placeHolderId)
}
+
+ private fun disposeHandles() {
+ disposableHandles.forEach { it.dispose() }
+ disposableHandles.clear()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
index d4ea728..9cf3c95 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
@@ -28,7 +28,6 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.onStart
/** Models UI state for the alpha of the AOD (always-on display). */
@SysUISingleton
@@ -43,15 +42,13 @@
/** The alpha level for the entire lockscreen while in AOD. */
val alpha: Flow<Float> =
combine(
- keyguardTransitionInteractor.transitionValue(KeyguardState.GONE).onStart {
- emit(0f)
- },
+ keyguardTransitionInteractor.currentKeyguardState,
merge(
keyguardInteractor.keyguardAlpha,
occludedToLockscreenTransitionViewModel.lockscreenAlpha,
)
- ) { transitionToGone, alpha ->
- if (transitionToGone == 1f) {
+ ) { currentKeyguardState, alpha ->
+ if (currentKeyguardState == KeyguardState.GONE) {
// Ensures content is not visible when in GONE state
0f
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
index ba04fd3..f5e6135 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
@@ -67,6 +67,8 @@
duration = 500.milliseconds,
onStart = { 0f },
onStep = { it },
+ onFinish = { 1f },
+ onCancel = { 1f },
)
val deviceEntryBackgroundViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(0f)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 09e4e75..06ca3af 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2472,11 +2472,9 @@
return 0;
}
if (!mKeyguardBypassController.getBypassEnabled()) {
- if (migrateClocksToBlueprint()) {
- View nsslPlaceholder = mView.getRootView().findViewById(R.id.nssl_placeholder);
- if (!mSplitShadeEnabled && nsslPlaceholder != null) {
- return nsslPlaceholder.getTop();
- }
+ if (migrateClocksToBlueprint() && !mSplitShadeEnabled) {
+ return (int) mKeyguardInteractor.getNotificationContainerBounds()
+ .getValue().getTop();
}
return mClockPositionResult.stackScrollerPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt
new file mode 100644
index 0000000..c74c396
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.interruption
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.util.Log
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+
+// Class to track avalanche trigger event time.
+@SysUISingleton
+class AvalancheProvider
+@Inject
+constructor(
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val logger: VisualInterruptionDecisionLogger,
+) {
+ val TAG = "AvalancheProvider"
+ val timeoutMs = 120000
+ var startTime: Long = 0L
+
+ private val avalancheTriggerIntents = mutableSetOf(
+ Intent.ACTION_AIRPLANE_MODE_CHANGED,
+ Intent.ACTION_BOOT_COMPLETED,
+ Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
+ Intent.ACTION_USER_SWITCHED
+ )
+
+ private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action in avalancheTriggerIntents) {
+
+ // Ignore when airplane mode turned on
+ if (intent.action == Intent.ACTION_AIRPLANE_MODE_CHANGED
+ && intent.getBooleanExtra(/* name= */ "state", /* defaultValue */ false)) {
+ Log.d(TAG, "broadcastReceiver: ignore airplane mode on")
+ return
+ }
+ Log.d(TAG, "broadcastReceiver received intent.action=" + intent.action)
+ startTime = System.currentTimeMillis()
+ }
+ }
+ }
+
+ fun register() {
+ val intentFilter = IntentFilter()
+ for (intent in avalancheTriggerIntents) {
+ intentFilter.addAction(intent)
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index 8e82442..20c8add 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -16,7 +16,10 @@
package com.android.systemui.statusbar.notification.interruption
+import android.app.Notification
import android.app.Notification.BubbleMetadata
+import android.app.Notification.CATEGORY_EVENT
+import android.app.Notification.CATEGORY_REMINDER
import android.app.Notification.VISIBILITY_PRIVATE
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
@@ -224,3 +227,68 @@
override fun shouldSuppress(entry: NotificationEntry) =
keyguardNotificationVisibilityProvider.shouldHideNotification(entry)
}
+
+
+class AvalancheSuppressor(
+ private val avalancheProvider: AvalancheProvider,
+ private val systemClock: SystemClock,
+) : VisualInterruptionFilter(
+ types = setOf(PEEK, PULSE),
+ reason = "avalanche",
+ ) {
+ val TAG = "AvalancheSuppressor"
+
+ enum class State {
+ ALLOW_CONVERSATION_AFTER_AVALANCHE,
+ ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME,
+ ALLOW_CALLSTYLE,
+ ALLOW_CATEGORY_REMINDER,
+ ALLOW_CATEGORY_EVENT,
+ ALLOW_FSI_WITH_PERMISSION_ON,
+ ALLOW_COLORIZED,
+ SUPPRESS
+ }
+
+ override fun shouldSuppress(entry: NotificationEntry): Boolean {
+ val timeSinceAvalanche = systemClock.currentTimeMillis() - avalancheProvider.startTime
+ val isActive = timeSinceAvalanche < avalancheProvider.timeoutMs
+ val state = allow(entry)
+ val suppress = isActive && state == State.SUPPRESS
+ reason = "avalanche suppress=$suppress isActive=$isActive state=$state"
+ return suppress
+ }
+
+ fun allow(entry: NotificationEntry): State {
+ if (
+ entry.ranking.isConversation &&
+ entry.sbn.notification.`when` > avalancheProvider.startTime
+ ) {
+ return State.ALLOW_CONVERSATION_AFTER_AVALANCHE
+ }
+
+ if (entry.channel?.isImportantConversation == true) {
+ return State.ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME
+ }
+
+ if (entry.sbn.notification.isStyle(Notification.CallStyle::class.java)) {
+ return State.ALLOW_CALLSTYLE
+ }
+
+ if (entry.sbn.notification.category == CATEGORY_REMINDER) {
+ return State.ALLOW_CATEGORY_REMINDER
+ }
+
+ if (entry.sbn.notification.category == CATEGORY_EVENT) {
+ return State.ALLOW_CATEGORY_EVENT
+ }
+
+ if (entry.sbn.notification.fullScreenIntent != null) {
+ return State.ALLOW_FSI_WITH_PERMISSION_ON
+ }
+
+ if (entry.sbn.notification.isColorized) {
+ return State.ALLOW_COLORIZED
+ }
+ return State.SUPPRESS
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index 6878a1e..dabb18b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE
+import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -45,22 +46,25 @@
class VisualInterruptionDecisionProviderImpl
@Inject
constructor(
- private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
- private val batteryController: BatteryController,
- deviceProvisionedController: DeviceProvisionedController,
- private val eventLog: EventLog,
- private val globalSettings: GlobalSettings,
- private val headsUpManager: HeadsUpManager,
- private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
- keyguardStateController: KeyguardStateController,
- private val logger: VisualInterruptionDecisionLogger,
- @Main private val mainHandler: Handler,
- private val powerManager: PowerManager,
- private val statusBarStateController: StatusBarStateController,
- private val systemClock: SystemClock,
- private val uiEventLogger: UiEventLogger,
- private val userTracker: UserTracker,
+ private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
+ private val batteryController: BatteryController,
+ deviceProvisionedController: DeviceProvisionedController,
+ private val eventLog: EventLog,
+ private val globalSettings: GlobalSettings,
+ private val headsUpManager: HeadsUpManager,
+ private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
+ keyguardStateController: KeyguardStateController,
+ private val logger: VisualInterruptionDecisionLogger,
+ @Main private val mainHandler: Handler,
+ private val powerManager: PowerManager,
+ private val statusBarStateController: StatusBarStateController,
+ private val systemClock: SystemClock,
+ private val uiEventLogger: UiEventLogger,
+ private val userTracker: UserTracker,
+ private val avalancheProvider: AvalancheProvider
+
) : VisualInterruptionDecisionProvider {
+
init {
check(!VisualInterruptionRefactor.isUnexpectedlyInLegacyMode())
}
@@ -166,6 +170,10 @@
addFilter(HunJustLaunchedFsiSuppressor())
addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider))
+ if (NotificationAvalancheSuppression.isEnabled) {
+ addFilter(AvalancheSuppressor(avalancheProvider, systemClock))
+ avalancheProvider.register()
+ }
started = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
index ee79727..2f80c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
@@ -85,7 +85,7 @@
/** A reason why visual interruptions might be suppressed based on the notification. */
abstract class VisualInterruptionFilter(
override val types: Set<VisualInterruptionType>,
- override val reason: String,
+ override var reason: String,
override val uiEventId: UiEventEnum? = null,
override val eventLogData: EventLogData? = null
) : VisualInterruptionSuppressor {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
index 6c2cbbe..50b08b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import kotlin.math.roundToInt
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.launch
/** Binds the shared notification container to its view-model. */
@@ -38,8 +39,8 @@
viewModel: NotificationStackAppearanceViewModel,
ambientState: AmbientState,
controller: NotificationStackScrollLayoutController,
- ) {
- view.repeatWhenAttached {
+ ): DisposableHandle {
+ return view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
viewModel.stackBounds.collect { bounds ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index a436f17..8b723da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -20,6 +20,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
@@ -40,9 +42,11 @@
shadeInteractor: ShadeInteractor,
flags: SceneContainerFlags,
featureFlags: FeatureFlagsClassic,
+ private val keyguardInteractor: KeyguardInteractor,
) {
/** DEBUG: whether the placeholder "Notifications" text should be shown. */
- val isPlaceholderTextVisible: Boolean = !flags.flexiNotifsEnabled()
+ val isPlaceholderTextVisible: Boolean =
+ !flags.flexiNotifsEnabled() && SceneContainerFlag.isEnabled
/** DEBUG: whether the placeholder should be made slightly visible for positional debugging. */
val isVisualDebuggingEnabled: Boolean = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES)
@@ -64,7 +68,10 @@
right: Float,
bottom: Float,
) {
- interactor.setStackBounds(NotificationContainerBounds(left, top, right, bottom))
+ val notificationContainerBounds =
+ NotificationContainerBounds(top = top, bottom = bottom, left = left, right = right)
+ keyguardInteractor.setNotificationContainerBounds(notificationContainerBounds)
+ interactor.setStackBounds(notificationContainerBounds)
}
/** The corner radius of the placeholder, in dp. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 25a7eb8..9517f82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -46,6 +46,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import org.junit.After
import org.junit.Assert.assertThrows
import org.junit.Assume.assumeTrue
import org.junit.Before
@@ -118,6 +119,11 @@
initAndAttachContainerView()
}
+ @After
+ fun tearDown() {
+ ViewUtils.detachView(parentView)
+ }
+
@Test
fun isEnabled_communalEnabled_returnsTrue() {
communalRepository.setIsCommunalEnabled(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index da68d9c..5410864 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.notification.interruption
+import android.app.Notification.CATEGORY_EVENT
+import android.app.Notification.CATEGORY_REMINDER
+import android.app.NotificationManager
import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -47,6 +50,7 @@
systemClock,
uiEventLogger,
userTracker,
+ avalancheProvider
)
}
@@ -70,6 +74,114 @@
}
}
+ // Avalanche tests are in VisualInterruptionDecisionProviderImplTest
+ // instead of VisualInterruptionDecisionProviderTestBase
+ // because avalanche code is based on the suppression refactor.
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(5)
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldNotHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_DEFAULT
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(15)
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isImportantConversation = true
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowCall() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isCall = true
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_REMINDER
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_EVENT
+ })
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowFsi() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ assertFsiNotSuppressed()
+ }
+ }
+
+ @Test
+ fun testAvalancheFilter_duringAvalanche_allowColorized() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) {
+ ensurePeekState()
+ assertShouldHeadsUp(buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isColorized = true
+ })
+ }
+ }
+
@Test
fun testPeekCondition_suppressesOnlyPeek() {
withCondition(TestCondition(types = setOf(PEEK)) { true }) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 2ac0cb7..f89b9cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -19,7 +19,10 @@
import android.app.ActivityManager
import android.app.Notification
import android.app.Notification.BubbleMetadata
+import android.app.Notification.EXTRA_COLORIZED
+import android.app.Notification.EXTRA_TEMPLATE
import android.app.Notification.FLAG_BUBBLE
+import android.app.Notification.FLAG_CAN_COLORIZE
import android.app.Notification.FLAG_FOREGROUND_SERVICE
import android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED
import android.app.Notification.FLAG_USER_INITIATED_JOB
@@ -50,6 +53,8 @@
import com.android.internal.logging.UiEventLogger.UiEventEnum
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.FakeBroadcastDispatcher
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.log.core.LogLevel
@@ -122,6 +127,7 @@
protected val systemClock = FakeSystemClock()
protected val uiEventLogger = UiEventLoggerFake()
protected val userTracker = FakeUserTracker()
+ protected val avalancheProvider: AvalancheProvider = mock()
protected abstract val provider: VisualInterruptionDecisionProvider
@@ -1097,6 +1103,8 @@
var whenMs: Long? = null
var isGrouped = false
var isGroupSummary = false
+ var isCall = false
+ var category: String? = null
var groupAlertBehavior: Int? = null
var hasBubbleMetadata = false
var hasFsi = false
@@ -1106,10 +1114,12 @@
var isUserInitiatedJob = false
var isBubble = false
var isStickyAndNotDemoted = false
+ var isColorized = false
// Set on NotificationEntryBuilder:
var importance = IMPORTANCE_DEFAULT
var canBubble: Boolean? = null
+ var isImportantConversation = false
// Set on NotificationEntry:
var hasJustLaunchedFsi = false
@@ -1118,6 +1128,7 @@
var packageSuspended = false
var visibilityOverride: Int? = null
var suppressedVisualEffects: Int? = null
+ var isConversation = false
private fun buildBubbleMetadata(): BubbleMetadata {
val builder =
@@ -1158,6 +1169,13 @@
nb.setGroupSummary(true)
}
+ if (isCall) {
+ nb.extras.putString(EXTRA_TEMPLATE, Notification.CallStyle::class.java.name)
+ }
+
+ if (category != null) {
+ nb.setCategory(category)
+ }
groupAlertBehavior?.let { nb.setGroupAlertBehavior(it) }
if (hasBubbleMetadata) {
@@ -1185,6 +1203,10 @@
if (isStickyAndNotDemoted) {
n.flags = n.flags or FLAG_FSI_REQUESTED_BUT_DENIED
}
+ if (isColorized) {
+ n.extras.putBoolean(EXTRA_COLORIZED, true)
+ n.flags = n.flags or FLAG_CAN_COLORIZE
+ }
}
.let { NotificationEntryBuilder().setNotification(it) }
.also { neb ->
@@ -1193,9 +1215,10 @@
neb.setTag(TEST_TAG)
neb.setImportance(importance)
- neb.setChannel(
- NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)
- )
+ val channel =
+ NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)
+ channel.isImportantConversation = isImportantConversation
+ neb.setChannel(channel)
canBubble?.let { neb.setCanBubble(it) }
}
@@ -1216,6 +1239,7 @@
}
visibilityOverride?.let { mrb.setVisibilityOverride(it) }
suppressedVisualEffects?.let { mrb.setSuppressedVisualEffects(it) }
+ mrb.setIsConversation(isConversation)
}
.build()
}
@@ -1287,7 +1311,7 @@
}
}
- private fun whenAgo(whenAgeMs: Long) = systemClock.currentTimeMillis() - whenAgeMs
+ protected fun whenAgo(whenAgeMs: Long) = systemClock.currentTimeMillis() - whenAgeMs
}
private const val TEST_CONTENT_TITLE = "Test Content Title"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
index 0356c2c..620ad9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
@@ -19,6 +19,7 @@
import android.os.Handler
import android.os.PowerManager
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
@@ -49,7 +50,8 @@
statusBarStateController: StatusBarStateController,
systemClock: SystemClock,
uiEventLogger: UiEventLogger,
- userTracker: UserTracker
+ userTracker: UserTracker,
+ avalancheProvider: AvalancheProvider
): VisualInterruptionDecisionProvider {
return if (VisualInterruptionRefactor.isEnabled) {
VisualInterruptionDecisionProviderImpl(
@@ -67,7 +69,8 @@
statusBarStateController,
systemClock,
uiEventLogger,
- userTracker
+ userTracker,
+ avalancheProvider
)
} else {
NotificationInterruptStateProviderWrapper(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 849a13b..b048949 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -153,6 +153,7 @@
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.AvalancheProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
@@ -313,6 +314,7 @@
@Mock private CameraLauncher mCameraLauncher;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private UserTracker mUserTracker;
+ @Mock private AvalancheProvider mAvalancheProvider;
@Mock private FingerprintManager mFingerprintManager;
@Mock IPowerManager mPowerManagerService;
@Mock ActivityStarter mActivityStarter;
@@ -367,7 +369,8 @@
mStatusBarStateController,
mFakeSystemClock,
mock(UiEventLogger.class),
- mUserTracker);
+ mUserTracker,
+ mAvalancheProvider);
mVisualInterruptionDecisionProvider.start();
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 3bde6e3..99c2dc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -315,6 +315,8 @@
@After
public void tearDown() {
+ // Detaching view stops flow collection and prevents memory leak.
+ ViewUtils.detachView(mScrimBehind);
finishAnimationsImmediately();
Arrays.stream(ScrimState.values()).forEach((scrim) -> {
scrim.setAodFrontScrimAlpha(0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index f3e9203..f4b36659 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -96,6 +96,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
@@ -151,6 +152,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.AvalancheProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionLogger;
@@ -587,7 +589,9 @@
mock(StatusBarStateController.class),
mock(SystemClock.class),
mock(UiEventLogger.class),
- mock(UserTracker.class));
+ mock(UserTracker.class),
+ mock(AvalancheProvider.class)
+ );
interruptionDecisionProvider.start();
mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
index d7e948e..29faa58 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.scene.shared.flag.sceneContainerFlags
@@ -29,5 +30,6 @@
shadeInteractor = shadeInteractor,
flags = sceneContainerFlags,
featureFlags = featureFlagsClassic,
+ keyguardInteractor = keyguardInteractor,
)
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 85fa65a..7b5932b 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -58,6 +58,11 @@
private static ScheduledFuture<?> sPendingTimeout;
/**
+ * When enabled, attempt to detect uncaught exceptions from background threads.
+ */
+ private static final boolean ENABLE_UNCAUGHT_EXCEPTION_DETECTION = false;
+
+ /**
* When set, an unhandled exception was discovered (typically on a background thread), and we
* capture it here to ensure it's reported as a test failure.
*/
@@ -75,8 +80,10 @@
}
public static void init(RavenwoodRule rule) {
- maybeThrowPendingUncaughtException(false);
- Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
+ if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+ maybeThrowPendingUncaughtException(false);
+ Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
+ }
RuntimeInit.redirectLogStreams();
@@ -129,7 +136,9 @@
android.os.Binder.reset$ravenwood();
android.os.Process.reset$ravenwood();
- maybeThrowPendingUncaughtException(true);
+ if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+ maybeThrowPendingUncaughtException(true);
+ }
}
public static void logTestRunner(String label, Description description) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 687def0..a61199a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1392,6 +1392,11 @@
}
@Override // Binder call
+ public int getMousePointerSpeed() {
+ return mNative.getMousePointerSpeed();
+ }
+
+ @Override // Binder call
public void tryPointerSpeed(int speed) {
if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
"tryPointerSpeed()")) {
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index e5f3484..b16df0f 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -119,6 +119,8 @@
*/
boolean transferTouch(IBinder destChannelToken, int displayId);
+ int getMousePointerSpeed();
+
void setPointerSpeed(int speed);
void setMousePointerAccelerationEnabled(int displayId, boolean enabled);
@@ -364,6 +366,9 @@
public native boolean transferTouch(IBinder destChannelToken, int displayId);
@Override
+ public native int getMousePointerSpeed();
+
+ @Override
public native void setPointerSpeed(int speed);
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index fff4939..95189ab 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3732,6 +3732,37 @@
return InputBindResult.INVALID_DISPLAY_ID;
}
+ // In case mShowForced flag affects the next client to keep IME visible, when
+ // the current client is leaving due to the next focused client, we clear
+ // mShowForced flag when the next client's targetSdkVersion is T or higher.
+ final boolean shouldClearFlag =
+ mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.mUid);
+ final boolean showForced = mVisibilityStateComputer.mShowForced;
+ if (mCurFocusedWindow != windowToken && showForced && shouldClearFlag) {
+ mVisibilityStateComputer.mShowForced = false;
+ }
+
+ // Verify if caller is a background user.
+ final int currentUserId = mSettings.getUserId();
+ if (userId != currentUserId) {
+ if (ArrayUtils.contains(
+ mUserManagerInternal.getProfileIds(currentUserId, false), userId)) {
+ // cross-profile access is always allowed here to allow
+ // profile-switching.
+ scheduleSwitchUserTaskLocked(userId, cs.mClient);
+ return InputBindResult.USER_SWITCHING;
+ }
+ Slog.w(TAG, "A background user is requesting window. Hiding IME.");
+ Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
+ + " a background user, use EditorInfo.targetInputMethodUser with"
+ + " INTERACT_ACROSS_USERS_FULL permission.");
+ hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
+ 0 /* flags */,
+ null /* resultReceiver */,
+ SoftInputShowHideReason.HIDE_INVALID_USER);
+ return InputBindResult.INVALID_USER;
+ }
+
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
editorInfo, inputConnection, remoteAccessibilityInputConnection,
@@ -3781,32 +3812,6 @@
+ " cs=" + cs);
}
- final boolean shouldClearFlag = mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.mUid);
- // In case mShowForced flag affects the next client to keep IME visible, when the current
- // client is leaving due to the next focused client, we clear mShowForced flag when the
- // next client's targetSdkVersion is T or higher.
- final boolean showForced = mVisibilityStateComputer.mShowForced;
- if (mCurFocusedWindow != windowToken && showForced && shouldClearFlag) {
- mVisibilityStateComputer.mShowForced = false;
- }
-
- final int currentUserId = mSettings.getUserId();
- if (userId != currentUserId) {
- if (ArrayUtils.contains(
- mUserManagerInternal.getProfileIds(currentUserId, false), userId)) {
- // cross-profile access is always allowed here to allow profile-switching.
- scheduleSwitchUserTaskLocked(userId, cs.mClient);
- return InputBindResult.USER_SWITCHING;
- }
- Slog.w(TAG, "A background user is requesting window. Hiding IME.");
- Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
- + " a background user, use EditorInfo.targetInputMethodUser with"
- + " INTERACT_ACROSS_USERS_FULL permission.");
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, SoftInputShowHideReason.HIDE_INVALID_USER);
- return InputBindResult.INVALID_USER;
- }
-
final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
final boolean startInputByWinGainedFocus =
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a06607b..7fb3e00 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -93,7 +93,6 @@
import android.os.IBinder;
import android.os.IProgressListener;
import android.os.Process;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -139,11 +138,11 @@
import com.android.internal.util.Preconditions;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
-import com.android.internal.widget.ILockSettingsStateListener;
import com.android.internal.widget.IWeakEscrowTokenActivatedListener;
import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.RebootEscrowListener;
import com.android.internal.widget.VerifyCredentialResponse;
@@ -185,6 +184,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -332,8 +332,8 @@
private HashMap<UserHandle, UserManager> mUserManagerCache = new HashMap<>();
- private final RemoteCallbackList<ILockSettingsStateListener> mLockSettingsStateListeners =
- new RemoteCallbackList<>();
+ private final CopyOnWriteArrayList<LockSettingsStateListener> mLockSettingsStateListeners =
+ new CopyOnWriteArrayList<>();
// This class manages life cycle events for encrypted users on File Based Encryption (FBE)
// devices. The most basic of these is to show/hide notifications about missing features until
@@ -2379,25 +2379,12 @@
}
private void notifyLockSettingsStateListeners(boolean success, int userId) {
- int i = mLockSettingsStateListeners.beginBroadcast();
- try {
- while (i > 0) {
- i--;
- try {
- if (success) {
- mLockSettingsStateListeners.getBroadcastItem(i)
- .onAuthenticationSucceeded(userId);
- } else {
- mLockSettingsStateListeners.getBroadcastItem(i)
- .onAuthenticationFailed(userId);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception while notifying LockSettingsStateListener:"
- + " success = " + success + ", userId = " + userId, e);
- }
+ for (LockSettingsStateListener listener : mLockSettingsStateListeners) {
+ if (success) {
+ listener.onAuthenticationSucceeded(userId);
+ } else {
+ listener.onAuthenticationFailed(userId);
}
- } finally {
- mLockSettingsStateListeners.finishBroadcast();
}
}
@@ -3720,15 +3707,15 @@
}
@Override
- public void registerLockSettingsStateListener(
- @NonNull ILockSettingsStateListener listener) {
- mLockSettingsStateListeners.register(listener);
+ public void registerLockSettingsStateListener(@NonNull LockSettingsStateListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ mLockSettingsStateListeners.add(listener);
}
@Override
public void unregisterLockSettingsStateListener(
- @NonNull ILockSettingsStateListener listener) {
- mLockSettingsStateListeners.unregister(listener);
+ @NonNull LockSettingsStateListener listener) {
+ mLockSettingsStateListeners.remove(listener);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 0bbad85..dc97e5f 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -819,6 +819,7 @@
* <p> The icon is returned without any treatment/overlay. In the rare case the app had multiple
* launcher activities, only one of the icons is returned arbitrarily.
*/
+ @Nullable
public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user,
String callingPackageName) {
Objects.requireNonNull(packageName);
@@ -844,7 +845,7 @@
// In the rare case the archived app defined more than two launcher activities, we choose
// the first one arbitrarily.
Bitmap icon = decodeIcon(archiveState.getActivityInfos().get(0));
- if (getAppOpsManager().checkOp(
+ if (icon != null && getAppOpsManager().checkOp(
AppOpsManager.OP_ARCHIVE_ICON_OVERLAY, callingUid, callingPackageName)
== MODE_ALLOWED) {
icon = includeCloudOverlay(icon);
@@ -900,6 +901,7 @@
return bitmap;
}
+ @Nullable
Bitmap includeCloudOverlay(Bitmap bitmap) {
Drawable cloudDrawable =
mContext.getResources()
@@ -920,7 +922,9 @@
final int iconSize = mContext.getSystemService(
ActivityManager.class).getLauncherLargeIconSize();
Bitmap appIconWithCloudOverlay = drawableToBitmap(layerDrawable, iconSize);
- bitmap.recycle();
+ if (bitmap != null) {
+ bitmap.recycle();
+ }
return appIconWithCloudOverlay;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 716aee3..e743172 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5150,6 +5150,15 @@
/** @return the orientation of the display when it's rotation is ROTATION_0. */
int getNaturalOrientation() {
+ return mBaseDisplayWidth <= mBaseDisplayHeight
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ }
+
+ /**
+ * Returns the orientation which is used for app's Configuration (excluding decor insets) when
+ * the display rotation is ROTATION_0.
+ */
+ int getNaturalConfigurationOrientation() {
final Configuration config = getConfiguration();
if (config.windowConfiguration.getDisplayRotation() == ROTATION_0) {
return config.orientation;
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 34d7651..4204670 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -132,7 +132,7 @@
void show(SurfaceControl.Transaction t, WindowContainer w) {
t.show(mInputSurface);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
- t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
+ t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1 + w.getChildCount());
}
void show(SurfaceControl.Transaction t, int layer) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 2d2857a..80894b2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1589,7 +1589,7 @@
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
// NOSENSOR means the display's "natural" orientation, so return that.
if (mDisplayContent != null) {
- return mDisplayContent.getNaturalOrientation();
+ return mDisplayContent.getNaturalConfigurationOrientation();
}
} else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// LOCKED means the activity's orientation remains unchanged, so return existing value.
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index cc08488..df7fb99 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -31,5 +31,8 @@
per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
per-file com_android_server_companion_virtual_InputController.cpp = file:/services/companion/java/com/android/server/companion/virtual/OWNERS
+# Memory
+per-file com_android_server_am_OomConnection.cpp = file:/MEMORY_OWNERS
+
# Bug component : 158088 = per-file *AnrTimer*
per-file *AnrTimer* = file:/PERFORMANCE_OWNERS
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 4a6b31c..810090a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -285,6 +285,7 @@
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiLightsOut(bool lightsOut);
void setPointerDisplayId(int32_t displayId);
+ int32_t getMousePointerSpeed();
void setPointerSpeed(int32_t speed);
void setMousePointerAccelerationEnabled(int32_t displayId, bool enabled);
void setTouchpadPointerSpeed(int32_t speed);
@@ -1219,6 +1220,11 @@
}
}
+int32_t NativeInputManager::getMousePointerSpeed() {
+ std::scoped_lock _l(mLock);
+ return mLocked.pointerSpeed;
+}
+
void NativeInputManager::setPointerSpeed(int32_t speed) {
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -2211,6 +2217,12 @@
}
}
+static jint nativeGetMousePointerSpeed(JNIEnv* env, jobject nativeImplObj) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+ return static_cast<jint>(im->getMousePointerSpeed());
+}
+
static void nativeSetPointerSpeed(JNIEnv* env, jobject nativeImplObj, jint speed) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -2865,6 +2877,7 @@
{"transferTouchFocus", "(Landroid/os/IBinder;Landroid/os/IBinder;Z)Z",
(void*)nativeTransferTouchFocus},
{"transferTouch", "(Landroid/os/IBinder;I)Z", (void*)nativeTransferTouch},
+ {"getMousePointerSpeed", "()I", (void*)nativeGetMousePointerSpeed},
{"setPointerSpeed", "(I)V", (void*)nativeSetPointerSpeed},
{"setMousePointerAccelerationEnabled", "(IZ)V",
(void*)nativeSetMousePointerAccelerationEnabled},
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 5081198..7053597 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -39,7 +39,6 @@
import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
-import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -49,8 +48,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.widget.ILockSettingsStateListener;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsStateListener;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
@@ -412,7 +411,7 @@
mSetFlagsRule.enableFlags(FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS);
final LockscreenCredential password = newPassword("password");
setCredential(PRIMARY_USER_ID, password);
- final ILockSettingsStateListener listener = mockLockSettingsStateListener();
+ final LockSettingsStateListener listener = mock(LockSettingsStateListener.class);
mLocalService.registerLockSettingsStateListener(listener);
assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -429,7 +428,7 @@
final LockscreenCredential password = newPassword("password");
setCredential(PRIMARY_USER_ID, password);
final LockscreenCredential badPassword = newPassword("badPassword");
- final ILockSettingsStateListener listener = mockLockSettingsStateListener();
+ final LockSettingsStateListener listener = mock(LockSettingsStateListener.class);
mLocalService.registerLockSettingsStateListener(listener);
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
@@ -445,7 +444,7 @@
final LockscreenCredential password = newPassword("password");
setCredential(PRIMARY_USER_ID, password);
final LockscreenCredential badPassword = newPassword("badPassword");
- final ILockSettingsStateListener listener = mockLockSettingsStateListener();
+ final LockSettingsStateListener listener = mock(LockSettingsStateListener.class);
mLocalService.registerLockSettingsStateListener(listener);
assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -599,12 +598,4 @@
assertNotEquals(0, mGateKeeperService.getSecureUserId(userId));
}
}
-
- private ILockSettingsStateListener mockLockSettingsStateListener() {
- ILockSettingsStateListener listener = mock(ILockSettingsStateListener.Stub.class);
- IBinder binder = mock(IBinder.class);
- when(binder.isBinderAlive()).thenReturn(true);
- when(listener.asBinder()).thenReturn(binder);
- return listener;
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 95850ac..f63ff6e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1003,7 +1003,13 @@
dc.computeScreenConfiguration(config, ROTATION_0);
dc.onRequestedOverrideConfigurationChanged(config);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
- assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getNaturalOrientation());
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getNaturalConfigurationOrientation());
+ window.setOverrideOrientation(SCREEN_ORIENTATION_NOSENSOR);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE,
+ window.getRequestedConfigurationOrientation());
+ // Note that getNaturalOrientation is based on logical display size. So it is portrait if
+ // the display width equals to height.
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, dc.getNaturalOrientation());
}
@Test
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
index b57b7c7..bb2ac51 100644
--- a/telecomm/OWNERS
+++ b/telecomm/OWNERS
@@ -6,4 +6,5 @@
rgreenwalt@google.com
grantmenke@google.com
pmadapurmath@google.com
-tjstuart@google.com
\ No newline at end of file
+tjstuart@google.com
+huiwang@google.com
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index eb7e67d..1749545 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1927,34 +1927,25 @@
* Then for SDK 35+, if the caller identity is personal profile, then this will return
* subscription 1 only and vice versa.
*
- * <p> The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
- * {@link SubscriptionInfo#getSubscriptionId}.
+ * <p> Returned records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
+ * {@link SubscriptionInfo#getSubscriptionId}. Beginning with Android SDK 35, this method will
+ * never return null.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see
* {@link TelephonyManager#hasCarrierPrivileges}).
*
- * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
- * <ul>
- * <li>
- * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
- * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
- * invoked in the future.
- * </li>
- * <li>
- * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
- * </li>
- * <li>
- * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
- * then by {@link SubscriptionInfo#getSubscriptionId}.
- * </li>
- * </ul>
+ * @return a list of the active {@link SubscriptionInfo} that is visible to the caller. If
+ * an empty list or null is returned, then there are no active subscriptions that
+ * are visible to the caller. If the number of active subscriptions available to
+ * any caller changes, then this change will be indicated by
+ * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged}.
*
* @throws UnsupportedOperationException If the device does not have
- * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+ * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
+ public @Nullable List<SubscriptionInfo> getActiveSubscriptionInfoList() {
List<SubscriptionInfo> activeList = null;
try {
@@ -1970,6 +1961,8 @@
if (activeList != null) {
activeList = activeList.stream().filter(subInfo -> isSubscriptionVisible(subInfo))
.collect(Collectors.toList());
+ } else {
+ activeList = Collections.emptyList();
}
return activeList;
}
@@ -1998,12 +1991,7 @@
* {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
*/
public @NonNull List<SubscriptionInfo> getCompleteActiveSubscriptionInfoList() {
- List<SubscriptionInfo> completeList = getActiveSubscriptionInfoList(
- /* userVisibleonly */false);
- if (completeList == null) {
- completeList = new ArrayList<>();
- }
- return completeList;
+ return getActiveSubscriptionInfoList(/* userVisibleonly */ false);
}
/**
@@ -2032,7 +2020,7 @@
*
* @hide
*/
- public @Nullable List<SubscriptionInfo> getActiveSubscriptionInfoList(boolean userVisibleOnly) {
+ public @NonNull List<SubscriptionInfo> getActiveSubscriptionInfoList(boolean userVisibleOnly) {
List<SubscriptionInfo> activeList = null;
try {
@@ -2045,11 +2033,13 @@
// ignore it
}
- if (!userVisibleOnly || activeList == null) {
- return activeList;
- } else {
+ if (activeList == null || activeList.isEmpty()) {
+ return Collections.emptyList();
+ } else if (userVisibleOnly) {
return activeList.stream().filter(subInfo -> isSubscriptionVisible(subInfo))
.collect(Collectors.toList());
+ } else {
+ return activeList;
}
}
@@ -2086,7 +2076,7 @@
* @hide
*/
@SystemApi
- public List<SubscriptionInfo> getAvailableSubscriptionInfoList() {
+ public @Nullable List<SubscriptionInfo> getAvailableSubscriptionInfoList() {
List<SubscriptionInfo> result = null;
try {
@@ -2098,7 +2088,7 @@
} catch (RemoteException ex) {
// ignore it
}
- return result;
+ return (result == null) ? Collections.emptyList() : result;
}
/**
@@ -2128,7 +2118,7 @@
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
*/
- public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() {
+ public @Nullable List<SubscriptionInfo> getAccessibleSubscriptionInfoList() {
List<SubscriptionInfo> result = null;
try {
@@ -2139,7 +2129,7 @@
} catch (RemoteException ex) {
// ignore it
}
- return result;
+ return (result == null) ? Collections.emptyList() : result;
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 89661a4..f82463b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18709,9 +18709,9 @@
*/
@SystemApi
@FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
- public static final class EmergencyCallDiagnosticParams {
+ public static final class EmergencyCallDiagnosticData {
public static final class Builder {
- private boolean mCollectTelecomDumpSys;
+ private boolean mCollectTelecomDumpsys;
private boolean mCollectTelephonyDumpsys;
// If this is set to a value other than -1L, then the logcat collection is enabled.
@@ -18724,9 +18724,9 @@
* @param collectTelecomDumpsys Determines whether telecom dumpsys should be collected.
* @return Builder instance corresponding to the configured call diagnostic params.
*/
- public @NonNull Builder setTelecomDumpSysCollectionEnabled(
+ public @NonNull Builder setTelecomDumpsysCollectionEnabled(
boolean collectTelecomDumpsys) {
- mCollectTelecomDumpSys = collectTelecomDumpsys;
+ mCollectTelecomDumpsys = collectTelecomDumpsys;
return this;
}
@@ -18735,7 +18735,7 @@
* @param collectTelephonyDumpsys Determines if telephony dumpsys should be collected.
* @return Builder instance corresponding to the configured call diagnostic params.
*/
- public @NonNull Builder setTelephonyDumpSysCollectionEnabled(
+ public @NonNull Builder setTelephonyDumpsysCollectionEnabled(
boolean collectTelephonyDumpsys) {
mCollectTelephonyDumpsys = collectTelephonyDumpsys;
return this;
@@ -18753,35 +18753,35 @@
}
/**
- * Build the EmergencyCallDiagnosticParams from the provided Builder config.
- * @return {@link EmergencyCallDiagnosticParams} instance from provided builder.
+ * Build the EmergencyCallDiagnosticData from the provided Builder config.
+ * @return {@link EmergencyCallDiagnosticData} instance from provided builder.
*/
- public @NonNull EmergencyCallDiagnosticParams build() {
- return new EmergencyCallDiagnosticParams(mCollectTelecomDumpSys,
+ public @NonNull EmergencyCallDiagnosticData build() {
+ return new EmergencyCallDiagnosticData(mCollectTelecomDumpsys,
mCollectTelephonyDumpsys, mLogcatStartTimeMillis);
}
}
- private boolean mCollectTelecomDumpSys;
+ private boolean mCollectTelecomDumpsys;
private boolean mCollectTelephonyDumpsys;
private boolean mCollectLogcat;
private long mLogcatStartTimeMillis;
private static long sUnsetLogcatStartTime = -1L;
- private EmergencyCallDiagnosticParams(boolean collectTelecomDumpSys,
+ private EmergencyCallDiagnosticData(boolean collectTelecomDumpsys,
boolean collectTelephonyDumpsys, long logcatStartTimeMillis) {
- mCollectTelecomDumpSys = collectTelecomDumpSys;
+ mCollectTelecomDumpsys = collectTelecomDumpsys;
mCollectTelephonyDumpsys = collectTelephonyDumpsys;
mLogcatStartTimeMillis = logcatStartTimeMillis;
mCollectLogcat = logcatStartTimeMillis != sUnsetLogcatStartTime;
}
- public boolean isTelecomDumpSysCollectionEnabled() {
- return mCollectTelecomDumpSys;
+ public boolean isTelecomDumpsysCollectionEnabled() {
+ return mCollectTelecomDumpsys;
}
- public boolean isTelephonyDumpSysCollectionEnabled() {
+ public boolean isTelephonyDumpsysCollectionEnabled() {
return mCollectTelephonyDumpsys;
}
@@ -18796,12 +18796,12 @@
@Override
public String toString() {
- return "EmergencyCallDiagnosticParams{" +
- "mCollectTelecomDumpSys=" + mCollectTelecomDumpSys +
- ", mCollectTelephonyDumpsys=" + mCollectTelephonyDumpsys +
- ", mCollectLogcat=" + mCollectLogcat +
- ", mLogcatStartTimeMillis=" + mLogcatStartTimeMillis +
- '}';
+ return "EmergencyCallDiagnosticData{"
+ + "mCollectTelecomDumpsys=" + mCollectTelecomDumpsys
+ + ", mCollectTelephonyDumpsys=" + mCollectTelephonyDumpsys
+ + ", mCollectLogcat=" + mCollectLogcat
+ + ", mLogcatStartTimeMillis=" + mLogcatStartTimeMillis
+ + '}';
}
}
@@ -18809,7 +18809,7 @@
* Request telephony to persist state for debugging emergency call failures.
*
* @param dropboxTag Tag to use when persisting data to dropbox service.
- * @param params Parameters controlling what is collected.
+ * @param data Parameters controlling what is collected in the diagnostics.
*
* @hide
*/
@@ -18817,7 +18817,7 @@
@FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
@RequiresPermission(android.Manifest.permission.DUMP)
public void persistEmergencyCallDiagnosticData(@NonNull String dropboxTag,
- @NonNull EmergencyCallDiagnosticParams params) {
+ @NonNull EmergencyCallDiagnosticData data) {
try {
ITelephony telephony = ITelephony.Stub.asInterface(
TelephonyFrameworkInitializer
@@ -18826,10 +18826,10 @@
.get());
if (telephony != null) {
telephony.persistEmergencyCallDiagnosticData(dropboxTag,
- params.isLogcatCollectionEnabled(),
- params.getLogcatCollectionStartTimeMillis(),
- params.isTelecomDumpSysCollectionEnabled(),
- params.isTelephonyDumpSysCollectionEnabled());
+ data.isLogcatCollectionEnabled(),
+ data.getLogcatCollectionStartTimeMillis(),
+ data.isTelecomDumpsysCollectionEnabled(),
+ data.isTelephonyDumpsysCollectionEnabled());
}
} catch (RemoteException e) {
Log.e(TAG, "Error while persistEmergencyCallDiagnosticData: " + e);