Bug 1853102 - Crash dialog "Continue with add-ons disabled" option is truncated on some devices.

(cherry picked from commit 9e3d31b0abd0caffb078fce69555a5524d2d174d)
fenix/118.0
Arturo Mejia 9 months ago committed by Mergify
parent 9064ac07c0
commit d1ab207de6

@ -5,6 +5,9 @@
package org.mozilla.fenix.addons package org.mozilla.fenix.addons
import android.content.Context import android.content.Context
import android.view.LayoutInflater
import android.widget.Button
import android.widget.TextView
import androidx.annotation.UiContext import androidx.annotation.UiContext
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import mozilla.components.browser.state.action.ExtensionProcessDisabledPopupAction import mozilla.components.browser.state.action.ExtensionProcessDisabledPopupAction
@ -36,25 +39,31 @@ private fun presentDialog(
appName: String, appName: String,
) { ) {
val message = context.getString(R.string.addon_process_crash_dialog_message, appName) val message = context.getString(R.string.addon_process_crash_dialog_message, appName)
var onDismissDialog: (() -> Unit)? = null
builder.apply { val layout = LayoutInflater.from(context)
setCancelable(false) .inflate(R.layout.crash_extension_dialog, null, false)
setTitle(R.string.addon_process_crash_dialog_title) layout?.apply {
setMessage(message) findViewById<TextView>(R.id.message)?.text = message
setPositiveButton(R.string.addon_process_crash_dialog_retry_button_text) { dialog, _ -> findViewById<Button>(R.id.positive)?.setOnClickListener {
engine.enableExtensionProcessSpawning() engine.enableExtensionProcessSpawning()
Addons.extensionsProcessUiRetry.add() Addons.extensionsProcessUiRetry.add()
store.dispatch(ExtensionProcessDisabledPopupAction(false)) store.dispatch(ExtensionProcessDisabledPopupAction(false))
dialog.dismiss() onDismissDialog?.invoke()
} }
setNegativeButton(R.string.addon_process_crash_dialog_disable_addons_button_text) { dialog, _ -> findViewById<Button>(R.id.negative)?.setOnClickListener {
Addons.extensionsProcessUiDisable.add() Addons.extensionsProcessUiDisable.add()
store.dispatch(ExtensionProcessDisabledPopupAction(false)) store.dispatch(ExtensionProcessDisabledPopupAction(false))
dialog.dismiss() onDismissDialog?.invoke()
} }
} }
builder.apply {
setCancelable(false)
setView(layout)
setTitle(R.string.addon_process_crash_dialog_title)
}
builder.show() val dialog = builder.show()
onDismissDialog = { dialog?.dismiss() }
} }
/** /**

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?><!-- 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/. -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginVertical="8dp"
android:textColor="?attr/textPrimary"
tools:text="@string/addon_process_crash_dialog_message" />
<Button
android:id="@+id/positive"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/addon_process_crash_dialog_retry_button_text"
android:textAlignment="textEnd"
android:textColor="?textAccent" />
<Button
android:id="@+id/negative"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/addon_process_crash_dialog_disable_addons_button_text"
android:textAlignment="textEnd"
android:textColor="?textAccent" />
</LinearLayout>
</ScrollView>

@ -4,14 +4,15 @@
package org.mozilla.fenix.addons package org.mozilla.fenix.addons
import android.content.Context import android.view.View
import android.content.DialogInterface.OnClickListener import android.widget.Button
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import mozilla.components.browser.state.action.ExtensionProcessDisabledPopupAction import mozilla.components.browser.state.action.ExtensionProcessDisabledPopupAction
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.Engine
import mozilla.components.support.test.argumentCaptor import mozilla.components.support.test.argumentCaptor
import mozilla.components.support.test.libstate.ext.waitUntilIdle import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.test.rule.MainCoroutineRule import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.whenever import mozilla.components.support.test.whenever
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
@ -19,12 +20,10 @@ import org.junit.Assert.assertTrue
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock import org.mockito.Mockito.mock
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
@ -36,17 +35,18 @@ class ExtensionProcessDisabledControllerTest {
@Test @Test
fun `WHEN showExtensionProcessDisabledPopup is true AND positive button clicked then enable extension process spawning`() { fun `WHEN showExtensionProcessDisabledPopup is true AND positive button clicked then enable extension process spawning`() {
val context: Context = mock()
val store = BrowserStore() val store = BrowserStore()
val engine: Engine = mock() val engine: Engine = mock()
val dialog: AlertDialog = mock()
val appName = "TestApp" val appName = "TestApp"
val builder: AlertDialog.Builder = mock() val builder: AlertDialog.Builder = mock()
val controller = ExtensionProcessDisabledController(context, store, engine, builder, appName) val controller =
controller.start() ExtensionProcessDisabledController(testContext, store, engine, builder, appName)
val buttonsContainerCaptor = argumentCaptor<View>()
whenever(context.getString(anyInt(), anyString())).thenReturn("TestString") controller.start()
val posClickCaptor = argumentCaptor<OnClickListener>() whenever(builder.show()).thenReturn(dialog)
assertFalse(store.state.showExtensionProcessDisabledPopup) assertFalse(store.state.showExtensionProcessDisabledPopup)
@ -55,12 +55,11 @@ class ExtensionProcessDisabledControllerTest {
store.waitUntilIdle() store.waitUntilIdle()
assertTrue(store.state.showExtensionProcessDisabledPopup) assertTrue(store.state.showExtensionProcessDisabledPopup)
verify(builder).setPositiveButton(anyInt(), posClickCaptor.capture()) verify(builder).setView(buttonsContainerCaptor.capture())
verify(builder).show() verify(builder).show()
val dialog: AlertDialog = mock() buttonsContainerCaptor.value.findViewById<Button>(R.id.positive).performClick()
posClickCaptor.value.onClick(dialog, 1)
store.waitUntilIdle() store.waitUntilIdle()
verify(engine).enableExtensionProcessSpawning() verify(engine).enableExtensionProcessSpawning()
@ -70,17 +69,18 @@ class ExtensionProcessDisabledControllerTest {
@Test @Test
fun `WHEN showExtensionProcessDisabledPopup is true AND negative button clicked then dismiss without enabling extension process spawning`() { fun `WHEN showExtensionProcessDisabledPopup is true AND negative button clicked then dismiss without enabling extension process spawning`() {
val context: Context = mock()
val store = BrowserStore() val store = BrowserStore()
val engine: Engine = mock() val engine: Engine = mock()
val appName = "TestApp" val appName = "TestApp"
val dialog: AlertDialog = mock()
val builder: AlertDialog.Builder = mock() val builder: AlertDialog.Builder = mock()
val controller = ExtensionProcessDisabledController(context, store, engine, builder, appName) val controller =
controller.start() ExtensionProcessDisabledController(testContext, store, engine, builder, appName)
val buttonsContainerCaptor = argumentCaptor<View>()
whenever(context.getString(anyInt(), anyString())).thenReturn("TestString") controller.start()
val negClickCaptor = argumentCaptor<OnClickListener>() whenever(builder.show()).thenReturn(dialog)
assertFalse(store.state.showExtensionProcessDisabledPopup) assertFalse(store.state.showExtensionProcessDisabledPopup)
@ -89,12 +89,11 @@ class ExtensionProcessDisabledControllerTest {
store.waitUntilIdle() store.waitUntilIdle()
assertTrue(store.state.showExtensionProcessDisabledPopup) assertTrue(store.state.showExtensionProcessDisabledPopup)
verify(builder).setNegativeButton(anyInt(), negClickCaptor.capture()) verify(builder).setView(buttonsContainerCaptor.capture())
verify(builder).show() verify(builder).show()
val dialog: AlertDialog = mock() buttonsContainerCaptor.value.findViewById<Button>(R.id.negative).performClick()
negClickCaptor.value.onClick(dialog, 1)
store.waitUntilIdle() store.waitUntilIdle()
assertFalse(store.state.showExtensionProcessDisabledPopup) assertFalse(store.state.showExtensionProcessDisabledPopup)

Loading…
Cancel
Save