diff options
20 files changed, 356 insertions, 417 deletions
diff --git a/boot/preloaded-classes b/boot/preloaded-classes index a696e03d5bdf..afd9984cb124 100644 --- a/boot/preloaded-classes +++ b/boot/preloaded-classes @@ -6469,6 +6469,7 @@ android.os.connectivity.WifiActivityEnergyInfo$1 android.os.connectivity.WifiActivityEnergyInfo android.os.connectivity.WifiBatteryStats$1 android.os.connectivity.WifiBatteryStats +android.os.flagging.AconfigPackage android.os.health.HealthKeys$Constant android.os.health.HealthKeys$Constants android.os.health.HealthKeys$SortedIntArray diff --git a/config/preloaded-classes b/config/preloaded-classes index ed402767ee64..343de0bf3b98 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -6473,6 +6473,7 @@ android.os.connectivity.WifiActivityEnergyInfo$1 android.os.connectivity.WifiActivityEnergyInfo android.os.connectivity.WifiBatteryStats$1 android.os.connectivity.WifiBatteryStats +android.os.flagging.AconfigPackage android.os.health.HealthKeys$Constant android.os.health.HealthKeys$Constants android.os.health.HealthKeys$SortedIntArray diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp index 634098074cca..9b7200436f02 100644 --- a/core/tests/overlaytests/host/Android.bp +++ b/core/tests/overlaytests/host/Android.bp @@ -28,14 +28,14 @@ java_test_host { test_suites: [ "device-tests", ], - target_required: [ - "OverlayHostTests_NonPlatformSignatureOverlay", - "OverlayHostTests_PlatformSignatureStaticOverlay", - "OverlayHostTests_PlatformSignatureOverlay", - "OverlayHostTests_UpdateOverlay", - "OverlayHostTests_FrameworkOverlayV1", - "OverlayHostTests_FrameworkOverlayV2", - "OverlayHostTests_AppOverlayV1", - "OverlayHostTests_AppOverlayV2", + device_common_data: [ + ":OverlayHostTests_NonPlatformSignatureOverlay", + ":OverlayHostTests_PlatformSignatureStaticOverlay", + ":OverlayHostTests_PlatformSignatureOverlay", + ":OverlayHostTests_UpdateOverlay", + ":OverlayHostTests_FrameworkOverlayV1", + ":OverlayHostTests_FrameworkOverlayV2", + ":OverlayHostTests_AppOverlayV1", + ":OverlayHostTests_AppOverlayV2", ], } diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java index b893b45611fb..ac2927711c9a 100644 --- a/mms/java/android/telephony/MmsManager.java +++ b/mms/java/android/telephony/MmsManager.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import com.android.internal.telephony.IMms; @@ -69,9 +70,9 @@ public class MmsManager { return; } - iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri, - locationUrl, configOverrides, sentIntent, messageId, - mContext.getAttributionTag()); + iMms.sendMessage(subId, /* placeholder callingUser= */ UserHandle.USER_NULL, + ActivityThread.currentPackageName(), contentUri, locationUrl, + configOverrides, sentIntent, messageId, mContext.getAttributionTag()); } catch (RemoteException e) { // Ignore it } @@ -101,9 +102,9 @@ public class MmsManager { if (iMms == null) { return; } - iMms.downloadMessage(subId, ActivityThread.currentPackageName(), - locationUrl, contentUri, configOverrides, downloadedIntent, - messageId, mContext.getAttributionTag()); + iMms.downloadMessage(subId, /* placeholder callingUser= */ UserHandle.USER_NULL, + ActivityThread.currentPackageName(), locationUrl, contentUri, + configOverrides, downloadedIntent, messageId, mContext.getAttributionTag()); } catch (RemoteException e) { // Ignore it } diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl index 3cdde10e4fc2..1c7595164de2 100644 --- a/mms/java/com/android/internal/telephony/IMms.aidl +++ b/mms/java/com/android/internal/telephony/IMms.aidl @@ -29,6 +29,7 @@ interface IMms { * Send an MMS message with attribution tag. * * @param subId the SIM id + * @param callingUser user id of the calling app * @param callingPkg the package name of the calling app * @param contentUri the content uri from which to read MMS message encoded in standard MMS * PDU format @@ -40,7 +41,7 @@ interface IMms { * @param messageId An id that uniquely identifies the message requested to be sent. * @param attributionTag a tag that attributes the call to a client App. */ - void sendMessage(int subId, String callingPkg, in Uri contentUri, + void sendMessage(int subId, in int callingUser, String callingPkg, in Uri contentUri, String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent, in long messageId, String attributionTag); @@ -48,6 +49,7 @@ interface IMms { * Download an MMS message using known location and transaction id * * @param subId the SIM id + * @param callingUser user id of the calling app * @param callingPkg the package name of the calling app * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained * from the MMS WAP push notification @@ -60,7 +62,7 @@ interface IMms { * @param messageId An id that uniquely identifies the message requested to be downloaded. * @param attributionTag a tag that attributes the call to a client App. */ - void downloadMessage(int subId, String callingPkg, String locationUrl, + void downloadMessage(int subId, in int callingUser, String callingPkg, String locationUrl, in Uri contentUri, in Bundle configOverrides, in PendingIntent downloadedIntent, in long messageId, String attributionTag); @@ -82,6 +84,7 @@ interface IMms { /** * Import a multimedia message into system's MMS store * + * @param callingUser user id of the calling app * @param callingPkg the package name of the calling app * @param contentUri the content uri from which to read PDU of the message to import * @param messageId the optional message id @@ -90,7 +93,7 @@ interface IMms { * @param read if the message is read * @return the message URI, null if failed */ - Uri importMultimediaMessage(String callingPkg, in Uri contentUri, String messageId, + Uri importMultimediaMessage(in int callingUser, String callingPkg, in Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read); /** @@ -146,11 +149,12 @@ interface IMms { /** * Add a multimedia message draft to system MMS store * + * @param callingUser user id of the calling app * @param callingPkg the package name of the calling app * @param contentUri the content Uri from which to read PDU data of the draft MMS * @return the URI of the stored draft message */ - Uri addMultimediaMessageDraft(String callingPkg, in Uri contentUri); + Uri addMultimediaMessageDraft(in int callingUser, String callingPkg, in Uri contentUri); /** * Send a system stored MMS message diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index cf11ac028858..6bd6072a2f43 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -200,9 +200,11 @@ package android.nfc { method @Nullable @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public android.nfc.T4tNdefNfceeCcFileInfo readCcfile(); method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public byte[] readData(@IntRange(from=0, to=65535) int); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int writeData(@IntRange(from=0, to=65535) int, @NonNull byte[]); + field public static final int CLEAR_DATA_FAILED_DEVICE_BUSY = -1; // 0xffffffff field public static final int CLEAR_DATA_FAILED_INTERNAL = 0; // 0x0 field public static final int CLEAR_DATA_SUCCESS = 1; // 0x1 field public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6; // 0xfffffffa + field public static final int WRITE_DATA_ERROR_DEVICE_BUSY = -9; // 0xfffffff7 field public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; // 0xfffffff9 field public static final int WRITE_DATA_ERROR_INTERNAL = -1; // 0xffffffff field public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4; // 0xfffffffc @@ -217,21 +219,14 @@ package android.nfc { method public int describeContents(); method @IntRange(from=15, to=32767) public int getCcFileLength(); method @IntRange(from=0xffffffff, to=65535) public int getFileId(); - method @IntRange(from=15, to=65535) public int getMaxReadLength(); method @IntRange(from=5, to=32767) public int getMaxSize(); - method @IntRange(from=13, to=65535) public int getMaxWriteLength(); - method public int getReadAccess(); method public int getVersion(); - method public int getWriteAccess(); + method public boolean isReadAllowed(); + method public boolean isWriteAllowed(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.nfc.T4tNdefNfceeCcFileInfo> CREATOR; - field public static final int READ_ACCESS_GRANTED_RESTRICTED = 128; // 0x80 - field public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0 field public static final int VERSION_2_0 = 32; // 0x20 field public static final int VERSION_3_0 = 48; // 0x30 - field public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 128; // 0x80 - field public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0 - field public static final int WRITE_ACCESS_NOT_GRANTED = 255; // 0xff } } diff --git a/nfc/java/android/nfc/T4tNdefNfcee.java b/nfc/java/android/nfc/T4tNdefNfcee.java index 06d02c54eb2e..05a30aad76fc 100644 --- a/nfc/java/android/nfc/T4tNdefNfcee.java +++ b/nfc/java/android/nfc/T4tNdefNfcee.java @@ -100,9 +100,14 @@ public final class T4tNdefNfcee { public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; /** * Returns flag for {@link #writeData(int, byte[])}. - * It idicates write data fail due to invalid ndef format. + * It indicates write data fail due to invalid ndef format. */ public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8; + /** + * Returns flag for {@link #writeData(int, byte[])}. + * It indicates write data fail if a concurrent NDEF NFCEE operation is ongoing. + */ + public static final int WRITE_DATA_ERROR_DEVICE_BUSY = -9; /** * Possible return values for {@link #writeData(int, byte[])}. @@ -119,6 +124,7 @@ public final class T4tNdefNfcee { WRITE_DATA_ERROR_CONNECTION_FAILED, WRITE_DATA_ERROR_EMPTY_PAYLOAD, WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED, + WRITE_DATA_ERROR_DEVICE_BUSY, }) @Retention(RetentionPolicy.SOURCE) public @interface WriteDataStatus{} @@ -128,6 +134,9 @@ public final class T4tNdefNfcee { * * <p>This is an I/O operation and will block until complete. It must * not be called from the main application thread.</p> + * <p>Applications must send complete Ndef Message payload, do not need to fragment + * the payload, it will be automatically fragmented and defragmented by + * {@link #writeData} if it exceeds max message length limits</p> * * @param fileId File id (Refer NFC Forum Type 4 Tag Specification * Section 4.2 File Identifiers and Access Conditions @@ -155,9 +164,10 @@ public final class T4tNdefNfcee { * @param fileId File Id (Refer * Section 4.2 File Identifiers and Access Conditions * for more information) from which to read. - * @return - Returns Ndef message if success + * @return - Returns complete Ndef message if success * Refer to Nfc forum NDEF specification NDEF Message section - * @throws IllegalStateException if read fails because the fileId is invalid. + * @throws IllegalStateException if read fails because the fileId is invalid + * or if a concurrent operation is in progress. * @hide */ @SystemApi @@ -179,6 +189,12 @@ public final class T4tNdefNfcee { * It indicates clear data failed due to internal error while processing the clear. */ public static final int CLEAR_DATA_FAILED_INTERNAL = 0; + /** + * Return flag for {@link #clearNdefData()}. + * It indicates clear data failed if a concurrent NDEF NFCEE operation is ongoing. + */ + public static final int CLEAR_DATA_FAILED_DEVICE_BUSY = -1; + /** * Possible return values for {@link #clearNdefData()}. @@ -188,6 +204,7 @@ public final class T4tNdefNfcee { @IntDef(prefix = { "CLEAR_DATA_" }, value = { CLEAR_DATA_SUCCESS, CLEAR_DATA_FAILED_INTERNAL, + CLEAR_DATA_FAILED_DEVICE_BUSY, }) @Retention(RetentionPolicy.SOURCE) public @interface ClearDataStatus{} @@ -245,6 +262,7 @@ public final class T4tNdefNfcee { * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details. * * @return Returns CC file content if success or null if failed to read. + * @throws IllegalStateException if the device is busy. * @hide */ @SystemApi diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java index 5fca0529124e..ce67f8f9aea7 100644 --- a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java +++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java @@ -47,14 +47,6 @@ public final class T4tNdefNfceeCcFileInfo implements Parcelable { */ private int mVersion; /** - * Indicates the max data size by a single ReadBinary<p> - */ - private int mMaxReadLength; - /** - * Indicates the max data size by a single UpdateBinary<p> - */ - private int mMaxWriteLength; - /** * Indicates the NDEF File Identifier<p> */ private int mFileId; @@ -65,40 +57,35 @@ public final class T4tNdefNfceeCcFileInfo implements Parcelable { /** * Indicates the read access condition<p> */ - private int mReadAccess; + private boolean mIsReadAllowed; /** * Indicates the write access condition<p> */ - private int mWriteAccess; + private boolean mIsWriteAllowed; /** * Constructor to be used by NFC service and internal classes. * @hide */ - public T4tNdefNfceeCcFileInfo(int cclen, int version, int maxLe, int maxLc, + public T4tNdefNfceeCcFileInfo(int cclen, int version, int ndefFileId, int ndefMaxSize, - int ndefReadAccess, int ndefWriteAccess) { + boolean isReadAllowed, boolean isWriteAllowed) { mCcLength = cclen; mVersion = version; - mMaxWriteLength = maxLc; - mMaxReadLength = maxLe; mFileId = ndefFileId; mMaxSize = ndefMaxSize; - mReadAccess = ndefReadAccess; - mWriteAccess = ndefWriteAccess; + mIsReadAllowed = isReadAllowed; + mIsWriteAllowed = isWriteAllowed; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mCcLength); dest.writeInt(mVersion); - dest.writeInt(mMaxWriteLength); - dest.writeInt(mMaxReadLength); dest.writeInt(mFileId); dest.writeInt(mMaxSize); - dest.writeInt(mReadAccess); - dest.writeInt(mWriteAccess); + dest.writeBoolean(mIsReadAllowed); + dest.writeBoolean(mIsWriteAllowed); } /** @@ -146,30 +133,6 @@ public final class T4tNdefNfceeCcFileInfo implements Parcelable { } /** - * Indicates the max data size that can be read by a single invocation of - * {@link T4tNdefNfcee#readData(int)}. - * - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLe. - * @return max size of read (in bytes). - */ - @IntRange(from = 0xf, to = 0xffff) - public int getMaxReadLength() { - return mMaxReadLength; - } - - /** - * Indicates the max data size that can be written by a single invocation of - * {@link T4tNdefNfcee#writeData(int, byte[])} - * - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLc. - * @return max size of write (in bytes). - */ - @IntRange(from = 0xd, to = 0xffff) - public int getMaxWriteLength() { - return mMaxWriteLength; - } - - /** * Indicates the NDEF File Identifier. This is the identifier used in the last invocation of * {@link T4tNdefNfcee#writeData(int, byte[])} * @@ -191,73 +154,21 @@ public final class T4tNdefNfceeCcFileInfo implements Parcelable { } /** - * T4T tag read access granted without any security. - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - */ - public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0x0; - /** - * T4T tag read access granted with limited proprietary access only. - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - */ - public static final int READ_ACCESS_GRANTED_RESTRICTED = 0x80; - - /** - * Possible return values for {@link #getVersion()}. - * @hide - */ - @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = { - READ_ACCESS_GRANTED_RESTRICTED, - READ_ACCESS_GRANTED_UNRESTRICTED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ReadAccess {} - - /** * Indicates the read access condition. * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - * @return read access restriction + * @return boolean true if read access is allowed, otherwise false. */ - @ReadAccess - public int getReadAccess() { - return mReadAccess; + public boolean isReadAllowed() { + return mIsReadAllowed; } /** - * T4T tag write access granted without any security. - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - */ - public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0x0; - /** - * T4T tag write access granted with limited proprietary access only. - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - */ - public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 0x80; - /** - * T4T tag write access not granted. - * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - */ - public static final int WRITE_ACCESS_NOT_GRANTED = 0xFF; - - /** - * Possible return values for {@link #getVersion()}. - * @hide - */ - @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = { - WRITE_ACCESS_GRANTED_RESTRICTED, - WRITE_ACCESS_GRANTED_UNRESTRICTED, - WRITE_ACCESS_NOT_GRANTED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface WriteAccess {} - - /** * Indicates the write access condition. * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details. - * @return write access restriction + * @return boolean if write access is allowed, otherwise false. */ - @WriteAccess - public int getWriteAccess() { - return mWriteAccess; + public boolean isWriteAllowed() { + return mIsWriteAllowed; } @Override @@ -273,16 +184,14 @@ public final class T4tNdefNfceeCcFileInfo implements Parcelable { // NdefNfceeCcFileInfo fields int cclen = in.readInt(); int version = in.readInt(); - int maxLe = in.readInt(); - int maxLc = in.readInt(); int ndefFileId = in.readInt(); int ndefMaxSize = in.readInt(); - int ndefReadAccess = in.readInt(); - int ndefWriteAccess = in.readInt(); + boolean isReadAllowed = in.readBoolean(); + boolean isWriteAllowed = in.readBoolean(); - return new T4tNdefNfceeCcFileInfo(cclen, version, maxLe, maxLc, + return new T4tNdefNfceeCcFileInfo(cclen, version, ndefFileId, ndefMaxSize, - ndefReadAccess, ndefWriteAccess); + isReadAllowed, isWriteAllowed); } @Override diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index 2227943c0cc0..9140cefe4574 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -66,7 +66,6 @@ import java.util.Map; public final class DeviceConfigService extends Binder { private static final List<String> sAconfigTextProtoFilesOnDevice = List.of( "/system/etc/aconfig_flags.pb", - "/system_ext/etc/aconfig_flags.pb", "/product/etc/aconfig_flags.pb", "/vendor/etc/aconfig_flags.pb"); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 68b66dfa2657..3b4988e1f0e6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -171,7 +171,6 @@ final class SettingsState { private static final List<String> sAconfigTextProtoFilesOnDevice = List.of( "/system/etc/aconfig_flags.pb", - "/system_ext/etc/aconfig_flags.pb", "/product/etc/aconfig_flags.pb", "/vendor/etc/aconfig_flags.pb"); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt index 032979447861..0a4198a99bba 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt @@ -32,7 +32,8 @@ import java.util.Optional import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -125,14 +126,11 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes ) underTest = - HomeControlsKeyguardQuickAffordanceConfig( - context = context, - component = component, - ) + HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component) } @Test - fun state() = runBlockingTest { + fun state() = runTest(UnconfinedTestDispatcher()) { whenever(component.isEnabled()).thenReturn(isFeatureEnabled) whenever(controlsController.getFavorites()) .thenReturn( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt index 7d68cc0a3560..c9b436614505 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt @@ -19,19 +19,20 @@ package com.android.systemui.keyguard.data.quickaffordance import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult +import com.android.systemui.res.R import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import java.util.Optional import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -54,14 +55,11 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true)) underTest = - HomeControlsKeyguardQuickAffordanceConfig( - context = context, - component = component, - ) + HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component) } @Test - fun state_whenCannotShowWhileLocked_returnsHidden() = runBlockingTest { + fun state_whenCannotShowWhileLocked_returnsHidden() = runTest(UnconfinedTestDispatcher()) { whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false)) whenever(component.isEnabled()).thenReturn(true) whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon) @@ -81,7 +79,7 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } @Test - fun state_whenListingControllerIsMissing_returnsHidden() = runBlockingTest { + fun state_whenListingControllerIsMissing_returnsHidden() = runTest(UnconfinedTestDispatcher()) { whenever(component.isEnabled()).thenReturn(true) whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon) whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title) @@ -100,23 +98,25 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } @Test - fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() = runBlockingTest { - whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true)) + fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() = + runTest(UnconfinedTestDispatcher()) { + whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true)) - val onClickedResult = underTest.onTriggered(expandable) + val onClickedResult = underTest.onTriggered(expandable) - assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) - assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue() - } + assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) + assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue() + } @Test - fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() = runBlockingTest { - whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false)) + fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() = + runTest(UnconfinedTestDispatcher()) { + whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false)) - val onClickedResult = underTest.onTriggered(expandable) + val onClickedResult = underTest.onTriggered(expandable) - assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) - assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked) - .isFalse() - } + assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) + assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked) + .isFalse() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt index ca64cec98b2e..a3f07634940e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt @@ -29,7 +29,7 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -56,60 +56,63 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } @Test - fun affordance_setsUpRegistrationAndDeliversInitialModel() = runBlockingTest { - whenever(controller.isEnabledForLockScreenButton).thenReturn(true) - var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - - val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + fun affordance_setsUpRegistrationAndDeliversInitialModel() = + runTest(UnconfinedTestDispatcher()) { + whenever(controller.isEnabledForLockScreenButton).thenReturn(true) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + + val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() + verify(controller).addCallback(callbackCaptor.capture()) + verify(controller) + .registerQRCodeScannerChangeObservers( + QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, + QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE, + ) + assertVisibleState(latest) - val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() - verify(controller).addCallback(callbackCaptor.capture()) - verify(controller) - .registerQRCodeScannerChangeObservers( - QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, - QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE - ) - assertVisibleState(latest) - - job.cancel() - verify(controller).removeCallback(callbackCaptor.value) - } + job.cancel() + verify(controller).removeCallback(callbackCaptor.value) + } @Test - fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = runBlockingTest { - whenever(controller.isEnabledForLockScreenButton).thenReturn(true) - var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() - verify(controller).addCallback(callbackCaptor.capture()) + fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = + runTest(UnconfinedTestDispatcher()) { + whenever(controller.isEnabledForLockScreenButton).thenReturn(true) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() + verify(controller).addCallback(callbackCaptor.capture()) - whenever(controller.intent).thenReturn(INTENT_2) - callbackCaptor.value.onQRCodeScannerActivityChanged() + whenever(controller.intent).thenReturn(INTENT_2) + callbackCaptor.value.onQRCodeScannerActivityChanged() - assertVisibleState(latest) + assertVisibleState(latest) - job.cancel() - verify(controller).removeCallback(callbackCaptor.value) - } + job.cancel() + verify(controller).removeCallback(callbackCaptor.value) + } @Test - fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest { - var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() - verify(controller).addCallback(callbackCaptor.capture()) + fun affordance_scannerPreferenceChanged_deliversVisibleModel() = + runTest(UnconfinedTestDispatcher()) { + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() + verify(controller).addCallback(callbackCaptor.capture()) - whenever(controller.isEnabledForLockScreenButton).thenReturn(true) - callbackCaptor.value.onQRCodeScannerPreferenceChanged() + whenever(controller.isEnabledForLockScreenButton).thenReturn(true) + callbackCaptor.value.onQRCodeScannerPreferenceChanged() - assertVisibleState(latest) + assertVisibleState(latest) - job.cancel() - verify(controller).removeCallback(callbackCaptor.value) - } + job.cancel() + verify(controller).removeCallback(callbackCaptor.value) + } @Test - fun affordance_scannerPreferenceChanged_deliversNone() = runBlockingTest { + fun affordance_scannerPreferenceChanged_deliversNone() = runTest(UnconfinedTestDispatcher()) { var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() @@ -128,30 +131,29 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { fun onQuickAffordanceTriggered() { assertThat(underTest.onTriggered(mock())) .isEqualTo( - OnTriggeredResult.StartActivity( - intent = INTENT_1, - canShowWhileLocked = true, - ) + OnTriggeredResult.StartActivity(intent = INTENT_1, canShowWhileLocked = true) ) } @Test - fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = runTest { - whenever(controller.isAllowedOnLockScreen).thenReturn(true) - whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true) + fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = + runTest(UnconfinedTestDispatcher()) { + whenever(controller.isAllowedOnLockScreen).thenReturn(true) + whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true) - assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default()) - } + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default()) + } @Test - fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = runTest { - whenever(controller.isAllowedOnLockScreen).thenReturn(true) - whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false) - - assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) - } + fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = + runTest(UnconfinedTestDispatcher()) { + whenever(controller.isAllowedOnLockScreen).thenReturn(true) + whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false) + + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) { assertThat(latest) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS index 1f66c91b3573..1ed8c068f974 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS @@ -1,3 +1,4 @@ # Bug component: 44215 -include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file +include /core/java/android/view/accessibility/OWNERS +jonesriley@google.com
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt index 2c1718176571..bfbdc50c32b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt @@ -24,9 +24,9 @@ import android.os.Handler import android.os.Looper import android.os.PatternMatcher import android.os.UserHandle -import androidx.test.filters.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger import com.android.systemui.dump.DumpManager @@ -40,8 +40,9 @@ import java.util.concurrent.Executor import junit.framework.Assert.assertSame import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.advanceUntilIdle -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -68,39 +69,28 @@ class BroadcastDispatcherTest : SysuiTestCase() { val DEFAULT_PERMISSION: String? = null fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + const val TEST_ACTION = "TEST_ACTION" const val TEST_SCHEME = "TEST_SCHEME" const val TEST_PATH = "TEST_PATH" const val TEST_TYPE = "test/type" } - @Mock - private lateinit var mockContext: Context - @Mock - private lateinit var mockUBRUser0: UserBroadcastDispatcher - @Mock - private lateinit var mockUBRUser1: UserBroadcastDispatcher - @Mock - private lateinit var broadcastReceiver: BroadcastReceiver - @Mock - private lateinit var broadcastReceiverOther: BroadcastReceiver - @Mock - private lateinit var intentFilter: IntentFilter - @Mock - private lateinit var intentFilterOther: IntentFilter - @Mock - private lateinit var mockHandler: Handler - @Mock - private lateinit var logger: BroadcastDispatcherLogger - @Mock - private lateinit var userTracker: UserTracker - @Mock - private lateinit var removalPendingStore: PendingRemovalStore + @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockUBRUser0: UserBroadcastDispatcher + @Mock private lateinit var mockUBRUser1: UserBroadcastDispatcher + @Mock private lateinit var broadcastReceiver: BroadcastReceiver + @Mock private lateinit var broadcastReceiverOther: BroadcastReceiver + @Mock private lateinit var intentFilter: IntentFilter + @Mock private lateinit var intentFilterOther: IntentFilter + @Mock private lateinit var mockHandler: Handler + @Mock private lateinit var logger: BroadcastDispatcherLogger + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var removalPendingStore: PendingRemovalStore private lateinit var mainExecutor: Executor - @Captor - private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData> + @Captor private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData> private lateinit var testableLooper: TestableLooper private lateinit var broadcastDispatcher: BroadcastDispatcher @@ -112,7 +102,8 @@ class BroadcastDispatcherTest : SysuiTestCase() { mainExecutor = FakeExecutor(FakeSystemClock()) `when`(mockContext.mainExecutor).thenReturn(mainExecutor) - broadcastDispatcher = TestBroadcastDispatcher( + broadcastDispatcher = + TestBroadcastDispatcher( mockContext, mainExecutor, testableLooper.looper, @@ -121,7 +112,8 @@ class BroadcastDispatcherTest : SysuiTestCase() { logger, userTracker, removalPendingStore, - mapOf(0 to mockUBRUser0, 1 to mockUBRUser1)) + mapOf(0 to mockUBRUser0, 1 to mockUBRUser1), + ) // These should be valid filters `when`(intentFilter.countActions()).thenReturn(1) @@ -131,10 +123,18 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test fun testAddingReceiverToCorrectUBR() { - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, user0) broadcastDispatcher.registerReceiverWithHandler( - broadcastReceiverOther, intentFilterOther, mockHandler, user1) + broadcastReceiver, + intentFilter, + mockHandler, + user0, + ) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiverOther, + intentFilterOther, + mockHandler, + user1, + ) testableLooper.processAllMessages() @@ -152,7 +152,11 @@ class BroadcastDispatcherTest : SysuiTestCase() { fun testAddingReceiverToCorrectUBR_executor() { broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mainExecutor, user0) broadcastDispatcher.registerReceiver( - broadcastReceiverOther, intentFilterOther, mainExecutor, user1) + broadcastReceiverOther, + intentFilterOther, + mainExecutor, + user1, + ) testableLooper.processAllMessages() @@ -169,7 +173,10 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test fun testAddReceiverDefaultFlag_handler() { broadcastDispatcher.registerReceiverWithHandler( - broadcastReceiver, intentFilter, mockHandler) + broadcastReceiver, + intentFilter, + mockHandler, + ) testableLooper.processAllMessages() verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG)) @@ -183,7 +190,11 @@ class BroadcastDispatcherTest : SysuiTestCase() { val flag = 3 broadcastDispatcher.registerReceiverWithHandler( - broadcastReceiver, intentFilter, mockHandler, flags = flag) + broadcastReceiver, + intentFilter, + mockHandler, + flags = flag, + ) testableLooper.processAllMessages() verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag)) @@ -212,7 +223,7 @@ class BroadcastDispatcherTest : SysuiTestCase() { broadcastReceiver, intentFilter, flags = flag, - permission = permission + permission = permission, ) testableLooper.processAllMessages() @@ -250,10 +261,18 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test fun testRemovingReceiversRemovesFromAllUBR() { - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, user0) - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, user1) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiver, + intentFilter, + mockHandler, + user0, + ) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiver, + intentFilter, + mockHandler, + user1, + ) broadcastDispatcher.unregisterReceiver(broadcastReceiver) @@ -265,10 +284,18 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test fun testRemoveReceiverFromUser() { - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, user0) - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, user1) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiver, + intentFilter, + mockHandler, + user0, + ) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiver, + intentFilter, + mockHandler, + user1, + ) broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0) @@ -282,13 +309,17 @@ class BroadcastDispatcherTest : SysuiTestCase() { fun testRegisterCurrentAsActualUser() { `when`(userTracker.userId).thenReturn(user1.identifier) - broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, - mockHandler, UserHandle.CURRENT) + broadcastDispatcher.registerReceiverWithHandler( + broadcastReceiver, + intentFilter, + mockHandler, + UserHandle.CURRENT, + ) testableLooper.processAllMessages() - verify(mockUBRUser1).registerReceiver( - capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED)) + verify(mockUBRUser1) + .registerReceiver(capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED)) assertSame(broadcastReceiver, argumentCaptor.value.receiver) } @@ -300,41 +331,38 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test(expected = IllegalArgumentException::class) fun testFilterMustNotContainDataScheme() { - val testFilter = IntentFilter(TEST_ACTION).apply { - addDataScheme(TEST_SCHEME) - } + val testFilter = IntentFilter(TEST_ACTION).apply { addDataScheme(TEST_SCHEME) } broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } @Test(expected = IllegalArgumentException::class) fun testFilterMustNotContainDataAuthority() { - val testFilter = IntentFilter(TEST_ACTION).apply { - addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java)) - } + val testFilter = + IntentFilter(TEST_ACTION).apply { + addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java)) + } broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } @Test(expected = IllegalArgumentException::class) fun testFilterMustNotContainDataPath() { - val testFilter = IntentFilter(TEST_ACTION).apply { - addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL) - } + val testFilter = + IntentFilter(TEST_ACTION).apply { + addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL) + } broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } @Test(expected = IllegalArgumentException::class) fun testFilterMustNotContainDataType() { - val testFilter = IntentFilter(TEST_ACTION).apply { - addDataType(TEST_TYPE) - } + val testFilter = IntentFilter(TEST_ACTION).apply { addDataType(TEST_TYPE) } broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } @Test(expected = IllegalArgumentException::class) fun testFilterMustNotSetPriority() { - val testFilter = IntentFilter(TEST_ACTION).apply { - priority = IntentFilter.SYSTEM_HIGH_PRIORITY - } + val testFilter = + IntentFilter(TEST_ACTION).apply { priority = IntentFilter.SYSTEM_HIGH_PRIORITY } broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } @@ -366,12 +394,14 @@ class BroadcastDispatcherTest : SysuiTestCase() { val inOrderUser0 = inOrder(mockUBRUser0, removalPendingStore) inOrderUser0.verify(mockUBRUser0).unregisterReceiver(broadcastReceiver) - inOrderUser0.verify(removalPendingStore) + inOrderUser0 + .verify(removalPendingStore) .clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL) val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore) inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver) - inOrderUser1.verify(removalPendingStore) + inOrderUser1 + .verify(removalPendingStore) .clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL) } @@ -385,21 +415,21 @@ class BroadcastDispatcherTest : SysuiTestCase() { val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore) inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver) - inOrderUser1.verify(removalPendingStore) + inOrderUser1 + .verify(removalPendingStore) .clearPendingRemoval(broadcastReceiver, user1.identifier) } @Test - fun testBroadcastFlow() = runBlockingTest { - val flow = broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver -> - intent to receiver - } + fun testBroadcastFlow() = runTest(UnconfinedTestDispatcher()) { + val flow = + broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver -> + intent to receiver + } // Collect the values into collectedValues. val collectedValues = mutableListOf<Pair<Intent, BroadcastReceiver>>() - val job = launch { - flow.collect { collectedValues.add(it) } - } + val job = launch { flow.collect { collectedValues.add(it) } } testableLooper.processAllMessages() verify(mockUBRUser1).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG)) @@ -436,17 +466,18 @@ class BroadcastDispatcherTest : SysuiTestCase() { logger: BroadcastDispatcherLogger, userTracker: UserTracker, removalPendingStore: PendingRemovalStore, - var mockUBRMap: Map<Int, UserBroadcastDispatcher> - ) : BroadcastDispatcher( - context, - mainExecutor, - backgroundRunningLooper, - backgroundRunningExecutor, - dumpManager, - logger, - userTracker, - removalPendingStore - ) { + var mockUBRMap: Map<Int, UserBroadcastDispatcher>, + ) : + BroadcastDispatcher( + context, + mainExecutor, + backgroundRunningLooper, + backgroundRunningExecutor, + dumpManager, + logger, + userTracker, + removalPendingStore, + ) { override fun createUBRForUser(userId: Int): UserBroadcastDispatcher { return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt index 0669cb8b8ba5..fceeb752194b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt @@ -37,7 +37,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.TestScope import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -125,11 +125,7 @@ class UserRepositoryImplTest : SysuiTestCase() { whenever(mainUser.identifier).thenReturn(mainUserId) underTest = create(this) - val initialExpectedValue = - setUpUsers( - count = 3, - selectedIndex = 0, - ) + val initialExpectedValue = setUpUsers(count = 3, selectedIndex = 0) var userInfos: List<UserInfo>? = null var selectedUserInfo: UserInfo? = null underTest.userInfos.onEach { userInfos = it }.launchIn(this) @@ -140,23 +136,14 @@ class UserRepositoryImplTest : SysuiTestCase() { assertThat(selectedUserInfo).isEqualTo(initialExpectedValue[0]) assertThat(underTest.lastSelectedNonGuestUserId).isEqualTo(selectedUserInfo?.id) - val secondExpectedValue = - setUpUsers( - count = 4, - selectedIndex = 1, - ) + val secondExpectedValue = setUpUsers(count = 4, selectedIndex = 1) underTest.refreshUsers() assertThat(userInfos).isEqualTo(secondExpectedValue) assertThat(selectedUserInfo).isEqualTo(secondExpectedValue[1]) assertThat(underTest.lastSelectedNonGuestUserId).isEqualTo(selectedUserInfo?.id) val selectedNonGuestUserId = selectedUserInfo?.id - val thirdExpectedValue = - setUpUsers( - count = 2, - isLastGuestUser = true, - selectedIndex = 1, - ) + val thirdExpectedValue = setUpUsers(count = 2, isLastGuestUser = true, selectedIndex = 1) underTest.refreshUsers() assertThat(userInfos).isEqualTo(thirdExpectedValue) assertThat(selectedUserInfo).isEqualTo(thirdExpectedValue[1]) @@ -168,12 +155,7 @@ class UserRepositoryImplTest : SysuiTestCase() { @Test fun refreshUsers_sortsByCreationTime_guestUserLast() = runSelfCancelingTest { underTest = create(this) - val unsortedUsers = - setUpUsers( - count = 3, - selectedIndex = 0, - isLastGuestUser = true, - ) + val unsortedUsers = setUpUsers(count = 3, selectedIndex = 0, isLastGuestUser = true) unsortedUsers[0].creationTime = 999 unsortedUsers[1].creationTime = 900 unsortedUsers[2].creationTime = 950 @@ -197,30 +179,22 @@ class UserRepositoryImplTest : SysuiTestCase() { ): List<UserInfo> { val userInfos = (0 until count).map { index -> - createUserInfo( - index, - isGuest = isLastGuestUser && index == count - 1, - ) + createUserInfo(index, isGuest = isLastGuestUser && index == count - 1) } whenever(manager.aliveUsers).thenReturn(userInfos) tracker.set(userInfos, selectedIndex) return userInfos } + @Test fun userTrackerCallback_updatesSelectedUserInfo() = runSelfCancelingTest { underTest = create(this) var selectedUserInfo: UserInfo? = null underTest.selectedUserInfo.onEach { selectedUserInfo = it }.launchIn(this) - setUpUsers( - count = 2, - selectedIndex = 0, - ) + setUpUsers(count = 2, selectedIndex = 0) tracker.onProfileChanged() assertThat(selectedUserInfo?.id).isEqualTo(0) - setUpUsers( - count = 2, - selectedIndex = 1, - ) + setUpUsers(count = 2, selectedIndex = 1) tracker.onProfileChanged() assertThat(selectedUserInfo?.id).isEqualTo(1) } @@ -259,10 +233,7 @@ class UserRepositoryImplTest : SysuiTestCase() { assertThat(selectedUser!!.selectionStatus).isEqualTo(SelectionStatus.SELECTION_IN_PROGRESS) } - private fun createUserInfo( - id: Int, - isGuest: Boolean, - ): UserInfo { + private fun createUserInfo(id: Int, isGuest: Boolean): UserInfo { val flags = 0 return UserInfo( id, @@ -312,16 +283,14 @@ class UserRepositoryImplTest : SysuiTestCase() { * Executes the given block of execution within the scope of a dedicated [CoroutineScope] which * is then automatically canceled and cleaned-up. */ - private fun runSelfCancelingTest( - block: suspend CoroutineScope.() -> Unit, - ) = + private fun runSelfCancelingTest(block: suspend CoroutineScope.() -> Unit) = runBlocking(Dispatchers.Main.immediate) { val scope = CoroutineScope(coroutineContext + Job()) block(scope) scope.cancel() } - private fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl { + private fun create(scope: CoroutineScope = TestScope()): UserRepositoryImpl { return UserRepositoryImpl( appContext = context, manager = manager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt index 01795e92d141..670c84dcfed2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt @@ -27,6 +27,7 @@ import com.android.internal.logging.UiEventLogger import com.android.systemui.GuestResetOrExitSessionReceiver import com.android.systemui.GuestResumeSessionReceiver import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.model.ShowDialogRequestModel @@ -34,8 +35,9 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.kotlinArgumentCaptor import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -62,9 +64,10 @@ class GuestUserInteractorTest : SysuiTestCase() { @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver @Mock private lateinit var otherContext: Context + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) private lateinit var underTest: GuestUserInteractor - private lateinit var scope: TestCoroutineScope private lateinit var repository: FakeUserRepository @Before @@ -72,7 +75,6 @@ class GuestUserInteractorTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(manager.createGuest(any())).thenReturn(GUEST_USER_INFO) - scope = TestCoroutineScope() repository = FakeUserRepository() repository.setUserInfos(ALL_USERS) @@ -82,17 +84,17 @@ class GuestUserInteractorTest : SysuiTestCase() { private fun initGuestUserInteractor(context: Context) = GuestUserInteractor( applicationContext = context, - applicationScope = scope, - mainDispatcher = IMMEDIATE, - backgroundDispatcher = IMMEDIATE, + applicationScope = testScope, + mainDispatcher = testDispatcher, + backgroundDispatcher = testDispatcher, manager = manager, repository = repository, deviceProvisionedController = deviceProvisionedController, devicePolicyManager = devicePolicyManager, refreshUsersScheduler = RefreshUsersScheduler( - applicationScope = scope, - mainDispatcher = IMMEDIATE, + applicationScope = testScope, + mainDispatcher = testDispatcher, repository = repository, ), uiEventLogger = uiEventLogger, @@ -118,7 +120,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun onDeviceBootCompleted_allowedToAdd_createGuest() = - runBlocking(IMMEDIATE) { + testScope.runTest { setAllowedToAdd() underTest.onDeviceBootCompleted() @@ -129,7 +131,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun onDeviceBootCompleted_awaitProvisioning_andCreateGuest() = - runBlocking(IMMEDIATE) { + testScope.runTest { setAllowedToAdd(isAllowed = false) underTest.onDeviceBootCompleted() val captor = @@ -145,7 +147,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun createAndSwitchTo() = - runBlocking(IMMEDIATE) { + testScope.runTest { underTest.createAndSwitchTo( showDialog = showDialog, dismissDialog = dismissDialog, @@ -160,7 +162,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun createAndSwitchTo_failsToCreate_doesNotSwitchTo() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.createGuest(any())).thenReturn(null) underTest.createAndSwitchTo( @@ -177,7 +179,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_returnsToTargetUser() = - runBlocking(IMMEDIATE) { + testScope.runTest { repository.setSelectedUserInfo(GUEST_USER_INFO) val targetUserId = NON_GUEST_USER_INFO.id @@ -197,7 +199,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_returnsToLastNonGuest() = - runBlocking(IMMEDIATE) { + testScope.runTest { val expectedUserId = NON_GUEST_USER_INFO.id whenever(manager.getUserInfo(expectedUserId)).thenReturn(NON_GUEST_USER_INFO) repository.lastSelectedNonGuestUserId = expectedUserId @@ -219,7 +221,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_lastNonGuestWasRemoved_returnsToMainUser() = - runBlocking(IMMEDIATE) { + testScope.runTest { val removedUserId = 310 val mainUserId = 10 repository.lastSelectedNonGuestUserId = removedUserId @@ -242,7 +244,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_guestWasEphemeral_itIsRemoved() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true) repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO)) repository.setSelectedUserInfo(EPHEMERAL_GUEST_USER_INFO) @@ -265,7 +267,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_forceRemoveGuest_itIsRemoved() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true) repository.setSelectedUserInfo(GUEST_USER_INFO) val targetUserId = NON_GUEST_USER_INFO.id @@ -287,7 +289,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_selectedDifferentFromGuestUser_doNothing() = - runBlocking(IMMEDIATE) { + testScope.runTest { repository.setSelectedUserInfo(NON_GUEST_USER_INFO) underTest.exit( @@ -304,7 +306,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun exit_selectedIsActuallyNotAguestUser_doNothing() = - runBlocking(IMMEDIATE) { + testScope.runTest { repository.setSelectedUserInfo(NON_GUEST_USER_INFO) underTest.exit( @@ -321,7 +323,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun remove_returnsToTargetUser() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true) repository.setSelectedUserInfo(GUEST_USER_INFO) @@ -342,7 +344,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun remove_selectedDifferentFromGuestUser_doNothing() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true) repository.setSelectedUserInfo(NON_GUEST_USER_INFO) @@ -359,7 +361,7 @@ class GuestUserInteractorTest : SysuiTestCase() { @Test fun remove_selectedIsActuallyNotAguestUser_doNothing() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true) repository.setSelectedUserInfo(NON_GUEST_USER_INFO) @@ -395,11 +397,7 @@ class GuestUserInteractorTest : SysuiTestCase() { companion object { private val IMMEDIATE = Dispatchers.Main.immediate private val NON_GUEST_USER_INFO = - UserInfo( - /* id= */ 818, - /* name= */ "non_guest", - /* flags= */ UserInfo.FLAG_FULL, - ) + UserInfo(/* id= */ 818, /* name= */ "non_guest", /* flags= */ UserInfo.FLAG_FULL) private val GUEST_USER_INFO = UserInfo( /* id= */ 669, @@ -416,10 +414,6 @@ class GuestUserInteractorTest : SysuiTestCase() { /* flags= */ UserInfo.FLAG_EPHEMERAL or UserInfo.FLAG_FULL, UserManager.USER_TYPE_FULL_GUEST, ) - private val ALL_USERS = - listOf( - NON_GUEST_USER_INFO, - GUEST_USER_INFO, - ) + private val ALL_USERS = listOf(NON_GUEST_USER_INFO, GUEST_USER_INFO) } } diff --git a/ravenwood/scripts/extract-last-soong-commands.py b/ravenwood/scripts/extract-last-soong-commands.py index bdc1de0c44f4..c08d4aa799a5 100755 --- a/ravenwood/scripts/extract-last-soong-commands.py +++ b/ravenwood/scripts/extract-last-soong-commands.py @@ -48,6 +48,7 @@ def main(args): with open(outfile, "w") as out: out.write(HEADER) + count = 0 with gzip.open(log) as f: for line in f: s = line.decode("utf-8") @@ -63,7 +64,8 @@ def main(args): if m: command = m.groups()[0] - out.write('#========\n') + count += 1 + out.write(f'### Command {count} ========\n') # Show the full command line before executing it. out.write('#echo ' + shlex.quote(command) + '\n') diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index ced7773eff56..11de25832a2d 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -130,17 +130,18 @@ public class MmsServiceBroker extends SystemService { } @Override - public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl, - Bundle configOverrides, PendingIntent sentIntent, long messageId, + public void sendMessage(int subId, int callingUser, String callingPkg, + Uri contentUri, String locationUrl, Bundle configOverrides, + PendingIntent sentIntent, long messageId, String attributionTag) throws RemoteException { returnPendingIntentWithError(sentIntent); } @Override - public void downloadMessage(int subId, String callingPkg, String locationUrl, - Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent, - long messageId, String attributionTag) - throws RemoteException { + public void downloadMessage(int subId, int callingUser, String callingPkg, + String locationUrl, Uri contentUri, Bundle configOverrides, + PendingIntent downloadedIntent, + long messageId, String attributionTag) throws RemoteException { returnPendingIntentWithError(downloadedIntent); } @@ -151,8 +152,9 @@ public class MmsServiceBroker extends SystemService { } @Override - public Uri importMultimediaMessage(String callingPkg, Uri contentUri, String messageId, - long timestampSecs, boolean seen, boolean read) throws RemoteException { + public Uri importMultimediaMessage(int callingUser, String callingPkg, + Uri contentUri, String messageId, long timestampSecs, + boolean seen, boolean read) throws RemoteException { return null; } @@ -187,8 +189,8 @@ public class MmsServiceBroker extends SystemService { } @Override - public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri) - throws RemoteException { + public Uri addMultimediaMessageDraft(int callingUser, String callingPkg, + Uri contentUri) throws RemoteException { return null; } @@ -333,9 +335,9 @@ public class MmsServiceBroker extends SystemService { private static final String PHONE_PACKAGE_NAME = "com.android.phone"; @Override - public void sendMessage(int subId, String callingPkg, Uri contentUri, - String locationUrl, Bundle configOverrides, PendingIntent sentIntent, - long messageId, String attributionTag) + public void sendMessage(int subId, int callingUser, String callingPkg, + Uri contentUri, String locationUrl, Bundle configOverrides, + PendingIntent sentIntent, long messageId, String attributionTag) throws RemoteException { Slog.d(TAG, "sendMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message"); @@ -360,14 +362,15 @@ public class MmsServiceBroker extends SystemService { CarrierMessagingService.SERVICE_INTERFACE, Intent.FLAG_GRANT_READ_URI_PERMISSION, subId); - getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl, - configOverrides, sentIntent, messageId, attributionTag); + getServiceGuarded().sendMessage(subId, getCallingUserId(), callingPkg, contentUri, + locationUrl, configOverrides, sentIntent, messageId, attributionTag); } @Override - public void downloadMessage(int subId, String callingPkg, String locationUrl, - Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent, - long messageId, String attributionTag) throws RemoteException { + public void downloadMessage(int subId, int callingUser, String callingPkg, + String locationUrl, Uri contentUri, Bundle configOverrides, + PendingIntent downloadedIntent, long messageId, String attributionTag) + throws RemoteException { Slog.d(TAG, "downloadMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS, "Download MMS message"); @@ -381,8 +384,8 @@ public class MmsServiceBroker extends SystemService { Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, subId); - getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri, - configOverrides, downloadedIntent, messageId, attributionTag); + getServiceGuarded().downloadMessage(subId, getCallingUserId(), callingPkg, locationUrl, + contentUri, configOverrides, downloadedIntent, messageId, attributionTag); } @Override @@ -399,8 +402,8 @@ public class MmsServiceBroker extends SystemService { } @Override - public Uri importMultimediaMessage(String callingPkg, Uri contentUri, - String messageId, long timestampSecs, boolean seen, boolean read) + public Uri importMultimediaMessage(int callingUser, String callingPkg, + Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { @@ -408,8 +411,8 @@ public class MmsServiceBroker extends SystemService { // while writing the TelephonyProvider return FAKE_MMS_SENT_URI; } - return getServiceGuarded().importMultimediaMessage( - callingPkg, contentUri, messageId, timestampSecs, seen, read); + return getServiceGuarded().importMultimediaMessage(getCallingUserId(), callingPkg, + contentUri, messageId, timestampSecs, seen, read); } @Override @@ -467,15 +470,16 @@ public class MmsServiceBroker extends SystemService { } @Override - public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri) - throws RemoteException { + public Uri addMultimediaMessageDraft(int callingUser, String callingPkg, + Uri contentUri) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { // Silently fail AppOps failure due to not being the default SMS app // while writing the TelephonyProvider return FAKE_MMS_DRAFT_URI; } - return getServiceGuarded().addMultimediaMessageDraft(callingPkg, contentUri); + return getServiceGuarded().addMultimediaMessageDraft(getCallingUserId(), callingPkg, + contentUri); } @Override @@ -572,4 +576,13 @@ public class MmsServiceBroker extends SystemService { if (info == null) return INVALID_SIM_SLOT_INDEX; return info.getSimSlotIndex(); } + + /** + * Retrieves the calling user id. + * @return The id of the calling user. + */ + private int getCallingUserId() { + return Binder.getCallingUserHandle().getIdentifier(); + } + } diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index 1208b6ef396f..08ceb61e14a8 100644 --- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -142,6 +142,8 @@ public class ActivityServiceConnectionsHolder<T> { /** Used by {@link ActivityRecord#dump}. */ @Override public String toString() { - return String.valueOf(mConnections); + synchronized (mActivity) { + return String.valueOf(mConnections); + } } } |