Merge "Adds ChooserPinMigration core startable" into udc-dev am: 7e0a03f03c
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22141205 Change-Id: I004e09eacc212a0c257b46be8d54d61b9e6b0689 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -347,6 +347,15 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
|
<uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
|
||||||
|
|
||||||
|
<!-- Intent Chooser -->
|
||||||
|
<permission
|
||||||
|
android:name="android.permission.ADD_CHOOSER_PINS"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
<uses-permission android:name="android.permission.ADD_CHOOSER_PINS" />
|
||||||
|
<permission
|
||||||
|
android:name="android.permission.RECEIVE_CHOOSER_PIN_MIGRATION"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
|
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
|
||||||
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
|
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
|
||||||
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
|
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.MODE_PRIVATE
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
|
import android.os.storage.StorageManager
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.util.Supplier
|
||||||
|
import com.android.internal.R
|
||||||
|
import com.android.systemui.broadcast.BroadcastSender
|
||||||
|
import com.android.systemui.flags.FeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a migration of pinned targets to the unbundled chooser if legacy data exists.
|
||||||
|
*
|
||||||
|
* Sends an explicit broadcast with the contents of the legacy pin preferences. The broadcast is
|
||||||
|
* protected by the RECEIVE_CHOOSER_PIN_MIGRATION permission. This class requires the
|
||||||
|
* ADD_CHOOSER_PINS permission in order to be able to send this broadcast.
|
||||||
|
*/
|
||||||
|
class ChooserPinMigration
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val featureFlags: FeatureFlags,
|
||||||
|
private val broadcastSender: BroadcastSender,
|
||||||
|
legacyPinPrefsFileSupplier: LegacyPinPrefsFileSupplier,
|
||||||
|
) : CoreStartable {
|
||||||
|
|
||||||
|
private val legacyPinPrefsFile = legacyPinPrefsFileSupplier.get()
|
||||||
|
private val chooserComponent =
|
||||||
|
ComponentName.unflattenFromString(
|
||||||
|
context.resources.getString(R.string.config_chooserActivity)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
if (migrationIsRequired()) {
|
||||||
|
doMigration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun migrationIsRequired(): Boolean {
|
||||||
|
return featureFlags.isEnabled(Flags.CHOOSER_MIGRATION_ENABLED) &&
|
||||||
|
legacyPinPrefsFile.exists() &&
|
||||||
|
chooserComponent?.packageName != null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doMigration() {
|
||||||
|
Log.i(TAG, "Beginning migration")
|
||||||
|
|
||||||
|
val legacyPinPrefs = context.getSharedPreferences(legacyPinPrefsFile, MODE_PRIVATE)
|
||||||
|
|
||||||
|
if (legacyPinPrefs.all.isEmpty()) {
|
||||||
|
Log.i(TAG, "No data to migrate, deleting legacy file")
|
||||||
|
} else {
|
||||||
|
sendSharedPreferences(legacyPinPrefs)
|
||||||
|
Log.i(TAG, "Legacy data sent, deleting legacy preferences")
|
||||||
|
|
||||||
|
val legacyPinPrefsEditor = legacyPinPrefs.edit()
|
||||||
|
legacyPinPrefsEditor.clear()
|
||||||
|
if (!legacyPinPrefsEditor.commit()) {
|
||||||
|
Log.e(TAG, "Failed to delete legacy preferences")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!legacyPinPrefsFile.delete()) {
|
||||||
|
Log.e(TAG, "Legacy preferences deleted, but failed to delete legacy preferences file")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Legacy preference deletion complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendSharedPreferences(sharedPreferences: SharedPreferences) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
|
||||||
|
sharedPreferences.all.entries.forEach { (key, value) ->
|
||||||
|
when (value) {
|
||||||
|
is Boolean -> bundle.putBoolean(key, value)
|
||||||
|
else -> Log.e(TAG, "Unsupported preference type for $key: ${value?.javaClass}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendBundle(bundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendBundle(bundle: Bundle) {
|
||||||
|
val intent =
|
||||||
|
Intent().apply {
|
||||||
|
`package` = chooserComponent?.packageName!!
|
||||||
|
action = BROADCAST_ACTION
|
||||||
|
putExtras(bundle)
|
||||||
|
}
|
||||||
|
broadcastSender.sendBroadcast(intent, BROADCAST_PERMISSION)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "PinnedShareTargetMigration"
|
||||||
|
private const val BROADCAST_ACTION = "android.intent.action.CHOOSER_PIN_MIGRATION"
|
||||||
|
private const val BROADCAST_PERMISSION = "android.permission.RECEIVE_CHOOSER_PIN_MIGRATION"
|
||||||
|
|
||||||
|
class LegacyPinPrefsFileSupplier @Inject constructor(private val context: Context) :
|
||||||
|
Supplier<File> {
|
||||||
|
|
||||||
|
override fun get(): File {
|
||||||
|
val packageDirectory =
|
||||||
|
Environment.getDataUserCePackageDirectory(
|
||||||
|
StorageManager.UUID_PRIVATE_INTERNAL,
|
||||||
|
context.userId,
|
||||||
|
context.packageName,
|
||||||
|
)
|
||||||
|
val sharedPrefsDirectory = File(packageDirectory, "shared_prefs")
|
||||||
|
return File(sharedPrefsDirectory, "chooser_pin_settings.xml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.dagger
|
package com.android.systemui.dagger
|
||||||
|
|
||||||
import com.android.keyguard.KeyguardBiometricLockoutLogger
|
import com.android.keyguard.KeyguardBiometricLockoutLogger
|
||||||
|
import com.android.systemui.ChooserPinMigration
|
||||||
import com.android.systemui.ChooserSelector
|
import com.android.systemui.ChooserSelector
|
||||||
import com.android.systemui.CoreStartable
|
import com.android.systemui.CoreStartable
|
||||||
import com.android.systemui.LatencyTester
|
import com.android.systemui.LatencyTester
|
||||||
@@ -75,6 +76,13 @@ abstract class SystemUICoreStartableModule {
|
|||||||
@ClassKey(AuthController::class)
|
@ClassKey(AuthController::class)
|
||||||
abstract fun bindAuthController(service: AuthController): CoreStartable
|
abstract fun bindAuthController(service: AuthController): CoreStartable
|
||||||
|
|
||||||
|
/** Inject into ChooserPinMigration. */
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(ChooserPinMigration::class)
|
||||||
|
@PerUser
|
||||||
|
abstract fun bindChooserPinMigration(sysui: ChooserPinMigration): CoreStartable
|
||||||
|
|
||||||
/** Inject into ChooserCoreStartable. */
|
/** Inject into ChooserCoreStartable. */
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|||||||
@@ -610,6 +610,9 @@ object Flags {
|
|||||||
val SHARESHEET_SCROLLABLE_IMAGE_PREVIEW =
|
val SHARESHEET_SCROLLABLE_IMAGE_PREVIEW =
|
||||||
releasedFlag(1504, "sharesheet_scrollable_image_preview")
|
releasedFlag(1504, "sharesheet_scrollable_image_preview")
|
||||||
|
|
||||||
|
// TODO(b/274137694) Tracking Bug
|
||||||
|
val CHOOSER_MIGRATION_ENABLED = unreleasedFlag(1505, "chooser_migration_enabled")
|
||||||
|
|
||||||
// 1700 - clipboard
|
// 1700 - clipboard
|
||||||
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
|
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
|
||||||
// TODO(b/267162944): Tracking bug
|
// TODO(b/267162944): Tracking bug
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.broadcast.BroadcastSender
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import java.io.File
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.verifyZeroInteractions
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@SmallTest
|
||||||
|
class ChooserPinMigrationTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private val fakeFeatureFlags = FakeFeatureFlags()
|
||||||
|
private val fakePreferences =
|
||||||
|
mutableMapOf(
|
||||||
|
"TestPinnedPackage/TestPinnedClass" to true,
|
||||||
|
"TestUnpinnedPackage/TestUnpinnedClass" to false,
|
||||||
|
)
|
||||||
|
private val intent = kotlinArgumentCaptor<Intent>()
|
||||||
|
private val permission = kotlinArgumentCaptor<String>()
|
||||||
|
|
||||||
|
private lateinit var chooserPinMigration: ChooserPinMigration
|
||||||
|
|
||||||
|
@Mock private lateinit var mockContext: Context
|
||||||
|
@Mock private lateinit var mockResources: Resources
|
||||||
|
@Mock
|
||||||
|
private lateinit var mockLegacyPinPrefsFileSupplier:
|
||||||
|
ChooserPinMigration.Companion.LegacyPinPrefsFileSupplier
|
||||||
|
@Mock private lateinit var mockFile: File
|
||||||
|
@Mock private lateinit var mockSharedPreferences: SharedPreferences
|
||||||
|
@Mock private lateinit var mockSharedPreferencesEditor: SharedPreferences.Editor
|
||||||
|
@Mock private lateinit var mockBroadcastSender: BroadcastSender
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
whenever(mockContext.resources).thenReturn(mockResources)
|
||||||
|
whenever(mockContext.getSharedPreferences(any<File>(), anyInt()))
|
||||||
|
.thenReturn(mockSharedPreferences)
|
||||||
|
whenever(mockResources.getString(anyInt())).thenReturn("TestPackage/TestClass")
|
||||||
|
whenever(mockSharedPreferences.all).thenReturn(fakePreferences)
|
||||||
|
whenever(mockSharedPreferences.edit()).thenReturn(mockSharedPreferencesEditor)
|
||||||
|
whenever(mockSharedPreferencesEditor.commit()).thenReturn(true)
|
||||||
|
whenever(mockLegacyPinPrefsFileSupplier.get()).thenReturn(mockFile)
|
||||||
|
whenever(mockFile.exists()).thenReturn(true)
|
||||||
|
whenever(mockFile.delete()).thenReturn(true)
|
||||||
|
fakeFeatureFlags.set(Flags.CHOOSER_MIGRATION_ENABLED, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_performsMigration() {
|
||||||
|
// Arrange
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockBroadcastSender).sendBroadcast(intent.capture(), permission.capture())
|
||||||
|
assertThat(intent.value.action).isEqualTo("android.intent.action.CHOOSER_PIN_MIGRATION")
|
||||||
|
assertThat(intent.value.`package`).isEqualTo("TestPackage")
|
||||||
|
assertThat(intent.value.extras?.keySet()).hasSize(2)
|
||||||
|
assertThat(intent.value.hasExtra("TestPinnedPackage/TestPinnedClass")).isTrue()
|
||||||
|
assertThat(intent.value.getBooleanExtra("TestPinnedPackage/TestPinnedClass", false))
|
||||||
|
.isTrue()
|
||||||
|
assertThat(intent.value.hasExtra("TestUnpinnedPackage/TestUnpinnedClass")).isTrue()
|
||||||
|
assertThat(intent.value.getBooleanExtra("TestUnpinnedPackage/TestUnpinnedClass", true))
|
||||||
|
.isFalse()
|
||||||
|
assertThat(permission.value).isEqualTo("android.permission.RECEIVE_CHOOSER_PIN_MIGRATION")
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockSharedPreferencesEditor).clear()
|
||||||
|
verify(mockSharedPreferencesEditor).commit()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_doesNotDeleteLegacyPreferencesFile_whenClearingItFails() {
|
||||||
|
// Arrange
|
||||||
|
whenever(mockSharedPreferencesEditor.commit()).thenReturn(false)
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockBroadcastSender).sendBroadcast(intent.capture(), permission.capture())
|
||||||
|
assertThat(intent.value.action).isEqualTo("android.intent.action.CHOOSER_PIN_MIGRATION")
|
||||||
|
assertThat(intent.value.`package`).isEqualTo("TestPackage")
|
||||||
|
assertThat(intent.value.extras?.keySet()).hasSize(2)
|
||||||
|
assertThat(intent.value.hasExtra("TestPinnedPackage/TestPinnedClass")).isTrue()
|
||||||
|
assertThat(intent.value.getBooleanExtra("TestPinnedPackage/TestPinnedClass", false))
|
||||||
|
.isTrue()
|
||||||
|
assertThat(intent.value.hasExtra("TestUnpinnedPackage/TestUnpinnedClass")).isTrue()
|
||||||
|
assertThat(intent.value.getBooleanExtra("TestUnpinnedPackage/TestUnpinnedClass", true))
|
||||||
|
.isFalse()
|
||||||
|
assertThat(permission.value).isEqualTo("android.permission.RECEIVE_CHOOSER_PIN_MIGRATION")
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockSharedPreferencesEditor).clear()
|
||||||
|
verify(mockSharedPreferencesEditor).commit()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile, never()).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_OnlyDeletesLegacyPreferencesFile_whenEmpty() {
|
||||||
|
// Arrange
|
||||||
|
whenever(mockSharedPreferences.all).thenReturn(emptyMap())
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockBroadcastSender)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockSharedPreferencesEditor)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_DoesNotDoMigration_whenFlagIsDisabled() {
|
||||||
|
// Arrange
|
||||||
|
fakeFeatureFlags.set(Flags.CHOOSER_MIGRATION_ENABLED, false)
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockBroadcastSender)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockSharedPreferencesEditor)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile, never()).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_DoesNotDoMigration_whenLegacyPreferenceFileNotPresent() {
|
||||||
|
// Arrange
|
||||||
|
whenever(mockFile.exists()).thenReturn(false)
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockBroadcastSender)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockSharedPreferencesEditor)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile, never()).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun start_DoesNotDoMigration_whenConfiguredChooserComponentIsInvalid() {
|
||||||
|
// Arrange
|
||||||
|
whenever(mockResources.getString(anyInt())).thenReturn("InvalidComponent")
|
||||||
|
chooserPinMigration =
|
||||||
|
ChooserPinMigration(
|
||||||
|
mockContext,
|
||||||
|
fakeFeatureFlags,
|
||||||
|
mockBroadcastSender,
|
||||||
|
mockLegacyPinPrefsFileSupplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
chooserPinMigration.start()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockBroadcastSender)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyZeroInteractions(mockSharedPreferencesEditor)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(mockFile, never()).delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user