1
0
Fork 0

For #4977: Migrate fennec shortcuts (#7251)

* For #4977 - Support opening Fennec pinned website shortcuts in Fenix

Fennec's pinned website shortcuts are set to open the BrowserApp activity.
So we need a new activity alias to actually catch such Intents. Otherwise they
would open "org.mozilla.firefox/.App" without any way to inform that this is
the result of the user clicking on a pinned shortcut.
For actually checking if the newly received Intent is of a Fennec pinned
shortcut we introduce a new FennecBookmarkShortcutsIntentProcessor which will
prepare the Intent to open the shortcut's URL in a new tab.

* For #4977 - Don't keep IntentReceiverActivity on the back stack

For successive Fennec pinned shortcuts to create a new IntentReceiverActivity
and be processed as normal we need to not keep this as our task root.

* For #4977 - Test the FennecBookmarkShortcutsIntentProcessor
master
Mugurell 2020-01-07 19:07:51 +02:00 committed by Sawyer Blatz
parent fdb1f505cc
commit 8454f208af
5 changed files with 165 additions and 2 deletions

View File

@ -48,6 +48,14 @@
android:resource="@xml/shortcuts" />
</activity-alias>
<!--
Fennec declared entry for homescreen pinned shortcuts.
-->
<activity-alias
android:name="org.mozilla.gecko.BrowserApp"
android:targetActivity=".IntentReceiverActivity">
</activity-alias>
<activity
android:name=".HomeActivity"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize|layoutDirection|smallestScreenSize|screenLayout"

View File

@ -64,8 +64,9 @@ class IntentReceiverActivity : Activity() {
intent.setClassName(applicationContext, intentProcessorType.activityClassName)
intent.putExtra(HomeActivity.OPEN_TO_BROWSER, intentProcessorType.shouldOpenToBrowser(intent))
startActivity(intent)
// finish() before starting another activity. Don't keep this on the activities back stack.
finish()
startActivity(intent)
}
}

View File

@ -16,6 +16,7 @@ import mozilla.components.feature.pwa.intent.TrustedWebActivityIntentProcessor
import mozilla.components.feature.search.SearchUseCases
import mozilla.components.feature.session.SessionUseCases
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.home.intent.FennecBookmarkShortcutsIntentProcessor
import org.mozilla.fenix.test.Mockable
/**
@ -62,7 +63,8 @@ class IntentProcessors(
apiKey = BuildConfig.DIGITAL_ASSET_LINKS_TOKEN,
store = customTabsStore
),
WebAppIntentProcessor(sessionManager, sessionUseCases.loadUrl, ManifestStorage(context))
WebAppIntentProcessor(sessionManager, sessionUseCases.loadUrl, ManifestStorage(context)),
FennecBookmarkShortcutsIntentProcessor(sessionManager, sessionUseCases.loadUrl)
)
}
}

View File

@ -0,0 +1,63 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import android.content.Intent.ACTION_VIEW
import androidx.annotation.VisibleForTesting
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineSession
import mozilla.components.feature.intent.ext.putSessionId
import mozilla.components.feature.intent.processing.IntentProcessor
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.support.utils.toSafeIntent
/**
* Legacy processor for pinned websites shortcuts created by Fennec.
* https://developer.android.com/guide/topics/ui/shortcuts/creating-shortcuts#pinned
*/
class FennecBookmarkShortcutsIntentProcessor(
private val sessionManager: SessionManager,
private val loadUrlUseCase: SessionUseCases.DefaultLoadUrlUseCase
) : IntentProcessor {
/**
* Returns true if this Intent is of a Fennec pinned shortcut.
*/
override fun matches(intent: Intent): Boolean {
return intent.toSafeIntent().action == ACTION_FENNEC_HOMESCREEN_SHORTCUT
}
/**
* If this is an Intent for a Fennec pinned website shortcut
* prepare it for opening website's URL in a new tab.
*/
override suspend fun process(intent: Intent): Boolean {
val safeIntent = intent.toSafeIntent()
val url = safeIntent.dataString
return if (!url.isNullOrEmpty() && matches(intent)) {
val session = Session(url, private = false, source = Session.Source.HOME_SCREEN)
sessionManager.add(session)
loadUrlUseCase(url, session, EngineSession.LoadUrlFlags.external())
intent.action = ACTION_VIEW
intent.putSessionId(session.id)
true
} else {
false
}
}
@VisibleForTesting
companion object {
/**
* Fennec set action for the pinned website shortcut Intent.
*/
const val ACTION_FENNEC_HOMESCREEN_SHORTCUT = "org.mozilla.gecko.BOOKMARK"
}
}

View File

@ -0,0 +1,89 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import android.net.Uri
import assertk.assertAll
import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isFalse
import assertk.assertions.isTrue
import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import io.mockk.verifyAll
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineSession
import mozilla.components.feature.intent.ext.getSessionId
import mozilla.components.feature.session.SessionUseCases
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.home.intent.FennecBookmarkShortcutsIntentProcessor.Companion.ACTION_FENNEC_HOMESCREEN_SHORTCUT
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import java.util.UUID
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class FennecBookmarkShortcutsIntentProcessorTest {
private val sessionManager = mockk<SessionManager>(relaxed = true)
private val loadUrlUseCase = mockk<SessionUseCases.DefaultLoadUrlUseCase>(relaxed = true)
@Test
fun `only match Fennec pinned shortcut Intents`() {
val processor = FennecBookmarkShortcutsIntentProcessor(sessionManager, loadUrlUseCase)
assertAll {
assertThat(processor.matches(Intent(ACTION_FENNEC_HOMESCREEN_SHORTCUT))).isTrue()
assertThat(processor.matches(Intent("ShouldNotMatch"))).isFalse()
assertThat(processor.matches(Intent())).isFalse()
}
}
@Test
fun `do not process blank Intents`() = runBlocking {
val processor = FennecBookmarkShortcutsIntentProcessor(sessionManager, loadUrlUseCase)
val fennecShortcutsIntent = Intent(ACTION_FENNEC_HOMESCREEN_SHORTCUT)
fennecShortcutsIntent.data = Uri.parse("http://mozilla.org")
val wasEmptyIntentProcessed = processor.matches(Intent())
assertThat(wasEmptyIntentProcessed).isFalse()
verify {
sessionManager wasNot Called
loadUrlUseCase wasNot Called
}
}
@Test
fun `processing a Fennec shortcut Intent results in loading it's URL in a new Session`() = runBlocking {
mockkStatic(UUID::class)
// The Session constructor uses UUID.randomUUID().toString() as the default value for it's id field
every { UUID.randomUUID().toString() } returns "test"
val processor = FennecBookmarkShortcutsIntentProcessor(sessionManager, loadUrlUseCase)
val fennecShortcutsIntent = Intent(ACTION_FENNEC_HOMESCREEN_SHORTCUT)
val testUrl = "http://mozilla.org"
fennecShortcutsIntent.data = Uri.parse(testUrl)
val expectedSession = Session(testUrl, private = false, source = Session.Source.HOME_SCREEN)
val wasIntentProcessed = processor.process(fennecShortcutsIntent)
assertAll {
assertThat(wasIntentProcessed).isTrue()
assertThat(fennecShortcutsIntent.action).isEqualTo(Intent.ACTION_VIEW)
assertThat(fennecShortcutsIntent.getSessionId()).isEqualTo(expectedSession.id)
}
verifyAll {
sessionManager.add(expectedSession)
loadUrlUseCase(testUrl, expectedSession, EngineSession.LoadUrlFlags.external())
}
}
}