diff --git a/.editorconfig b/.editorconfig index 1cd48550..e15a1ece 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,7 @@ ij_kotlin_allow_trailing_comma_on_call_site = true ij_kotlin_name_count_to_use_star_import = 2147483647 ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 ij_kotlin_packages_to_use_import_on_demand = unset +ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 1 ktlint_code_style = android_studio ktlint_function_naming_ignore_when_annotated_with = Composable ktlint_standard_function-expression-body = disabled diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a1698f89..c41bbdfe 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -164,40 +164,17 @@ - - - - - - - - + android:theme="@style/Theme.Compose"> + android:value="com.android.messaging.ui.conversationlist.ConversationListActivity" /> diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9a2f88b5..4ba8d3b3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -168,6 +168,11 @@ dependencies { androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.compose.ui.test.junit4) + androidTestImplementation(libs.androidx.test.espresso.contrib) + androidTestImplementation(libs.androidx.test.espresso.core) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.androidx.test.rules) + androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.hilt.android.testing) kspAndroidTest(libs.hilt.compiler) diff --git a/app/src/androidTest/java/com/android/messaging/ui/appsettings/general/ui/AppSettingsScreenTest.kt b/app/src/androidTest/java/com/android/messaging/ui/appsettings/general/ui/AppSettingsScreenTest.kt new file mode 100644 index 00000000..8851e322 --- /dev/null +++ b/app/src/androidTest/java/com/android/messaging/ui/appsettings/general/ui/AppSettingsScreenTest.kt @@ -0,0 +1,224 @@ +package com.android.messaging.ui.appsettings.general.ui + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.android.messaging.R +import com.android.messaging.ui.appsettings.general.model.AppSettingsUiState +import com.android.messaging.ui.appsettings.screen.SettingsScreenModel +import com.android.messaging.ui.appsettings.screen.model.SettingsAction as Action +import com.android.messaging.ui.core.AppTheme +import io.mockk.mockk +import io.mockk.verify +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class AppSettingsScreenTest { + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + private lateinit var screenModel: SettingsScreenModel + + @Before + fun setup() { + screenModel = mockk(relaxed = true) + } + + @Test + fun defaultSmsAppItem_displaysLabel() { + val appSettings = AppSettingsUiState( + isDefaultSmsApp = true, + defaultSmsAppLabel = "Messaging", + ) + + setContent(appSettings = appSettings) + + composeTestRule.onNodeWithText("Messaging").assertIsDisplayed() + } + + @Test + fun defaultSmsAppClick_delegatesToScreenModel() { + val appSettings = AppSettingsUiState( + isDefaultSmsApp = true, + defaultSmsAppLabel = "Messaging", + ) + + setContent(appSettings = appSettings) + + val title = composeTestRule.activity.getString(R.string.sms_disabled_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.DefaultSmsAppClicked(true)) + } + } + + @Test + fun notificationsClick_delegatesToScreenModel() { + setContent() + + val title = composeTestRule.activity.getString( + R.string.notifications_enabled_conversation_pref_title, + ) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.NotificationsClicked) + } + } + + @Test + fun sendSoundToggle_delegatesToScreenModel() { + val appSettings = AppSettingsUiState(sendSoundEnabled = true) + + setContent(appSettings = appSettings) + + val title = composeTestRule.activity.getString(R.string.send_sound_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.SendSoundChanged(false)) + } + } + + @Test + fun debugSection_hiddenWhenDebugDisabled() { + val appSettings = AppSettingsUiState(isDebugEnabled = false) + + setContent(appSettings = appSettings) + + val debugTitle = composeTestRule.activity.getString(R.string.debug_category_pref_title) + composeTestRule.onNodeWithText(debugTitle).assertDoesNotExist() + + val dumpSmsTitle = composeTestRule.activity.getString(R.string.dump_sms_pref_title) + composeTestRule.onNodeWithText(dumpSmsTitle).assertDoesNotExist() + } + + @Test + fun debugSection_shownWhenDebugEnabled() { + val appSettings = AppSettingsUiState( + isDebugEnabled = true, + dumpSmsEnabled = false, + dumpMmsEnabled = false, + ) + + setContent(appSettings = appSettings) + + val debugTitle = composeTestRule.activity.getString(R.string.debug_category_pref_title) + composeTestRule.onNodeWithText(debugTitle).assertIsDisplayed() + + val dumpSmsTitle = composeTestRule.activity.getString(R.string.dump_sms_pref_title) + composeTestRule.onNodeWithText(dumpSmsTitle).assertIsDisplayed() + + val dumpMmsTitle = composeTestRule.activity.getString(R.string.dump_mms_pref_title) + composeTestRule.onNodeWithText(dumpMmsTitle).assertIsDisplayed() + } + + @Test + fun dumpSmsToggle_delegatesToScreenModel() { + val appSettings = AppSettingsUiState( + isDebugEnabled = true, + dumpSmsEnabled = false, + ) + + setContent(appSettings = appSettings) + + val title = composeTestRule.activity.getString(R.string.dump_sms_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.DumpSmsChanged(true)) + } + } + + @Test + fun dumpMmsToggle_delegatesToScreenModel() { + val appSettings = AppSettingsUiState( + isDebugEnabled = true, + dumpMmsEnabled = false, + ) + + setContent(appSettings = appSettings) + + val title = composeTestRule.activity.getString(R.string.dump_mms_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.DumpMmsChanged(true)) + } + } + + @Test + fun licensesClick_delegatesToScreenModel() { + setContent() + + val title = composeTestRule.activity.getString(R.string.menu_license) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.LicensesClicked) + } + } + + @Test + fun advancedSettings_shownWhenTopLevel() { + var advancedClicks = 0 + + composeTestRule.setContent { + AppTheme { + AppSettingsScreen( + appSettings = AppSettingsUiState(), + screenModel = screenModel, + onNavigateBack = {}, + isTopLevel = true, + onAdvancedClick = { advancedClicks += 1 }, + ) + } + } + + val advancedTitle = composeTestRule.activity.getString(R.string.advanced_settings) + composeTestRule.onNodeWithText(advancedTitle).assertIsDisplayed() + composeTestRule.onNodeWithText(advancedTitle).performClick() + + composeTestRule.runOnIdle { + assertEquals(1, advancedClicks) + } + } + + @Test + fun advancedSettings_hiddenWhenNotTopLevel() { + composeTestRule.setContent { + AppTheme { + AppSettingsScreen( + appSettings = AppSettingsUiState(), + screenModel = screenModel, + onNavigateBack = {}, + isTopLevel = false, + onAdvancedClick = null, + ) + } + } + + val advancedTitle = composeTestRule.activity.getString(R.string.advanced_settings) + composeTestRule.onNodeWithText(advancedTitle).assertDoesNotExist() + } + + private fun setContent( + appSettings: AppSettingsUiState = AppSettingsUiState(), + ) { + composeTestRule.setContent { + AppTheme { + AppSettingsScreen( + appSettings = appSettings, + screenModel = screenModel, + onNavigateBack = {}, + ) + } + } + } +} diff --git a/app/src/androidTest/java/com/android/messaging/ui/appsettings/screen/SettingsScreenTest.kt b/app/src/androidTest/java/com/android/messaging/ui/appsettings/screen/SettingsScreenTest.kt new file mode 100644 index 00000000..a031129b --- /dev/null +++ b/app/src/androidTest/java/com/android/messaging/ui/appsettings/screen/SettingsScreenTest.kt @@ -0,0 +1,196 @@ +package com.android.messaging.ui.appsettings.screen + +import androidx.activity.ComponentActivity +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.compose.LocalLifecycleOwner +import com.android.messaging.R +import com.android.messaging.ui.appsettings.general.model.AppSettingsUiState +import com.android.messaging.ui.appsettings.screen.SettingsScreen +import com.android.messaging.ui.appsettings.screen.SettingsScreenModel +import com.android.messaging.ui.appsettings.screen.model.SettingsNavRoute +import com.android.messaging.ui.appsettings.screen.model.SettingsUiState +import com.android.messaging.ui.appsettings.subscription.model.SubscriptionSettingsUiState +import com.android.messaging.ui.core.AppTheme +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class SettingsScreenTest { + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + private val fakeUiStateFlow = MutableStateFlow(createSingleSimState()) + private lateinit var screenModel: SettingsScreenModel + + @Before + fun setup() { + screenModel = mockk(relaxed = true) + every { screenModel.uiState } returns fakeUiStateFlow + } + + @Test + fun singleSim_skipsMainScreen_showsAppSettings() { + fakeUiStateFlow.value = createSingleSimState() + + setScreenContent() + + val generalTitle = composeTestRule.activity.getString(R.string.settings_activity_title) + composeTestRule.onNodeWithText(generalTitle).assertIsDisplayed() + + val sendSoundTitle = composeTestRule.activity.getString(R.string.send_sound_pref_title) + composeTestRule.onNodeWithText(sendSoundTitle).assertIsDisplayed() + } + + @Test + fun multiSim_showsMainScreen_withSubscriptions() { + fakeUiStateFlow.value = createMultiSimState() + + setScreenContent() + + val settingsTitle = composeTestRule.activity.getString(R.string.settings_activity_title) + composeTestRule.onNodeWithText(settingsTitle).assertIsDisplayed() + + composeTestRule.onNodeWithText("SIM 1").assertIsDisplayed() + composeTestRule.onNodeWithText("SIM 2").assertIsDisplayed() + } + + @Test + fun multiSim_generalSettingsClick_navigatesToAppSettings() { + fakeUiStateFlow.value = createMultiSimState() + + setScreenContent() + + val generalSettings = composeTestRule.activity.getString(R.string.general_settings) + composeTestRule.onNodeWithText(generalSettings).performClick() + composeTestRule.waitForIdle() + + val sendSoundTitle = composeTestRule.activity.getString(R.string.send_sound_pref_title) + composeTestRule.onNodeWithText(sendSoundTitle).assertIsDisplayed() + } + + @Test + fun lifecycleResume_refreshesState() { + fakeUiStateFlow.value = createSingleSimState() + lateinit var lifecycleOwner: TestLifecycleOwner + + composeTestRule.runOnIdle { + lifecycleOwner = TestLifecycleOwner( + initialState = Lifecycle.State.STARTED, + ) + } + + composeTestRule.setContent { + CompositionLocalProvider(LocalLifecycleOwner provides lifecycleOwner) { + AppTheme { + SettingsScreen( + onNavigateBack = {}, + screenModel = screenModel, + ) + } + } + } + + composeTestRule.runOnIdle { + lifecycleOwner.moveTo(state = Lifecycle.State.RESUMED) + } + composeTestRule.waitForIdle() + + verify(atLeast = 1) { + screenModel.refreshState() + } + } + + @Test + fun singleSim_showsAdvancedSettings() { + fakeUiStateFlow.value = createSingleSimState() + + setScreenContent() + + val advancedTitle = composeTestRule.activity.getString(R.string.advanced_settings) + composeTestRule.onNodeWithText(advancedTitle).assertIsDisplayed() + } + + private fun setScreenContent( + initialRoute: SettingsNavRoute = SettingsNavRoute.Main, + ) { + composeTestRule.setContent { + AppTheme { + SettingsScreen( + onNavigateBack = {}, + initialRoute = initialRoute, + screenModel = screenModel, + ) + } + } + } + + private fun createSingleSimState(): SettingsUiState { + return SettingsUiState( + appSettings = AppSettingsUiState( + isDefaultSmsApp = true, + defaultSmsAppLabel = "Messaging", + sendSoundEnabled = true, + ), + subscriptionSettings = listOf( + SubscriptionSettingsUiState( + subId = 1, + displayName = "Advanced Settings", + displayDetail = "+1234567890", + ), + ), + isMultiSim = false, + ) + } + + private fun createMultiSimState(): SettingsUiState { + return SettingsUiState( + appSettings = AppSettingsUiState( + isDefaultSmsApp = true, + defaultSmsAppLabel = "Messaging", + sendSoundEnabled = true, + ), + subscriptionSettings = listOf( + SubscriptionSettingsUiState( + subId = 1, + displayName = "SIM 1", + displayDetail = "+1234567890", + ), + SubscriptionSettingsUiState( + subId = 2, + displayName = "SIM 2", + displayDetail = "+0987654321", + ), + ), + isMultiSim = true, + ) + } + + private class TestLifecycleOwner( + initialState: Lifecycle.State, + ) : LifecycleOwner { + private val lifecycleRegistry = LifecycleRegistry(this) + + init { + lifecycleRegistry.currentState = initialState + } + + override val lifecycle: Lifecycle + get() = lifecycleRegistry + + fun moveTo(state: Lifecycle.State) { + lifecycleRegistry.currentState = state + } + } +} diff --git a/app/src/androidTest/java/com/android/messaging/ui/appsettings/subscription/ui/SubscriptionSettingsScreenTest.kt b/app/src/androidTest/java/com/android/messaging/ui/appsettings/subscription/ui/SubscriptionSettingsScreenTest.kt new file mode 100644 index 00000000..cb146b5f --- /dev/null +++ b/app/src/androidTest/java/com/android/messaging/ui/appsettings/subscription/ui/SubscriptionSettingsScreenTest.kt @@ -0,0 +1,306 @@ +package com.android.messaging.ui.appsettings.subscription.ui + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsEnabled +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.android.messaging.R +import com.android.messaging.ui.appsettings.screen.SettingsScreenModel +import com.android.messaging.ui.appsettings.screen.model.SettingsAction as Action +import com.android.messaging.ui.appsettings.subscription.model.SubscriptionSettingsUiState +import com.android.messaging.ui.core.AppTheme +import io.mockk.mockk +import io.mockk.verify +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class SubscriptionSettingsScreenTest { + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + private lateinit var screenModel: SettingsScreenModel + + @Before + fun setup() { + screenModel = mockk(relaxed = true) + } + + @Test + fun mmsCategoryHeader_isDisplayed() { + setContent(subscriptionSettings = createDefaultSubscription()) + + val mmsTitle = composeTestRule.activity.getString( + R.string.mms_messaging_category_pref_title, + ) + composeTestRule.onNodeWithText(mmsTitle).assertIsDisplayed() + } + + @Test + fun groupMms_shownWhenSupported() { + val sub = createDefaultSubscription(isGroupMmsSupported = true) + setContent(subscriptionSettings = sub) + + val groupMmsTitle = composeTestRule.activity.getString(R.string.group_mms_pref_title) + composeTestRule.onNodeWithText(groupMmsTitle).assertIsDisplayed() + } + + @Test + fun groupMms_hiddenWhenNotSupported() { + val sub = createDefaultSubscription(isGroupMmsSupported = false) + setContent(subscriptionSettings = sub) + + val groupMmsTitle = composeTestRule.activity.getString(R.string.group_mms_pref_title) + composeTestRule.onNodeWithText(groupMmsTitle).assertDoesNotExist() + } + + @Test + fun groupMmsClick_showsDialog() { + val sub = createDefaultSubscription( + isGroupMmsSupported = true, + isDefaultSmsApp = true, + ) + setContent(subscriptionSettings = sub) + + val groupMmsTitle = composeTestRule.activity.getString(R.string.group_mms_pref_title) + composeTestRule.onNodeWithText(groupMmsTitle).performClick() + composeTestRule.waitForIdle() + + val disableLabel = composeTestRule.activity.getString(R.string.disable_group_mms) + composeTestRule.onNodeWithText(disableLabel).assertIsDisplayed() + + val okText = composeTestRule.activity.getString(android.R.string.ok) + composeTestRule.onNodeWithText(okText).assertIsDisplayed() + + val cancelText = composeTestRule.activity.getString(android.R.string.cancel) + composeTestRule.onNodeWithText(cancelText).assertIsDisplayed() + } + + @Test + fun phoneNumberItem_displaysCurrentNumber() { + val sub = createDefaultSubscription(displayDetail = "+1234567890") + setContent(subscriptionSettings = sub) + + composeTestRule.onNodeWithText("+1234567890").assertIsDisplayed() + } + + @Test + fun phoneNumberClick_showsDialog() { + val sub = createDefaultSubscription(phoneNumber = "+1234567890") + setContent(subscriptionSettings = sub) + + val phoneTitle = composeTestRule.activity.getString(R.string.mms_phone_number_pref_title) + composeTestRule.onNodeWithText(phoneTitle).performClick() + composeTestRule.waitForIdle() + + val okText = composeTestRule.activity.getString(android.R.string.ok) + composeTestRule.onNodeWithText(okText).assertIsDisplayed() + } + + @Test + fun autoRetrieveMms_toggleDelegatesToScreenModel() { + val sub = createDefaultSubscription( + isDefaultSmsApp = true, + autoRetrieveMms = true, + ) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.auto_retrieve_mms_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.AutoRetrieveMmsChanged(1, false)) + } + } + + @Test + fun autoRetrieveMmsWhenRoaming_disabledWhenAutoRetrieveOff() { + val sub = createDefaultSubscription( + isDefaultSmsApp = true, + autoRetrieveMms = false, + ) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString( + R.string.auto_retrieve_mms_when_roaming_pref_title, + ) + composeTestRule.onNodeWithText(title).assertIsNotEnabled() + } + + @Test + fun autoRetrieveMmsWhenRoaming_enabledWhenAutoRetrieveOn() { + val sub = createDefaultSubscription( + isDefaultSmsApp = true, + autoRetrieveMms = true, + ) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString( + R.string.auto_retrieve_mms_when_roaming_pref_title, + ) + composeTestRule.onNodeWithText(title).assertIsEnabled() + } + + @Test + fun deliveryReports_shownWhenSupported() { + val sub = createDefaultSubscription(isDeliveryReportsSupported = true) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.delivery_reports_pref_title) + composeTestRule.onNodeWithText(title).assertIsDisplayed() + } + + @Test + fun deliveryReports_hiddenWhenNotSupported() { + val sub = createDefaultSubscription(isDeliveryReportsSupported = false) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.delivery_reports_pref_title) + composeTestRule.onNodeWithText(title).assertDoesNotExist() + } + + @Test + fun deliveryReportsToggle_delegatesToScreenModel() { + val sub = createDefaultSubscription( + isDeliveryReportsSupported = true, + isDefaultSmsApp = true, + deliveryReportsEnabled = false, + ) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.delivery_reports_pref_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.DeliveryReportsChanged(1, true)) + } + } + + @Test + fun wirelessAlerts_shownWhenSupported() { + val sub = createDefaultSubscription(isWirelessAlertsSupported = true) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.wireless_alerts_title) + composeTestRule.onNodeWithText(title).assertIsDisplayed() + } + + @Test + fun wirelessAlerts_hiddenWhenNotSupported() { + val sub = createDefaultSubscription(isWirelessAlertsSupported = false) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.wireless_alerts_title) + composeTestRule.onNodeWithText(title).assertDoesNotExist() + } + + @Test + fun wirelessAlertsClick_delegatesToScreenModel() { + val sub = createDefaultSubscription(isWirelessAlertsSupported = true) + setContent(subscriptionSettings = sub) + + val title = composeTestRule.activity.getString(R.string.wireless_alerts_title) + composeTestRule.onNodeWithText(title).performClick() + + verify(exactly = 1) { + screenModel.onAction(Action.WirelessAlertsClicked(1)) + } + } + + @Test + fun advancedCategory_shownWhenDeliveryReportsOrWirelessAlertsSupported() { + val sub = createDefaultSubscription( + isDeliveryReportsSupported = true, + isWirelessAlertsSupported = false, + ) + setContent(subscriptionSettings = sub) + + val advancedTitle = + composeTestRule.activity.getString(R.string.advanced_category_pref_title) + composeTestRule.onNodeWithText(advancedTitle).assertIsDisplayed() + } + + @Test + fun advancedCategory_hiddenWhenNeitherSupported() { + val sub = createDefaultSubscription( + isDeliveryReportsSupported = false, + isWirelessAlertsSupported = false, + ) + setContent(subscriptionSettings = sub) + + val advancedTitle = + composeTestRule.activity.getString(R.string.advanced_category_pref_title) + composeTestRule.onNodeWithText(advancedTitle).assertDoesNotExist() + } + + @Test + fun settingsDisabled_whenNotDefaultSmsApp() { + val sub = createDefaultSubscription( + isDefaultSmsApp = false, + isGroupMmsSupported = true, + isDeliveryReportsSupported = true, + ) + setContent(subscriptionSettings = sub) + + val groupMmsTitle = composeTestRule.activity.getString(R.string.group_mms_pref_title) + composeTestRule.onNodeWithText(groupMmsTitle).assertIsNotEnabled() + + val autoRetrieveTitle = composeTestRule.activity.getString( + R.string.auto_retrieve_mms_pref_title, + ) + composeTestRule.onNodeWithText(autoRetrieveTitle).assertIsNotEnabled() + + val deliveryTitle = composeTestRule.activity.getString(R.string.delivery_reports_pref_title) + composeTestRule.onNodeWithText(deliveryTitle).assertIsNotEnabled() + } + + private fun setContent( + subscriptionSettings: SubscriptionSettingsUiState = createDefaultSubscription(), + ) { + composeTestRule.setContent { + AppTheme { + SubscriptionSettingsScreen( + subscriptionSettings = subscriptionSettings, + title = "Advanced Settings", + screenModel = screenModel, + onNavigateBack = {}, + ) + } + } + } + + private fun createDefaultSubscription( + subId: Int = 1, + displayDetail: String = "+1234567890", + phoneNumber: String = "+1234567890", + defaultPhoneNumber: String = "+1234567890", + isGroupMmsSupported: Boolean = false, + isGroupMmsEnabled: Boolean = true, + autoRetrieveMms: Boolean = true, + autoRetrieveMmsWhenRoaming: Boolean = false, + isDeliveryReportsSupported: Boolean = false, + deliveryReportsEnabled: Boolean = false, + isWirelessAlertsSupported: Boolean = false, + isDefaultSmsApp: Boolean = true, + ): SubscriptionSettingsUiState { + return SubscriptionSettingsUiState( + subId = subId, + displayName = "SIM 1", + displayDetail = displayDetail, + phoneNumber = phoneNumber, + defaultPhoneNumber = defaultPhoneNumber, + isGroupMmsSupported = isGroupMmsSupported, + isGroupMmsEnabled = isGroupMmsEnabled, + autoRetrieveMms = autoRetrieveMms, + autoRetrieveMmsWhenRoaming = autoRetrieveMmsWhenRoaming, + isDeliveryReportsSupported = isDeliveryReportsSupported, + deliveryReportsEnabled = deliveryReportsEnabled, + isWirelessAlertsSupported = isWirelessAlertsSupported, + isDefaultSmsApp = isDefaultSmsApp, + ) + } +} diff --git a/app/src/androidTest/java/com/android/messaging/ui/conversation/ConversationUserFlowTest.kt b/app/src/androidTest/java/com/android/messaging/ui/conversation/ConversationUserFlowTest.kt new file mode 100644 index 00000000..981c40ca --- /dev/null +++ b/app/src/androidTest/java/com/android/messaging/ui/conversation/ConversationUserFlowTest.kt @@ -0,0 +1,76 @@ +package com.android.messaging.ui.conversation + +import android.os.ParcelFileDescriptor +import android.widget.EditText +import android.widget.ImageButton +import androidx.recyclerview.widget.RecyclerView +import androidx.test.core.app.ActivityScenario +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.messaging.R +import com.android.messaging.debug.seedTestData +import com.android.messaging.ui.conversationlist.ConversationListActivity +import org.hamcrest.Matchers.allOf +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ConversationUserFlowTest { + + @Before + fun setUpDefaultSmsApp() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val packageName = instrumentation.targetContext.packageName + val command = "cmd role add-role-holder android.app.role.SMS $packageName" + val parcelFileDescriptor = instrumentation.uiAutomation.executeShellCommand(command) + + ParcelFileDescriptor.AutoCloseInputStream(parcelFileDescriptor).use { inputStream -> + val result = String(inputStream.readBytes()) + println("Role assignment result: $result") + } + } + + @Test + fun conversationListToConversation_uiElementsArePresent() { + val scenario = ActivityScenario.launch( + ConversationListActivity::class.java, + ) + + onView(withId(android.R.id.list)) + .check(matches(isDisplayed())) + + onView(withId(R.id.start_new_conversation_button)) + .check(matches(isDisplayed())) + + onView(withId(android.R.id.list)) + .perform( + RecyclerViewActions.actionOnItemAtPosition(0, click()), + ) + + onView(allOf(withId(R.id.compose_message_text), isAssignableFrom(EditText::class.java))) + .check(matches(isDisplayed())) + + onView(allOf(withId(R.id.attach_media_button), isAssignableFrom(ImageButton::class.java))) + .check(matches(isDisplayed())) + + scenario.close() + } + + companion object { + @JvmStatic + @BeforeClass + fun seedOnce() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + seedTestData(context) + } + } +} diff --git a/app/src/test/java/com/android/messaging/testutil/MainDispatcherRule.kt b/app/src/test/java/com/android/messaging/testutil/MainDispatcherRule.kt new file mode 100644 index 00000000..6780db1c --- /dev/null +++ b/app/src/test/java/com/android/messaging/testutil/MainDispatcherRule.kt @@ -0,0 +1,24 @@ +package com.android.messaging.testutil + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + val testDispatcher: TestDispatcher = StandardTestDispatcher(), +) : TestWatcher() { + + override fun starting(description: Description) { + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} diff --git a/app/src/test/java/com/android/messaging/ui/appsettings/screen/SettingsViewModelTest.kt b/app/src/test/java/com/android/messaging/ui/appsettings/screen/SettingsViewModelTest.kt new file mode 100644 index 00000000..8479b559 --- /dev/null +++ b/app/src/test/java/com/android/messaging/ui/appsettings/screen/SettingsViewModelTest.kt @@ -0,0 +1,356 @@ +package com.android.messaging.ui.appsettings.screen + +import app.cash.turbine.test +import com.android.messaging.testutil.MainDispatcherRule +import com.android.messaging.ui.appsettings.general.delegate.AppSettingsDelegate +import com.android.messaging.ui.appsettings.general.model.AppSettingsUiState +import com.android.messaging.ui.appsettings.screen.model.SettingsAction as Action +import com.android.messaging.ui.appsettings.screen.model.SettingsScreenEffect +import com.android.messaging.ui.appsettings.screen.model.SettingsUiState +import com.android.messaging.ui.appsettings.subscription.delegate.SubscriptionSettingsDelegate +import com.android.messaging.ui.appsettings.subscription.delegate.SubscriptionSettingsState +import com.android.messaging.ui.appsettings.subscription.model.SubscriptionSettingsUiState +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(RobolectricTestRunner::class) +class SettingsViewModelTest { + + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + + @Test + fun init_bindsAllDelegates() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val subDelegate = FakeSubscriptionSettingsDelegate() + + createViewModel( + appSettingsDelegate = appDelegate, + subscriptionSettingsDelegate = subDelegate, + ) + advanceUntilIdle() + + assertEquals(1, appDelegate.bindCalls) + assertEquals(1, subDelegate.bindCalls) + } + } + + @Test + fun uiState_combinesDelegateStates() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel( + appSettingsDelegate = appDelegate, + subscriptionSettingsDelegate = subDelegate, + ) + + val appState = AppSettingsUiState( + isDefaultSmsApp = true, + defaultSmsAppLabel = "Messaging", + sendSoundEnabled = false, + ) + val subscription = SubscriptionSettingsUiState( + subId = 1, + displayName = "SIM 1", + ) + appDelegate.stateFlow.value = appState + subDelegate.stateFlow.value = SubscriptionSettingsState( + subscriptions = listOf(subscription), + isMultiSim = false, + ) + + viewModel.uiState.test { + assertEquals(SettingsUiState(), awaitItem()) + + val mappedState = awaitItem() + assertEquals(appState, mappedState.appSettings) + assertEquals(listOf(subscription), mappedState.subscriptionSettings) + assertEquals(false, mappedState.isMultiSim) + cancelAndIgnoreRemainingEvents() + } + } + } + + @Test + fun refreshState_refreshesBothDelegates() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel( + appSettingsDelegate = appDelegate, + subscriptionSettingsDelegate = subDelegate, + ) + + viewModel.refreshState() + + assertEquals(1, appDelegate.refreshCalls) + assertEquals(1, subDelegate.refreshCalls) + } + } + + @Test + fun onSendSoundChanged_delegatesToAppSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val viewModel = createViewModel(appSettingsDelegate = appDelegate) + + viewModel.onAction(Action.SendSoundChanged(enabled = false)) + + assertEquals(listOf(false), appDelegate.sendSoundChanges) + } + } + + @Test + fun onDumpSmsChanged_delegatesToAppSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val viewModel = createViewModel(appSettingsDelegate = appDelegate) + + viewModel.onAction(Action.DumpSmsChanged(enabled = true)) + + assertEquals(listOf(true), appDelegate.dumpSmsChanges) + } + } + + @Test + fun onDumpMmsChanged_delegatesToAppSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val appDelegate = FakeAppSettingsDelegate() + val viewModel = createViewModel(appSettingsDelegate = appDelegate) + + viewModel.onAction(Action.DumpMmsChanged(enabled = true)) + + assertEquals(listOf(true), appDelegate.dumpMmsChanges) + } + } + + @Test + fun onGroupMmsChanged_delegatesToSubscriptionSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel(subscriptionSettingsDelegate = subDelegate) + + viewModel.onAction(Action.GroupMmsChanged(subId = 1, enabled = false)) + + assertEquals(listOf(1 to false), subDelegate.groupMmsChanges) + } + } + + @Test + fun onPhoneNumberChanged_delegatesToSubscriptionSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel(subscriptionSettingsDelegate = subDelegate) + + viewModel.onAction(Action.PhoneNumberChanged(subId = 1, phoneNumber = "+1555000111")) + + assertEquals(listOf(1 to "+1555000111"), subDelegate.phoneNumberChanges) + } + } + + @Test + fun onAutoRetrieveMmsChanged_delegatesToSubscriptionSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel(subscriptionSettingsDelegate = subDelegate) + + viewModel.onAction(Action.AutoRetrieveMmsChanged(subId = 2, enabled = true)) + + assertEquals(listOf(2 to true), subDelegate.autoRetrieveMmsChanges) + } + } + + @Test + fun onAutoRetrieveMmsWhenRoamingChanged_delegatesToSubscriptionSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel(subscriptionSettingsDelegate = subDelegate) + + viewModel.onAction(Action.AutoRetrieveMmsWhenRoamingChanged(subId = 1, enabled = true)) + + assertEquals(listOf(1 to true), subDelegate.autoRetrieveMmsWhenRoamingChanges) + } + } + + @Test + fun onDeliveryReportsChanged_delegatesToSubscriptionSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val subDelegate = FakeSubscriptionSettingsDelegate() + val viewModel = createViewModel(subscriptionSettingsDelegate = subDelegate) + + viewModel.onAction(Action.DeliveryReportsChanged(subId = 1, enabled = true)) + + assertEquals(listOf(1 to true), subDelegate.deliveryReportsChanges) + } + } + + @Test + fun onDefaultSmsAppClick_whenDefault_emitsOpenManageDefaultApps() { + runTest(context = mainDispatcherRule.testDispatcher) { + val viewModel = createViewModel() + advanceUntilIdle() + + viewModel.effects.test { + viewModel.onAction(Action.DefaultSmsAppClicked(isCurrentlyDefault = true)) + + assertEquals(SettingsScreenEffect.OpenManageDefaultApps, awaitItem()) + cancelAndIgnoreRemainingEvents() + } + } + } + + @Test + fun onDefaultSmsAppClick_whenNotDefault_emitsRequestDefaultSmsApp() { + runTest(context = mainDispatcherRule.testDispatcher) { + val viewModel = createViewModel() + advanceUntilIdle() + + viewModel.effects.test { + viewModel.onAction(Action.DefaultSmsAppClicked(isCurrentlyDefault = false)) + + assertEquals(SettingsScreenEffect.RequestDefaultSmsApp, awaitItem()) + cancelAndIgnoreRemainingEvents() + } + } + } + + @Test + fun onNotificationsClick_emitsOpenNotificationSettings() { + runTest(context = mainDispatcherRule.testDispatcher) { + val viewModel = createViewModel() + advanceUntilIdle() + + viewModel.effects.test { + viewModel.onAction(Action.NotificationsClicked) + + assertEquals(SettingsScreenEffect.OpenNotificationSettings, awaitItem()) + cancelAndIgnoreRemainingEvents() + } + } + } + + @Test + fun onWirelessAlertsClick_emitsOpenWirelessAlerts() { + runTest(context = mainDispatcherRule.testDispatcher) { + val viewModel = createViewModel() + advanceUntilIdle() + + viewModel.effects.test { + viewModel.onAction(Action.WirelessAlertsClicked(subId = 1)) + + assertEquals(SettingsScreenEffect.OpenWirelessAlerts(subId = 1), awaitItem()) + cancelAndIgnoreRemainingEvents() + } + } + } + + @Test + fun onLicensesClick_emitsOpenLicenses() { + runTest(context = mainDispatcherRule.testDispatcher) { + val viewModel = createViewModel() + advanceUntilIdle() + + viewModel.effects.test { + viewModel.onAction(Action.LicensesClicked) + + assertEquals(SettingsScreenEffect.OpenLicenses, awaitItem()) + cancelAndIgnoreRemainingEvents() + } + } + } + + private fun createViewModel( + appSettingsDelegate: AppSettingsDelegate = FakeAppSettingsDelegate(), + subscriptionSettingsDelegate: SubscriptionSettingsDelegate = + FakeSubscriptionSettingsDelegate(), + ): SettingsViewModel { + return SettingsViewModel( + appSettingsDelegate = appSettingsDelegate, + subscriptionSettingsDelegate = subscriptionSettingsDelegate, + ) + } + + private class FakeAppSettingsDelegate : AppSettingsDelegate { + val stateFlow = MutableStateFlow(AppSettingsUiState()) + override val state: StateFlow = stateFlow + + var bindCalls = 0 + var refreshCalls = 0 + val sendSoundChanges = mutableListOf() + val dumpSmsChanges = mutableListOf() + val dumpMmsChanges = mutableListOf() + + override fun bind(scope: CoroutineScope) { + bindCalls += 1 + } + + override fun refresh() { + refreshCalls += 1 + } + + override fun onSendSoundChanged(enabled: Boolean) { + sendSoundChanges += enabled + } + + override fun onDumpSmsChanged(enabled: Boolean) { + dumpSmsChanges += enabled + } + + override fun onDumpMmsChanged(enabled: Boolean) { + dumpMmsChanges += enabled + } + } + + private class FakeSubscriptionSettingsDelegate : SubscriptionSettingsDelegate { + val stateFlow = MutableStateFlow(SubscriptionSettingsState()) + override val state: StateFlow = stateFlow + + var bindCalls = 0 + var refreshCalls = 0 + val groupMmsChanges = mutableListOf>() + val phoneNumberChanges = mutableListOf>() + val autoRetrieveMmsChanges = mutableListOf>() + val autoRetrieveMmsWhenRoamingChanges = mutableListOf>() + val deliveryReportsChanges = mutableListOf>() + + override fun bind(scope: CoroutineScope) { + bindCalls += 1 + } + + override fun refresh() { + refreshCalls += 1 + } + + override fun onGroupMmsChanged(subId: Int, enabled: Boolean) { + groupMmsChanges += subId to enabled + } + + override fun onPhoneNumberChanged(subId: Int, phoneNumber: String) { + phoneNumberChanges += subId to phoneNumber + } + + override fun onAutoRetrieveMmsChanged(subId: Int, enabled: Boolean) { + autoRetrieveMmsChanges += subId to enabled + } + + override fun onAutoRetrieveMmsWhenRoamingChanged(subId: Int, enabled: Boolean) { + autoRetrieveMmsWhenRoamingChanges += subId to enabled + } + + override fun onDeliveryReportsChanged(subId: Int, enabled: Boolean) { + deliveryReportsChanges += subId to enabled + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 99fe9844..6cfa7ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,10 @@ mockk = "1.14.9" robolectric = "4.16.1" turbine = "1.2.1" +androidx-test-espresso = "3.7.0" +androidx-test-ext-junit = "1.3.0" +androidx-test-runner = "1.7.0" + [libraries] androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } @@ -77,6 +81,12 @@ hilt-gradle-plugin = { module = "com.google.dagger:hilt-android-gradle-plugin", kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } ksp-gradle-plugin = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version.ref = "ksp" } +androidx-test-espresso-contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "androidx-test-espresso" } +androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" } +androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-ext-junit" } +androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test-runner" } +androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 96f92386..687ec417 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -86,6 +86,11 @@ + + + + + @@ -100,9 +105,6 @@ - - - @@ -143,9 +145,6 @@ - - - @@ -206,9 +205,6 @@ - - - @@ -254,13 +250,21 @@ + + + + + + + + + + + - - - @@ -282,17 +286,11 @@ - - - - - - @@ -309,9 +307,6 @@ - - - @@ -322,9 +317,6 @@ - - - @@ -808,9 +800,6 @@ - - - @@ -823,6 +812,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -848,6 +870,11 @@ + + + + + @@ -910,9 +937,6 @@ - - - @@ -965,9 +989,6 @@ - - - @@ -1017,9 +1038,6 @@ - - - @@ -1137,9 +1155,6 @@ - - - @@ -1155,9 +1170,6 @@ - - - @@ -1174,9 +1186,6 @@ - - - @@ -1239,9 +1248,6 @@ - - - @@ -1296,9 +1302,6 @@ - - - @@ -1320,9 +1323,6 @@ - - - @@ -1339,9 +1339,6 @@ - - - @@ -1406,9 +1403,6 @@ - - - @@ -1425,9 +1419,6 @@ - - - @@ -1484,9 +1475,6 @@ - - - @@ -1531,9 +1519,6 @@ - - - @@ -1613,9 +1598,6 @@ - - - @@ -1632,9 +1614,6 @@ - - - @@ -1718,12 +1697,6 @@ - - - - - - @@ -1743,9 +1716,6 @@ - - - @@ -1756,9 +1726,6 @@ - - - @@ -1786,9 +1753,6 @@ - - - @@ -1801,53 +1765,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + - - + + @@ -1861,46 +1787,48 @@ - - - + + + - - + + - - - - - + + - - - - - - + + + - - + + - - + + - - - + + + + + + - - + + + + + + + - - + + - - + + @@ -1914,32 +1842,26 @@ - - - + + + - - + + - - - - - + + - - - - - - + + + - - + + - - + + @@ -1953,6 +1875,17 @@ + + + + + + + + + + + @@ -1964,13 +1897,21 @@ + + + + + + + + + + + - - - @@ -2027,13 +1968,32 @@ + + + + + + + + + + + + + + + + + + + + + + - - - @@ -2283,6 +2243,14 @@ + + + + + + + + @@ -2463,9 +2431,6 @@ - - - @@ -2563,9 +2528,6 @@ - - - @@ -2574,9 +2536,6 @@ - - - @@ -2585,9 +2544,6 @@ - - - @@ -2596,9 +2552,6 @@ - - - @@ -2607,9 +2560,6 @@ - - - @@ -2618,9 +2568,6 @@ - - - @@ -2629,9 +2576,6 @@ - - - @@ -2640,9 +2584,6 @@ - - - @@ -2651,9 +2592,6 @@ - - - @@ -2662,9 +2600,6 @@ - - - @@ -2673,9 +2608,6 @@ - - - @@ -2684,9 +2616,6 @@ - - - @@ -2695,9 +2624,6 @@ - - - @@ -2706,9 +2632,6 @@ - - - @@ -2717,9 +2640,6 @@ - - - @@ -2728,9 +2648,6 @@ - - - @@ -2739,9 +2656,6 @@ - - - @@ -2761,9 +2675,6 @@ - - - @@ -2831,6 +2742,11 @@ + + + + + @@ -2852,11 +2768,24 @@ - - + + + + - - + + + + + + + + + + + + + @@ -2874,9 +2803,6 @@ - - - @@ -2885,9 +2811,6 @@ - - - @@ -2901,9 +2824,6 @@ - - - @@ -2917,9 +2837,6 @@ - - - @@ -2985,9 +2902,6 @@ - - - @@ -2999,12 +2913,6 @@ - - - - - - @@ -3028,9 +2936,6 @@ - - - @@ -3061,9 +2966,6 @@ - - - @@ -3259,9 +3161,6 @@ - - - @@ -3270,9 +3169,6 @@ - - - @@ -3284,12 +3180,6 @@ - - - - - - @@ -3366,12 +3256,6 @@ - - - - - - @@ -3380,9 +3264,6 @@ - - - @@ -3503,9 +3384,6 @@ - - - @@ -3531,9 +3409,6 @@ - - - @@ -3570,9 +3445,6 @@ - - - @@ -3589,9 +3461,6 @@ - - - @@ -3619,9 +3488,6 @@ - - - @@ -3630,8 +3496,24 @@ - - + + + + + + + + + + + + + + + + + + @@ -3661,9 +3543,6 @@ - - - @@ -3672,9 +3551,6 @@ - - - @@ -3683,9 +3559,6 @@ - - - @@ -3694,9 +3567,6 @@ - - - @@ -3705,9 +3575,6 @@ - - - @@ -3716,9 +3583,6 @@ - - - @@ -3936,20 +3800,6 @@ - - - - - - - - - - - - - - @@ -4002,9 +3852,6 @@ - - - @@ -4036,9 +3883,6 @@ - - - @@ -4077,9 +3921,6 @@ - - - @@ -4320,9 +4161,6 @@ - - - @@ -4450,9 +4288,6 @@ - - - @@ -4474,9 +4309,6 @@ - - - @@ -4493,9 +4325,6 @@ - - - @@ -4512,9 +4341,6 @@ - - - @@ -4531,9 +4357,6 @@ - - - @@ -4550,9 +4373,6 @@ - - - @@ -4561,9 +4381,6 @@ - - - @@ -4580,9 +4397,6 @@ - - - @@ -4591,9 +4405,6 @@ - - - @@ -4698,9 +4509,6 @@ - - - @@ -4717,9 +4525,6 @@ - - - @@ -4736,9 +4541,6 @@ - - - @@ -4755,9 +4557,6 @@ - - - @@ -4774,9 +4573,6 @@ - - - @@ -4793,9 +4589,6 @@ - - - @@ -4812,9 +4605,6 @@ - - - @@ -4831,9 +4621,6 @@ - - - @@ -4860,9 +4647,6 @@ - - - @@ -4879,9 +4663,6 @@ - - - @@ -4898,9 +4679,6 @@ - - - @@ -4917,9 +4695,6 @@ - - - @@ -4928,9 +4703,6 @@ - - - @@ -4947,9 +4719,6 @@ - - - @@ -4958,9 +4727,6 @@ - - - @@ -4986,9 +4752,6 @@ - - - @@ -5085,9 +4848,6 @@ - - - @@ -5099,9 +4859,6 @@ - - - @@ -5132,9 +4889,6 @@ - - - @@ -5229,12 +4983,6 @@ - - - - - - @@ -5268,9 +5016,6 @@ - - - @@ -5282,9 +5027,6 @@ - - - @@ -5307,9 +5049,6 @@ - - - @@ -5321,9 +5060,6 @@ - - - @@ -5349,9 +5085,6 @@ - - - @@ -5364,16 +5097,24 @@ + + + + + + + + + + + + + + - - - - - - @@ -5398,9 +5139,6 @@ - - - @@ -5412,9 +5150,6 @@ - - - @@ -5431,9 +5166,6 @@ - - - @@ -5509,9 +5241,6 @@ - - - @@ -5523,13 +5252,24 @@ - - - + + + + + + + + + + + + + + @@ -5544,18 +5284,18 @@ - - - + + + - - + + - - + + - - + + @@ -5572,6 +5312,20 @@ + + + + + + + + + + + + + + @@ -5584,9 +5338,6 @@ - - - @@ -5595,9 +5346,6 @@ - - - @@ -5611,9 +5359,6 @@ - - - @@ -5622,9 +5367,6 @@ - - - @@ -5677,49 +5419,31 @@ - - - - - - - - - - - - - - - - - - @@ -5760,9 +5484,6 @@ - - - @@ -5893,9 +5614,6 @@ - - - @@ -5904,9 +5622,6 @@ - - - @@ -5915,9 +5630,6 @@ - - - @@ -5942,9 +5654,6 @@ - - - @@ -5991,9 +5700,6 @@ - - - @@ -6117,9 +5823,6 @@ - - - @@ -6142,9 +5845,6 @@ - - - @@ -6172,9 +5872,6 @@ - - - @@ -6207,9 +5904,6 @@ - - - @@ -6218,9 +5912,6 @@ - - - @@ -6229,9 +5920,6 @@ - - - @@ -6312,9 +6000,6 @@ - - - @@ -6323,9 +6008,6 @@ - - - @@ -6337,12 +6019,6 @@ - - - - - - @@ -6365,9 +6041,6 @@ - - - @@ -6376,9 +6049,6 @@ - - - @@ -6390,12 +6060,6 @@ - - - - - - @@ -6450,9 +6114,6 @@ - - - @@ -6461,9 +6122,6 @@ - - - @@ -6504,6 +6162,11 @@ + + + + + @@ -6513,9 +6176,6 @@ - - - @@ -6531,9 +6191,6 @@ - - - @@ -6553,9 +6210,6 @@ - - - @@ -6576,6 +6230,11 @@ + + + + + @@ -6680,6 +6339,20 @@ + + + + + + + + + + + + + + @@ -6725,9 +6398,6 @@ - - - diff --git a/res/layout/group_mms_setting_dialog.xml b/res/layout/group_mms_setting_dialog.xml deleted file mode 100644 index efc3b004..00000000 --- a/res/layout/group_mms_setting_dialog.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - diff --git a/res/layout/settings_item_view.xml b/res/layout/settings_item_view.xml deleted file mode 100644 index a434c111..00000000 --- a/res/layout/settings_item_view.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - diff --git a/res/values/colors.xml b/res/values/colors.xml index 19ee2ec8..fe9c0723 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -151,11 +151,6 @@ #03a9f4 #4d4d4d - #4d4d4d - #6d6d6d - #333333 - #000000 - @color/primary_color #424242 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 59a4148f..a69dd85d 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -143,11 +143,6 @@ 10dp 5dp - 16sp - 14sp - 60dp - 14sp - 40dp 30dp diff --git a/res/values/styles.xml b/res/values/styles.xml index fa5884d4..cc9ff474 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -67,10 +67,6 @@ @color/archived_conversation_action_bar_background_color_dark - - - - - - - -