Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
For #12565 Implement the common part of search widget in Android Comp…
Browse files Browse the repository at this point in the history
…onents
  • Loading branch information
iorgamgabriel committed Aug 10, 2022
2 parents a982c83 + 2cdbf4b commit 66b2014
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,18 @@ class SessionStorage(
return true
}

val stateToPersist = if (state.selectedTabId != null && state.selectedTab == null) {
// "about:crashparent" is meant for testing purposes only. If saved/restored then it will
// continue to crash the app until data is cleared. Therefore, we are filtering it out.
val updatedTabList = state.tabs.filterNot { it.content.url == "about:crashparent" }
val updatedState = state.copy(tabs = updatedTabList)

val stateToPersist = if (updatedState.selectedTabId != null && updatedState.selectedTab == null) {
// Needs investigation to figure out and prevent cause:
// https://github.com/mozilla-mobile/android-components/issues/8417
logger.error("Selected tab ID set, but tab with matching ID not found. Clearing selection.")
state.copy(selectedTabId = null)
updatedState.copy(selectedTabId = null)
} else {
state
updatedState
}

return synchronized(sessionFileLock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,34 @@ class SessionStorageTest {
// the first one if all tabs have the same last access value.
assertEquals("mozilla", browsingSession.selectedTabId)
}

@Test
fun `WHEN saving state with crash parent tab THEN don't save tab`() {
val state = BrowserState(
tabs = listOf(
createTab(url = "about:crashparent", id = "crash"),
createTab(url = "https://getpocket.com", id = "pocket")
),
selectedTabId = "crash"
)

val engine = FakeEngine()

val storage = SessionStorage(testContext, engine)
val persisted = storage.save(state)
assertTrue(persisted)

// Read it back
val browsingSession = storage.restore()
assertNotNull(browsingSession!!)

assertEquals(1, browsingSession.tabs.size)
assertEquals("https://getpocket.com", browsingSession.tabs[0].state.url)

// Selected tab doesn't exist so we take to most recently accessed one, or
// the first one if all tabs have the same last access value.
assertEquals("pocket", browsingSession.selectedTabId)
}
}

internal fun TabSessionState.assertSameAs(tab: RecoverableTab) {
Expand Down
9 changes: 1 addition & 8 deletions components/feature/search/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
<!-- 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/. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="mozilla.components.feature.search">

<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
</manifest>
<manifest package="mozilla.components.feature.search" />
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.speech.RecognizerIntent
import android.view.View
import android.widget.RemoteViews
import androidx.annotation.Dimension
Expand All @@ -26,8 +25,8 @@ import mozilla.components.feature.search.widget.BaseVoiceSearchActivity.Companio
import mozilla.components.support.utils.PendingIntentUtils

/**
* It contains all the Gui and behaviour for AppWidgetProvider.
* Needs to be extended in client app.
* An abstract [AppWidgetProvider] that implements core behaviour needed to support a Search Widget
* on the launcher.
*/
abstract class AppSearchWidgetProvider : AppWidgetProvider() {

Expand Down Expand Up @@ -102,14 +101,10 @@ abstract class AppSearchWidgetProvider : AppWidgetProvider() {
putExtra(SPEECH_PROCESSING, true)
}

val intentSpeech = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)

return intentSpeech.resolveActivity(context.packageManager)?.let {
PendingIntent.getActivity(
context,
REQUEST_CODE_VOICE, voiceIntent, PendingIntentUtils.defaultFlags
)
}
return PendingIntent.getActivity(
context,
REQUEST_CODE_VOICE, voiceIntent, PendingIntentUtils.defaultFlags
)
}

private fun updateWidgetLayout(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
package mozilla.components.feature.search.widget

import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.speech.RecognizerIntent
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
Expand All @@ -26,8 +28,7 @@ abstract class BaseVoiceSearchActivity : AppCompatActivity() {
*/
private var previousIntent: Intent? = null

@VisibleForTesting
private var activityResultLauncher: ActivityResultLauncher<Intent>? = null
private var activityResultLauncher: ActivityResultLauncher<Intent> = getActivityResultLauncher()

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Expand All @@ -36,12 +37,6 @@ abstract class BaseVoiceSearchActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityResultLauncher = getActivityResultLauncher()
if (Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).resolveActivity(packageManager) == null) {
finish()
return
}

// Retrieve the previous intent from the saved state
previousIntent = savedInstanceState?.get(PREVIOUS_INTENT) as Intent?
if (previousIntent.isForSpeechProcessing()) {
Expand Down Expand Up @@ -111,7 +106,12 @@ abstract class BaseVoiceSearchActivity : AppCompatActivity() {
)
}
onSpeechRecognitionStarted()
activityResultLauncher?.launch(intentSpeech)
try {
activityResultLauncher.launch(intentSpeech)
} catch (e: ActivityNotFoundException) {
Log.e(TAG, "ActivityNotFoundException " + e.message.toString())
finish()
}
}

/**
Expand All @@ -128,5 +128,6 @@ abstract class BaseVoiceSearchActivity : AppCompatActivity() {
* In [BaseVoiceSearchActivity] activity, used to store if the speech processing should start.
*/
const val SPEECH_PROCESSING = "speech_processing"
const val TAG = "BaseVoiceSearchActivity"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package mozilla.components.feature.search.widget

import java.util.Locale

class VoiceSearchActivityExtendedForTests : BaseVoiceSearchActivity() {
class BaseVoiceSearchActivityExtendedForTests : BaseVoiceSearchActivity() {

override fun getCurrentLocale(): Locale {
return Locale.getDefault()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@ import org.robolectric.android.controller.ActivityController
import org.robolectric.shadows.ShadowActivity

@RunWith(RobolectricTestRunner::class)
class VoiceSearchActivityTest {
class BaseVoiceSearchActivityTest {

private lateinit var controller: ActivityController<VoiceSearchActivityExtendedForTests>
private lateinit var activity: VoiceSearchActivityExtendedForTests
private lateinit var controller: ActivityController<BaseVoiceSearchActivityExtendedForTests>
private lateinit var activity: BaseVoiceSearchActivityExtendedForTests
private lateinit var shadow: ShadowActivity

@Before
fun setup() {
val intent = Intent()
intent.putExtra(SPEECH_PROCESSING, true)

controller = Robolectric.buildActivity(VoiceSearchActivityExtendedForTests::class.java, intent)
controller = Robolectric.buildActivity(BaseVoiceSearchActivityExtendedForTests::class.java, intent)
activity = controller.get()
shadow = shadowOf(activity)
}
Expand Down Expand Up @@ -72,7 +72,7 @@ class VoiceSearchActivityTest {
val intent = Intent()
intent.putExtra(SPEECH_PROCESSING, false)

val controller = Robolectric.buildActivity(VoiceSearchActivityExtendedForTests::class.java, intent)
val controller = Robolectric.buildActivity(BaseVoiceSearchActivityExtendedForTests::class.java, intent)
val activity = controller.get()

controller.create()
Expand All @@ -83,7 +83,7 @@ class VoiceSearchActivityTest {
@Test
fun `process null intent`() {
allowVoiceIntentToResolveActivity()
val controller = Robolectric.buildActivity(VoiceSearchActivityExtendedForTests::class.java, null)
val controller = Robolectric.buildActivity(BaseVoiceSearchActivityExtendedForTests::class.java, null)
val activity = controller.get()

controller.create()
Expand Down Expand Up @@ -130,10 +130,4 @@ class VoiceSearchActivityTest {

assertTrue(activity.isFinishing)
}

@Test
fun `handle no activity able to resolve voice intent`() {
controller.create()
assertTrue(activity.isFinishing)
}
}
3 changes: 3 additions & 0 deletions components/lib/crash/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<!-- Label of notification showing that the crash report service is running. %1$s will be replaced with the name of the organization (e.g. Mozilla). -->
<string name="mozac_lib_send_crash_report_in_progress">Envoi du rapport de plantage à %1$s</string>

<!-- Label of notification showing that the crash handling service is gathering the crash data. -->
<string name="mozac_lib_gathering_crash_data_in_progress">Collecte des données de plantage</string>

<!-- Label of notification showing that the telemetry service is gathering the crash data. -->
<string name="mozac_lib_gathering_crash_telemetry_in_progress">Collecte des données de télémétrie du plantage</string>

Expand Down
3 changes: 3 additions & 0 deletions components/lib/crash/src/main/res/values-sl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<!-- Label of notification showing that the crash report service is running. %1$s will be replaced with the name of the organization (e.g. Mozilla). -->
<string name="mozac_lib_send_crash_report_in_progress">Pošiljanje poročila o sesutju organizaciji %1$s</string>

<!-- Label of notification showing that the crash handling service is gathering the crash data. -->
<string name="mozac_lib_gathering_crash_data_in_progress">Zbiranje podatkov o sesutju</string>

<!-- Label of notification showing that the telemetry service is gathering the crash data. -->
<string name="mozac_lib_gathering_crash_telemetry_in_progress">Zbiranje telemetričnih podatkov o sesutju</string>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class NimbusPlugin implements Plugin<Project> {
// a) this plugin is going to live in the AS repo (eventually)
// See https://github.com/mozilla-mobile/android-components/issues/11422 for tying this
// to a version that is specified in buildSrc/src/main/java/Dependencies.kt
return "93.5.0"
return "93.6.0"
}

// Try one or more hosts to download the given file.
Expand Down

0 comments on commit 66b2014

Please sign in to comment.