diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/passwordprotected/ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/passwordprotected/ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest.kt new file mode 100644 index 0000000000..6da001deb9 --- /dev/null +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/passwordprotected/ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest.kt @@ -0,0 +1,192 @@ +/* + * © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com + * Contributors: denbond7 + */ + +package com.flowcrypt.email.ui.gmailapi.passwordprotected + +import android.Manifest +import android.app.Instrumentation +import android.content.Intent +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.openLinkWithText +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction +import androidx.test.espresso.intent.matcher.IntentMatchers.hasData +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.MediumTest +import com.flowcrypt.email.R +import com.flowcrypt.email.TestConstants +import com.flowcrypt.email.api.retrofit.ApiHelper +import com.flowcrypt.email.api.retrofit.response.api.ClientConfigurationResponse +import com.flowcrypt.email.junit.annotations.EnterpriseTest +import com.flowcrypt.email.junit.annotations.FlowCryptTestSettings +import com.flowcrypt.email.junit.annotations.OutgoingMessageConfiguration +import com.flowcrypt.email.rules.AddRecipientsToDatabaseRule +import com.flowcrypt.email.rules.ClearAppSettingsRule +import com.flowcrypt.email.rules.FlowCryptMockWebServerRule +import com.flowcrypt.email.rules.GrantPermissionRuleChooser +import com.flowcrypt.email.rules.RetryRule +import com.flowcrypt.email.rules.ScreenshotTestRule +import okhttp3.mockwebserver.Dispatcher +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.RecordedRequest +import org.hamcrest.Matchers.allOf +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.rules.TestRule +import org.junit.runner.RunWith +import java.net.HttpURLConnection +import java.util.concurrent.TimeUnit + +/** + * @author Denys Bondarenko + */ +@MediumTest +@RunWith(AndroidJUnit4::class) +@FlowCryptTestSettings(useCommonIdling = false, useIntents = true) +@EnterpriseTest +@OutgoingMessageConfiguration( + to = [], + cc = [], + bcc = [], + message = "", + subject = "", + isNew = true +) +class ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest : + BaseComposeScreenPasswordProtectedDisallowedTermsTest( + ACCOUNT_ENTITY_WITH_EXISTING_OPTIONAL_PARAMETERS + ) { + + private var attemptsToUseDefaultBehavior = 2 + + override val mockWebServerRule = + FlowCryptMockWebServerRule(TestConstants.MOCK_WEB_SERVER_PORT, object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + return when { + request.path.equals("/api/v1/client-configuration?domain=flowcrypt.test") -> { + if (attemptsToUseDefaultBehavior == 0) { + MockResponse() + .setResponseCode(HttpURLConnection.HTTP_OK) + .setBody( + ApiHelper.getInstance(getTargetContext()).gson.toJson( + ClientConfigurationResponse( + clientConfiguration = ACCOUNT_ENTITY_WITH_EXISTING_OPTIONAL_PARAMETERS.clientConfiguration?.copy( + disallowPasswordMessagesErrorText = UPDATED_ERROR_TEXT, + disallowPasswordMessagesForTerms = TERMS + ) + ) + ) + ) + } else { + attemptsToUseDefaultBehavior-- + handleCommonAPICalls(request) + } + } + + else -> handleCommonAPICalls(request) + } + } + }) + + @get:Rule + var ruleChain: TestRule = + RuleChain.outerRule(RetryRule.DEFAULT) + .around(ClearAppSettingsRule()) + .around(GrantPermissionRuleChooser.grant(Manifest.permission.POST_NOTIFICATIONS)) + .around(mockWebServerRule) + .around(addAccountToDatabaseRule) + .around(addPrivateKeyToDatabaseRule) + .around(AddRecipientsToDatabaseRule(prepareRecipientsForTest())) + .around(addLabelsToDatabaseRule) + .around(activityScenarioRule) + .around(ScreenshotTestRule()) + + @Test + fun testDialogWithErrorText() { + intentsRelease() + + //do checking before updating client configuration + MATCHING_SUBJECTS.forEach { subject -> + onView(withId(R.id.editTextEmailSubject)) + .perform(scrollTo(), click(), replaceText(subject)) + + waitForObjectWithText(subject, TimeUnit.SECONDS.toMillis(5)) + + onView(withId(R.id.menuActionSend)) + .check(matches(isDisplayed())) + .perform(click()) + + isDialogWithTextDisplayed( + decorView, + ERROR_TEXT + ) + + Intents.init() + //test that URL is openable + val expectingIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(URL)) + //mocking intent to prevent actual navigation during test + Intents.intending(expectingIntent).respondWith(Instrumentation.ActivityResult(0, null)) + //performing action + onView(withText(ERROR_TEXT)) + .perform(openLinkWithText(URL)) + //asserting our expected intent was recorded + Intents.intended(expectingIntent) + Intents.release() + + onView(withId(android.R.id.button1)) + .check(matches(isDisplayed())) + .perform(click()) + } + + //go to ProvidePasswordToProtectMsgFragment and go back to trigger updating + onView(withId(R.id.btnSetWebPortalPassword)) + .perform(click()) + Espresso.pressBack() + //need to wait while threads will be synced + Thread.sleep(2000) + + //check that client configuration was updated + MATCHING_SUBJECTS.first().let { subject -> + onView(withId(R.id.editTextEmailSubject)) + .perform(scrollTo(), click(), replaceText(subject)) + + waitForObjectWithText(subject, TimeUnit.SECONDS.toMillis(5)) + + onView(withId(R.id.menuActionSend)) + .check(matches(isDisplayed())) + .perform(click()) + + isDialogWithTextDisplayed( + decorView, + UPDATED_ERROR_TEXT + ) + + onView(withId(android.R.id.button1)) + .check(matches(isDisplayed())) + .perform(click()) + } + } + + companion object { + const val UPDATED_ERROR_TEXT = "Updated: Password-protected messages are disabled" + + val ACCOUNT_ENTITY_WITH_EXISTING_OPTIONAL_PARAMETERS = + BASE_ACCOUNT_ENTITY.copy( + clientConfiguration = BASE_ACCOUNT_ENTITY.clientConfiguration?.copy( + disallowPasswordMessagesErrorText = ERROR_TEXT, + disallowPasswordMessagesForTerms = TERMS + ) + ) + } +} diff --git a/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/CreateMessageFragment.kt b/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/CreateMessageFragment.kt index fa5cb62476..ac735ef8fa 100644 --- a/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/CreateMessageFragment.kt +++ b/FlowCrypt/src/main/java/com/flowcrypt/email/ui/activity/fragment/CreateMessageFragment.kt @@ -42,6 +42,7 @@ import androidx.navigation.fragment.navArgs import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.flowcrypt.email.BuildConfig import com.flowcrypt.email.Constants import com.flowcrypt.email.R import com.flowcrypt.email.api.email.EmailUtil @@ -86,6 +87,7 @@ import com.flowcrypt.email.jetpack.viewmodel.DraftViewModel import com.flowcrypt.email.jetpack.viewmodel.PrivateKeysViewModel import com.flowcrypt.email.jetpack.viewmodel.RecipientsAutoCompleteViewModel import com.flowcrypt.email.jetpack.viewmodel.RecipientsViewModel +import com.flowcrypt.email.jetpack.workmanager.RefreshClientConfigurationWorker import com.flowcrypt.email.model.DialogItem import com.flowcrypt.email.model.MessageEncryptionType import com.flowcrypt.email.model.MessageType @@ -553,7 +555,7 @@ class CreateMessageFragment : BaseFragment(), if (selectedItemPosition != null && selectedItemPosition != AdapterView.INVALID_POSITION && (binding?.spinnerFrom?.adapter?.count ?: 0) > selectedItemPosition ) { - val isItemEnabled = fromAddressesAdapter?.isEnabled(selectedItemPosition) ?: true + val isItemEnabled = fromAddressesAdapter?.isEnabled(selectedItemPosition) != false binding?.editTextFrom?.setTextColor(if (isItemEnabled) originalColor else colorGray) } } @@ -983,13 +985,13 @@ class CreateMessageFragment : BaseFragment(), } private fun updateViewsFromServiceInfo() { - binding?.editTextEmailSubject?.isFocusable = args.serviceInfo?.isSubjectEditable ?: false + binding?.editTextEmailSubject?.isFocusable = args.serviceInfo?.isSubjectEditable == true binding?.editTextEmailSubject?.isFocusableInTouchMode = - args.serviceInfo?.isSubjectEditable ?: false + args.serviceInfo?.isSubjectEditable == true - binding?.editTextEmailMessage?.isFocusable = args.serviceInfo?.isMsgEditable ?: false + binding?.editTextEmailMessage?.isFocusable = args.serviceInfo?.isMsgEditable == true binding?.editTextEmailMessage?.isFocusableInTouchMode = - args.serviceInfo?.isMsgEditable ?: false + args.serviceInfo?.isMsgEditable == true if (args.serviceInfo?.systemMsg?.isNotEmpty() == true) { binding?.editTextEmailMessage?.setText(args.serviceInfo?.systemMsg) @@ -1361,6 +1363,10 @@ class CreateMessageFragment : BaseFragment(), BlendModeColorFilterCompat.createBlendModeColorFilterCompat( ContextCompat.getColor(context, R.color.colorPrimary), BlendModeCompat.MODULATE ) + + if (BuildConfig.FLAVOR == Constants.FLAVOR_NAME_ENTERPRISE) { + RefreshClientConfigurationWorker.enqueue(requireContext()) + } } } } @@ -1498,7 +1504,7 @@ class CreateMessageFragment : BaseFragment(), when (recipientType) { Message.RecipientType.TO -> toRecipientsChipRecyclerViewAdapter.submitList( recipients, - args.serviceInfo?.isToFieldEditable ?: true + args.serviceInfo?.isToFieldEditable != false ) Message.RecipientType.CC -> ccRecipientsChipRecyclerViewAdapter.submitList(recipients)