Add My Vault and Password Generator Quick Settings tiles (#3764)

This commit is contained in:
mpbw2 2024-08-26 09:53:10 -04:00 committed by GitHub
parent 76a3265bbb
commit 9dbb40f33b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 175 additions and 4 deletions

View file

@ -72,6 +72,7 @@
<action android:name="com.x8bit.bitwarden.fido2.ACTION_CREATE_PASSKEY" />
<action android:name="com.x8bit.bitwarden.fido2.ACTION_GET_PASSKEY" />
<action android:name="com.x8bit.bitwarden.fido2.ACTION_UNLOCK_ACCOUNT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@ -191,6 +192,42 @@
android:value="true" />
</service>
<!--
The GeneratorTileService 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 generator
tile services.
-->
<!--suppress AndroidDomInspection -->
<service
android:name="com.x8bit.bitwarden.GeneratorTileService"
android:exported="true"
android:icon="@drawable/ic_generator"
android:label="@string/password_generator"
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>
<!--
The MyVaultTileService 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 vault
tile services.
-->
<!--suppress AndroidDomInspection -->
<service
android:name="com.x8bit.bitwarden.MyVaultTileService"
android:exported="true"
android:icon="@drawable/ic_notification"
android:label="@string/my_vault"
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>
<meta-data
android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_restrictions" />

View file

@ -7,10 +7,14 @@ 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.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_VAULT_TILE_SERVICE_NAME = "com.x8bit.bitwarden.MyVaultTileService"
private const val LEGACY_GENERATOR_TILE_SERVICE_NAME = "com.x8bit.bitwarden.GeneratorTileService"
/**
* A factory class that allows us to intercept when a manifest element is being instantiated
@ -20,10 +24,11 @@ private const val LEGACY_CREDENTIAL_SERVICE_NAME =
@OmitFromCoverage
class BitwardenAppComponentFactory : AppComponentFactory() {
/**
* Used to intercept when the [BitwardenAutofillService] or [BitwardenFido2ProviderService] 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 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.
*/
override fun instantiateServiceCompat(
cl: ClassLoader,
@ -48,6 +53,18 @@ class BitwardenAppComponentFactory : AppComponentFactory() {
}
}
LEGACY_VAULT_TILE_SERVICE_NAME -> {
super.instantiateServiceCompat(cl, BitwardenVaultTileService::class.java.name, intent)
}
LEGACY_GENERATOR_TILE_SERVICE_NAME -> {
super.instantiateServiceCompat(
cl,
BitwardenGeneratorTileService::class.java.name,
intent,
)
}
else -> super.instantiateServiceCompat(cl, className, intent)
}
}

View file

@ -0,0 +1,43 @@
package com.x8bit.bitwarden.data.tiles
import android.annotation.SuppressLint
import android.os.Build
import android.service.quicksettings.TileService
import androidx.annotation.Keep
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Runnable
import javax.inject.Inject
/**
* A service for handling the Password Generator quick settings tile.
*/
@AndroidEntryPoint
@Keep
@OmitFromCoverage
class BitwardenGeneratorTileService : TileService() {
@Inject
lateinit var intentManager: IntentManager
override fun onClick() {
if (isLocked) {
unlockAndRun(Runnable { launchGenerator() })
} else {
launchGenerator()
}
}
@Suppress("DEPRECATION")
@SuppressLint("StartActivityAndCollapseDeprecated")
private fun launchGenerator() {
val intent = intentManager.createTileIntent("bitwarden://password_generator")
if (isBuildVersionBelow(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
startActivityAndCollapse(intent)
} else {
startActivityAndCollapse(intentManager.createTilePendingIntent(0, intent))
}
}
}

View file

@ -0,0 +1,43 @@
package com.x8bit.bitwarden.data.tiles
import android.annotation.SuppressLint
import android.os.Build
import android.service.quicksettings.TileService
import androidx.annotation.Keep
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Runnable
import javax.inject.Inject
/**
* A service for handling the My Vault quick settings tile.
*/
@AndroidEntryPoint
@Keep
@OmitFromCoverage
class BitwardenVaultTileService : TileService() {
@Inject
lateinit var intentManager: IntentManager
override fun onClick() {
if (isLocked) {
unlockAndRun(Runnable { launchVault() })
} else {
launchVault()
}
}
@Suppress("DEPRECATION")
@SuppressLint("StartActivityAndCollapseDeprecated")
private fun launchVault() {
val intent = intentManager.createTileIntent("bitwarden://my_vault")
if (isBuildVersionBelow(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
startActivityAndCollapse(intent)
} else {
startActivityAndCollapse(intentManager.createTilePendingIntent(0, intent))
}
}
}

View file

@ -87,6 +87,17 @@ interface IntentManager {
*/
fun createDocumentIntent(fileName: String): Intent
/**
* Creates an intent using [data] when selecting a quick settings tile.
*/
fun createTileIntent(data: String): Intent
/**
* Creates a pending intent using [requestCode] and [tileIntent] when selecting a quick
* settings tile on API 34+.
*/
fun createTilePendingIntent(requestCode: Int, tileIntent: Intent): PendingIntent
/**
* Creates a pending intent to use when providing [androidx.credentials.provider.CreateEntry]
* instances for FIDO 2 credential creation.

View file

@ -20,8 +20,10 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.runtime.Composable
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.credentials.CredentialManager
import com.x8bit.bitwarden.BuildConfig
import com.x8bit.bitwarden.MainActivity
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
@ -215,6 +217,24 @@ class IntentManagerImpl(
putExtra(Intent.EXTRA_TITLE, fileName)
}
override fun createTileIntent(data: String): Intent {
return Intent(
context,
MainActivity::class.java,
)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(data.toUri())
}
override fun createTilePendingIntent(requestCode: Int, tileIntent: Intent): PendingIntent {
return PendingIntent.getActivity(
context,
requestCode,
tileIntent,
PendingIntent.FLAG_IMMUTABLE,
)
}
override fun createFido2CreationPendingIntent(
action: String,
userId: String,