support private mode for custom tabs
This commit is contained in:
@@ -12,3 +12,4 @@
|
||||
build/
|
||||
pubspec.lock
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
|
||||
+5
-1
@@ -235,7 +235,9 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
||||
private fun openInBrowser(sessionId: String) {
|
||||
val activity = requireActivity()
|
||||
val store = components.core.store
|
||||
val url = store.state.findCustomTab(sessionId)?.content?.url ?: return
|
||||
val customTab = store.state.findCustomTab(sessionId) ?: return
|
||||
val url = customTab.content.url
|
||||
val isPrivateCustomTab = customTab.content.private
|
||||
|
||||
sessionFeature?.get()?.release()
|
||||
|
||||
@@ -243,6 +245,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
||||
val mainIntent = Intent(Intent.ACTION_VIEW, android.net.Uri.parse(url)).apply {
|
||||
setClassName(activity, "eu.weblibre.gecko.MainActivity")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtra(PRIVATE_BROWSING_MODE, isPrivateCustomTab)
|
||||
}
|
||||
activity.startActivity(mainIntent)
|
||||
|
||||
@@ -354,6 +357,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
||||
companion object {
|
||||
private const val CUSTOM_TAB_SESSION_ID_KEY = "custom_tab_session_id"
|
||||
private const val WEB_APP_MANIFEST_URL_KEY = "web_app_manifest_url"
|
||||
private const val PRIVATE_BROWSING_MODE = "private_browsing_mode"
|
||||
|
||||
fun create(
|
||||
customTabSessionId: String,
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ import eu.weblibre.flutter_mozilla_components.GlobalComponents
|
||||
class AuthIntentReceiverActivity : Activity() {
|
||||
companion object {
|
||||
private const val TAG = "AuthIntentReceiver"
|
||||
private const val PRIVATE_BROWSING_MODE = "private_browsing_mode"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -32,7 +33,7 @@ class AuthIntentReceiverActivity : Activity() {
|
||||
val processed = CustomTabIntentProcessor(
|
||||
components.useCases.customTabsUseCases.add,
|
||||
resources,
|
||||
isPrivate = false,
|
||||
isPrivate = sourceIntent.getBooleanExtra(PRIVATE_BROWSING_MODE, false),
|
||||
).process(sourceIntent)
|
||||
|
||||
if (processed) {
|
||||
|
||||
+5
-1
@@ -42,6 +42,7 @@ import java.io.File
|
||||
class IntentReceiverActivity : Activity() {
|
||||
companion object {
|
||||
private const val TAG = "IntentReceiverActivity"
|
||||
private const val PRIVATE_BROWSING_MODE = "private_browsing_mode"
|
||||
}
|
||||
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||
@@ -81,6 +82,9 @@ class IntentReceiverActivity : Activity() {
|
||||
}
|
||||
|
||||
private fun routeIntent(intent: Intent) {
|
||||
val privateBrowsingMode = intent.getBooleanExtra(PRIVATE_BROWSING_MODE, false)
|
||||
intent.putExtra(PRIVATE_BROWSING_MODE, privateBrowsingMode)
|
||||
|
||||
// Check if this is our custom PWA intent with profile metadata
|
||||
val profileUuid = intent.getStringExtra(PwaConstants.EXTRA_PWA_PROFILE_UUID)
|
||||
val contextId = intent.getStringExtra(PwaConstants.EXTRA_PWA_CONTEXT_ID)
|
||||
@@ -107,7 +111,7 @@ class IntentReceiverActivity : Activity() {
|
||||
"CustomTab" to CustomTabIntentProcessor(
|
||||
components.useCases.customTabsUseCases.add,
|
||||
resources,
|
||||
isPrivate = false,
|
||||
isPrivate = privateBrowsingMode,
|
||||
),
|
||||
"PWA" to WebAppIntentProcessor(
|
||||
components.core.store,
|
||||
|
||||
+36
-9
@@ -16,6 +16,7 @@ import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
@@ -46,6 +47,7 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
|
||||
private val toolbarCard: MaterialCardView
|
||||
private val closeButton: ImageButton
|
||||
private val privateMaskIcon: ImageView
|
||||
private val securityIcon: ImageView
|
||||
private val titleText: TextView
|
||||
private val urlText: TextView
|
||||
@@ -58,6 +60,7 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
private var urlScope: CoroutineScope? = null
|
||||
private var titleScope: CoroutineScope? = null
|
||||
private var securityScope: CoroutineScope? = null
|
||||
private var isPrivateSession: Boolean = false
|
||||
|
||||
var onCloseListener: (() -> Unit)? = null
|
||||
var onShareListener: (() -> Unit)? = null
|
||||
@@ -69,6 +72,7 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
|
||||
toolbarCard = findViewById(R.id.toolbarCard)
|
||||
closeButton = findViewById(R.id.closeButton)
|
||||
privateMaskIcon = findViewById(R.id.privateMaskIcon)
|
||||
securityIcon = findViewById(R.id.securityIcon)
|
||||
titleText = findViewById(R.id.titleText)
|
||||
urlText = findViewById(R.id.urlText)
|
||||
@@ -89,9 +93,17 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
this.sessionId = sessionId
|
||||
this.store = store
|
||||
|
||||
toolbarColor?.let { applyCustomColors(it) }
|
||||
val tab = store.state.findCustomTab(sessionId)
|
||||
isPrivateSession = tab?.content?.private == true
|
||||
|
||||
store.state.findCustomTab(sessionId)?.let { tab ->
|
||||
if (toolbarColor != null) {
|
||||
applyCustomColors(toolbarColor)
|
||||
} else {
|
||||
applyMaterial3Colors()
|
||||
applyIcons()
|
||||
}
|
||||
|
||||
tab?.let {
|
||||
updateTitle(tab)
|
||||
updateUrl(tab)
|
||||
updateSecurityIcon(tab)
|
||||
@@ -118,14 +130,16 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
private fun applyMaterial3Colors() {
|
||||
val surfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface)
|
||||
val onSurfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface)
|
||||
val onSurfaceVariantColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurfaceVariant)
|
||||
toolbarCard.setCardBackgroundColor(surfaceColor)
|
||||
titleText.setTextColor(onSurfaceColor)
|
||||
urlText.setTextColor(onSurfaceColor)
|
||||
urlText.setTextColor(onSurfaceVariantColor)
|
||||
}
|
||||
|
||||
private fun applyIcons() {
|
||||
val iconColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurfaceVariant)
|
||||
|
||||
updatePrivateMaskIcon()
|
||||
closeButton.setImageDrawable(mdiIcon(CommunityMaterial.Icon.cmd_close, 20, iconColor))
|
||||
shareButton.setImageDrawable(mdiIcon(CommunityMaterial.Icon3.cmd_share_variant, 18, iconColor))
|
||||
openInBrowserButton.setImageDrawable(
|
||||
@@ -145,6 +159,7 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
titleText.setTextColor(textColor)
|
||||
urlText.setTextColor(textColor)
|
||||
|
||||
updatePrivateMaskIcon()
|
||||
closeButton.setImageDrawable(mdiIcon(CommunityMaterial.Icon.cmd_close, 20, textColor))
|
||||
shareButton.setImageDrawable(mdiIcon(CommunityMaterial.Icon3.cmd_share_variant, 18, textColor))
|
||||
openInBrowserButton.setImageDrawable(
|
||||
@@ -242,17 +257,29 @@ class CustomTabToolbar @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private fun updateSecurityIcon(tab: CustomTabSessionState) {
|
||||
val neutralIconColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurfaceVariant)
|
||||
val errorIconColor = MaterialColors.getColor(this, android.R.attr.colorError)
|
||||
|
||||
val securityInfoKnown = tab.content.securityInfo.host.isNotBlank()
|
||||
|
||||
if (tab.content.loading || !securityInfoKnown) {
|
||||
val color = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurfaceVariant)
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock_open_outline, 16, color))
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock_open_outline, 16, neutralIconColor))
|
||||
} else if (tab.content.securityInfo.isSecure) {
|
||||
val color = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurfaceVariant)
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock, 16, color))
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock, 16, neutralIconColor))
|
||||
} else {
|
||||
val color = MaterialColors.getColor(this, android.R.attr.colorError)
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock_open_outline, 16, color))
|
||||
securityIcon.setImageDrawable(mdiIcon(CommunityMaterial.Icon2.cmd_lock_open_outline, 16, errorIconColor))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePrivateMaskIcon() {
|
||||
privateMaskIcon.visibility = if (isPrivateSession) View.VISIBLE else View.GONE
|
||||
if (isPrivateSession) {
|
||||
val privateMaskColor = ContextCompat.getColor(context, R.color.private_tab_mask_accent)
|
||||
privateMaskIcon.setImageDrawable(
|
||||
mdiIcon(CommunityMaterial.Icon.cmd_domino_mask, 16, privateMaskColor)
|
||||
)
|
||||
} else {
|
||||
privateMaskIcon.setImageDrawable(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ class CustomTabToolbarFeature(
|
||||
|
||||
override fun start() {
|
||||
val tab = store.state.findCustomTab(sessionId) ?: return
|
||||
|
||||
val toolbarColor = tab.config.colorSchemes?.defaultColorSchemeParams?.toolbarColor
|
||||
|
||||
toolbar.bind(sessionId, store, toolbarColor)
|
||||
|
||||
@@ -45,6 +45,15 @@
|
||||
android:paddingHorizontal="8dp"
|
||||
android:paddingVertical="6dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/privateMaskIcon"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/securityIcon"
|
||||
android:layout_width="18dp"
|
||||
|
||||
@@ -4,4 +4,6 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color name="icons">#ffffffff</color>
|
||||
</resources>
|
||||
<!-- Keep in sync with app/lib/core/design/app_colors.dart privateTabPurple -->
|
||||
<color name="private_tab_mask_accent">#FF8000D7</color>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user