From a0146d3fb73dd4f9f9666472ea79a409d0885648 Mon Sep 17 00:00:00 2001 From: Stanley Wang Date: Fri, 24 Dec 2021 18:09:58 +0800 Subject: [PATCH 1/4] Fix the problem that some items can't be searched in Privacy category. The source of problem is that the controller returns the wrong availability status value and the searchable attribut of the preference is false. Fix: 200249682 Test: manual test and see the search result Change-Id: I2265514c49303f6a0910f1be84b281fccb9abb45 --- res/xml/privacy_dashboard_settings.xml | 4 +--- .../android/settings/privacy/CameraToggleController.java | 2 +- src/com/android/settings/privacy/MicToggleController.java | 2 +- .../privacy/WorkPolicyInfoPreferenceController.java | 4 +--- .../privacy/WorkPolicyInfoPreferenceControllerTest.java | 8 ++++---- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml index cd7d79836e7..7e1d5ced190 100644 --- a/res/xml/privacy_dashboard_settings.xml +++ b/res/xml/privacy_dashboard_settings.xml @@ -49,7 +49,6 @@ android:key="privacy_permissions_usage" android:title="@string/permissions_usage_title" android:summary="@string/permissions_usage_summary" - settings:searchable="false" settings:controller="com.android.settings.privacy.PrivacyHubPreferenceController"> @@ -58,8 +57,7 @@ + android:summary="@string/runtime_permissions_summary_control_app_access"> diff --git a/src/com/android/settings/privacy/CameraToggleController.java b/src/com/android/settings/privacy/CameraToggleController.java index 1a5da76869c..756553c4bf6 100644 --- a/src/com/android/settings/privacy/CameraToggleController.java +++ b/src/com/android/settings/privacy/CameraToggleController.java @@ -40,7 +40,7 @@ public class CameraToggleController extends SensorToggleController { public int getAvailabilityStatus() { return mSensorPrivacyManagerHelper.supportsSensorToggle(getSensor()) && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "camera_toggle_enabled", - true) ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; + true) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privacy/MicToggleController.java b/src/com/android/settings/privacy/MicToggleController.java index 23d41d65cc8..c2389d2439e 100644 --- a/src/com/android/settings/privacy/MicToggleController.java +++ b/src/com/android/settings/privacy/MicToggleController.java @@ -40,7 +40,7 @@ public class MicToggleController extends SensorToggleController { public int getAvailabilityStatus() { return mSensorPrivacyManagerHelper.supportsSensorToggle(getSensor()) && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "mic_toggle_enabled", - true) ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; + true) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java b/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java index 977d1bf79e9..55ba0646af5 100644 --- a/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java +++ b/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java @@ -37,9 +37,7 @@ public class WorkPolicyInfoPreferenceController extends BasePreferenceController @Override public int getAvailabilityStatus() { - return mEnterpriseProvider.hasWorkPolicyInfo() - ? AVAILABLE_UNSEARCHABLE - : UNSUPPORTED_ON_DEVICE; + return mEnterpriseProvider.hasWorkPolicyInfo() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java index 79aec301e17..82444aade07 100644 --- a/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java @@ -16,7 +16,7 @@ package com.android.settings.privacy; -import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; @@ -33,8 +33,8 @@ import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; -import org.junit.runner.RunWith; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -64,12 +64,12 @@ public class WorkPolicyInfoPreferenceControllerTest { } @Test - public void getAvailabilityStatus_haveWorkPolicyInfo_shouldReturnAvailableUnsearchable() { + public void getAvailabilityStatus_haveWorkPolicyInfo_shouldReturnAvailable() { when(mEnterpriseProvider.hasWorkPolicyInfo()).thenReturn(true); WorkPolicyInfoPreferenceController controller = new WorkPolicyInfoPreferenceController(mContext, "test_key"); - assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test From dbe31b8e6b997753937f5e86df1a2367a5bdc66a Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Thu, 30 Sep 2021 09:09:59 +0000 Subject: [PATCH 2/4] eSIM deprecated API test Refactoring Test: build Bug: 159354974 Change-Id: Iedeb90f186ab9f82894e2fecef86d339c8989542 Merged-In: Iedeb90f186ab9f82894e2fecef86d339c8989542 --- .../simstatus/SimStatusDialogController.java | 2 +- .../network/EnableMultiSimSidecar.java | 34 ++-- .../settings/network/SubscriptionUtil.java | 9 +- .../settings/network/UiccSlotUtil.java | 4 +- .../ToggleSubscriptionDialogActivity.java | 5 +- .../sim/receivers/SimSlotChangeHandler.java | 7 +- .../sim/receivers/SimSlotChangeReceiver.java | 11 +- .../SimStatusDialogControllerTest.java | 148 +++++++++++++++--- 8 files changed, 165 insertions(+), 55 deletions(-) diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java index 95f74fa18ce..f2bce78392e 100644 --- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java @@ -631,7 +631,7 @@ public class SimStatusDialogController implements LifecycleObserver { final List infos = mTelephonyManager.getUiccCardsInfo(); for (UiccCardInfo info : infos) { - if (info.getSlotIndex() == pSlotId) { + if (info.getPhysicalSlotIndex() == pSlotId) { if (info.isEuicc()) { shouldHaveEid = true; eid = info.getEid(); diff --git a/src/com/android/settings/network/EnableMultiSimSidecar.java b/src/com/android/settings/network/EnableMultiSimSidecar.java index 4a3243323c2..aefd55f00e8 100644 --- a/src/com/android/settings/network/EnableMultiSimSidecar.java +++ b/src/com/android/settings/network/EnableMultiSimSidecar.java @@ -24,6 +24,7 @@ import android.content.IntentFilter; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; +import android.telephony.UiccPortInfo; import android.telephony.UiccSlotInfo; import android.util.ArraySet; import android.util.Log; @@ -62,23 +63,23 @@ public class EnableMultiSimSidecar extends AsyncTaskSidecar { @Override public void onReceive(Context context, Intent intent) { int readySimsCount = getReadySimsCount(); - int activeSlotsCount = getActiveSlotsCount(); - // If the number of ready SIM count and active slots equal to the number of SIMs + int activePortsCount = getActivePortsCount(); + // If the number of ready SIM count and active ports equal to the number of SIMs // need to be activated, the device is successfully switched to multiple active // SIM mode. - if (readySimsCount == mNumOfActiveSim && activeSlotsCount == mNumOfActiveSim) { + if (readySimsCount == mNumOfActiveSim && activePortsCount == mNumOfActiveSim) { Log.i( TAG, - String.format("%d slots are active and ready.", mNumOfActiveSim)); + String.format("%d ports are active and ready.", mNumOfActiveSim)); mSimCardStateChangedLatch.countDown(); return; } Log.i( TAG, String.format( - "%d slots are active and %d SIMs are ready. Keep waiting until" + "%d ports are active and %d SIMs are ready. Keep waiting until" + " timeout.", - activeSlotsCount, readySimsCount)); + activePortsCount, readySimsCount)); } }; @@ -162,19 +163,22 @@ public class EnableMultiSimSidecar extends AsyncTaskSidecar { return readyCardsCount; } - // Get active slots count from {@code TelephonyManager#getUiccSlotsInfo}. - private int getActiveSlotsCount() { + // Get active port count from {@code TelephonyManager#getUiccSlotsInfo}. + private int getActivePortsCount() { UiccSlotInfo[] slotsInfo = mTelephonyManager.getUiccSlotsInfo(); if (slotsInfo == null) { return 0; } - int activeSlots = 0; + int activePorts = 0; for (UiccSlotInfo slotInfo : slotsInfo) { - if (slotInfo != null && slotInfo.getIsActive()) { - activeSlots++; + for (UiccPortInfo portInfo : slotInfo.getPorts()) { + if (slotInfo != null && portInfo.isActive()) { + activePorts++; + } } + } - return activeSlots; + return activePorts; } /** Returns a list of active removable logical slot ids. */ @@ -185,8 +189,10 @@ public class EnableMultiSimSidecar extends AsyncTaskSidecar { } Set activeRemovableLogicalSlotIds = new ArraySet<>(); for (UiccSlotInfo info : infos) { - if (info != null && info.getIsActive() && info.isRemovable()) { - activeRemovableLogicalSlotIds.add(info.getLogicalSlotIdx()); + for (UiccPortInfo portInfo :info.getPorts()) { + if (info != null && portInfo.isActive() && info.isRemovable()) { + activeRemovableLogicalSlotIds.add(portInfo.getLogicalSlotIndex()); + } } } return activeRemovableLogicalSlotIds; diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index 2d6077868df..c77a294d1c4 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -87,8 +87,8 @@ public class SubscriptionUtil { if (slotInfo == null) { return false; } - return !slotInfo.getIsEuicc() && !slotInfo.getIsActive() && - slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT; + return !slotInfo.getIsEuicc() && !slotInfo.getPorts().stream().findFirst().get() + .isActive() && slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT; } /** @@ -179,7 +179,8 @@ public class SubscriptionUtil { // verify if subscription is inserted within slot for (UiccSlotInfo slotInfo : slotsInfo) { if ((slotInfo != null) && (!slotInfo.getIsEuicc()) - && (slotInfo.getLogicalSlotIdx() == subInfo.getSimSlotIndex())) { + && (slotInfo.getPorts().stream().findFirst().get().getLogicalSlotIndex() + == subInfo.getSimSlotIndex())) { return true; } } @@ -576,7 +577,7 @@ public class SubscriptionUtil { if (!cardInfo.isRemovable() || cardInfo.getCardId() == TelephonyManager.UNSUPPORTED_CARD_ID) { Log.i(TAG, "Skip embedded card or invalid cardId on slot: " - + cardInfo.getSlotIndex()); + + cardInfo.getPhysicalSlotIndex()); continue; } Log.i(TAG, "Target removable cardId :" + cardInfo.getCardId()); diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java index 6113f5a6aef..ccf3f91e868 100644 --- a/src/com/android/settings/network/UiccSlotUtil.java +++ b/src/com/android/settings/network/UiccSlotUtil.java @@ -96,7 +96,7 @@ public class UiccSlotUtil { if (slotId == INVALID_PHYSICAL_SLOT_ID) { for (int i = 0; i < slots.length; i++) { if (slots[i].isRemovable() - && !slots[i].getIsActive() + && !slots[i].getPorts().stream().findFirst().get().isActive() && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) { performSwitchToRemovableSlot(i, context); @@ -107,7 +107,7 @@ public class UiccSlotUtil { if (slotId >= slots.length || !slots[slotId].isRemovable()) { throw new UiccSlotsException("The given slotId is not a removable slot: " + slotId); } - if (!slots[slotId].getIsActive()) { + if (!slots[slotId].getPorts().stream().findFirst().get().isActive()) { performSwitchToRemovableSlot(slotId, context); } } diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java index 0064e6ccfd2..65d8cd7eaed 100644 --- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java +++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java @@ -462,7 +462,8 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc slot -> slot != null && slot.isRemovable() - && slot.getIsActive() + && slot.getPorts().stream().anyMatch( + port -> port.isActive()) && slot.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_PRESENT); if (mIsEsimOperation && isRemovableSimEnabled) { @@ -476,7 +477,7 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc Log.i( TAG, "Removable SIM operation and eSIM profile is enabled. DSDS condition" - + " satisfied."); + + " satisfied."); return true; } Log.i(TAG, "DSDS condition not satisfied."); diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java index fe44389c6b6..e0bc9cd7995 100644 --- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java +++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java @@ -164,14 +164,12 @@ public class SimSlotChangeHandler { private void handleSimInsert(UiccSlotInfo removableSlotInfo) { Log.i(TAG, "Handle SIM inserted."); - if (!isSuwFinished(mContext)) { Log.i(TAG, "Still in SUW. Handle SIM insertion after SUW is finished"); setSuwRemovableSlotAction(mContext, LAST_USER_ACTION_IN_SUW_INSERT); return; } - - if (removableSlotInfo.getIsActive()) { + if (removableSlotInfo.getPorts().stream().findFirst().get().isActive()) { Log.i(TAG, "The removable slot is already active. Do nothing."); return; } @@ -213,7 +211,8 @@ public class SimSlotChangeHandler { List groupedEmbeddedSubscriptions = getGroupedEmbeddedSubscriptions(); - if (groupedEmbeddedSubscriptions.size() == 0 || !removableSlotInfo.getIsActive()) { + if (groupedEmbeddedSubscriptions.size() == 0 || !removableSlotInfo.getPorts().stream() + .findFirst().get().isActive()) { Log.i(TAG, "eSIM slot is active or no subscriptions exist. Do nothing."); return; } diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java b/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java index f2c7c6588a3..f144c6b5ad0 100644 --- a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java +++ b/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; +import android.telephony.UiccPortInfo; import android.telephony.UiccSlotInfo; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; @@ -116,9 +117,11 @@ public class SimSlotChangeReceiver extends BroadcastReceiver { if (cardInfo == null) { continue; } - if (!TextUtils.isEmpty(slotInfo.getCardId()) - || !TextUtils.isEmpty(cardInfo.getIccId())) { - isAllCardStringsEmpty = false; + for (UiccPortInfo portInfo : cardInfo.getPorts()) { + if (!TextUtils.isEmpty(slotInfo.getCardId()) + || !TextUtils.isEmpty(portInfo.getIccId())) { + isAllCardStringsEmpty = false; + } } } @@ -139,7 +142,7 @@ public class SimSlotChangeReceiver extends BroadcastReceiver { return null; } return cardInfos.stream() - .filter(info -> info.getSlotIndex() == physicalSlotIndex) + .filter(info -> info.getPhysicalSlotIndex() == physicalSlotIndex) .findFirst() .orElse(null); } diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java index dfe2bc05f2d..5360dac0ce7 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -54,6 +54,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; +import android.telephony.UiccPortInfo; import android.telephony.euicc.EuiccManager; import androidx.lifecycle.LifecycleOwner; @@ -73,6 +74,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -387,17 +389,34 @@ public class SimStatusDialogControllerTest { false, // isEuicc 0, // cardId null, // eid - "123451234567890", // iccid 0, // slotIndex - true); // isRemovable + true, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo1); UiccCardInfo uiccCardInfo2 = new UiccCardInfo( true, // isEuicc 1, // cardId null, // eid (unavailable) - null, // iccid 1, // slotIndex - false); // isRemovable + false, // isRemovable + false, + Collections.singletonList( + new UiccPortInfo( + null, // iccId + 1, // portIdx + 1, // logicalSlotIdx + true // isActive + ) + ) + ); uiccCardInfos.add(uiccCardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -427,17 +446,31 @@ public class SimStatusDialogControllerTest { true, // isEuicc 0, // cardId TEST_EID_FROM_CARD, // eid - null, // iccid 0, // slotIndex - false); // isRemovable + false, // isRemovable + false, + Collections.singletonList(new UiccPortInfo( + null, // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ))); uiccCardInfos.add(uiccCardInfo1); UiccCardInfo uiccCardInfo2 = new UiccCardInfo( false, // isEuicc 1, // cardId null, // eid - "123451234567890", // iccid 1, // slotIndex - true); // isRemovable + true, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 1, // portIdx + 1, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -468,17 +501,34 @@ public class SimStatusDialogControllerTest { false, // isEuicc 0, // cardId null, // eid - "123451234567890", // iccid 0, // slotIndex - true); // isRemovable + true, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 1, // portIdx + 1, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo1); UiccCardInfo uiccCardInfo2 = new UiccCardInfo( true, // isEuicc 1, // cardId null, // eid (unavailable) - null, // iccid 1, // slotIndex - false); // isRemovable + false, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + null, // iccId + 1, // portIdx + 1, // logicalSlotIdx + true // isActive + ) + ) + ); uiccCardInfos.add(uiccCardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -511,17 +561,33 @@ public class SimStatusDialogControllerTest { false, // isEuicc 0, // cardId null, // eid - "123451234567890", // iccid 0, // slotIndex - true); // isRemovable + true, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo1); UiccCardInfo uiccCardInfo2 = new UiccCardInfo( true, // isEuicc 1, // cardId TEST_EID_FROM_CARD, // eid - null, // iccid 1, // slotIndex - false); // isRemovable + false, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + null, // iccId + 1, // portIdx + 1, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -552,9 +618,17 @@ public class SimStatusDialogControllerTest { true, // isEuicc 0, // cardId TEST_EID_FROM_CARD, // eid (not used) - null, // iccid 0, // slotIndex - false); // isRemovable + false, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + null, // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -583,9 +657,18 @@ public class SimStatusDialogControllerTest { true, // isEuicc (eUICC slot is selected) 0, // cardId TEST_EID_FROM_CARD, // eid (not used) - null, // iccid 0, // slotIndex - false); // isRemovable + false, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + null, // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ) + ) + ); uiccCardInfos.add(uiccCardInfo); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -616,9 +699,18 @@ public class SimStatusDialogControllerTest { false, // isEuicc (eUICC slot is not selected) 0, // cardId null, // eid - "123451234567890", // iccid 0, // slotIndex - true); // isRemovable + true, // isRemovable + false, // isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + + ) + )); uiccCardInfos.add(uiccCardInfo); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); @@ -649,9 +741,17 @@ public class SimStatusDialogControllerTest { false, // isEuicc 0, // cardId null, // eid - "123451234567890", // iccid 0, // slotIndex - true); // isRemovable + true, // isRemovable + false, //isMultipleEnabledProfileSupported + Collections.singletonList( + new UiccPortInfo( + "123451234567890", // iccId + 0, // portIdx + 0, // logicalSlotIdx + true // isActive + ) + )); uiccCardInfos.add(uiccCardInfo); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos); From 4fdf8be369b5c591e5719b433c4f75e3aff10112 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Mon, 22 Nov 2021 07:50:43 +0800 Subject: [PATCH 3/4] [MEP] eSIM deprecated API Refactoring The telephony APIs were changed, the Settings needs the refactoring. Bug: 206801604 Test: build pass. atest QuerySimSlotIndexTest (PASS) atest SelectableSubscriptionsTest (PASS) Change-Id: Ic3244333b7d3750b88ecb3dbc5d7036da50b9d4d Merged-In: Ic3244333b7d3750b88ecb3dbc5d7036da50b9d4d --- .../network/helper/QuerySimSlotIndex.java | 36 +- .../network/helper/QuerySimSlotIndexTest.java | 322 ++++++++++++++++++ 2 files changed, 342 insertions(+), 16 deletions(-) create mode 100644 tests/unit/src/com/android/settings/network/helper/QuerySimSlotIndexTest.java diff --git a/src/com/android/settings/network/helper/QuerySimSlotIndex.java b/src/com/android/settings/network/helper/QuerySimSlotIndex.java index b70a148d2e4..ee53f94966f 100644 --- a/src/com/android/settings/network/helper/QuerySimSlotIndex.java +++ b/src/com/android/settings/network/helper/QuerySimSlotIndex.java @@ -17,14 +17,16 @@ package com.android.settings.network.helper; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.UiccPortInfo; import android.telephony.UiccSlotInfo; import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicIntegerArray; +import java.util.stream.IntStream; /** - * This is a Callable class which query slot index within device + * This is a Callable class which query logical slot index within device */ public class QuerySimSlotIndex implements Callable { private static final String TAG = "QuerySimSlotIndex"; @@ -58,30 +60,32 @@ public class QuerySimSlotIndex implements Callable { return new AtomicIntegerArray(0); } int slotIndexFilter = mOnlySlotWithSim ? 0 : SubscriptionManager.INVALID_SIM_SLOT_INDEX; + return new AtomicIntegerArray(Arrays.stream(slotInfo) - .filter(slot -> filterSlot(slot)) - .mapToInt(slot -> mapToSlotIndex(slot)) + .flatMapToInt(slot -> mapToLogicalSlotIndex(slot)) .filter(slotIndex -> (slotIndex >= slotIndexFilter)) .toArray()); } - protected boolean filterSlot(UiccSlotInfo slotInfo) { + protected IntStream mapToLogicalSlotIndex(UiccSlotInfo slotInfo) { + if (slotInfo == null) { + return IntStream.of(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + } + if (slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_ABSENT) { + return IntStream.of(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + } + return slotInfo.getPorts().stream() + .filter(port -> filterPort(port)) + .mapToInt(port -> port.getLogicalSlotIndex()); + } + + protected boolean filterPort(UiccPortInfo uiccPortInfo) { if (mDisabledSlotsIncluded) { return true; } - if (slotInfo == null) { + if (uiccPortInfo == null) { return false; } - return slotInfo.getIsActive(); - } - - protected int mapToSlotIndex(UiccSlotInfo slotInfo) { - if (slotInfo == null) { - return SubscriptionManager.INVALID_SIM_SLOT_INDEX; - } - if (slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_ABSENT) { - return SubscriptionManager.INVALID_SIM_SLOT_INDEX; - } - return slotInfo.getLogicalSlotIdx(); + return uiccPortInfo.isActive(); } } \ No newline at end of file diff --git a/tests/unit/src/com/android/settings/network/helper/QuerySimSlotIndexTest.java b/tests/unit/src/com/android/settings/network/helper/QuerySimSlotIndexTest.java new file mode 100644 index 00000000000..36532a12bdc --- /dev/null +++ b/tests/unit/src/com/android/settings/network/helper/QuerySimSlotIndexTest.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.network.helper; + +import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.telephony.TelephonyManager; +import android.telephony.UiccPortInfo; +import android.telephony.UiccSlotInfo; +import android.util.Log; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settingslib.utils.ThreadUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicIntegerArray; + +@RunWith(AndroidJUnit4.class) +public class QuerySimSlotIndexTest { + private static final String TAG = "QSSI_Test"; + + @Mock + private TelephonyManager mTelephonyManager; + + Future mActiveSimSlotIndex; + Future mAllSimSlotIndex; + + @Before + public void setUp() { + // query in background thread + mAllSimSlotIndex = ThreadUtils.postOnBackgroundThread( + new QuerySimSlotIndex(mTelephonyManager, true, true)); + // query in background thread + mActiveSimSlotIndex = ThreadUtils.postOnBackgroundThread( + new QuerySimSlotIndex(mTelephonyManager, false, true)); + } + + @Test + public void allSimSlotIndexCall_nullInput_getNoneNullEmptyList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(null); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(0); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_oneSimAndActivePsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSim_ActivePsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(0); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_oneSimAndActiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSim_ActiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_twoSimsAndActivePsimActiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActivePsimActiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_twoSimsAndtwoActiveEsims_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_twoActiveEsims()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_twoSimsAndActivePsimInactiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActivePsimInactiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void allSimSlotIndexCall_twoSimsAndActiveEsimInactivePsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActiveEsimInactivePsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_nullInput_getNoneNullEmptyList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(null); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(0); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_oneSimAndActivePsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSim_ActivePsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(0); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_oneSimAndActiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSim_ActiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_twoSimsAndActivePsimActiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActivePsimActiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_twoSimsAndtwoActiveEsims_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_twoActiveEsims()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0)).isEqualTo(0); + assertThat(result.get(1)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_twoSimsAndActivePsimInactiveEsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActivePsimInactiveEsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(0); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + @Test + public void activeSimSlotIndexCall_twoSimsAndActiveEsimInactivePsim_getList() { + try { + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(twoSims_ActiveEsimInactivePsim()); + List result = SelectableSubscriptions.atomicToList(mActiveSimSlotIndex.get()); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0)).isEqualTo(1); + } catch (Exception exception) { + Log.w(TAG, "Fail to request subIdList", exception); + } + } + + private UiccSlotInfo[] oneSim_ActivePsim() { + return new UiccSlotInfo[]{createUiccSlotInfo(false, 0, true)}; + } + + private UiccSlotInfo[] oneSim_ActiveEsim() { + return new UiccSlotInfo[]{createUiccSlotInfo(true, 1, true)}; + } + + private UiccSlotInfo[] twoSims_ActivePsimActiveEsim() { + return new UiccSlotInfo[]{ + createUiccSlotInfo(false, 0, true), + createUiccSlotInfo(true, 1, true)}; + } + + private UiccSlotInfo[] twoSims_twoActiveEsims() { + return new UiccSlotInfo[]{ + createUiccSlotInfoForTwoEsim(true, true)}; + } + + private UiccSlotInfo[] twoSims_ActivePsimInactiveEsim() { + return new UiccSlotInfo[]{ + createUiccSlotInfo(false, 0, true), + createUiccSlotInfo(true, 1, false)}; + } + + private UiccSlotInfo[] twoSims_ActiveEsimInactivePsim() { + return new UiccSlotInfo[]{ + createUiccSlotInfo(false, 0, false), + createUiccSlotInfo(true, 1, true)}; + } + + //ToDo: add more cases. + /* + private List threeSims_ActivePsimTwoinactiveEsim(){ + } + private List threeSims_twoActiveEsimsInactivePsim(){ + } + private List threeSims_ActiveEsimInactivePsimInactiveEsim(){ + } + private List threeSims_ActivePsimActiveEsimInactiveEsim(){ + } + */ + + private UiccSlotInfo createUiccSlotInfo(boolean isEuicc, int logicalSlotIdx, + boolean isActive) { + return new UiccSlotInfo( + isEuicc, /* isEuicc */ + "123", /* cardId */ + CARD_STATE_INFO_PRESENT, /* cardStateInfo */ + true, /* isExtendApduSupported */ + true, /* isRemovable */ + Collections.singletonList( + new UiccPortInfo("" /* iccId */, 0 /* portIdx */, + logicalSlotIdx /* logicalSlotIdx */, isActive /* isActive */)) + ); + } + + private UiccSlotInfo createUiccSlotInfoForTwoEsim(boolean isActiveEsim1, + boolean isActiveEsim2) { + return new UiccSlotInfo( + true, /* isEuicc */ + "123", /* cardId */ + CARD_STATE_INFO_PRESENT, /* cardStateInfo */ + true, /* isExtendApduSupported */ + true, /* isRemovable */ + Arrays.asList( + new UiccPortInfo("" /* iccId */, 0 /* portIdx */, + 0 /* logicalSlotIdx */, isActiveEsim1 /* isActive */), + new UiccPortInfo("" /* iccId */, 1 /* portIdx */, + 1 /* logicalSlotIdx */, isActiveEsim2 /* isActive */)) + ); + } +} From 07dd833a6a8fcdbec84e8ca12fe63f2a3a0954f0 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Mon, 3 Jan 2022 18:25:04 +0800 Subject: [PATCH 4/4] FRP bypass defense in the settings app Over the last few years, there have been a number of Factory Reset Protection bypass bugs in the SUW flow. It's unlikely to defense all points from individual apps. Therefore, we decide to block some critical pages when user doesn't complete the SUW flow. Test: Can't open the certain pages in the suw flow. Fix: 200746457 Bug: 202975040 Fix: 213091525 Fix: 213090835 Fix: 201561699 Fix: 213090827 Fix: 213090875 Change-Id: Ia18f367109df5af7da0a5acad7702898a459d32e --- .../settings/SettingsPreferenceFragment.java | 22 +++++- .../accounts/AccountDashboardFragment.java | 5 ++ .../appinfo/AppInfoDashboardFragment.java | 5 ++ .../DevelopmentSettingsDashboardFragment.java | 5 ++ .../system/ResetDashboardFragment.java | 5 ++ .../SettingsPreferenceFragmentTest.java | 74 +++++++++++++++++++ .../AccountDashboardFragmentTest.java | 5 ++ .../appinfo/AppInfoDashboardFragmentTest.java | 5 ++ ...elopmentSettingsDashboardFragmentTest.java | 5 ++ .../system/ResetDashboardFragmentTest.java | 40 ++++++++++ 10 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java index 1d6a48d0465..d3e1c49c06f 100644 --- a/src/com/android/settings/SettingsPreferenceFragment.java +++ b/src/com/android/settings/SettingsPreferenceFragment.java @@ -54,6 +54,7 @@ import com.android.settingslib.search.Indexable; import com.android.settingslib.widget.LayoutPreference; import com.google.android.material.appbar.AppBarLayout; +import com.google.android.setupcompat.util.WizardManagerHelper; import java.util.UUID; @@ -63,7 +64,7 @@ import java.util.UUID; public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment implements DialogCreatable, HelpResourceProvider, Indexable { - private static final String TAG = "SettingsPreference"; + private static final String TAG = "SettingsPreferenceFragment"; private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; @@ -121,6 +122,15 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF public HighlightablePreferenceGroupAdapter mAdapter; private boolean mPreferenceHighlighted = false; + @Override + public void onAttach(Context context) { + if (shouldSkipForInitialSUW() && !WizardManagerHelper.isDeviceProvisioned(getContext())) { + Log.w(TAG, "Skip " + getClass().getSimpleName() + " before SUW completed."); + finish(); + } + super.onAttach(context); + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -267,6 +277,16 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF || (mAdapter.getPreferenceAdapterPosition(preference) != RecyclerView.NO_POSITION)); } + /** + * Whether UI should be skipped in the initial SUW flow. + * + * @return {@code true} when UI should be skipped in the initial SUW flow. + * {@code false} when UI should not be skipped in the initial SUW flow. + */ + protected boolean shouldSkipForInitialSUW() { + return false; + } + protected void onDataSetChanged() { highlightPreferenceIfNeeded(); updateEmptyView(); diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java index f57b124919d..a2b6182a715 100644 --- a/src/com/android/settings/accounts/AccountDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountDashboardFragment.java @@ -84,6 +84,11 @@ public class AccountDashboardFragment extends DashboardFragment { return controllers; } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + static void buildAutofillPreferenceControllers( Context context, List controllers) { controllers.add(new DefaultAutofillPreferenceController(context)); diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 159eec6ad69..243dc564be8 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -507,6 +507,11 @@ public class AppInfoDashboardFragment extends DashboardFragment return true; } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { stopListeningToPackageRemove(); // Create new intent to launch Uninstaller activity diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index c02ae42b376..946e0d744a5 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -215,6 +215,11 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + /** * Long-pressing a developer options quick settings tile will by default (see * QS_TILE_PREFERENCES in the manifest) take you to the developer options page. diff --git a/src/com/android/settings/system/ResetDashboardFragment.java b/src/com/android/settings/system/ResetDashboardFragment.java index e5fc8f14fd6..c352b9292b1 100644 --- a/src/com/android/settings/system/ResetDashboardFragment.java +++ b/src/com/android/settings/system/ResetDashboardFragment.java @@ -64,6 +64,11 @@ public class ResetDashboardFragment extends DashboardFragment { use(EraseEuiccDataController.class).setFragment(this); } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + private static List buildPreferenceControllers(Context context, Lifecycle lifecycle) { final List controllers = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java index cb53f69751c..648931134c5 100644 --- a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java @@ -23,11 +23,13 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.Bundle; +import android.provider.Settings; import android.view.View; import android.widget.FrameLayout; @@ -41,6 +43,7 @@ import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.widget.WorkOnlyCategory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,7 +67,9 @@ public class SettingsPreferenceFragmentTest { private PreferenceScreen mPreferenceScreen; private Context mContext; private TestFragment mFragment; + private TestFragment2 mFragment2; private View mEmptyView; + private int mInitDeviceProvisionedValue; @Before public void setUp() { @@ -72,13 +77,24 @@ public class SettingsPreferenceFragmentTest { FakeFeatureFactory.setupForTest(); mContext = RuntimeEnvironment.application; mFragment = spy(new TestFragment()); + mFragment2 = spy(new TestFragment2()); doReturn(mActivity).when(mFragment).getActivity(); when(mFragment.getContext()).thenReturn(mContext); + when(mFragment2.getContext()).thenReturn(mContext); mEmptyView = new View(mContext); ReflectionHelpers.setField(mFragment, "mEmptyView", mEmptyView); doReturn(ITEM_COUNT).when(mPreferenceScreen).getPreferenceCount(); + + mInitDeviceProvisionedValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + } + + @After + public void tearDown() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, mInitDeviceProvisionedValue); } @Test @@ -210,8 +226,66 @@ public class SettingsPreferenceFragmentTest { assertThat(mFragment.mPinnedHeaderFrameLayout.getVisibility()).isEqualTo(View.INVISIBLE); } + @Test + public void onAttach_shouldNotSkipForSUWAndDeviceIsProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + + mFragment.onAttach(mContext); + + verify(mFragment, never()).finish(); + } + + @Test + public void onAttach_shouldNotSkipForSUWAndDeviceIsNotProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + + mFragment.onAttach(mContext); + + verify(mFragment, never()).finish(); + } + + @Test + public void onAttach_shouldSkipForSUWAndDeviceIsDeviceProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + + mFragment2.onAttach(mContext); + + verify(mFragment2, never()).finish(); + } + + @Test + public void onAttach_shouldSkipForSUWAndDeviceProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + + mFragment2.onAttach(mContext); + + verify(mFragment2, times(1)).finish(); + } + public static class TestFragment extends SettingsPreferenceFragment { + @Override + protected boolean shouldSkipForInitialSUW() { + return false; + } + + @Override + public int getMetricsCategory() { + return 0; + } + } + + public static class TestFragment2 extends SettingsPreferenceFragment { + + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + @Override public int getMetricsCategory() { return 0; diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java index fe57090827d..921587e837f 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java @@ -114,4 +114,9 @@ public class AccountDashboardFragmentTest { assertThat(indexRaws).isNotEmpty(); } + + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java index 95d765935a9..2cec3d113c6 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java @@ -384,6 +384,11 @@ public final class AppInfoDashboardFragmentTest { .isTrue(); } + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } + @Implements(AppUtils.class) public static class ShadowAppUtils { diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java index 2d4082b9c75..bd4ee56a9c6 100644 --- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java @@ -278,6 +278,11 @@ public class DevelopmentSettingsDashboardFragmentTest { verify(controller).onDisableLogPersistDialogRejected(); } + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mDashboard.shouldSkipForInitialSUW()).isTrue(); + } + @Implements(EnableDevelopmentSettingWarningDialog.class) public static class ShadowEnableDevelopmentSettingWarningDialog { diff --git a/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java new file mode 100644 index 00000000000..c1d47887a70 --- /dev/null +++ b/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.system; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ResetDashboardFragmentTest { + + private ResetDashboardFragment mFragment; + + @Before + public void setup() { + mFragment = new ResetDashboardFragment(); + } + + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } +}