mirror of
https://github.com/ActivityLauncher/ActivityLauncher.git
synced 2026-08-10 17:33:29 +00:00
chore(refactor): use intents in LaunchRequest and ShortcutRequest
This commit is contained in:
parent
2ba06beadc
commit
da20db567c
27 changed files with 201 additions and 169 deletions
|
|
@ -29,16 +29,20 @@ class ActivityLauncherImplTest {
|
|||
val extras = Bundle().apply {
|
||||
putString("test_key", "test_value")
|
||||
}
|
||||
val request = LaunchRequest(componentName, extras)
|
||||
val intent = Intent().apply {
|
||||
component = componentName
|
||||
putExtras(extras)
|
||||
}
|
||||
val request = LaunchRequest(intent)
|
||||
|
||||
activityLauncher.launchActivity(request)
|
||||
|
||||
argumentCaptor<Intent>().apply {
|
||||
verify(context).startActivity(capture())
|
||||
val intent = firstValue
|
||||
assertEquals(componentName, intent.component)
|
||||
assertEquals("test_value", intent.getStringExtra("test_key"))
|
||||
assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK, intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
val capturedIntent = firstValue
|
||||
assertEquals(componentName, capturedIntent.component)
|
||||
assertEquals("test_value", capturedIntent.getStringExtra("test_key"))
|
||||
assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK, capturedIntent.flags and Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,14 +88,14 @@ class ProxyImplTest {
|
|||
fun testCreateLauncherIconDelegation() {
|
||||
val componentName = ComponentName("com.test", "Activity")
|
||||
val icon: IconCompat = mock()
|
||||
whenever(intentSigner.signRequest(any())).thenReturn("signature")
|
||||
whenever(intentSigner.signRequest(any<ShortcutRequest>())).thenReturn("signature")
|
||||
|
||||
// Mock the context and capture it to verify startActivity
|
||||
val mockContext: Context = mock()
|
||||
whenever(mockContext.packageManager).thenReturn(packageManager)
|
||||
val proxyWithMockContext = ShortcutCreatorProxyImpl(mockContext, intentSigner)
|
||||
|
||||
val request = ShortcutRequest("Test", componentName, icon)
|
||||
val request = ShortcutRequest("Test", Intent().setComponent(componentName), icon)
|
||||
proxyWithMockContext.createLauncherIcon(request, null)
|
||||
|
||||
verify(intentSigner).signRequest(eq(request))
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class ShortcutCreatorImplTest {
|
|||
android.graphics.Bitmap.createBitmap(1, 1, android.graphics.Bitmap.Config.ARGB_8888),
|
||||
)
|
||||
val signature = "test_signature"
|
||||
whenever(intentSigner.signRequest(any())).thenReturn(signature)
|
||||
whenever(intentSigner.signRequest(any<ShortcutRequest>())).thenReturn(signature)
|
||||
|
||||
val shortcutManager = mock<ShortcutManager>()
|
||||
val mockContext = object : android.content.ContextWrapper(context) {
|
||||
|
|
@ -105,7 +105,7 @@ class ShortcutCreatorImplTest {
|
|||
}
|
||||
|
||||
val shortcutCreatorWithMock = ShortcutCreatorImpl(mockContext, intentSigner)
|
||||
val request = ShortcutRequest("Test App", componentName, icon)
|
||||
val request = ShortcutRequest("Test App", Intent().setComponent(componentName), icon)
|
||||
|
||||
shortcutCreatorWithMock.createLauncherIcon(request)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ class ViewIntentParserImplTest {
|
|||
|
||||
val request = parser.parseLaunchRequest(intent)
|
||||
|
||||
assertEquals("com.example", request?.component?.packageName)
|
||||
assertEquals("com.example.MainActivity", request?.component?.className)
|
||||
assertEquals("com.example", request?.intent?.component?.packageName)
|
||||
assertEquals("com.example.MainActivity", request?.intent?.component?.className)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -45,8 +45,8 @@ class ViewIntentParserImplTest {
|
|||
}
|
||||
|
||||
val request = parser.parseLaunchRequest(intent)
|
||||
assertEquals("com.test", request?.component?.packageName)
|
||||
assertEquals("com.test.Activity", request?.component?.className)
|
||||
assertEquals("com.test", request?.intent?.component?.packageName)
|
||||
assertEquals("com.test.Activity", request?.intent?.component?.className)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -72,7 +72,7 @@ class ViewIntentParserImplTest {
|
|||
|
||||
val request = parser.parseShortcutRequest(intent)
|
||||
assertEquals("Test Name", request?.name)
|
||||
assertEquals("com.test", request?.component?.packageName)
|
||||
assertEquals("com.test.Activity", request?.component?.className)
|
||||
assertEquals("com.test", request?.intent?.component?.packageName)
|
||||
assertEquals("com.test.Activity", request?.intent?.component?.className)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ class MainActivityIntentTest {
|
|||
whenever(viewIntentParser.parseLaunchRequest(any())).thenAnswer { invocation: org.mockito.invocation.InvocationOnMock -> realParser.parseLaunchRequest(invocation.getArgument(0)) }
|
||||
whenever(viewIntentParser.parseShortcutRequest(any())).thenAnswer { invocation: org.mockito.invocation.InvocationOnMock -> realParser.parseShortcutRequest(invocation.getArgument(0)) }
|
||||
whenever(viewIntentParser.componentNameFromIntent(any())).thenAnswer { invocation: org.mockito.invocation.InvocationOnMock -> realParser.componentNameFromIntent(invocation.getArgument(0)) }
|
||||
whenever(viewIntentParser.packageFromIntent(any())).thenAnswer { invocation: org.mockito.invocation.InvocationOnMock -> realParser.packageFromIntent(invocation.getArgument(0)) }
|
||||
whenever(viewIntentParser.parseShortcutIntent(any())).thenAnswer { invocation: org.mockito.invocation.InvocationOnMock -> realParser.parseShortcutIntent(invocation.getArgument(0)) }
|
||||
whenever(settingsRepository.disclaimerAccepted).thenReturn(true)
|
||||
whenever(supportReminder.shouldDisplayReminder()).thenReturn(false)
|
||||
|
|
|
|||
|
|
@ -119,9 +119,8 @@ class ShortcutFlowTest {
|
|||
|
||||
ShortcutRequest(
|
||||
name = appName,
|
||||
component = launchIntent.component!!,
|
||||
intent = launchIntent,
|
||||
icon = mock<androidx.core.graphics.drawable.IconCompat>(),
|
||||
extras = launchIntent.extras,
|
||||
launcherPlugin = launchPlugin,
|
||||
)
|
||||
}
|
||||
|
|
@ -135,9 +134,12 @@ class ShortcutFlowTest {
|
|||
null
|
||||
} ?: return@thenAnswer null
|
||||
|
||||
val launchPluginStr = intent.getStringExtra(ShortcutCreator.INTENT_EXTRA_LAUNCH_PLUGIN)
|
||||
val launchPlugin = launchPluginStr?.let { ComponentName.unflattenFromString(it) }
|
||||
|
||||
LaunchRequest(
|
||||
component = launchIntent.component!!,
|
||||
extras = launchIntent.extras,
|
||||
intent = launchIntent,
|
||||
launcherPlugin = launchPlugin,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -164,9 +166,9 @@ class ShortcutFlowTest {
|
|||
ActivityScenario.launch<ShortcutActivity>(intent).use {
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(activityLauncher).launchActivity(captor.capture())
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("com.test.Activity", captor.firstValue.component.className)
|
||||
assertEquals("value", captor.firstValue.extras?.getString("key"))
|
||||
assertEquals("com.test", captor.firstValue.intent.component?.packageName)
|
||||
assertEquals("com.test.Activity", captor.firstValue.intent.component?.className)
|
||||
assertEquals("value", captor.firstValue.intent.extras?.getString("key"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +217,7 @@ class ShortcutFlowTest {
|
|||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(shortcutCreator).createLauncherIcon(captor.capture())
|
||||
assertEquals("Test App", captor.firstValue.name)
|
||||
assertEquals(componentName, captor.firstValue.component)
|
||||
assertEquals(componentName, captor.firstValue.intent.component)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +234,7 @@ class ShortcutFlowTest {
|
|||
ActivityScenario.launch<ShortcutActivity>(intent).use {
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(activityLauncher).launchActivity(captor.capture())
|
||||
assertEquals(componentName, captor.firstValue.component)
|
||||
assertEquals(componentName, captor.firstValue.intent.component)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +256,9 @@ class ShortcutFlowTest {
|
|||
|
||||
ActivityScenario.launch<ShortcutActivity>(intent).use {
|
||||
verify(activityLauncher, never()).launchActivity(any())
|
||||
verify(activityLauncherProxy).launchActivity(any(), eq(ComponentName.unflattenFromString(launchPlugin)))
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(activityLauncherProxy).launchActivity(captor.capture())
|
||||
assertEquals(ComponentName.unflattenFromString(launchPlugin), captor.firstValue.launcherPlugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.content.Intent
|
|||
import android.widget.Toast
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.R
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncher
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import javax.inject.Inject
|
||||
|
|
@ -13,7 +12,7 @@ import javax.inject.Inject
|
|||
class ActivityLauncherImpl @Inject constructor(@ApplicationContext private val context: Context) :
|
||||
ActivityLauncher {
|
||||
override fun launchActivity(request: LaunchRequest) {
|
||||
val intent = getActivityIntent(request.component, request.extras)
|
||||
val intent = request.intent
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.core.util.toIconCompat
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncherProxy
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreator
|
||||
|
|
@ -18,14 +17,13 @@ class ActivityLauncherProxyImpl @Inject constructor(
|
|||
) : ActivityLauncherProxy {
|
||||
private val pm: PackageManager = context.packageManager
|
||||
|
||||
override fun launchActivity(request: LaunchRequest, plugin: ComponentName?) {
|
||||
override fun launchActivity(request: LaunchRequest) {
|
||||
val intent = Intent(ActivityLauncherProxy.INTENT_LAUNCH_ACTIVITY)
|
||||
if (plugin != null) {
|
||||
intent.component = plugin
|
||||
if (request.launcherPlugin != null) {
|
||||
intent.component = request.launcherPlugin
|
||||
}
|
||||
|
||||
val launchIntent = getActivityIntent(request.component, request.extras)
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_INTENT, launchIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_INTENT, request.intent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
context.startActivity(intent)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package de.szalkowski.activitylauncher.data.launcher
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Base64
|
||||
import androidx.core.content.edit
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IntentSigner
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
import java.security.SecureRandom
|
||||
import javax.crypto.Mac
|
||||
|
|
@ -29,10 +31,12 @@ class IntentSignerImpl @Inject constructor(@ApplicationContext context: Context)
|
|||
}
|
||||
}
|
||||
|
||||
override fun signRequest(request: ShortcutRequest): String {
|
||||
val launchIntent = getActivityIntent(request.component, request.extras)
|
||||
val uri = launchIntent.toUri(0)
|
||||
val launcherPlugin = request.launcherPlugin?.flattenToString()
|
||||
override fun signRequest(request: ShortcutRequest): String = signIntent(request.intent, request.launcherPlugin)
|
||||
override fun signRequest(request: LaunchRequest): String = signIntent(request.intent, request.launcherPlugin)
|
||||
|
||||
private fun signIntent(intent: Intent, launcherPlugin: ComponentName?): String {
|
||||
val uri = intent.toUri(0)
|
||||
val launcherPlugin = launcherPlugin?.flattenToString()
|
||||
val message = if (launcherPlugin == null) {
|
||||
uri
|
||||
} else {
|
||||
|
|
@ -41,7 +45,7 @@ class IntentSignerImpl @Inject constructor(@ApplicationContext context: Context)
|
|||
return hmac256(key, message)
|
||||
}
|
||||
|
||||
override fun validateRequestSignature(request: ShortcutRequest, signature: String): Boolean {
|
||||
override fun validateRequestSignature(request: LaunchRequest, signature: String): Boolean {
|
||||
val compSignature = signRequest(request)
|
||||
return signature == compSignature
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import android.content.Intent
|
|||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IntentSigner
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreator
|
||||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
|
|
@ -28,10 +27,9 @@ class ShortcutCreatorImpl @Inject constructor(
|
|||
ShortcutActivity::class.java,
|
||||
)
|
||||
|
||||
val launchIntent = getActivityIntent(request.component, request.extras)
|
||||
intent.putExtra(
|
||||
ShortcutCreator.INTENT_EXTRA_INTENT,
|
||||
launchIntent.toUri(Intent.URI_INTENT_SCHEME),
|
||||
request.intent.toUri(Intent.URI_INTENT_SCHEME),
|
||||
)
|
||||
|
||||
val signature = intentSigner.signRequest(request)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.core.util.toIconCompat
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IntentSigner
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreator
|
||||
|
|
@ -28,8 +27,7 @@ class ShortcutCreatorProxyImpl @Inject constructor(
|
|||
}
|
||||
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_NAME, request.name)
|
||||
val launchIntent = getActivityIntent(request.component, request.extras)
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_INTENT, launchIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_INTENT, request.intent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_ICON, request.icon.toBundle())
|
||||
|
||||
val signature = intentSigner.signRequest(request)
|
||||
|
|
|
|||
|
|
@ -13,32 +13,24 @@ import javax.inject.Inject
|
|||
class ViewIntentParserImpl @Inject constructor(
|
||||
private val getActivityIconUseCase: GetActivityIconUseCase,
|
||||
) : ViewIntentParser {
|
||||
override fun packageFromIntent(intent: Intent): String? {
|
||||
if (intent.action != Intent.ACTION_VIEW) {
|
||||
return null
|
||||
}
|
||||
|
||||
return runCatching {
|
||||
val url = intent.dataString.orEmpty()
|
||||
if (url.startsWith("https://activitylauncher.net/activity/")) {
|
||||
val rawComponent = url.removePrefix("https://activitylauncher.net/activity/")
|
||||
ComponentName.unflattenFromString(rawComponent)?.packageName
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
override fun parseLaunchRequest(intent: Intent): LaunchRequest? {
|
||||
val launchIntentStr = intent.getStringExtra(ShortcutCreator.INTENT_EXTRA_INTENT)
|
||||
?: intent.getStringExtra(ShortcutCreator.LEGACY_INTENT_EXTRA_INTENT)
|
||||
val launchIntent = launchIntentStr?.let { parseShortcutIntent(it) }
|
||||
|
||||
val component = launchIntent?.component
|
||||
?: componentNameFromIntent(intent)
|
||||
?: return null
|
||||
val launcherPluginStr = intent.getStringExtra(ShortcutCreator.INTENT_EXTRA_LAUNCH_PLUGIN)
|
||||
val launcherPlugin = launcherPluginStr?.let { ComponentName.unflattenFromString(it) }
|
||||
|
||||
return LaunchRequest(component, launchIntent?.extras)
|
||||
if (launchIntent != null) {
|
||||
return LaunchRequest(launchIntent, launcherPlugin)
|
||||
}
|
||||
|
||||
val component = componentNameFromIntent(intent) ?: return null
|
||||
val newLaunchIntent = Intent().apply {
|
||||
this.component = component
|
||||
}
|
||||
|
||||
return LaunchRequest(newLaunchIntent, launcherPlugin)
|
||||
}
|
||||
|
||||
override fun parseShortcutRequest(intent: Intent): ShortcutRequest? {
|
||||
|
|
@ -55,7 +47,7 @@ class ViewIntentParserImpl @Inject constructor(
|
|||
val launcherPluginStr = intent.getStringExtra(ShortcutCreator.INTENT_EXTRA_LAUNCH_PLUGIN)
|
||||
val launcherPlugin = launcherPluginStr?.let { ComponentName.unflattenFromString(it) }
|
||||
|
||||
return ShortcutRequest(appName, component, icon, launchIntent.extras, launcherPlugin)
|
||||
return ShortcutRequest(appName, launchIntent, icon, launcherPlugin)
|
||||
}
|
||||
|
||||
override fun componentNameFromIntent(intent: Intent): ComponentName? {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package de.szalkowski.activitylauncher.domain.launcher
|
||||
|
||||
import android.content.ComponentName
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.model.PluginInfo
|
||||
|
||||
interface ActivityLauncherProxy {
|
||||
fun launchActivity(request: LaunchRequest, plugin: ComponentName? = null)
|
||||
fun launchActivity(request: LaunchRequest)
|
||||
|
||||
fun hasMultipleHandlers(): Boolean
|
||||
fun getPlugins(): List<PluginInfo>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package de.szalkowski.activitylauncher.domain.launcher
|
||||
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
|
||||
interface IntentSigner {
|
||||
fun signRequest(request: ShortcutRequest): String
|
||||
fun validateRequestSignature(request: ShortcutRequest, signature: String): Boolean
|
||||
fun signRequest(request: LaunchRequest): String
|
||||
fun validateRequestSignature(request: LaunchRequest, signature: String): Boolean
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
|||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
|
||||
interface ViewIntentParser {
|
||||
fun packageFromIntent(intent: Intent): String?
|
||||
fun componentNameFromIntent(intent: Intent): ComponentName?
|
||||
fun parseShortcutIntent(uri: String): Intent?
|
||||
fun parseLaunchRequest(intent: Intent): LaunchRequest?
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package de.szalkowski.activitylauncher.domain.model
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.os.Bundle
|
||||
import android.content.Intent
|
||||
|
||||
data class LaunchRequest(
|
||||
val component: ComponentName,
|
||||
val extras: Bundle? = null,
|
||||
val intent: Intent,
|
||||
val launcherPlugin: ComponentName? = null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
package de.szalkowski.activitylauncher.domain.model
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.os.Bundle
|
||||
import android.content.Intent
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
|
||||
data class ShortcutRequest(
|
||||
val name: String,
|
||||
val component: ComponentName,
|
||||
val intent: Intent,
|
||||
val icon: IconCompat,
|
||||
val extras: Bundle? = null,
|
||||
val launcherPlugin: ComponentName? = null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CreateShortcutUseCase @Inject constructor(
|
|||
private val shortcutCreatorProxy: ShortcutCreatorProxy,
|
||||
) {
|
||||
operator fun invoke(request: ShortcutRequest, shortcutPlugin: ComponentName? = null) {
|
||||
Log.i("CreateShortcutUseCase", "Creating shortcut: ${request.component.flattenToShortString()}")
|
||||
Log.i("CreateShortcutUseCase", "Creating shortcut: ${request.intent.component?.flattenToShortString()}")
|
||||
if (shortcutPlugin != null || shortcutCreatorProxy.hasMultipleHandlers()) {
|
||||
shortcutCreatorProxy.createLauncherIcon(request, shortcutPlugin)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package de.szalkowski.activitylauncher.domain.usecase.launcher
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.util.Log
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncher
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncherProxy
|
||||
|
|
@ -14,14 +13,15 @@ class LaunchActivityUseCase @Inject constructor(
|
|||
private val activityLauncherProxy: ActivityLauncherProxy,
|
||||
private val recentsRepository: RecentsRepository,
|
||||
) {
|
||||
operator fun invoke(request: LaunchRequest, launchPlugin: ComponentName? = null) {
|
||||
Log.i("LaunchActivityUseCase", "Launching activity: ${request.component.flattenToShortString()}")
|
||||
if (launchPlugin != null || activityLauncherProxy.hasMultipleHandlers()) {
|
||||
activityLauncherProxy.launchActivity(request, launchPlugin)
|
||||
operator fun invoke(request: LaunchRequest) {
|
||||
val component = request.intent.component ?: return
|
||||
Log.i("LaunchActivityUseCase", "Launching activity: ${component.flattenToShortString()}")
|
||||
if (request.launcherPlugin != null || activityLauncherProxy.hasMultipleHandlers()) {
|
||||
activityLauncherProxy.launchActivity(request)
|
||||
} else {
|
||||
activityLauncher.launchActivity(request)
|
||||
}
|
||||
recentsRepository.addActivity(request.component)
|
||||
recentsRepository.addActivity(component)
|
||||
}
|
||||
|
||||
fun hasMultipleHandlers(): Boolean = activityLauncherProxy.hasMultipleHandlers()
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ class MainActivity : AppCompatActivity(), ActionBarSearch {
|
|||
val launchRequest = viewIntentParser.parseLaunchRequest(intent)
|
||||
val componentNameFromExtra =
|
||||
intent.getParcelableExtra<ComponentName>(EXTRA_ACTIVITY_COMPONENT_NAME)
|
||||
val componentName = launchRequest?.component ?: componentNameFromExtra
|
||||
val componentName = launchRequest?.intent?.component ?: componentNameFromExtra
|
||||
|
||||
if (componentName != null) {
|
||||
val bundle = Bundle().apply {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import de.szalkowski.activitylauncher.domain.launcher.IntentSigner
|
|||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreator
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreatorProxy
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ViewIntentParser
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.usecase.launcher.LaunchActivityUseCase
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -98,16 +97,16 @@ class ShortcutActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun handleLaunchShortcut() {
|
||||
val request = viewIntentParser.parseShortcutRequest(intent) ?: return
|
||||
val request = viewIntentParser.parseLaunchRequest(intent) ?: return
|
||||
val signature = intent.getStringExtra(ShortcutCreator.INTENT_EXTRA_SIGNATURE).orEmpty()
|
||||
|
||||
if (!intentSigner.validateRequestSignature(request, signature)) {
|
||||
Log.e("ShortcutActivity", "Invalid signature for shortcut")
|
||||
redirectToMain(request.component)
|
||||
request.intent.component?.let { redirectToMain(it) }
|
||||
return
|
||||
}
|
||||
|
||||
launchActivityUseCase.invoke(LaunchRequest(request.component, request.extras), request.launcherPlugin)
|
||||
launchActivityUseCase.invoke(request)
|
||||
}
|
||||
|
||||
private fun handleLaunchActivity() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import de.szalkowski.activitylauncher.R
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.favorites.FavoritesRepository
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IconLoader
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
|
|
@ -170,9 +171,8 @@ class ActivityDetailsViewModel @Inject constructor(
|
|||
val icon = _editedIcon.value ?: getActivityIconUseCase(info.iconResourceName, info.componentName)
|
||||
val request = ShortcutRequest(
|
||||
name = info.name,
|
||||
component = info.componentName,
|
||||
intent = getActivityIntent(info.componentName, Bundle()),
|
||||
icon = icon,
|
||||
extras = Bundle(),
|
||||
launcherPlugin = _selectedLaunchPlugin.value?.componentName,
|
||||
)
|
||||
createShortcutUseCase(request, _selectedShortcutPlugin.value?.componentName)
|
||||
|
|
@ -189,10 +189,10 @@ class ActivityDetailsViewModel @Inject constructor(
|
|||
fun launchActivity() {
|
||||
val info = getEditedActivityInfo()
|
||||
val request = LaunchRequest(
|
||||
component = info.componentName,
|
||||
extras = Bundle(),
|
||||
intent = getActivityIntent(info.componentName, Bundle()),
|
||||
launcherPlugin = _selectedLaunchPlugin.value?.componentName,
|
||||
)
|
||||
launchActivityUseCase(request, _selectedLaunchPlugin.value?.componentName)
|
||||
launchActivityUseCase(request)
|
||||
}
|
||||
|
||||
fun shareActivity() {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.navigation.NavDirections
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IconLoader
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.packages.PackageRepository
|
||||
|
|
@ -49,7 +50,7 @@ abstract class BaseActivityListFragment : Fragment() {
|
|||
icon.loadDrawable(requireContext()) ?: requireContext().packageManager.defaultActivityIcon
|
||||
}
|
||||
adapter.onItemClick = { info ->
|
||||
launchActivityUseCase(LaunchRequest(info.componentName))
|
||||
launchActivityUseCase(LaunchRequest(getActivityIntent(info.componentName, null)))
|
||||
}
|
||||
adapter.onItemLongClick = { info ->
|
||||
runCatching {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.content.ComponentName
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
|
|
@ -47,69 +47,51 @@ class IntentSignerImplTest {
|
|||
|
||||
@Test
|
||||
fun testSignAndValidateRequest() = withMockedBase64 {
|
||||
val componentName = mock<ComponentName>()
|
||||
val icon = mock<androidx.core.graphics.drawable.IconCompat>()
|
||||
val request = ShortcutRequest("Test", componentName, icon)
|
||||
val intent = mock<Intent>()
|
||||
val shortcutRequest = ShortcutRequest("Test", intent, icon)
|
||||
val launchRequest = LaunchRequest(intent)
|
||||
|
||||
val intentUtilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
mockStatic(intentUtilClass).use { mockedIntentUtil ->
|
||||
mockedIntentUtil.`when`<Intent> {
|
||||
getActivityIntent(eq(componentName), anyOrNull())
|
||||
}.thenReturn(intent)
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
|
||||
val signature = signer.signRequest(request)
|
||||
val signature = signer.signRequest(shortcutRequest)
|
||||
|
||||
assertNotNull(signature)
|
||||
assertTrue(signer.validateRequestSignature(request, signature))
|
||||
}
|
||||
assertNotNull(signature)
|
||||
assertTrue(signer.validateRequestSignature(launchRequest, signature))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSignatureWithPlugin() = withMockedBase64 {
|
||||
val componentName = mock<ComponentName>()
|
||||
val icon = mock<androidx.core.graphics.drawable.IconCompat>()
|
||||
val plugin = mock<ComponentName>()
|
||||
whenever(plugin.flattenToString()).thenReturn("com.example/.Plugin")
|
||||
val requestWithPlugin = ShortcutRequest("Test", componentName, icon, launcherPlugin = plugin)
|
||||
val requestWithoutPlugin = ShortcutRequest("Test", componentName, icon)
|
||||
val intent = mock<Intent>()
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
|
||||
val intentUtilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
mockStatic(intentUtilClass).use { mockedIntentUtil ->
|
||||
mockedIntentUtil.`when`<Intent> {
|
||||
getActivityIntent(eq(componentName), anyOrNull())
|
||||
}.thenReturn(intent)
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
val shortcutRequestWithPlugin = ShortcutRequest("Test", intent, icon, launcherPlugin = plugin)
|
||||
val shortcutRequestWithoutPlugin = ShortcutRequest("Test", intent, icon)
|
||||
val launchRequestWithPlugin = LaunchRequest(intent, launcherPlugin = plugin)
|
||||
val launchRequestWithoutPlugin = LaunchRequest(intent)
|
||||
|
||||
val signatureWithPlugin = signer.signRequest(requestWithPlugin)
|
||||
val signatureWithoutPlugin = signer.signRequest(requestWithoutPlugin)
|
||||
val signatureWithPlugin = signer.signRequest(shortcutRequestWithPlugin)
|
||||
val signatureWithoutPlugin = signer.signRequest(shortcutRequestWithoutPlugin)
|
||||
|
||||
assertNotEquals(signatureWithPlugin, signatureWithoutPlugin)
|
||||
assertTrue(signer.validateRequestSignature(requestWithPlugin, signatureWithPlugin))
|
||||
assertFalse(signer.validateRequestSignature(requestWithPlugin, signatureWithoutPlugin))
|
||||
assertFalse(signer.validateRequestSignature(requestWithoutPlugin, signatureWithPlugin))
|
||||
}
|
||||
assertNotEquals(signatureWithPlugin, signatureWithoutPlugin)
|
||||
assertTrue(signer.validateRequestSignature(launchRequestWithPlugin, signatureWithPlugin))
|
||||
assertFalse(signer.validateRequestSignature(launchRequestWithPlugin, signatureWithoutPlugin))
|
||||
assertFalse(signer.validateRequestSignature(launchRequestWithoutPlugin, signatureWithPlugin))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKnownSignature() = withMockedBase64 {
|
||||
val componentName = mock<ComponentName>()
|
||||
val icon = mock<androidx.core.graphics.drawable.IconCompat>()
|
||||
val request = ShortcutRequest("Test", componentName, icon)
|
||||
val intent = mock<Intent>()
|
||||
val request = ShortcutRequest("Test", intent, icon)
|
||||
|
||||
val intentUtilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
mockStatic(intentUtilClass).use { mockedIntentUtil ->
|
||||
mockedIntentUtil.`when`<Intent> {
|
||||
getActivityIntent(eq(componentName), anyOrNull())
|
||||
}.thenReturn(intent)
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
whenever(intent.toUri(anyInt())).thenReturn("intent:#Intent;action=com.test.ACTION;end")
|
||||
|
||||
val signature = signer.signRequest(request)
|
||||
// Verified known signature for "intent:#Intent;action=com.test.ACTION;end" with key "test_key"
|
||||
assertEquals("kPThuLUm6BnZkfNuIuRuVZfj8IXOinD+dURnRv1Ytd8=", signature)
|
||||
}
|
||||
val signature = signer.signRequest(request)
|
||||
// Verified known signature for "intent:#Intent;action=com.test.ACTION;end" with key "test_key"
|
||||
assertEquals("kPThuLUm6BnZkfNuIuRuVZfj8IXOinD+dURnRv1Ytd8=", signature)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,16 @@ import org.mockito.kotlin.*
|
|||
class CreateShortcutUseCaseTest {
|
||||
private val shortcutCreator: ShortcutCreator = mock()
|
||||
private val shortcutCreatorProxy: ShortcutCreatorProxy = mock()
|
||||
private val componentName = ComponentName("com.test", "Activity")
|
||||
private val componentName = mock<ComponentName> {
|
||||
on { packageName } doReturn "com.test"
|
||||
on { className } doReturn "Activity"
|
||||
on { flattenToShortString() } doReturn "com.test/Activity"
|
||||
}
|
||||
private val icon = mock<androidx.core.graphics.drawable.IconCompat>()
|
||||
private val request = ShortcutRequest("Test", componentName, icon)
|
||||
private val intent = mock<android.content.Intent> {
|
||||
on { component } doReturn componentName
|
||||
}
|
||||
private val request = ShortcutRequest("Test", intent, icon)
|
||||
private lateinit var useCase: CreateShortcutUseCase
|
||||
|
||||
@Before
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package de.szalkowski.activitylauncher.domain.usecase.launcher
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncher
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ActivityLauncherProxy
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
|
|
@ -16,7 +17,11 @@ class LaunchActivityUseCaseTest {
|
|||
private val activityLauncherProxy: ActivityLauncherProxy = mock()
|
||||
private val recentsRepository: RecentsRepository = mock()
|
||||
private lateinit var useCase: LaunchActivityUseCase
|
||||
private val componentName = ComponentName("com.test", "Activity")
|
||||
private val componentName = mock<ComponentName> {
|
||||
on { packageName } doReturn "com.test"
|
||||
on { className } doReturn "Activity"
|
||||
on { flattenToShortString() } doReturn "com.test/Activity"
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
|
|
@ -25,7 +30,10 @@ class LaunchActivityUseCaseTest {
|
|||
|
||||
@Test
|
||||
fun `should launch activity and add to recents`() {
|
||||
val request = LaunchRequest(componentName)
|
||||
val intent = mock<Intent> {
|
||||
on { component } doReturn componentName
|
||||
}
|
||||
val request = LaunchRequest(intent)
|
||||
useCase.invoke(request)
|
||||
|
||||
verify(activityLauncher).launchActivity(eq(request))
|
||||
|
|
@ -35,10 +43,13 @@ class LaunchActivityUseCaseTest {
|
|||
@Test
|
||||
fun `should launch activity with plugin and add to recents`() {
|
||||
val plugin = ComponentName("com.plugin", "Plugin")
|
||||
val request = LaunchRequest(componentName)
|
||||
useCase.invoke(request, launchPlugin = plugin)
|
||||
val intent = mock<Intent> {
|
||||
on { component } doReturn componentName
|
||||
}
|
||||
val request = LaunchRequest(intent, launcherPlugin = plugin)
|
||||
useCase.invoke(request)
|
||||
|
||||
verify(activityLauncherProxy).launchActivity(eq(request), eq(plugin))
|
||||
verify(activityLauncherProxy).launchActivity(eq(request))
|
||||
verify(recentsRepository).addActivity(componentName)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.ComponentName
|
|||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import de.szalkowski.activitylauncher.R
|
||||
import de.szalkowski.activitylauncher.core.util.getActivityIntent
|
||||
import de.szalkowski.activitylauncher.domain.favorites.FavoritesRepository
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IconLoader
|
||||
import de.szalkowski.activitylauncher.domain.model.LaunchRequest
|
||||
|
|
@ -104,20 +105,34 @@ class ActivityDetailsViewModelTest {
|
|||
|
||||
@Test
|
||||
fun `should launch activity`() {
|
||||
viewModel.launchActivity()
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(launchActivityUseCase).invoke(captor.capture(), isNull())
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("Activity", captor.firstValue.component.className)
|
||||
val mockIntent = mock<android.content.Intent>()
|
||||
val utilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
org.mockito.Mockito.mockStatic(utilClass).use { mockedUtil ->
|
||||
mockedUtil.`when`<android.content.Intent> {
|
||||
getActivityIntent(eq(componentName), any())
|
||||
}.thenReturn(mockIntent)
|
||||
|
||||
viewModel.launchActivity()
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(launchActivityUseCase).invoke(captor.capture())
|
||||
assertEquals(mockIntent, captor.firstValue.intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should create shortcut`() {
|
||||
viewModel.createShortcut()
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), isNull())
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("Activity", captor.firstValue.component.className)
|
||||
val mockIntent = mock<android.content.Intent>()
|
||||
val utilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
org.mockito.Mockito.mockStatic(utilClass).use { mockedUtil ->
|
||||
mockedUtil.`when`<android.content.Intent> {
|
||||
getActivityIntent(eq(componentName), any())
|
||||
}.thenReturn(mockIntent)
|
||||
|
||||
viewModel.createShortcut()
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), isNull())
|
||||
assertEquals(mockIntent, captor.firstValue.intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -186,12 +201,20 @@ class ActivityDetailsViewModelTest {
|
|||
|
||||
newViewModel.selectLaunchPlugin(pluginComp)
|
||||
|
||||
newViewModel.launchActivity()
|
||||
val mockIntent = mock<android.content.Intent>()
|
||||
val utilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
org.mockito.Mockito.mockStatic(utilClass).use { mockedUtil ->
|
||||
mockedUtil.`when`<android.content.Intent> {
|
||||
getActivityIntent(eq(componentName), any())
|
||||
}.thenReturn(mockIntent)
|
||||
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(launchActivityUseCase).invoke(captor.capture(), eq(pluginComp))
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("Activity", captor.firstValue.component.className)
|
||||
newViewModel.launchActivity()
|
||||
|
||||
val captor = argumentCaptor<LaunchRequest>()
|
||||
verify(launchActivityUseCase).invoke(captor.capture())
|
||||
assertEquals(mockIntent, captor.firstValue.intent)
|
||||
assertEquals(pluginComp, captor.firstValue.launcherPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -208,12 +231,19 @@ class ActivityDetailsViewModelTest {
|
|||
|
||||
newViewModel.selectShortcutPlugin(pluginComp)
|
||||
|
||||
newViewModel.createShortcut()
|
||||
val mockIntent = mock<android.content.Intent>()
|
||||
val utilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
org.mockito.Mockito.mockStatic(utilClass).use { mockedUtil ->
|
||||
mockedUtil.`when`<android.content.Intent> {
|
||||
getActivityIntent(eq(componentName), any())
|
||||
}.thenReturn(mockIntent)
|
||||
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), eq(pluginComp))
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("Activity", captor.firstValue.component.className)
|
||||
newViewModel.createShortcut()
|
||||
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), eq(pluginComp))
|
||||
assertEquals(mockIntent, captor.firstValue.intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -230,13 +260,20 @@ class ActivityDetailsViewModelTest {
|
|||
|
||||
newViewModel.selectLaunchPlugin(pluginComp)
|
||||
|
||||
newViewModel.createShortcut()
|
||||
val mockIntent = mock<android.content.Intent>()
|
||||
val utilClass = Class.forName("de.szalkowski.activitylauncher.core.util.ActivityIntentKt")
|
||||
org.mockito.Mockito.mockStatic(utilClass).use { mockedUtil ->
|
||||
mockedUtil.`when`<android.content.Intent> {
|
||||
getActivityIntent(eq(componentName), any())
|
||||
}.thenReturn(mockIntent)
|
||||
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), isNull())
|
||||
assertEquals("com.test", captor.firstValue.component.packageName)
|
||||
assertEquals("Activity", captor.firstValue.component.className)
|
||||
assertEquals(pluginComp, captor.firstValue.launcherPlugin)
|
||||
newViewModel.createShortcut()
|
||||
|
||||
val captor = argumentCaptor<ShortcutRequest>()
|
||||
verify(createShortcutUseCase).invoke(captor.capture(), isNull())
|
||||
assertEquals(mockIntent, captor.firstValue.intent)
|
||||
assertEquals(pluginComp, captor.firstValue.launcherPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue