For #2818 - Adds Picture-in-Picture feature
parent
d3a5fe5eb4
commit
56eb2ec1d7
|
@ -72,6 +72,8 @@
|
|||
android:name=".HomeActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize|layoutDirection|smallestScreenSize|screenLayout"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -106,6 +108,8 @@
|
|||
android:label="@string/app_name"
|
||||
android:persistableMode="persistNever"
|
||||
android:taskAffinity=""
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
|
|
|
@ -48,4 +48,9 @@ object FeatureFlags {
|
|||
* https://github.com/mozilla-mobile/fenix/issues/9059
|
||||
*/
|
||||
val webPushIntegration = Config.channel.isNightlyOrDebug
|
||||
|
||||
/**
|
||||
* Enables picture-in-picture feature
|
||||
*/
|
||||
val pictureInPicture = Config.channel.isNightlyOrDebug
|
||||
}
|
||||
|
|
|
@ -219,6 +219,16 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
|
|||
super.onBackPressed()
|
||||
}
|
||||
|
||||
final override fun onUserLeaveHint() {
|
||||
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
|
||||
if (it is UserInteractionHandler && it.onHomePressed()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.onUserLeaveHint()
|
||||
}
|
||||
|
||||
protected open fun getBreadcrumbMessage(destination: NavDestination): String {
|
||||
val fragmentName = resources.getResourceEntryName(destination.id)
|
||||
return "Changing to fragment $fragmentName, isCustomTab: false"
|
||||
|
|
|
@ -31,6 +31,7 @@ import kotlinx.coroutines.withContext
|
|||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.session.runWithSessionIdOrSelected
|
||||
import mozilla.components.concept.engine.prompt.ShareData
|
||||
import mozilla.components.feature.accounts.FxaCapability
|
||||
import mozilla.components.feature.accounts.FxaWebChannelFeature
|
||||
|
@ -45,6 +46,7 @@ import mozilla.components.feature.prompts.PromptFeature
|
|||
import mozilla.components.feature.prompts.share.ShareDelegate
|
||||
import mozilla.components.feature.readerview.ReaderViewFeature
|
||||
import mozilla.components.feature.session.FullScreenFeature
|
||||
import mozilla.components.feature.session.PictureInPictureFeature
|
||||
import mozilla.components.feature.session.SessionFeature
|
||||
import mozilla.components.feature.session.SessionUseCases
|
||||
import mozilla.components.feature.session.SwipeRefreshFeature
|
||||
|
@ -123,6 +125,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
|
||||
private val webchannelIntegration = ViewBoundFeatureWrapper<FxaWebChannelFeature>()
|
||||
private val sitePermissionWifiIntegration = ViewBoundFeatureWrapper<SitePermissionsWifiIntegration>()
|
||||
private var pipFeature: PictureInPictureFeature? = null
|
||||
|
||||
var customTabSessionId: String? = null
|
||||
|
||||
|
@ -324,6 +327,15 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||
view = view
|
||||
)
|
||||
|
||||
if (FeatureFlags.pictureInPicture) {
|
||||
pipFeature = PictureInPictureFeature(
|
||||
requireComponents.core.sessionManager,
|
||||
requireActivity(),
|
||||
customTabSessionId,
|
||||
::pipModeChanged
|
||||
)
|
||||
}
|
||||
|
||||
appLinksFeature.set(
|
||||
feature = AppLinksFeature(
|
||||
context,
|
||||
|
@ -423,39 +435,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||
feature = FullScreenFeature(
|
||||
sessionManager,
|
||||
SessionUseCases(sessionManager),
|
||||
customTabSessionId
|
||||
) { inFullScreen ->
|
||||
if (inFullScreen) {
|
||||
FenixSnackbar.make(
|
||||
view = view,
|
||||
duration = Snackbar.LENGTH_SHORT,
|
||||
isDisplayedOnBrowserFragment = true
|
||||
)
|
||||
.setText(getString(R.string.full_screen_notification))
|
||||
.show()
|
||||
activity?.enterToImmersiveMode()
|
||||
browserToolbarView.view.visibility = View.GONE
|
||||
|
||||
if (FeatureFlags.dynamicBottomToolbar) {
|
||||
engineView.setDynamicToolbarMaxHeight(0)
|
||||
browserToolbarView.expand()
|
||||
// Without this, fullscreen has a margin at the top.
|
||||
engineView.setVerticalClipping(0)
|
||||
}
|
||||
} else {
|
||||
activity?.exitImmersiveModeIfNeeded()
|
||||
(activity as? HomeActivity)?.let { activity ->
|
||||
activity.themeManager.applyStatusBarTheme(activity)
|
||||
}
|
||||
browserToolbarView.view.visibility = View.VISIBLE
|
||||
if (FeatureFlags.dynamicBottomToolbar) {
|
||||
engineView.setDynamicToolbarMaxHeight(toolbarHeight)
|
||||
}
|
||||
}
|
||||
if (!FeatureFlags.dynamicBottomToolbar) {
|
||||
updateLayoutMargins(inFullScreen)
|
||||
}
|
||||
},
|
||||
customTabSessionId,
|
||||
::fullScreenChanged
|
||||
),
|
||||
owner = this,
|
||||
view = view
|
||||
)
|
||||
|
@ -593,7 +575,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||
if (findNavController().currentDestination?.id != R.id.searchFragment) {
|
||||
view?.hideKeyboard()
|
||||
}
|
||||
fullScreenFeature.onBackPressed()
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
@ -813,6 +794,63 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||
}
|
||||
}
|
||||
|
||||
override fun onHomePressed(): Boolean {
|
||||
if (pipFeature?.onHomePressed() == true) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun pipModeChanged(enabled: Boolean) {
|
||||
val fullScreenMode =
|
||||
requireComponents.core.sessionManager.runWithSessionIdOrSelected(customTabSessionId) { session ->
|
||||
session.fullScreenMode
|
||||
}
|
||||
// If we're exiting PIP mode and we're in fullscreen mode, then we should exit fullscreen mode as well.
|
||||
if (!enabled && fullScreenMode) {
|
||||
onBackPressed()
|
||||
fullScreenChanged(false)
|
||||
}
|
||||
}
|
||||
|
||||
final override fun onPictureInPictureModeChanged(enabled: Boolean) {
|
||||
pipFeature?.onPictureInPictureModeChanged(enabled)
|
||||
}
|
||||
|
||||
private fun fullScreenChanged(inFullScreen: Boolean) {
|
||||
if (inFullScreen) {
|
||||
FenixSnackbar.make(
|
||||
view = view!!,
|
||||
duration = Snackbar.LENGTH_SHORT,
|
||||
isDisplayedOnBrowserFragment = true
|
||||
)
|
||||
.setText(getString(R.string.full_screen_notification))
|
||||
.show()
|
||||
activity?.enterToImmersiveMode()
|
||||
browserToolbarView.view.visibility = View.GONE
|
||||
|
||||
if (FeatureFlags.dynamicBottomToolbar) {
|
||||
engineView.setDynamicToolbarMaxHeight(0)
|
||||
browserToolbarView.expand()
|
||||
// Without this, fullscreen has a margin at the top.
|
||||
engineView.setVerticalClipping(0)
|
||||
}
|
||||
} else {
|
||||
activity?.exitImmersiveModeIfNeeded()
|
||||
(activity as? HomeActivity)?.let { activity ->
|
||||
activity.themeManager.applyStatusBarTheme(activity)
|
||||
}
|
||||
browserToolbarView.view.visibility = View.VISIBLE
|
||||
if (FeatureFlags.dynamicBottomToolbar) {
|
||||
val toolbarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height)
|
||||
engineView.setDynamicToolbarMaxHeight(toolbarHeight)
|
||||
}
|
||||
}
|
||||
if (!FeatureFlags.dynamicBottomToolbar) {
|
||||
updateLayoutMargins(inFullScreen)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dereference these views when the fragment view is destroyed to prevent memory leaks
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue