Authenticated confirmation before deletion of eSim

adds an authentication confirmation before deleting an eSim
this feature is turned on/off in the security page

Bug: 138861284
Test: mp settingsg
Change-Id: I32e0e3bff2091ec1097b3c37fa066d966e3373df
This commit is contained in:
Lee Chou
2020-01-21 18:02:30 +08:00
parent c799e9236b
commit 5a65e2d5dd
9 changed files with 147 additions and 22 deletions

View File

@@ -206,6 +206,9 @@
com.android.settings.intelligence
</string>
<!-- Whether the confirmation for sim deletion is defaulted to be on or off-->
<bool name="config_sim_deletion_confirmation_default_on">false</bool>
<!-- Package Installer package name -->
<string name="config_package_installer_package_name" translatable="false">
com.android.packageinstaller

View File

@@ -9013,6 +9013,11 @@
<!-- [CHAR LIMIT=60] Unlock setting for screen pinning -->
<string name="screen_pinning_unlock_none">Lock device when unpinning</string>
<!-- [CHAR LIMIT=60] turn eSim deletion confirmation on/off -->
<string name="confirm_sim_deletion_title">Confirm SIM deletion</string>
<!-- [CHAR LIMIT=NONE] eSim deletion confirmation description -->
<string name="confirm_sim_deletion_description">Verify it\u0027s you before erasing a downloaded SIM</string>
<!-- Opening string on the dialog that prompts the user to confirm that they really want to delete their existing work profile. The administration app icon and name appear after the final colon. [CHAR LIMIT=NONE] -->
<string name="opening_paragraph_delete_profile_unknown_company">This work profile is managed by:</string>
<!-- Summary for work profile accounts group. [CHAR LIMIT=25] -->

View File

@@ -147,4 +147,11 @@
android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.security.ScreenPinningSettings" />
<SwitchPreference
android:order="90"
android:key="confirm_sim_deletion"
android:title="@string/confirm_sim_deletion_title"
android:summary="@string/confirm_sim_deletion_description"
settings:controller="com.android.settings.security.ConfirmSimDeletionPreferenceController"/>
</PreferenceScreen>

View File

@@ -18,15 +18,18 @@ package com.android.settings.network.telephony;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.euicc.EuiccManager;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.security.ConfirmSimDeletionPreferenceController;
import com.android.settings.wifi.dpp.WifiDppUtils;
/** This controls a preference allowing the user to delete the profile for an eSIM. */
public class DeleteSimProfilePreferenceController extends BasePreferenceController {
@@ -34,16 +37,19 @@ public class DeleteSimProfilePreferenceController extends BasePreferenceControll
private SubscriptionInfo mSubscriptionInfo;
private Fragment mParentFragment;
private int mRequestCode;
private boolean mConfirmationDefaultOn;
public DeleteSimProfilePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mConfirmationDefaultOn =
context.getResources()
.getBoolean(R.bool.config_sim_deletion_confirmation_default_on);
}
public void init(int subscriptionId, Fragment parentFragment, int requestCode) {
mParentFragment = parentFragment;
for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(
mContext)) {
for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
if (info.getSubscriptionId() == subscriptionId && info.isEmbedded()) {
mSubscriptionInfo = info;
break;
@@ -53,16 +59,27 @@ public class DeleteSimProfilePreferenceController extends BasePreferenceControll
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final Preference pref = screen.findPreference(getPreferenceKey());
pref.setOnPreferenceClickListener(p -> {
final Intent intent = new Intent(EuiccManager.ACTION_DELETE_SUBSCRIPTION_PRIVILEGED);
intent.putExtra(EuiccManager.EXTRA_SUBSCRIPTION_ID,
mSubscriptionInfo.getSubscriptionId());
mParentFragment.startActivityForResult(intent, mRequestCode);
public boolean handlePreferenceTreeClick(Preference preference) {
boolean confirmDeletion =
Settings.Global.getInt(
mContext.getContentResolver(),
ConfirmSimDeletionPreferenceController.KEY_CONFIRM_SIM_DELETION,
mConfirmationDefaultOn ? 1 : 0)
== 1;
if (confirmDeletion) {
WifiDppUtils.showLockScreen(mContext, () -> deleteSim());
} else {
deleteSim();
}
return true;
});
}
private void deleteSim() {
final Intent intent = new Intent(EuiccManager.ACTION_DELETE_SUBSCRIPTION_PRIVILEGED);
intent.putExtra(EuiccManager.EXTRA_SUBSCRIPTION_ID, mSubscriptionInfo.getSubscriptionId());
mParentFragment.startActivityForResult(intent, mRequestCode);
// result handled in MobileNetworkSettings
}
@Override
@@ -73,5 +90,4 @@ public class DeleteSimProfilePreferenceController extends BasePreferenceControll
return CONDITIONALLY_UNAVAILABLE;
}
}
}

View File

@@ -274,10 +274,12 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
break;
case REQUEST_CODE_DELETE_SUBSCRIPTION:
if (resultCode != Activity.RESULT_CANCELED) {
final Activity activity = getActivity();
if (activity != null && !activity.isFinishing()) {
activity.finish();
}
}
break;
default:

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2020 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.security;
import android.app.KeyguardManager;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.network.telephony.MobileNetworkUtils;
/** Enable/disable user confirmation before deleting an eSim */
public class ConfirmSimDeletionPreferenceController extends TogglePreferenceController {
public static final String KEY_CONFIRM_SIM_DELETION = "confirm_sim_deletion";
private boolean mConfirmationDefaultOn;
public ConfirmSimDeletionPreferenceController(Context context, String key) {
super(context, key);
mConfirmationDefaultOn =
context.getResources()
.getBoolean(R.bool.config_sim_deletion_confirmation_default_on);
}
@Override
public int getAvailabilityStatus() {
// hide if eSim is not supported on the device
return MobileNetworkUtils.showEuiccSettings(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
private boolean getGlobalState() {
return Settings.Global.getInt(
mContext.getContentResolver(),
KEY_CONFIRM_SIM_DELETION,
mConfirmationDefaultOn ? 1 : 0)
== 1;
}
@Override
public boolean isChecked() {
return getGlobalState();
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Global.putInt(
mContext.getContentResolver(), KEY_CONFIRM_SIM_DELETION, isChecked ? 1 : 0);
return true;
}
@Override
public void updateState(Preference preference) {
final KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
if (!keyguardManager.isKeyguardSecure()) {
preference.setEnabled(false);
if (preference instanceof TwoStatePreference) {
((TwoStatePreference) preference).setChecked(false);
}
preference.setSummary(R.string.disabled_because_no_backup_security);
} else {
preference.setEnabled(true);
if (preference instanceof TwoStatePreference) {
((TwoStatePreference) preference).setChecked(getGlobalState());
}
preference.setSummary(R.string.confirm_sim_deletion_description);
}
}
}

View File

@@ -20,7 +20,6 @@ import static com.android.settings.security.EncryptionStatusPreferenceController
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController;

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
@@ -34,6 +35,7 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.security.ConfirmSimDeletionPreferenceController;
import org.junit.After;
import org.junit.Before;
@@ -118,7 +120,11 @@ public class DeleteSimProfilePreferenceControllerTest {
public void onPreferenceClick_startsIntent() {
mController.init(SUB_ID, mFragment, REQUEST_CODE);
mController.displayPreference(mScreen);
mPreference.performClick();
// turn off confirmation before click
Settings.Global.putInt(mContext.getContentResolver(),
ConfirmSimDeletionPreferenceController.KEY_CONFIRM_SIM_DELETION, 0);
mController.handlePreferenceTreeClick(mPreference);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mFragment).startActivityForResult(intentCaptor.capture(), eq(REQUEST_CODE));

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.NetworkPolicyManager;
@@ -111,12 +112,12 @@ public class MobileNetworkSettingsTest {
public void onActivityResult_noActivity_noCrash() {
when(mFragment.getActivity()).thenReturn(null);
// this should not crash
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, 0, null);
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, Activity.RESULT_OK, null);
}
@Test
public void onActivityResult_deleteSubscription_activityFinishes() {
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, 0, null);
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, Activity.RESULT_OK, null);
verify(mActivity).finish();
}