@@ -145,9 +145,9 @@ import com.salesforce.androidsdk.util.SalesforceSDKLogger.e
145145import com.salesforce.androidsdk.util.SalesforceSDKLogger.w
146146import com.salesforce.androidsdk.util.UriFragmentParser
147147import kotlinx.coroutines.CoroutineScope
148- import kotlinx.coroutines.Dispatchers
149148import kotlinx.coroutines.Dispatchers.Default
150149import kotlinx.coroutines.Dispatchers.IO
150+ import kotlinx.coroutines.Dispatchers.Main
151151import kotlinx.coroutines.launch
152152import org.json.JSONObject
153153import java.lang.String.format
@@ -173,6 +173,8 @@ import java.security.cert.X509Certificate
173173 * them.
174174 */
175175open class LoginActivity : FragmentActivity () {
176+ private var customTabLauncher: ActivityResultLauncher <Intent >? = null
177+
176178 // View Model
177179 @VisibleForTesting(otherwise = PROTECTED )
178180 open val viewModel: LoginViewModel
@@ -224,7 +226,7 @@ open class LoginActivity : FragmentActivity() {
224226 SalesforceSDKManager .getInstance().setViewNavigationVisibility(this )
225227 }
226228
227- applyIntent(intent )
229+ applyIntent()
228230
229231 // Don't let sharedBrowserSession org setting stop a new user from logging in.
230232 if (intent.extras?.getBoolean(NEW_USER ) == true ) {
@@ -270,7 +272,7 @@ open class LoginActivity : FragmentActivity() {
270272 onBackPressedDispatcher.addCallback { handleBackBehavior() }
271273 }
272274
273- val customTabLauncher: ActivityResultLauncher < Intent > = registerForActivityResult(
275+ customTabLauncher = registerForActivityResult(
274276 ActivityResultContracts .StartActivityForResult ()
275277 ) { result: ActivityResult ->
276278 // Check if the user backed out of the custom tab.
@@ -285,48 +287,6 @@ open class LoginActivity : FragmentActivity() {
285287 }
286288 }
287289
288- // Take action on selected server change.
289- viewModel.selectedServer.observe(this ) { selectedServer ->
290-
291- // Guard against observing a selected server already provided by the intent data, such as a Salesforce Welcome Discovery mobile URL.
292- val selectedServerUri = selectedServer.toUri()
293- if (intent.data?.host == selectedServerUri.host) {
294- return @observe
295- }
296-
297- // Use the URL to switch between default or Salesforce Welcome Discovery log in, if applicable.
298- if (switchDefaultOrSalesforceWelcomeDiscoveryLogin(selectedServerUri)) {
299- return @observe
300- }
301-
302- if (viewModel.singleServerCustomTabActivity) {
303- // Skip fetching authorization and show custom tab immediately.
304- viewModel.reloadWebView()
305- viewModel.loginUrl.value?.let { url ->
306- loadLoginPageInCustomTab(url, customTabLauncher)
307- }
308- } else {
309- with (SalesforceSDKManager .getInstance()) {
310- // Fetch well known config and load in custom tab if required.
311- fetchAuthenticationConfiguration {
312- /* Browser-based authentication is applicable when not authenticating with a front-door bridge URL */
313- if (isBrowserLoginEnabled && ! viewModel.isUsingFrontDoorBridge) {
314- if (useWebServerAuthentication) {
315- viewModel.loginUrl.value?.let { url -> loadLoginPageInCustomTab(url, customTabLauncher) }
316- } else {
317- /* Reload the webview now that isBrowserLoginEnabled has been set
318- to true so that we generate an authorization URL with PKCE values. */
319- lifecycleScope.launch(Dispatchers .Main ) {
320- viewModel.reloadWebView()
321- viewModel.loginUrl.value?.let { url -> loadLoginPageInCustomTab(url, customTabLauncher) }
322- }
323- }
324- }
325- }
326- }
327- }
328- }
329-
330290 // Support magic links
331291 if (viewModel.jwt != null ) {
332292 swapJWTForAccessToken()
@@ -368,7 +328,9 @@ open class LoginActivity : FragmentActivity() {
368328 return
369329 }
370330
371- applyIntent(intent)
331+ // Store the new intent and apply it to the activity.
332+ setIntent(intent)
333+ applyIntent()
372334 }
373335
374336 private fun clearWebView (showServerPicker : Boolean = true) {
@@ -936,6 +898,9 @@ open class LoginActivity : FragmentActivity() {
936898 // endregion
937899 // region Salesforce Welcome Login Private Implementation
938900
901+ /* * The previously observed pending login server for use in switching between default and Salesforce Welcome Discovery log in */
902+ private var previousPendingLoginServer: String? = null
903+
939904 /* *
940905 * If the intent is for Salesforce Welcome Discovery, apply it to the activity.
941906 * @param intent The intent
@@ -996,51 +961,51 @@ open class LoginActivity : FragmentActivity() {
996961 .build()
997962
998963 /* *
999- * Determines if the provided proposed selected server URL is a switch from
964+ * Determines if the provided pending login server URL is a switch from
1000965 * Salesforce Welcome Discovery back to default log in.
1001- * @param proposedSelectedServerUrl The proposed selected server URL
1002- * @return Boolean true if the provided proposed selected server URL is a
966+ * @param pendingLoginServerUri The pending login server URL
967+ * @return Boolean true if the provided pending login server URL is a
1003968 * switch from Salesforce Welcome Discovery back to the default log in,
1004969 * false otherwise.
1005970 * */
1006971 private fun isSwitchFromSalesforceWelcomeDiscoveryToDefaultLogin (
1007- proposedSelectedServerUrl : Uri
1008- ) = viewModel.loginUrl.value ?.toUri()?.let { loginUrl ->
1009- isSalesforceWelcomeDiscoveryMobileUrl(loginUrl ) && ! (isSalesforceWelcomeDiscoveryMobileUrl(proposedSelectedServerUrl ))
972+ pendingLoginServerUri : Uri
973+ ) = previousPendingLoginServer ?.toUri()?.let { previousPendingLoginServerUri ->
974+ isSalesforceWelcomeDiscoveryUrlPath(previousPendingLoginServerUri ) && ! (isSalesforceWelcomeDiscoveryMobileUrl(this , pendingLoginServerUri ))
1010975 } ? : false
1011976
1012977 /* *
1013978 * Switches between default or Salesforce Welcome Discovery log in as needed
1014- * using the provided proposed selected server URL.
1015- * @param uri The proposed selected server URL
979+ * using the provided pending login server URL.
980+ * @param pendingLoginServerUri The pending login server URL
1016981 * @return Boolean true if a switch between default or Salesforce Welcome
1017982 * Discovery log is made, false otherwise.
1018983 */
1019- private fun switchDefaultOrSalesforceWelcomeDiscoveryLogin (uri : Uri ) =
984+ private fun switchDefaultOrSalesforceWelcomeDiscoveryLogin (pendingLoginServerUri : Uri ) =
1020985
1021- // If the selected server has changed to a new Salesforce Welcome Discovery URL and host.
1022- if (isSalesforceWelcomeDiscoveryUrlPath(uri )) {
986+ // If the pending login server is a change to a new Salesforce Welcome Discovery URL and host.
987+ if (isSalesforceWelcomeDiscoveryUrlPath(pendingLoginServerUri )) {
1023988
1024989 // Navigate to Salesforce Welcome Discovery.
1025990 startActivity(
1026991 Intent (
1027992 this ,
1028- LoginActivity :: class .java
993+ SalesforceSDKManager .getInstance().loginActivityClass
1029994 ).apply {
1030- data = generateSalesforceWelcomeDiscoveryMobileUrl(uri )
995+ data = generateSalesforceWelcomeDiscoveryMobileUrl(pendingLoginServerUri )
1031996 flags = FLAG_ACTIVITY_SINGLE_TOP
1032997 })
1033998 true
1034999 }
10351000
1036- // If the new selected server isn't a Salesforce Welcome Discovery URL but the previous was...
1037- else if (isSwitchFromSalesforceWelcomeDiscoveryToDefaultLogin(uri )) {
1001+ // If the pending login server isn't a Salesforce Welcome Discovery URL but the previous was...
1002+ else if (isSwitchFromSalesforceWelcomeDiscoveryToDefaultLogin(pendingLoginServerUri )) {
10381003
1039- // Navigate to login.
1004+ // Navigate to default login.
10401005 startActivity(
10411006 Intent (
10421007 this ,
1043- LoginActivity :: class .java
1008+ SalesforceSDKManager .getInstance().loginActivityClass
10441009 ).apply {
10451010 flags = FLAG_ACTIVITY_SINGLE_TOP
10461011 })
@@ -1062,6 +1027,8 @@ open class LoginActivity : FragmentActivity() {
10621027 uri : Uri
10631028 ): Boolean {
10641029 return if (isSalesforceWelcomeDiscoveryMobileCallbackUrl(uri)) {
1030+ // Stop observing the pending login server since the newly started default login will do so.
1031+ viewModel.pendingServer.removeObservers(this )
10651032 startDefaultLoginWithHintAndHost(
10661033 context = this ,
10671034 loginHint = uri.getQueryParameter(SALESFORCE_WELCOME_DISCOVERY_MOBILE_CALLBACK_URL_QUERY_PARAMETER_KEY_LOGIN_HINT ) ? : return false ,
@@ -1086,17 +1053,81 @@ open class LoginActivity : FragmentActivity() {
10861053 // endregion
10871054
10881055 /* *
1089- * Applies a new intent to the activity, for instance when the activity is
1090- * created or receives a new intent.
1091- * @param intent The new intent
1056+ * (Re-)applies the intent to the activity, for instance when the activity
1057+ * is created or receives a new intent.
10921058 */
1093- private fun applyIntent (intent : Intent ) {
1059+ private fun applyIntent () {
10941060
10951061 // If the intent is for Salesforce Welcome Discovery, apply it to the activity.
10961062 applySalesforceWelcomeDiscoveryIntent(intent)
10971063
10981064 // If the intent is for log in using a UI Bridge API front door URL, apply it to the activity.
10991065 applyUiBridgeApiFrontDoorUrl(intent)
1066+
1067+ // Apply the pending login server, if applicable.
1068+ applyPendingServer()
1069+ }
1070+
1071+ /* *
1072+ * Applies the pending login server. The authentication configuration will
1073+ * be fetched for the pending server and any applicable tasks will be
1074+ * performed such as browser based authentication. The pending login
1075+ * server will be set as the selected login server once the authentication
1076+ * configuration has been fetched.
1077+ */
1078+ private fun applyPendingServer () {
1079+
1080+ // Reset the observer to consume the current and future values.
1081+ viewModel.pendingServer.removeObservers(this )
1082+ viewModel.pendingServer.observe(this ) { pendingServer ->
1083+
1084+ // Guard against observing a pending login server already provided by the intent data, such as a Salesforce Welcome Discovery mobile URL.
1085+ val pendingServerUri = pendingServer.toUri()
1086+ if (intent.data?.host == pendingServerUri.host) {
1087+ previousPendingLoginServer = pendingServer
1088+ return @observe
1089+ }
1090+
1091+ // Use the URL to switch between default or Salesforce Welcome Discovery log in, if applicable.
1092+ if (switchDefaultOrSalesforceWelcomeDiscoveryLogin(pendingServerUri)) {
1093+ previousPendingLoginServer = pendingServer
1094+ return @observe
1095+ }
1096+
1097+ // Recall this pending login server for reference by future updates.
1098+ previousPendingLoginServer = pendingServer
1099+
1100+ if (viewModel.singleServerCustomTabActivity) {
1101+ // Skip fetching authorization and show custom tab immediately.
1102+ viewModel.selectedServer.value = pendingServer
1103+ viewModel.reloadWebView()
1104+ viewModel.loginUrl.value?.let { url ->
1105+ customTabLauncher?.let { loadLoginPageInCustomTab(url, it) }
1106+ }
1107+ } else {
1108+ with (SalesforceSDKManager .getInstance()) {
1109+ // Fetch the authentication configuration and load the login page in a custom tab if required.
1110+ fetchAuthenticationConfiguration {
1111+ lifecycleScope.launch(Main ) {
1112+ viewModel.selectedServer.value = pendingServer
1113+ /* Browser-based authentication is applicable when not authenticating with a front-door bridge URL */
1114+ if (isBrowserLoginEnabled && ! viewModel.isUsingFrontDoorBridge) {
1115+ if (useWebServerAuthentication) {
1116+ viewModel.loginUrl.value?.let { url ->
1117+ customTabLauncher?.let { loadLoginPageInCustomTab(url, it) }
1118+ }
1119+ } else {
1120+ /* Reload the webview now that isBrowserLoginEnabled has been set
1121+ to true so that we generate an authorization URL with PKCE values. */
1122+ viewModel.reloadWebView()
1123+ viewModel.loginUrl.value?.let { url -> customTabLauncher?.let { loadLoginPageInCustomTab(url, it) } }
1124+ }
1125+ }
1126+ }
1127+ }
1128+ }
1129+ }
1130+ }
11001131 }
11011132
11021133 /* *
@@ -1547,7 +1578,7 @@ open class LoginActivity : FragmentActivity() {
15471578 loginHint : String ,
15481579 loginHost : String ,
15491580 ) {
1550- Intent (context, LoginActivity :: class .java ).apply {
1581+ Intent (context, SalesforceSDKManager .getInstance().loginActivityClass ).apply {
15511582 putExtra(EXTRA_KEY_LOGIN_HINT , loginHint)
15521583 putExtra(EXTRA_KEY_LOGIN_HOST , loginHost)
15531584 flags = FLAG_ACTIVITY_SINGLE_TOP
0 commit comments