2019-01-09 23:22:58 +01:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2018-12-07 21:11:50 +01:00
|
|
|
package org.mozilla.fenix
|
|
|
|
|
2019-01-19 00:33:40 +01:00
|
|
|
import android.content.Context
|
2019-03-04 23:32:10 +01:00
|
|
|
import android.content.Intent
|
2018-12-07 21:11:50 +01:00
|
|
|
import android.os.Bundle
|
2019-01-19 00:33:40 +01:00
|
|
|
import android.util.AttributeSet
|
|
|
|
import android.view.View
|
2019-01-07 22:47:47 +01:00
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
2019-02-08 00:37:52 +01:00
|
|
|
import androidx.appcompat.widget.Toolbar
|
2019-02-06 23:31:39 +01:00
|
|
|
import androidx.navigation.fragment.NavHostFragment
|
2019-02-08 00:37:52 +01:00
|
|
|
import androidx.navigation.ui.AppBarConfiguration
|
|
|
|
import androidx.navigation.ui.NavigationUI
|
2019-05-29 00:26:36 +02:00
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.launch
|
2019-03-29 21:49:50 +01:00
|
|
|
import mozilla.components.browser.search.SearchEngine
|
2019-02-28 18:25:37 +01:00
|
|
|
import mozilla.components.browser.session.Session
|
2019-04-26 09:43:02 +02:00
|
|
|
import mozilla.components.browser.session.SessionManager
|
2019-01-19 00:33:40 +01:00
|
|
|
import mozilla.components.concept.engine.EngineView
|
2019-02-06 23:31:39 +01:00
|
|
|
import mozilla.components.feature.intent.IntentProcessor
|
2019-03-20 18:47:22 +01:00
|
|
|
import mozilla.components.lib.crash.Crash
|
2019-02-08 13:50:22 +01:00
|
|
|
import mozilla.components.support.base.feature.BackHandler
|
2019-02-28 18:25:37 +01:00
|
|
|
import mozilla.components.support.ktx.kotlin.isUrl
|
|
|
|
import mozilla.components.support.ktx.kotlin.toNormalizedUrl
|
2019-02-06 23:31:39 +01:00
|
|
|
import mozilla.components.support.utils.SafeIntent
|
2019-03-13 00:01:46 +01:00
|
|
|
import org.mozilla.fenix.components.metrics.Event
|
2019-01-23 22:39:53 +01:00
|
|
|
import org.mozilla.fenix.ext.components
|
2019-03-06 23:53:49 +01:00
|
|
|
import org.mozilla.fenix.home.HomeFragmentDirections
|
2019-03-21 20:41:41 +01:00
|
|
|
import org.mozilla.fenix.library.bookmarks.BookmarkFragmentDirections
|
2019-04-04 22:40:39 +02:00
|
|
|
import org.mozilla.fenix.library.bookmarks.selectfolder.SelectBookmarkFolderFragmentDirections
|
2019-04-05 22:11:05 +02:00
|
|
|
import org.mozilla.fenix.library.history.HistoryFragmentDirections
|
2019-03-06 23:53:49 +01:00
|
|
|
import org.mozilla.fenix.search.SearchFragmentDirections
|
2019-05-29 23:31:06 +02:00
|
|
|
import org.mozilla.fenix.settings.AccountProblemFragmentDirections
|
2019-05-15 06:44:28 +02:00
|
|
|
import org.mozilla.fenix.settings.PairFragmentDirections
|
2019-03-06 23:53:49 +01:00
|
|
|
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
2019-05-15 06:44:28 +02:00
|
|
|
import org.mozilla.fenix.settings.TurnOnSyncFragmentDirections
|
2019-05-02 17:59:13 +02:00
|
|
|
import org.mozilla.fenix.utils.Settings
|
2018-12-07 21:11:50 +01:00
|
|
|
|
2019-03-04 23:32:10 +01:00
|
|
|
@SuppressWarnings("TooManyFunctions")
|
2019-01-31 18:58:52 +01:00
|
|
|
open class HomeActivity : AppCompatActivity() {
|
2019-03-18 22:32:03 +01:00
|
|
|
open val isCustomTab = false
|
2019-04-26 09:43:02 +02:00
|
|
|
private var sessionObserver: SessionManager.Observer? = null
|
2019-03-18 22:32:03 +01:00
|
|
|
|
2019-05-31 00:49:58 +02:00
|
|
|
lateinit var themeManager: ThemeManager
|
|
|
|
|
2019-03-20 18:47:22 +01:00
|
|
|
private val navHost by lazy {
|
|
|
|
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
|
|
|
|
}
|
|
|
|
|
2019-05-31 00:49:58 +02:00
|
|
|
lateinit var browsingModeManager: BrowsingModeManager
|
2019-02-15 18:31:03 +01:00
|
|
|
|
2018-12-07 21:11:50 +01:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
2019-05-31 00:49:58 +02:00
|
|
|
browsingModeManager = createBrowsingModeManager()
|
|
|
|
themeManager = createThemeManager(when (browsingModeManager.isPrivate) {
|
|
|
|
true -> ThemeManager.Theme.Private
|
|
|
|
false -> ThemeManager.Theme.Normal
|
|
|
|
})
|
2019-02-06 23:31:39 +01:00
|
|
|
|
2019-02-08 18:43:17 +01:00
|
|
|
setTheme(themeManager.currentTheme)
|
2019-05-31 00:49:58 +02:00
|
|
|
ThemeManager.applyStatusBarTheme(window, themeManager, this)
|
2019-02-23 02:12:29 +01:00
|
|
|
|
|
|
|
setContentView(R.layout.activity_home)
|
|
|
|
|
2019-05-01 19:07:38 +02:00
|
|
|
// Add ids to this that we don't want to have a toolbar back button
|
|
|
|
val appBarConfiguration = AppBarConfiguration.Builder().build()
|
2019-02-08 00:37:52 +01:00
|
|
|
val navigationToolbar = findViewById<Toolbar>(R.id.navigationToolbar)
|
|
|
|
setSupportActionBar(navigationToolbar)
|
2019-03-20 18:47:22 +01:00
|
|
|
NavigationUI.setupWithNavController(navigationToolbar, navHost.navController, appBarConfiguration)
|
2019-06-04 17:08:06 +02:00
|
|
|
navigationToolbar.setNavigationOnClickListener {
|
|
|
|
onBackPressed()
|
|
|
|
}
|
2019-05-23 22:05:30 +02:00
|
|
|
supportActionBar?.hide()
|
2019-02-28 18:25:37 +01:00
|
|
|
|
2019-03-19 04:49:17 +01:00
|
|
|
intent
|
|
|
|
?.let { SafeIntent(it) }
|
|
|
|
?.let {
|
|
|
|
when {
|
|
|
|
isCustomTab -> Event.OpenedApp.Source.CUSTOM_TAB
|
|
|
|
it.isLauncherIntent -> Event.OpenedApp.Source.APP_ICON
|
|
|
|
it.action == Intent.ACTION_VIEW -> Event.OpenedApp.Source.LINK
|
|
|
|
else -> null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?.also { components.analytics.metrics.track(Event.OpenedApp(it)) }
|
2019-03-18 22:32:03 +01:00
|
|
|
|
2019-03-05 00:14:33 +01:00
|
|
|
handleOpenedFromExternalSourceIfNecessary(intent)
|
2019-03-04 23:32:10 +01:00
|
|
|
}
|
2019-03-22 07:05:28 +01:00
|
|
|
|
2019-04-26 09:43:02 +02:00
|
|
|
override fun onDestroy() {
|
|
|
|
sessionObserver?.let { components.core.sessionManager.unregister(it) }
|
|
|
|
super.onDestroy()
|
|
|
|
}
|
|
|
|
|
2019-03-04 23:32:10 +01:00
|
|
|
override fun onNewIntent(intent: Intent?) {
|
|
|
|
super.onNewIntent(intent)
|
2019-03-20 18:47:22 +01:00
|
|
|
handleCrashIfNecessary(intent)
|
2019-03-05 00:14:33 +01:00
|
|
|
handleOpenedFromExternalSourceIfNecessary(intent)
|
2018-12-07 21:11:50 +01:00
|
|
|
}
|
2019-01-19 00:33:40 +01:00
|
|
|
|
2019-05-29 00:26:36 +02:00
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
|
|
// Make sure accountManager is initialized.
|
|
|
|
components.backgroundServices.accountManager.initAsync().await()
|
|
|
|
// If we're authenticated, kick-off a sync and a device state refresh.
|
|
|
|
components.backgroundServices.accountManager.authenticatedAccount()?.let {
|
|
|
|
components.backgroundServices.syncManager.syncNow(startup = true)
|
|
|
|
it.deviceConstellation().refreshDeviceStateAsync().await()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-31 20:33:56 +01:00
|
|
|
override fun onCreateView(
|
|
|
|
parent: View?,
|
|
|
|
name: String,
|
|
|
|
context: Context,
|
|
|
|
attrs: AttributeSet
|
|
|
|
): View? =
|
2019-01-19 00:33:40 +01:00
|
|
|
when (name) {
|
2019-01-31 18:58:52 +01:00
|
|
|
EngineView::class.java.name -> components.core.engine.createView(context, attrs).asView()
|
2019-01-19 00:33:40 +01:00
|
|
|
else -> super.onCreateView(parent, name, context, attrs)
|
|
|
|
}
|
2019-02-01 06:52:26 +01:00
|
|
|
|
|
|
|
override fun onBackPressed() {
|
|
|
|
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
|
|
|
|
if (it is BackHandler && it.onBackPressed()) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
super.onBackPressed()
|
|
|
|
}
|
2019-02-06 23:31:39 +01:00
|
|
|
|
2019-03-20 18:47:22 +01:00
|
|
|
private fun handleCrashIfNecessary(intent: Intent?) {
|
2019-04-25 23:07:01 +02:00
|
|
|
if (intent == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (!Crash.isCrashIntent(intent)) {
|
|
|
|
return
|
|
|
|
}
|
2019-03-20 18:47:22 +01:00
|
|
|
|
|
|
|
openToCrashReporter(intent)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun openToCrashReporter(intent: Intent) {
|
|
|
|
val directions = NavGraphDirections.actionGlobalCrashReporter(intent)
|
|
|
|
navHost.navController.navigate(directions)
|
|
|
|
}
|
|
|
|
|
2019-03-05 00:14:33 +01:00
|
|
|
private fun handleOpenedFromExternalSourceIfNecessary(intent: Intent?) {
|
2019-05-31 00:43:32 +02:00
|
|
|
if (intent?.extras?.getBoolean(OPEN_TO_BROWSER) != true) return
|
2019-04-29 22:49:01 +02:00
|
|
|
|
2019-04-29 17:30:32 +02:00
|
|
|
this.intent.putExtra(OPEN_TO_BROWSER, false)
|
|
|
|
var customTabSessionId: String? = null
|
2019-03-04 23:32:10 +01:00
|
|
|
|
2019-04-29 21:32:30 +02:00
|
|
|
if (isCustomTab) {
|
|
|
|
customTabSessionId = SafeIntent(intent).getStringExtra(IntentProcessor.ACTIVE_SESSION_ID)
|
2019-04-29 17:30:32 +02:00
|
|
|
}
|
2019-04-29 21:32:30 +02:00
|
|
|
|
|
|
|
openToBrowser(BrowserDirection.FromGlobal, customTabSessionId)
|
2019-02-28 18:25:37 +01:00
|
|
|
}
|
|
|
|
|
2019-05-09 23:21:33 +02:00
|
|
|
@Suppress("LongParameterList")
|
2019-03-29 21:49:50 +01:00
|
|
|
fun openToBrowserAndLoad(
|
2019-04-25 22:00:09 +02:00
|
|
|
searchTermOrURL: String,
|
2019-04-29 21:32:30 +02:00
|
|
|
newTab: Boolean,
|
|
|
|
from: BrowserDirection,
|
2019-04-29 17:30:32 +02:00
|
|
|
customTabSessionId: String? = null,
|
2019-05-09 23:21:33 +02:00
|
|
|
engine: SearchEngine? = null,
|
|
|
|
forceSearch: Boolean = false
|
2019-03-29 21:49:50 +01:00
|
|
|
) {
|
2019-04-29 17:30:32 +02:00
|
|
|
openToBrowser(from, customTabSessionId)
|
2019-05-09 23:21:33 +02:00
|
|
|
load(searchTermOrURL, newTab, engine, forceSearch)
|
2019-02-28 18:25:37 +01:00
|
|
|
}
|
|
|
|
|
2019-05-15 06:45:58 +02:00
|
|
|
@Suppress("ComplexMethod")
|
2019-04-29 17:30:32 +02:00
|
|
|
fun openToBrowser(from: BrowserDirection, customTabSessionId: String? = null) {
|
2019-06-06 21:16:31 +02:00
|
|
|
if (sessionObserver == null)
|
|
|
|
sessionObserver = subscribeToSessions()
|
|
|
|
|
2019-05-31 19:57:34 +02:00
|
|
|
if (navHost.navController.currentDestination?.id == R.id.browserFragment) return
|
|
|
|
val directions = if (!navHost.navController.popBackStack(R.id.browserFragment, false)) {
|
|
|
|
when (from) {
|
|
|
|
BrowserDirection.FromGlobal -> NavGraphDirections.actionGlobalBrowser(customTabSessionId)
|
|
|
|
BrowserDirection.FromHome ->
|
|
|
|
HomeFragmentDirections.actionHomeFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromSearch ->
|
2019-05-31 00:05:34 +02:00
|
|
|
SearchFragmentDirections.actionSearchFragmentToBrowserFragment(customTabSessionId)
|
2019-05-31 19:57:34 +02:00
|
|
|
BrowserDirection.FromSettings ->
|
|
|
|
SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromBookmarks ->
|
|
|
|
BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromBookmarksFolderSelect ->
|
|
|
|
SelectBookmarkFolderFragmentDirections
|
|
|
|
.actionBookmarkSelectFolderFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromHistory ->
|
|
|
|
HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromPair ->
|
|
|
|
PairFragmentDirections.actionPairFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromTurnOnSync ->
|
|
|
|
TurnOnSyncFragmentDirections.actionTurnOnSyncFragmentToBrowserFragment(customTabSessionId)
|
|
|
|
BrowserDirection.FromAccountProblem ->
|
|
|
|
AccountProblemFragmentDirections.actionAccountProblemFragmentToBrowserFragment(customTabSessionId)
|
2019-05-31 00:05:34 +02:00
|
|
|
}
|
2019-05-31 19:57:34 +02:00
|
|
|
} else {
|
|
|
|
null
|
2019-03-06 23:53:49 +01:00
|
|
|
}
|
2019-05-31 19:57:34 +02:00
|
|
|
|
2019-05-31 00:05:34 +02:00
|
|
|
directions?.let {
|
|
|
|
navHost.navController.navigate(it)
|
|
|
|
}
|
2019-02-06 23:31:39 +01:00
|
|
|
}
|
|
|
|
|
2019-05-09 23:21:33 +02:00
|
|
|
private fun load(searchTermOrURL: String, newTab: Boolean, engine: SearchEngine?, forceSearch: Boolean) {
|
2019-02-28 18:25:37 +01:00
|
|
|
val isPrivate = this.browsingModeManager.isPrivate
|
|
|
|
|
2019-04-29 21:32:30 +02:00
|
|
|
val loadUrlUseCase = if (newTab) {
|
2019-02-28 18:25:37 +01:00
|
|
|
if (isPrivate) {
|
|
|
|
components.useCases.tabsUseCases.addPrivateTab
|
|
|
|
} else {
|
|
|
|
components.useCases.tabsUseCases.addTab
|
|
|
|
}
|
|
|
|
} else components.useCases.sessionUseCases.loadUrl
|
|
|
|
|
|
|
|
val searchUseCase: (String) -> Unit = { searchTerms ->
|
2019-04-29 21:32:30 +02:00
|
|
|
if (newTab) {
|
2019-02-28 18:25:37 +01:00
|
|
|
components.useCases.searchUseCases.newTabSearch
|
2019-03-29 21:49:50 +01:00
|
|
|
.invoke(searchTerms, Session.Source.USER_ENTERED, true, isPrivate, searchEngine = engine)
|
|
|
|
} else components.useCases.searchUseCases.defaultSearch.invoke(searchTerms, engine)
|
2019-02-28 18:25:37 +01:00
|
|
|
}
|
|
|
|
|
2019-05-09 23:21:33 +02:00
|
|
|
if (!forceSearch && searchTermOrURL.isUrl()) {
|
2019-04-25 22:00:09 +02:00
|
|
|
loadUrlUseCase.invoke(searchTermOrURL.toNormalizedUrl())
|
2019-02-28 18:25:37 +01:00
|
|
|
} else {
|
2019-04-25 22:00:09 +02:00
|
|
|
searchUseCase.invoke(searchTermOrURL)
|
2019-02-28 18:25:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 09:43:02 +02:00
|
|
|
private val singleSessionObserver = object : Session.Observer {
|
|
|
|
var urlLoading: String? = null
|
|
|
|
|
|
|
|
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
|
|
|
super.onLoadingStateChanged(session, loading)
|
|
|
|
|
|
|
|
if (loading) urlLoading = session.url
|
|
|
|
else if (urlLoading != null && !session.private)
|
|
|
|
components.analytics.metrics.track(Event.UriOpened)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-27 07:00:22 +02:00
|
|
|
fun updateThemeForSession(session: Session) {
|
|
|
|
if (session.private && !themeManager.currentTheme.isPrivate()) {
|
|
|
|
browsingModeManager.mode = BrowsingModeManager.Mode.Private
|
|
|
|
} else if (!session.private && themeManager.currentTheme.isPrivate()) {
|
|
|
|
browsingModeManager.mode = BrowsingModeManager.Mode.Normal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 00:49:58 +02:00
|
|
|
private fun createBrowsingModeManager(): BrowsingModeManager {
|
2019-05-31 01:14:25 +02:00
|
|
|
return if (isCustomTab) {
|
|
|
|
CustomTabBrowsingModeManager()
|
|
|
|
} else {
|
|
|
|
DefaultBrowsingModeManager(Settings.getInstance(this).createBrowserModeStorage()) {
|
|
|
|
themeManager.setTheme(when (it.isPrivate()) {
|
|
|
|
true -> ThemeManager.Theme.Private
|
|
|
|
false -> ThemeManager.Theme.Normal
|
|
|
|
})
|
|
|
|
}
|
2019-05-31 01:13:06 +02:00
|
|
|
}
|
2019-05-31 00:49:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun createThemeManager(currentTheme: ThemeManager.Theme): ThemeManager {
|
2019-05-31 01:14:25 +02:00
|
|
|
return if (isCustomTab) {
|
|
|
|
CustomTabThemeManager()
|
|
|
|
} else {
|
|
|
|
DefaultThemeManager(currentTheme) {
|
|
|
|
setTheme(it)
|
|
|
|
recreate()
|
|
|
|
}
|
2019-05-31 01:13:06 +02:00
|
|
|
}
|
2019-05-31 00:49:58 +02:00
|
|
|
}
|
|
|
|
|
2019-04-26 09:43:02 +02:00
|
|
|
private fun subscribeToSessions(): SessionManager.Observer {
|
|
|
|
|
|
|
|
return object : SessionManager.Observer {
|
|
|
|
override fun onAllSessionsRemoved() {
|
|
|
|
super.onAllSessionsRemoved()
|
|
|
|
components.core.sessionManager.sessions.forEach {
|
|
|
|
it.unregister(singleSessionObserver)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onSessionAdded(session: Session) {
|
|
|
|
super.onSessionAdded(session)
|
2019-05-24 19:07:08 +02:00
|
|
|
session.register(singleSessionObserver, this@HomeActivity)
|
2019-04-26 09:43:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onSessionRemoved(session: Session) {
|
|
|
|
super.onSessionRemoved(session)
|
|
|
|
session.unregister(singleSessionObserver)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onSessionsRestored() {
|
|
|
|
super.onSessionsRestored()
|
|
|
|
components.core.sessionManager.sessions.forEach {
|
2019-05-24 19:07:08 +02:00
|
|
|
it.register(singleSessionObserver, this@HomeActivity)
|
2019-04-26 09:43:02 +02:00
|
|
|
}
|
|
|
|
}
|
2019-05-24 19:07:08 +02:00
|
|
|
}.also { components.core.sessionManager.register(it, this) }
|
2019-04-26 09:43:02 +02:00
|
|
|
}
|
|
|
|
|
2019-02-06 23:31:39 +01:00
|
|
|
companion object {
|
|
|
|
const val OPEN_TO_BROWSER = "open_to_browser"
|
|
|
|
}
|
2018-12-07 21:11:50 +01:00
|
|
|
}
|
2019-03-06 23:53:49 +01:00
|
|
|
|
|
|
|
enum class BrowserDirection {
|
2019-05-15 06:44:28 +02:00
|
|
|
FromGlobal, FromHome, FromSearch, FromSettings, FromBookmarks,
|
2019-05-24 23:18:27 +02:00
|
|
|
FromBookmarksFolderSelect, FromHistory, FromPair, FromTurnOnSync,
|
2019-05-29 23:31:06 +02:00
|
|
|
FromAccountProblem
|
2019-03-06 23:53:49 +01:00
|
|
|
}
|