diff --git a/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensions.kt index e12f00ce74..72aecde640 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensions.kt @@ -20,8 +20,8 @@ fun FilledPartition.buildDataset( autofillAppInfo: AutofillAppInfo, ): Dataset { val remoteViewsPlaceholder = buildAutofillRemoteViews( - packageName = autofillAppInfo.packageName, - title = autofillCipher.name, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) val datasetBuilder = Dataset.Builder() diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViews.kt b/app/src/main/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViews.kt index 8ccea2cb49..cecdde36d3 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViews.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViews.kt @@ -1,22 +1,69 @@ package com.x8bit.bitwarden.ui.autofill +import android.content.Context import android.widget.RemoteViews import com.x8bit.bitwarden.R +import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo +import com.x8bit.bitwarden.data.autofill.model.AutofillCipher +import com.x8bit.bitwarden.ui.autofill.util.isSystemDarkMode /** * Build [RemoteViews] for representing an autofill suggestion. */ fun buildAutofillRemoteViews( - packageName: String, - title: String, + autofillAppInfo: AutofillAppInfo, + autofillCipher: AutofillCipher, ): RemoteViews = RemoteViews( - packageName, + autofillAppInfo.packageName, R.layout.autofill_remote_view, ) .apply { setTextViewText( - R.id.text, - title, + R.id.title, + autofillCipher.name, + ) + setTextViewText( + R.id.subtitle, + autofillCipher.subtitle, + ) + setImageViewResource( + R.id.icon, + autofillCipher.iconRes, + ) + + setInt( + R.id.container, + "setBackgroundColor", + autofillAppInfo.context.surface, + ) + setInt( + R.id.icon, + "setColorFilter", + autofillAppInfo.context.onSurface, + ) + setInt( + R.id.title, + "setTextColor", + autofillAppInfo.context.onSurface, + ) + setInt( + R.id.subtitle, + "setTextColor", + autofillAppInfo.context.onSurfaceVariant, ) } + +private val Context.onSurface: Int + get() = getColor( + if (isSystemDarkMode) R.color.dark_on_surface else R.color.on_surface, + ) +private val Context.onSurfaceVariant: Int + get() = getColor( + if (isSystemDarkMode) R.color.dark_on_surface_variant else R.color.on_surface_variant, + ) + +private val Context.surface: Int + get() = getColor( + if (isSystemDarkMode) R.color.dark_surface else R.color.surface, + ) diff --git a/app/src/main/res/layout/autofill_remote_view.xml b/app/src/main/res/layout/autofill_remote_view.xml index b433796732..36eee78dcb 100644 --- a/app/src/main/res/layout/autofill_remote_view.xml +++ b/app/src/main/res/layout/autofill_remote_view.xml @@ -1,6 +1,40 @@ - + + + + + + + + + + + diff --git a/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensionsTest.kt index c693f9dac9..07620ead6a 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/FilledPartitionExtensionsTest.kt @@ -81,8 +81,8 @@ class FilledPartitionExtensionsTest { val inlinePresentation: InlinePresentation = mockk() every { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) } returns remoteViews every { @@ -110,8 +110,8 @@ class FilledPartitionExtensionsTest { assertEquals(dataset, actual) verify(exactly = 1) { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) inlinePresentationSpec.createCipherInlinePresentationOrNull( autofillAppInfo = autofillAppInfo, @@ -137,11 +137,10 @@ class FilledPartitionExtensionsTest { packageName = PACKAGE_NAME, sdkInt = 18, ) - val inlinePresentation: InlinePresentation = mockk() every { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) } returns remoteViews every { @@ -160,8 +159,8 @@ class FilledPartitionExtensionsTest { assertEquals(dataset, actual) verify(exactly = 1) { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) filledItem.applyToDatasetPreTiramisu( datasetBuilder = any(), @@ -183,8 +182,8 @@ class FilledPartitionExtensionsTest { val inlinePresentation: InlinePresentation = mockk() every { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) } returns remoteViews every { @@ -210,8 +209,8 @@ class FilledPartitionExtensionsTest { assertEquals(dataset, actual) verify(exactly = 1) { buildAutofillRemoteViews( - packageName = PACKAGE_NAME, - title = CIPHER_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) inlinePresentationSpec.createCipherInlinePresentationOrNull( autofillAppInfo = autofillAppInfo, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViewsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViewsTest.kt index 6f92e44732..068b90186f 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViewsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/autofill/BitwardenRemoteViewsTest.kt @@ -1,52 +1,119 @@ package com.x8bit.bitwarden.ui.autofill -import android.content.res.Resources +import android.content.Context import android.widget.RemoteViews import com.x8bit.bitwarden.R -import io.mockk.confirmVerified +import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo +import com.x8bit.bitwarden.data.autofill.model.AutofillCipher +import com.x8bit.bitwarden.ui.autofill.util.isSystemDarkMode import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.mockkConstructor +import io.mockk.mockkStatic import io.mockk.runs import io.mockk.unmockkConstructor +import io.mockk.unmockkStatic import io.mockk.verify import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class BitwardenRemoteViewsTest { - private val testResources: Resources = mockk() + private val testContext: Context = mockk { + every { this@mockk.getColor(R.color.dark_on_surface) } returns DARK_ON_SURFACE_COLOR + every { + this@mockk.getColor(R.color.dark_on_surface_variant) + } returns DARK_ON_SURFACE_VARIANT_COLOR + every { this@mockk.getColor(R.color.dark_surface) } returns DARK_SURFACE_COLOR + every { this@mockk.getColor(R.color.on_surface) } returns ON_SURFACE_COLOR + every { this@mockk.getColor(R.color.on_surface_variant) } returns ON_SURFACE_VARIANT_COLOR + every { this@mockk.getColor(R.color.surface) } returns SURFACE_COLOR + } + private val autofillAppInfo: AutofillAppInfo = mockk { + every { this@mockk.context } returns testContext + every { this@mockk.packageName } returns PACKAGE_NAME + } + private val autofillCipher: AutofillCipher = mockk { + every { this@mockk.iconRes } returns ICON_RES + every { this@mockk.name } returns NAME + every { this@mockk.subtitle } returns SUBTITLE + } @BeforeEach fun setup() { + mockkStatic(Context::isSystemDarkMode) mockkConstructor(RemoteViews::class) } @AfterEach fun teardown() { + unmockkStatic(Context::isSystemDarkMode) unmockkConstructor(RemoteViews::class) - confirmVerified( - testResources, - ) } @Test - fun `buildAutofillRemoteViews should set text`() { + fun `buildAutofillRemoteViews should set values and light mode colors when not night mode`() { // Setup - val title = "Bitwarden" + every { testContext.isSystemDarkMode } returns false every { anyConstructed() .setTextViewText( - R.id.text, - title, + R.id.title, + NAME, + ) + } just runs + every { + anyConstructed() + .setTextViewText( + R.id.subtitle, + SUBTITLE, + ) + } just runs + every { + anyConstructed() + .setImageViewResource( + R.id.icon, + ICON_RES, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.container, + "setBackgroundColor", + SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.icon, + "setColorFilter", + ON_SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.title, + "setTextColor", + ON_SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.subtitle, + "setTextColor", + ON_SURFACE_VARIANT_COLOR, ) } just runs // Test buildAutofillRemoteViews( - title = title, - packageName = PACKAGE_NAME, + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, ) // Note: impossible to do a useful test of the returned RemoteViews due to mockking @@ -57,13 +124,166 @@ class BitwardenRemoteViewsTest { verify(exactly = 1) { anyConstructed() .setTextViewText( - R.id.text, - title, + R.id.title, + NAME, + ) + anyConstructed() + .setTextViewText( + R.id.subtitle, + SUBTITLE, + ) + anyConstructed() + .setImageViewResource( + R.id.icon, + ICON_RES, + ) + anyConstructed() + .setInt( + R.id.container, + "setBackgroundColor", + SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.icon, + "setColorFilter", + ON_SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.title, + "setTextColor", + ON_SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.subtitle, + "setTextColor", + ON_SURFACE_VARIANT_COLOR, ) } } - companion object { - private const val PACKAGE_NAME: String = "com.x8bit.bitwarden" + @Test + fun `buildAutofillRemoteViews should set values and dark mode colors when night mode`() { + // Setup + every { testContext.isSystemDarkMode } returns true + every { + anyConstructed() + .setTextViewText( + R.id.title, + NAME, + ) + } just runs + every { + anyConstructed() + .setTextViewText( + R.id.subtitle, + SUBTITLE, + ) + } just runs + every { + anyConstructed() + .setImageViewResource( + R.id.icon, + ICON_RES, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.container, + "setBackgroundColor", + DARK_SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.icon, + "setColorFilter", + DARK_ON_SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.title, + "setTextColor", + DARK_ON_SURFACE_COLOR, + ) + } just runs + every { + anyConstructed() + .setInt( + R.id.subtitle, + "setTextColor", + DARK_ON_SURFACE_VARIANT_COLOR, + ) + } just runs + + // Test + buildAutofillRemoteViews( + autofillAppInfo = autofillAppInfo, + autofillCipher = autofillCipher, + ) + + // Note: impossible to do a useful test of the returned RemoteViews due to mockking + // constraints of the [RemoteViews] constructor. Our best bet is to make sure the correct + // operations are performed on the constructed [RemoteViews]. + + // Verify + verify(exactly = 1) { + anyConstructed() + .setTextViewText( + R.id.title, + NAME, + ) + anyConstructed() + .setTextViewText( + R.id.subtitle, + SUBTITLE, + ) + anyConstructed() + .setImageViewResource( + R.id.icon, + ICON_RES, + ) + anyConstructed() + .setInt( + R.id.container, + "setBackgroundColor", + DARK_SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.icon, + "setColorFilter", + DARK_ON_SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.title, + "setTextColor", + DARK_ON_SURFACE_COLOR, + ) + anyConstructed() + .setInt( + R.id.subtitle, + "setTextColor", + DARK_ON_SURFACE_VARIANT_COLOR, + ) + } } } + +private const val DARK_ON_SURFACE_COLOR: Int = 321 +private const val DARK_ON_SURFACE_VARIANT_COLOR: Int = 654 +private const val DARK_SURFACE_COLOR: Int = 987 +private const val ICON_RES: Int = 41421421 +private const val NAME: String = "NAME" +private const val ON_SURFACE_COLOR: Int = 123 +private const val ON_SURFACE_VARIANT_COLOR: Int = 456 +private const val PACKAGE_NAME: String = "com.x8bit.bitwarden" +private const val SUBTITLE: String = "SUBTITLE" +private const val SURFACE_COLOR: Int = 789