Loading core/java/android/app/ApplicationPackageManager.java +21 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IRemoteCallback; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; Loading Loading @@ -3918,4 +3919,24 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowFromSystemServer(); } } @Override public void registerPackageMonitorCallback(@NonNull IRemoteCallback callback, int userId) { Objects.requireNonNull(callback); try { mPM.registerPackageMonitorCallback(callback, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void unregisterPackageMonitorCallback(@NonNull IRemoteCallback callback) { Objects.requireNonNull(callback); try { mPM.unregisterPackageMonitorCallback(callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } core/java/android/content/pm/IPackageManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.content.pm.dex.IArtManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.content.IntentSender; Loading Loading @@ -818,4 +819,8 @@ interface IPackageManager { boolean[] canPackageQuery(String sourcePackageName, in String[] targetPackageNames, int userId); boolean waitForHandler(long timeoutMillis, boolean forBackgroundHandler); void registerPackageMonitorCallback(IRemoteCallback callback, int userId); void unregisterPackageMonitorCallback(IRemoteCallback callback); } core/java/android/content/pm/PackageManager.java +32 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; Loading Loading @@ -2575,6 +2576,13 @@ public abstract class PackageManager { /** {@hide} */ public static final String EXTRA_MOVE_ID = "android.content.pm.extra.MOVE_ID"; /** * Extra field name for notifying package change event. Currently, it is used by PackageMonitor. * @hide */ public static final String EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT = "android.content.pm.extra.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT"; /** * Usable by the required verifier as the {@code verificationCode} argument * for {@link PackageManager#verifyPendingInstall} to indicate that it will Loading Loading @@ -11039,4 +11047,28 @@ public abstract class PackageManager { throw new UnsupportedOperationException( "relinquishUpdateOwnership not implemented in subclass"); } /** * Register for notifications of package changes such as install, removal and other events. * * @param callback the callback to register for receiving the change events * @param userId The id of registered user * @hide */ public void registerPackageMonitorCallback(@NonNull IRemoteCallback callback, int userId) { throw new UnsupportedOperationException( "registerPackageMonitorCallback not implemented in subclass"); } /** * Unregister for notifications of package changes such as install, removal and other events. * * @param callback the callback to unregister for receiving the change events * @see #registerPackageMonitorCallback(IRemoteCallback, int) * @hide */ public void unregisterPackageMonitorCallback(@NonNull IRemoteCallback callback) { throw new UnsupportedOperationException( "unregisterPackageMonitorCallback not implemented in subclass"); } } core/java/com/android/internal/content/PackageMonitor.java +71 −26 Original line number Diff line number Diff line Loading @@ -22,15 +22,22 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IRemoteCallback; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.util.Objects; import java.util.concurrent.Executor; /** * Helper class for monitoring the state of packages: adding, removing, Loading @@ -41,7 +48,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { final IntentFilter mPackageFilt; final IntentFilter mNonDataFilt; final IntentFilter mExternalFilt; Context mRegisteredContext; Handler mRegisteredHandler; Loading @@ -55,15 +61,16 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { String[] mTempArray = new String[1]; PackageMonitorCallback mPackageMonitorCallback; @UnsupportedAppUsage public PackageMonitor() { final boolean isCore = UserHandle.isCore(android.os.Process.myUid()); mPackageFilt = new IntentFilter(); mPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); // Settings app sends the broadcast mPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); // AMS sends the broadcast mPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); mPackageFilt.addDataScheme("package"); Loading @@ -72,20 +79,11 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } mNonDataFilt = new IntentFilter(); mNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); // UserController sends the broadcast mNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); mNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED); mNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); if (isCore) { mNonDataFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); } mExternalFilt = new IntentFilter(); mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); if (isCore) { mExternalFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); } } @UnsupportedAppUsage Loading @@ -102,6 +100,15 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { public void register(Context context, UserHandle user, boolean externalStorage, Handler handler) { // Remove until all using code are updated to new method. register(context, user, handler); } /** * Register for notifications of package changes such as install, removal and other events. */ public void register(Context context, UserHandle user, Handler handler) { if (mRegisteredContext != null) { throw new IllegalStateException("Already registered"); } Loading @@ -110,15 +117,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { if (user != null) { context.registerReceiverAsUser(this, user, mPackageFilt, null, mRegisteredHandler); context.registerReceiverAsUser(this, user, mNonDataFilt, null, mRegisteredHandler); if (externalStorage) { context.registerReceiverAsUser(this, user, mExternalFilt, null, mRegisteredHandler); } } else { context.registerReceiver(this, mPackageFilt, null, mRegisteredHandler); context.registerReceiver(this, mNonDataFilt, null, mRegisteredHandler); if (externalStorage) { context.registerReceiver(this, mExternalFilt, null, mRegisteredHandler); } if (mPackageMonitorCallback == null) { PackageManager pm = mRegisteredContext.getPackageManager(); if (pm != null) { mPackageMonitorCallback = new PackageMonitorCallback(this, new HandlerExecutor(mRegisteredHandler)); int userId = user != null ? user.getIdentifier() : mRegisteredContext.getUserId(); pm.registerPackageMonitorCallback(mPackageMonitorCallback, userId); } } } Loading @@ -133,6 +142,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { throw new IllegalStateException("Not registered"); } mRegisteredContext.unregisterReceiver(this); PackageManager pm = mRegisteredContext.getPackageManager(); if (pm != null && mPackageMonitorCallback != null) { pm.unregisterPackageMonitorCallback(mPackageMonitorCallback); } mPackageMonitorCallback = null; mRegisteredContext = null; } Loading Loading @@ -330,6 +345,10 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { doHandlePackageEvent(intent); } private void doHandlePackageEvent(Intent intent) { mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (mChangeUserId == UserHandle.USER_NULL) { Loading Loading @@ -465,4 +484,30 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { onFinishPackageChanges(); mChangeUserId = UserHandle.USER_NULL; } private static final class PackageMonitorCallback extends IRemoteCallback.Stub { private final PackageMonitor mPackageMonitor; private final Executor mExecutor; PackageMonitorCallback(PackageMonitor monitor, Executor executor) { mPackageMonitor = monitor; mExecutor = executor; } @Override public void sendResult(Bundle data) throws RemoteException { onHandlePackageMonitorCallback(data); } private void onHandlePackageMonitorCallback(Bundle bundle) { Intent intent = bundle.getParcelable( PackageManager.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT, Intent.class); if (intent == null) { Log.w(TAG, "No intent is set for PackageMonitorCallback"); return; } mExecutor.execute(() -> mPackageMonitor.doHandlePackageEvent(intent)); } } } packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.controls.controller import android.content.Context import android.content.pm.PackageManager import android.os.Handler import android.os.UserHandle import android.testing.AndroidTestingRunner Loading @@ -34,6 +35,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest Loading @@ -42,12 +44,14 @@ class PackageUpdateMonitorTest : SysuiTestCase() { @Mock private lateinit var context: Context @Mock private lateinit var bgHandler: Handler @Mock private lateinit var packageManager: PackageManager private lateinit var underTest: PackageUpdateMonitor @Before fun setup() { MockitoAnnotations.initMocks(this) whenever(context.packageManager).thenReturn(packageManager) } @Test Loading @@ -58,9 +62,16 @@ class PackageUpdateMonitorTest : SysuiTestCase() { // There are two receivers registered verify(context, times(2)) .registerReceiverAsUser(any(), eq(USER), any(), eq(null), eq(bgHandler)) verify(packageManager).registerPackageMonitorCallback(any(), eq(USER.getIdentifier())) // context will be used to get PackageManager, the test should clear invocations // for next startMonitoring() assertion clearInvocations(context) underTest.startMonitoring() // No more interactions for registerReceiverAsUser verifyNoMoreInteractions(context) // No more interactions for registerPackageMonitorCallback verifyNoMoreInteractions(packageManager) } @Test Loading @@ -69,12 +80,20 @@ class PackageUpdateMonitorTest : SysuiTestCase() { underTest.startMonitoring() clearInvocations(context) clearInvocations(packageManager) underTest.stopMonitoring() verify(context).unregisterReceiver(any()) verify(packageManager).unregisterPackageMonitorCallback(any()) // context will be used to get PackageManager, the test should clear invocations // for next stopMonitoring() assertion clearInvocations(context) underTest.stopMonitoring() // No more interactions for unregisterReceiver verifyNoMoreInteractions(context) // No more interactions for unregisterPackageMonitorCallback verifyNoMoreInteractions(packageManager) } @Test Loading Loading
core/java/android/app/ApplicationPackageManager.java +21 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IRemoteCallback; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; Loading Loading @@ -3918,4 +3919,24 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowFromSystemServer(); } } @Override public void registerPackageMonitorCallback(@NonNull IRemoteCallback callback, int userId) { Objects.requireNonNull(callback); try { mPM.registerPackageMonitorCallback(callback, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void unregisterPackageMonitorCallback(@NonNull IRemoteCallback callback) { Objects.requireNonNull(callback); try { mPM.unregisterPackageMonitorCallback(callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
core/java/android/content/pm/IPackageManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.content.pm.dex.IArtManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.content.IntentSender; Loading Loading @@ -818,4 +819,8 @@ interface IPackageManager { boolean[] canPackageQuery(String sourcePackageName, in String[] targetPackageNames, int userId); boolean waitForHandler(long timeoutMillis, boolean forBackgroundHandler); void registerPackageMonitorCallback(IRemoteCallback callback, int userId); void unregisterPackageMonitorCallback(IRemoteCallback callback); }
core/java/android/content/pm/PackageManager.java +32 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; Loading Loading @@ -2575,6 +2576,13 @@ public abstract class PackageManager { /** {@hide} */ public static final String EXTRA_MOVE_ID = "android.content.pm.extra.MOVE_ID"; /** * Extra field name for notifying package change event. Currently, it is used by PackageMonitor. * @hide */ public static final String EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT = "android.content.pm.extra.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT"; /** * Usable by the required verifier as the {@code verificationCode} argument * for {@link PackageManager#verifyPendingInstall} to indicate that it will Loading Loading @@ -11039,4 +11047,28 @@ public abstract class PackageManager { throw new UnsupportedOperationException( "relinquishUpdateOwnership not implemented in subclass"); } /** * Register for notifications of package changes such as install, removal and other events. * * @param callback the callback to register for receiving the change events * @param userId The id of registered user * @hide */ public void registerPackageMonitorCallback(@NonNull IRemoteCallback callback, int userId) { throw new UnsupportedOperationException( "registerPackageMonitorCallback not implemented in subclass"); } /** * Unregister for notifications of package changes such as install, removal and other events. * * @param callback the callback to unregister for receiving the change events * @see #registerPackageMonitorCallback(IRemoteCallback, int) * @hide */ public void unregisterPackageMonitorCallback(@NonNull IRemoteCallback callback) { throw new UnsupportedOperationException( "unregisterPackageMonitorCallback not implemented in subclass"); } }
core/java/com/android/internal/content/PackageMonitor.java +71 −26 Original line number Diff line number Diff line Loading @@ -22,15 +22,22 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IRemoteCallback; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.util.Objects; import java.util.concurrent.Executor; /** * Helper class for monitoring the state of packages: adding, removing, Loading @@ -41,7 +48,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { final IntentFilter mPackageFilt; final IntentFilter mNonDataFilt; final IntentFilter mExternalFilt; Context mRegisteredContext; Handler mRegisteredHandler; Loading @@ -55,15 +61,16 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { String[] mTempArray = new String[1]; PackageMonitorCallback mPackageMonitorCallback; @UnsupportedAppUsage public PackageMonitor() { final boolean isCore = UserHandle.isCore(android.os.Process.myUid()); mPackageFilt = new IntentFilter(); mPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); // Settings app sends the broadcast mPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); // AMS sends the broadcast mPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); mPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); mPackageFilt.addDataScheme("package"); Loading @@ -72,20 +79,11 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } mNonDataFilt = new IntentFilter(); mNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); // UserController sends the broadcast mNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); mNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED); mNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); if (isCore) { mNonDataFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); } mExternalFilt = new IntentFilter(); mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); if (isCore) { mExternalFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); } } @UnsupportedAppUsage Loading @@ -102,6 +100,15 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { public void register(Context context, UserHandle user, boolean externalStorage, Handler handler) { // Remove until all using code are updated to new method. register(context, user, handler); } /** * Register for notifications of package changes such as install, removal and other events. */ public void register(Context context, UserHandle user, Handler handler) { if (mRegisteredContext != null) { throw new IllegalStateException("Already registered"); } Loading @@ -110,15 +117,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { if (user != null) { context.registerReceiverAsUser(this, user, mPackageFilt, null, mRegisteredHandler); context.registerReceiverAsUser(this, user, mNonDataFilt, null, mRegisteredHandler); if (externalStorage) { context.registerReceiverAsUser(this, user, mExternalFilt, null, mRegisteredHandler); } } else { context.registerReceiver(this, mPackageFilt, null, mRegisteredHandler); context.registerReceiver(this, mNonDataFilt, null, mRegisteredHandler); if (externalStorage) { context.registerReceiver(this, mExternalFilt, null, mRegisteredHandler); } if (mPackageMonitorCallback == null) { PackageManager pm = mRegisteredContext.getPackageManager(); if (pm != null) { mPackageMonitorCallback = new PackageMonitorCallback(this, new HandlerExecutor(mRegisteredHandler)); int userId = user != null ? user.getIdentifier() : mRegisteredContext.getUserId(); pm.registerPackageMonitorCallback(mPackageMonitorCallback, userId); } } } Loading @@ -133,6 +142,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { throw new IllegalStateException("Not registered"); } mRegisteredContext.unregisterReceiver(this); PackageManager pm = mRegisteredContext.getPackageManager(); if (pm != null && mPackageMonitorCallback != null) { pm.unregisterPackageMonitorCallback(mPackageMonitorCallback); } mPackageMonitorCallback = null; mRegisteredContext = null; } Loading Loading @@ -330,6 +345,10 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { doHandlePackageEvent(intent); } private void doHandlePackageEvent(Intent intent) { mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (mChangeUserId == UserHandle.USER_NULL) { Loading Loading @@ -465,4 +484,30 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { onFinishPackageChanges(); mChangeUserId = UserHandle.USER_NULL; } private static final class PackageMonitorCallback extends IRemoteCallback.Stub { private final PackageMonitor mPackageMonitor; private final Executor mExecutor; PackageMonitorCallback(PackageMonitor monitor, Executor executor) { mPackageMonitor = monitor; mExecutor = executor; } @Override public void sendResult(Bundle data) throws RemoteException { onHandlePackageMonitorCallback(data); } private void onHandlePackageMonitorCallback(Bundle bundle) { Intent intent = bundle.getParcelable( PackageManager.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT, Intent.class); if (intent == null) { Log.w(TAG, "No intent is set for PackageMonitorCallback"); return; } mExecutor.execute(() -> mPackageMonitor.doHandlePackageEvent(intent)); } } }
packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.controls.controller import android.content.Context import android.content.pm.PackageManager import android.os.Handler import android.os.UserHandle import android.testing.AndroidTestingRunner Loading @@ -34,6 +35,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest Loading @@ -42,12 +44,14 @@ class PackageUpdateMonitorTest : SysuiTestCase() { @Mock private lateinit var context: Context @Mock private lateinit var bgHandler: Handler @Mock private lateinit var packageManager: PackageManager private lateinit var underTest: PackageUpdateMonitor @Before fun setup() { MockitoAnnotations.initMocks(this) whenever(context.packageManager).thenReturn(packageManager) } @Test Loading @@ -58,9 +62,16 @@ class PackageUpdateMonitorTest : SysuiTestCase() { // There are two receivers registered verify(context, times(2)) .registerReceiverAsUser(any(), eq(USER), any(), eq(null), eq(bgHandler)) verify(packageManager).registerPackageMonitorCallback(any(), eq(USER.getIdentifier())) // context will be used to get PackageManager, the test should clear invocations // for next startMonitoring() assertion clearInvocations(context) underTest.startMonitoring() // No more interactions for registerReceiverAsUser verifyNoMoreInteractions(context) // No more interactions for registerPackageMonitorCallback verifyNoMoreInteractions(packageManager) } @Test Loading @@ -69,12 +80,20 @@ class PackageUpdateMonitorTest : SysuiTestCase() { underTest.startMonitoring() clearInvocations(context) clearInvocations(packageManager) underTest.stopMonitoring() verify(context).unregisterReceiver(any()) verify(packageManager).unregisterPackageMonitorCallback(any()) // context will be used to get PackageManager, the test should clear invocations // for next stopMonitoring() assertion clearInvocations(context) underTest.stopMonitoring() // No more interactions for unregisterReceiver verifyNoMoreInteractions(context) // No more interactions for unregisterPackageMonitorCallback verifyNoMoreInteractions(packageManager) } @Test Loading