Skip to content

Commit 6f30715

Browse files
@W-20874450: [Android] Cherry pick MDM fix for 13.1.1 patch (#2818)
1 parent 70c7c9e commit 6f30715

4 files changed

Lines changed: 128 additions & 17 deletions

File tree

libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/LoginViewModel.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ import com.salesforce.androidsdk.auth.defaultBuildAccountName
6262
import com.salesforce.androidsdk.auth.onAuthFlowComplete
6363
import com.salesforce.androidsdk.config.BootConfig
6464
import com.salesforce.androidsdk.config.LoginServerManager.LoginServer
65+
import com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey.OnlyShowAuthorizedHosts
66+
import com.salesforce.androidsdk.config.RuntimeConfig.getRuntimeConfig
6567
import com.salesforce.androidsdk.security.SalesforceKeyGenerator.getRandom128ByteKey
6668
import com.salesforce.androidsdk.security.SalesforceKeyGenerator.getSHA256Hash
6769
import com.salesforce.androidsdk.ui.LoginActivity.Companion.ABOUT_BLANK
@@ -156,6 +158,8 @@ open class LoginViewModel(val bootConfig: BootConfig) : ViewModel() {
156158
internal val defaultTitleText: String
157159
get() = if (loginUrl.value == ABOUT_BLANK) "" else selectedServer.value ?: ""
158160

161+
internal val serverPickerAddConnectionButtonVisible = !getRuntimeConfig(SalesforceSDKManager.getInstance().appContext).getBoolean(OnlyShowAuthorizedHosts)
162+
159163
/** Additional Auth Values used for login. */
160164
open var additionalParameters = hashMapOf<String, String>()
161165

libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/components/PickerBottomSheet.kt

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,9 @@ import androidx.compose.ui.Modifier
9494
import androidx.compose.ui.focus.FocusRequester
9595
import androidx.compose.ui.focus.focusRequester
9696
import androidx.compose.ui.graphics.Color
97-
import androidx.compose.ui.platform.LocalContext
9897
import androidx.compose.ui.graphics.asImageBitmap
9998
import androidx.compose.ui.graphics.painter.BitmapPainter
100-
import androidx.compose.ui.res.painterResource
99+
import androidx.compose.ui.platform.LocalContext
101100
import androidx.compose.ui.res.stringResource
102101
import androidx.compose.ui.semantics.contentDescription
103102
import androidx.compose.ui.semantics.semantics
@@ -124,7 +123,9 @@ import com.salesforce.androidsdk.R.string.sf__server_url_default_custom_label
124123
import com.salesforce.androidsdk.R.string.sf__server_url_default_custom_url
125124
import com.salesforce.androidsdk.R.string.sf__server_url_save
126125
import com.salesforce.androidsdk.accounts.UserAccount
126+
import com.salesforce.androidsdk.accounts.UserAccountManager
127127
import com.salesforce.androidsdk.app.SalesforceSDKManager
128+
import com.salesforce.androidsdk.config.LoginServerManager
128129
import com.salesforce.androidsdk.config.LoginServerManager.LoginServer
129130
import com.salesforce.androidsdk.ui.LoginViewModel
130131
import com.salesforce.androidsdk.ui.theme.hintTextColor
@@ -146,10 +147,21 @@ internal const val TEXT_SELECTION_ALPHA = 0.2f
146147
@OptIn(ExperimentalMaterial3Api::class)
147148
@Composable
148149
fun PickerBottomSheet(pickerStyle: PickerStyle) {
149-
val viewModel: LoginViewModel = viewModel(factory = SalesforceSDKManager.getInstance().loginViewModelFactory)
150-
val loginServerManager = SalesforceSDKManager.getInstance().loginServerManager
151-
val userAccountManager = SalesforceSDKManager.getInstance().userAccountManager
152-
val activity = LocalContext.current.getActivity()
150+
TestablePickerBottomSheet(
151+
pickerStyle = pickerStyle,
152+
)
153+
}
154+
155+
@OptIn(ExperimentalMaterial3Api::class)
156+
@Composable
157+
@VisibleForTesting
158+
internal fun TestablePickerBottomSheet(
159+
pickerStyle: PickerStyle,
160+
viewModel: LoginViewModel = viewModel(factory = SalesforceSDKManager.getInstance().loginViewModelFactory),
161+
loginServerManager: LoginServerManager = SalesforceSDKManager.getInstance().loginServerManager,
162+
userAccountManager: UserAccountManager = SalesforceSDKManager.getInstance().userAccountManager,
163+
activity: FragmentActivity? = LocalContext.current.getActivity(),
164+
) {
153165
val onNewLoginServerSelected = { newSelectedServer: Any?, closePicker: Boolean ->
154166
if (newSelectedServer != null && newSelectedServer is LoginServer) {
155167
viewModel.showServerPicker.value = !closePicker
@@ -194,8 +206,9 @@ fun PickerBottomSheet(pickerStyle: PickerStyle) {
194206
when (pickerStyle) {
195207
PickerStyle.LoginServerPicker ->
196208
PickerBottomSheet(
197-
pickerStyle,
198-
sheetState,
209+
addButtonVisible = viewModel.serverPickerAddConnectionButtonVisible,
210+
pickerStyle = pickerStyle,
211+
sheetState = sheetState,
199212
list = loginServerManager.loginServers,
200213
selectedListItem = loginServerManager.selectedLoginServer,
201214
onItemSelected = onNewLoginServerSelected,
@@ -206,8 +219,8 @@ fun PickerBottomSheet(pickerStyle: PickerStyle) {
206219

207220
PickerStyle.UserAccountPicker ->
208221
PickerBottomSheet(
209-
pickerStyle,
210-
sheetState,
222+
pickerStyle = pickerStyle,
223+
sheetState = sheetState,
211224
list = userAccountManager.authenticatedUsers,
212225
selectedListItem = userAccountManager.currentUser,
213226
onItemSelected = onUserAccountSelected,
@@ -228,6 +241,7 @@ internal fun PickerBottomSheet(
228241
sheetState: SheetState,
229242
list: List<Any>,
230243
selectedListItem: Any?,
244+
addButtonVisible: Boolean = true,
231245
onItemSelected: (Any?, Boolean) -> Unit,
232246
getValidServer: ((String) -> String?)? = null,
233247
addNewLoginServer: ((String, String) -> Unit)? = null,
@@ -428,7 +442,7 @@ internal fun PickerBottomSheet(
428442
)
429443

430444
// Add New Connection/Account Button
431-
if (listItem == mutableList.last()) {
445+
if (listItem == mutableList.last() && addButtonVisible) {
432446
OutlinedButton(
433447
onClick = {
434448
when (pickerStyle) {

libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/rest/ClientManagerMockTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.salesforce.androidsdk.rest
22

33
import android.accounts.Account
44
import android.content.Context
5+
import android.content.Context.MODE_PRIVATE
56
import android.content.Intent
67
import androidx.test.filters.SmallTest
78
import androidx.test.platform.app.InstrumentationRegistry
@@ -53,6 +54,10 @@ class ClientManagerMockTest {
5354
every { packageName } returns "packageName"
5455
every { sendBroadcast(any()) } just runs
5556
every { externalCacheDir } returns null
57+
every { filesDir } returns targetContext.filesDir
58+
every { getSharedPreferences(any(), any()) } answers {
59+
targetContext.getSharedPreferences(firstArg(), MODE_PRIVATE)
60+
}
5661
}
5762

5863
mockkObject(SalesforceSDKManager)

libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/ui/PickerBottomSheetTest.kt

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,18 @@ import androidx.compose.ui.test.onNodeWithText
4747
import androidx.compose.ui.test.performClick
4848
import androidx.compose.ui.test.performTextClearance
4949
import androidx.compose.ui.test.performTextInput
50+
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
51+
import com.salesforce.androidsdk.R.string.sf__account_selector_text
52+
import com.salesforce.androidsdk.R.string.sf__custom_url_button
53+
import com.salesforce.androidsdk.R.string.sf__pick_server
54+
import com.salesforce.androidsdk.accounts.UserAccountManager
5055
import com.salesforce.androidsdk.config.LoginServerManager.LoginServer
5156
import com.salesforce.androidsdk.ui.components.AddConnection
5257
import com.salesforce.androidsdk.ui.components.PickerBottomSheet
5358
import com.salesforce.androidsdk.ui.components.PickerStyle
59+
import com.salesforce.androidsdk.ui.components.TestablePickerBottomSheet
5460
import com.salesforce.androidsdk.ui.components.UserAccountMock
61+
import io.mockk.mockk
5562
import org.junit.Assert
5663
import org.junit.Rule
5764
import org.junit.Test
@@ -97,6 +104,44 @@ class PickerBottomSheetTest {
97104

98105
// Google's recommended naming scheme for test is "thingUnderTest_TriggerOfTest_ResultOfTest"
99106

107+
// region Public API Tests
108+
109+
@OptIn(ExperimentalMaterial3Api::class)
110+
@Test
111+
fun pickerBottomSheet_publicApiUserAccountPicker_displaysUserAccountPicker() {
112+
val userAccountManager = mockk<UserAccountManager>(relaxed = true)
113+
composeTestRule.setContent {
114+
TestablePickerBottomSheet(
115+
pickerStyle = PickerStyle.UserAccountPicker,
116+
userAccountManager = userAccountManager
117+
)
118+
}
119+
120+
val context = getInstrumentation().targetContext
121+
val button = composeTestRule.onNode(hasText(context.getString(sf__account_selector_text)))
122+
123+
button.assertIsDisplayed()
124+
}
125+
126+
@OptIn(ExperimentalMaterial3Api::class)
127+
@Test
128+
fun pickerBottomSheet_publicApiLoginServerPicker_displaysLoginServerPicker() {
129+
val userAccountManager = mockk<UserAccountManager>(relaxed = true)
130+
composeTestRule.setContent {
131+
TestablePickerBottomSheet(
132+
pickerStyle = PickerStyle.LoginServerPicker,
133+
userAccountManager = userAccountManager
134+
)
135+
}
136+
137+
val context = getInstrumentation().targetContext
138+
val button = composeTestRule.onNode(hasText(context.getString(sf__pick_server)))
139+
140+
button.assertIsDisplayed()
141+
}
142+
143+
// endregion
144+
100145
// region Add Connection Tests
101146
@Test
102147
fun saveButton_RespondsTo_InputValidation() {
@@ -238,6 +283,38 @@ class PickerBottomSheetTest {
238283
customListItem.onChildAt(0).assertIsSelected()
239284
}
240285

286+
@OptIn(ExperimentalMaterial3Api::class)
287+
@Test
288+
fun serverList_AddButtonVisibleTrue_DisplaysAddNewConnectionButton() {
289+
composeTestRule.setContent {
290+
PickerBottomSheetTestWrapper(
291+
pickerStyle = PickerStyle.LoginServerPicker,
292+
addButtonVisible = true,
293+
)
294+
}
295+
296+
val context = getInstrumentation().targetContext
297+
val button = composeTestRule.onNode(hasText(context.getString(sf__custom_url_button)))
298+
299+
button.assertIsDisplayed()
300+
}
301+
302+
@OptIn(ExperimentalMaterial3Api::class)
303+
@Test
304+
fun serverList_AddButtonVisibleFalse_HidesAddNewConnectionButton() {
305+
composeTestRule.setContent {
306+
PickerBottomSheetTestWrapper(
307+
pickerStyle = PickerStyle.LoginServerPicker,
308+
addButtonVisible = false,
309+
)
310+
}
311+
312+
val context = getInstrumentation().targetContext
313+
val button = composeTestRule.onNode(hasText(context.getString(sf__custom_url_button)))
314+
315+
button.assertDoesNotExist()
316+
}
317+
241318
@OptIn(ExperimentalMaterial3Api::class)
242319
@Test
243320
fun selectedServer_UpdatesOn_UIServerSelection() {
@@ -369,17 +446,28 @@ internal fun PickerBottomSheetTestWrapper(
369446
initialValue = SheetValue.Expanded,
370447
skipHiddenState = false,
371448
),
372-
list: List<Any> = when(pickerStyle) {
449+
list: List<Any> = when (pickerStyle) {
373450
PickerStyle.LoginServerPicker -> serverList
374451
PickerStyle.UserAccountPicker -> userList
375452
},
376453
selectedListItem: Any = list.first(),
377-
onItemSelected: (Any?, Boolean) -> Unit = { _,_ -> },
454+
addButtonVisible: Boolean = true,
455+
onItemSelected: (Any?, Boolean) -> Unit = { _, _ -> },
378456
getValidServer: ((String) -> String?)? = { _ -> "" },
379-
addNewLoginServer: ((String, String) -> Unit)? = { _,_ -> },
457+
addNewLoginServer: ((String, String) -> Unit)? = { _, _ -> },
380458
removeLoginServer: ((LoginServer) -> Unit)? = { },
381459
addNewAccount: (() -> Unit)? = { },
382460
) {
383-
PickerBottomSheet(pickerStyle, sheetState, list, selectedListItem, onItemSelected, getValidServer,
384-
addNewLoginServer, removeLoginServer, addNewAccount)
385-
}
461+
PickerBottomSheet(
462+
pickerStyle = pickerStyle,
463+
sheetState = sheetState,
464+
list = list,
465+
selectedListItem = selectedListItem,
466+
addButtonVisible = addButtonVisible,
467+
onItemSelected = onItemSelected,
468+
getValidServer = getValidServer,
469+
addNewLoginServer = addNewLoginServer,
470+
removeLoginServer = removeLoginServer,
471+
addNewAccount = addNewAccount,
472+
)
473+
}

0 commit comments

Comments
 (0)