mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
PM-11483: Create AutofillTileService (#3844)
This commit is contained in:
parent
17c579bfc2
commit
7e5203efa5
9 changed files with 176 additions and 5 deletions
|
@ -3,6 +3,24 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application tools:ignore="MissingApplicationIcon">
|
||||
<!--
|
||||
The AutofillTileService name below refers to the legacy Xamarin app's service name.
|
||||
This must always match in order for the app to properly query if it is providing autofill
|
||||
tile services.
|
||||
-->
|
||||
<!--suppress AndroidDomInspection -->
|
||||
<service
|
||||
android:name="com.x8bit.bitwarden.AutofillTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_notification"
|
||||
android:label="@string/autofill"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
tools:ignore="MissingClass">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Disable Crashlytics for debug builds -->
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
|
|
|
@ -77,6 +77,13 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AccessibilityActivity"
|
||||
android:exported="false"
|
||||
android:launchMode="singleTop"
|
||||
android:noHistory="true"
|
||||
android:theme="@android:style/Theme.NoDisplay" />
|
||||
|
||||
<activity
|
||||
android:name=".AutofillTotpCopyActivity"
|
||||
android:exported="true"
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package com.x8bit.bitwarden
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
|
||||
/**
|
||||
* An activity to be launched and then immediately closed so that the OS Shade can be collapsed
|
||||
* after the user clicks on the Autofill Quick Tile.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
class AccessibilityActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
finish()
|
||||
}
|
||||
}
|
|
@ -3,16 +3,19 @@ package com.x8bit.bitwarden
|
|||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.app.AppComponentFactory
|
||||
import com.x8bit.bitwarden.data.autofill.BitwardenAutofillService
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.BitwardenFido2ProviderService
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
import com.x8bit.bitwarden.data.tiles.BitwardenAutofillTileService
|
||||
import com.x8bit.bitwarden.data.tiles.BitwardenGeneratorTileService
|
||||
import com.x8bit.bitwarden.data.tiles.BitwardenVaultTileService
|
||||
|
||||
private const val LEGACY_AUTOFILL_SERVICE_NAME = "com.x8bit.bitwarden.Autofill.AutofillService"
|
||||
private const val LEGACY_CREDENTIAL_SERVICE_NAME =
|
||||
"com.x8bit.bitwarden.Autofill.CredentialProviderService"
|
||||
private const val LEGACY_AUTOFILL_TILE_SERVICE_NAME = "com.x8bit.bitwarden.AutofillTileService"
|
||||
private const val LEGACY_VAULT_TILE_SERVICE_NAME = "com.x8bit.bitwarden.MyVaultTileService"
|
||||
private const val LEGACY_GENERATOR_TILE_SERVICE_NAME = "com.x8bit.bitwarden.GeneratorTileService"
|
||||
|
||||
|
@ -21,14 +24,20 @@ private const val LEGACY_GENERATOR_TILE_SERVICE_NAME = "com.x8bit.bitwarden.Gene
|
|||
* and modify various characteristics before initialization.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@Keep
|
||||
@OmitFromCoverage
|
||||
class BitwardenAppComponentFactory : AppComponentFactory() {
|
||||
/**
|
||||
* Used to intercept when the [BitwardenAutofillService], [BitwardenFido2ProviderService],
|
||||
* [BitwardenVaultTileService], or [BitwardenGeneratorTileService] is being instantiated and
|
||||
* modify which service is created. This is required because the [className] used in the
|
||||
* manifest must match the legacy Xamarin app service name but the service name in this app is
|
||||
* different.
|
||||
* Used to intercept when certain legacy services are being instantiated and modify which
|
||||
* service is created. This is required because the [className] used in the manifest must match
|
||||
* the legacy Xamarin app service name but the service name in this app is different.
|
||||
*
|
||||
* Services currently being managed:
|
||||
* * [BitwardenAutofillService]
|
||||
* * [BitwardenAutofillTileService]
|
||||
* * [BitwardenFido2ProviderService]
|
||||
* * [BitwardenVaultTileService]
|
||||
* * [BitwardenGeneratorTileService]
|
||||
*/
|
||||
override fun instantiateServiceCompat(
|
||||
cl: ClassLoader,
|
||||
|
@ -39,6 +48,14 @@ class BitwardenAppComponentFactory : AppComponentFactory() {
|
|||
super.instantiateServiceCompat(cl, BitwardenAutofillService::class.java.name, intent)
|
||||
}
|
||||
|
||||
LEGACY_AUTOFILL_TILE_SERVICE_NAME -> {
|
||||
super.instantiateServiceCompat(
|
||||
cl,
|
||||
BitwardenAutofillTileService::class.java.name,
|
||||
intent,
|
||||
)
|
||||
}
|
||||
|
||||
LEGACY_CREDENTIAL_SERVICE_NAME -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
super.instantiateServiceCompat(
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.x8bit.bitwarden.data.accessibility.di
|
||||
|
||||
import com.x8bit.bitwarden.data.accessibility.manager.AccessibilityAutofillManager
|
||||
import com.x8bit.bitwarden.data.accessibility.manager.AccessibilityAutofillManagerImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Provides dependencies within the accessibility package.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AccessibilityModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providesAccessibilityInvokeManager(): AccessibilityAutofillManager =
|
||||
AccessibilityAutofillManagerImpl()
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.x8bit.bitwarden.data.accessibility.manager
|
||||
|
||||
/**
|
||||
* A relay manager used to notify the accessibility service to attempt an autofill.
|
||||
*/
|
||||
interface AccessibilityAutofillManager {
|
||||
/**
|
||||
* Indicates that the Autofill tile has been clicked and we attempt an accessibility-based
|
||||
* autofill.
|
||||
*/
|
||||
var isAccessibilityTileClicked: Boolean
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.x8bit.bitwarden.data.accessibility.manager
|
||||
|
||||
/**
|
||||
* The default implementation for the [AccessibilityAutofillManager].
|
||||
*/
|
||||
class AccessibilityAutofillManagerImpl : AccessibilityAutofillManager {
|
||||
override var isAccessibilityTileClicked: Boolean = false
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.x8bit.bitwarden.data.tiles
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.TileService
|
||||
import androidx.annotation.Keep
|
||||
import com.x8bit.bitwarden.AccessibilityActivity
|
||||
import com.x8bit.bitwarden.data.accessibility.manager.AccessibilityAutofillManager
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A service for handling the Autofill quick settings tile.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
@Keep
|
||||
@OmitFromCoverage
|
||||
class BitwardenAutofillTileService : TileService() {
|
||||
@Inject
|
||||
lateinit var accessibilityAutofillManager: AccessibilityAutofillManager
|
||||
|
||||
override fun onClick() {
|
||||
if (isLocked) {
|
||||
unlockAndRun { launchAutofill() }
|
||||
} else {
|
||||
launchAutofill()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StartActivityAndCollapseDeprecated")
|
||||
private fun launchAutofill() {
|
||||
accessibilityAutofillManager.isAccessibilityTileClicked = true
|
||||
val intent = Intent(applicationContext, AccessibilityActivity::class.java)
|
||||
if (isBuildVersionBelow(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
|
||||
@Suppress("DEPRECATION")
|
||||
startActivityAndCollapse(intent)
|
||||
} else {
|
||||
startActivityAndCollapse(
|
||||
PendingIntent.getActivity(
|
||||
applicationContext,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.x8bit.bitwarden.data.accessibility.manager
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AccessibilityAutofillManagerTest {
|
||||
private val accessibilityAutofillManager: AccessibilityAutofillManager =
|
||||
AccessibilityAutofillManagerImpl()
|
||||
|
||||
@Test
|
||||
fun `isAccessibilityTileClicked should simply hold the state it is provided`() {
|
||||
assertFalse(accessibilityAutofillManager.isAccessibilityTileClicked)
|
||||
accessibilityAutofillManager.isAccessibilityTileClicked = true
|
||||
assertTrue(accessibilityAutofillManager.isAccessibilityTileClicked)
|
||||
accessibilityAutofillManager.isAccessibilityTileClicked = false
|
||||
assertFalse(accessibilityAutofillManager.isAccessibilityTileClicked)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue