1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.development; 18 19 import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_ENABLE_OEM_UNLOCK; 20 21 import android.app.Activity; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.pm.PackageManager; 25 import android.content.res.Resources; 26 import android.os.SystemProperties; 27 import android.os.UserHandle; 28 import android.os.UserManager; 29 import android.service.oemlock.OemLockManager; 30 import android.telephony.TelephonyManager; 31 import android.text.TextUtils; 32 import android.util.Log; 33 34 import androidx.annotation.Nullable; 35 import androidx.annotation.VisibleForTesting; 36 import androidx.preference.Preference; 37 import androidx.preference.PreferenceScreen; 38 39 import com.android.settings.R; 40 import com.android.settings.core.PreferenceControllerMixin; 41 import com.android.settings.password.ChooseLockSettingsHelper; 42 import com.android.settingslib.RestrictedSwitchPreference; 43 import com.android.settingslib.development.DeveloperOptionsPreferenceController; 44 45 public class OemUnlockPreferenceController extends DeveloperOptionsPreferenceController implements 46 Preference.OnPreferenceChangeListener, PreferenceControllerMixin, OnActivityResultListener { 47 48 private static final String PREFERENCE_KEY = "oem_unlock_enable"; 49 private static final String TAG = "OemUnlockPreferenceController"; 50 private static final String OEM_UNLOCK_SUPPORTED_KEY = "ro.oem_unlock_supported"; 51 private static final String UNSUPPORTED = "-9999"; 52 private static final String SUPPORTED = "1"; 53 54 private final OemLockManager mOemLockManager; 55 private final UserManager mUserManager; 56 private final TelephonyManager mTelephonyManager; 57 private final Activity mActivity; 58 @Nullable private final DevelopmentSettingsDashboardFragment mFragment; 59 private RestrictedSwitchPreference mPreference; 60 OemUnlockPreferenceController(Context context, Activity activity, @Nullable DevelopmentSettingsDashboardFragment fragment)61 public OemUnlockPreferenceController(Context context, Activity activity, 62 @Nullable DevelopmentSettingsDashboardFragment fragment) { 63 super(context); 64 65 if (!TextUtils.equals(SystemProperties.get(OEM_UNLOCK_SUPPORTED_KEY, UNSUPPORTED), 66 SUPPORTED)) { 67 mOemLockManager = null; 68 Log.w(TAG, "oem_unlock not supported."); 69 } else { 70 mOemLockManager = (OemLockManager) context.getSystemService(Context.OEM_LOCK_SERVICE); 71 } 72 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 73 mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 74 mActivity = activity; 75 mFragment = fragment; 76 } 77 78 @Override isAvailable()79 public boolean isAvailable() { 80 return mOemLockManager != null; 81 } 82 83 @Override getPreferenceKey()84 public String getPreferenceKey() { 85 return PREFERENCE_KEY; 86 } 87 88 @Override displayPreference(PreferenceScreen screen)89 public void displayPreference(PreferenceScreen screen) { 90 super.displayPreference(screen); 91 92 mPreference = screen.findPreference(getPreferenceKey()); 93 } 94 95 @Override onPreferenceChange(Preference preference, Object newValue)96 public boolean onPreferenceChange(Preference preference, Object newValue) { 97 boolean isUnlocked = (Boolean) newValue; 98 if (isUnlocked) { 99 if (!showKeyguardConfirmation(mContext.getResources(), 100 REQUEST_CODE_ENABLE_OEM_UNLOCK)) { 101 confirmEnableOemUnlock(); 102 } 103 } else { 104 mOemLockManager.setOemUnlockAllowedByUser(false); 105 OemLockInfoDialog.show(mFragment); 106 } 107 return true; 108 } 109 110 @Override updateState(Preference preference)111 public void updateState(Preference preference) { 112 super.updateState(preference); 113 mPreference.setChecked(isOemUnlockedAllowed()); 114 updateOemUnlockSettingDescription(); 115 // Showing mEnableOemUnlock preference as device has persistent data block. 116 mPreference.setDisabledByAdmin(null); 117 mPreference.setEnabled(enableOemUnlockPreference()); 118 if (mPreference.isEnabled()) { 119 // Check restriction, disable mEnableOemUnlock and apply policy transparency. 120 mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET); 121 } 122 } 123 124 @Override onActivityResult(int requestCode, int resultCode, Intent data)125 public boolean onActivityResult(int requestCode, int resultCode, Intent data) { 126 if (requestCode == REQUEST_CODE_ENABLE_OEM_UNLOCK) { 127 if (resultCode == Activity.RESULT_OK) { 128 if (mPreference.isChecked()) { 129 confirmEnableOemUnlock(); 130 } else { 131 mOemLockManager.setOemUnlockAllowedByUser(false); 132 } 133 } 134 return true; 135 } 136 return false; 137 } 138 139 @Override onDeveloperOptionsSwitchEnabled()140 protected void onDeveloperOptionsSwitchEnabled() { 141 handleDeveloperOptionsToggled(); 142 } 143 onOemUnlockConfirmed()144 public void onOemUnlockConfirmed() { 145 mOemLockManager.setOemUnlockAllowedByUser(true); 146 } 147 onOemUnlockDismissed()148 public void onOemUnlockDismissed() { 149 if (mPreference == null) { 150 return; 151 } 152 updateState(mPreference); 153 } 154 handleDeveloperOptionsToggled()155 private void handleDeveloperOptionsToggled() { 156 mPreference.setEnabled(enableOemUnlockPreference()); 157 if (mPreference.isEnabled()) { 158 // Check restriction, disable mEnableOemUnlock and apply policy transparency. 159 mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET); 160 } 161 } 162 updateOemUnlockSettingDescription()163 private void updateOemUnlockSettingDescription() { 164 int oemUnlockSummary = com.android.settingslib.R.string.oem_unlock_enable_summary; 165 if (isBootloaderUnlocked()) { 166 oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_bootloader_unlocked; 167 } else if (isSimLockedDevice()) { 168 oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_sim_locked_device; 169 } else if (!isOemUnlockAllowedByUserAndCarrier()) { 170 // If the device isn't SIM-locked but OEM unlock is disallowed by some party, this 171 // means either some other carrier restriction is in place or the device hasn't been 172 // able to confirm which restrictions (SIM-lock or otherwise) apply. 173 oemUnlockSummary = 174 R.string.oem_unlock_enable_disabled_summary_connectivity_or_locked; 175 } 176 mPreference.setSummary(mContext.getResources().getString(oemUnlockSummary)); 177 } 178 179 /** Returns {@code true} if the device is SIM-locked. Otherwise, returns {@code false}. */ isSimLockedDevice()180 private boolean isSimLockedDevice() { 181 if (!mContext.getPackageManager().hasSystemFeature( 182 PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)) { 183 Log.w(TAG, 184 "getAllowedCarriers is unsupported without " 185 + "PackageManager#FEATURE_TELEPHONY_CARRIERLOCK"); 186 return false; 187 } 188 int phoneCount = mTelephonyManager.getPhoneCount(); 189 for (int i = 0; i < phoneCount; i++) { 190 if (mTelephonyManager.getAllowedCarriers(i).size() > 0) { 191 return true; 192 } 193 } 194 return false; 195 } 196 197 /** 198 * Returns {@code true} if the bootloader has been unlocked. Otherwise, returns {code false}. 199 */ 200 @VisibleForTesting isBootloaderUnlocked()201 boolean isBootloaderUnlocked() { 202 return mOemLockManager.isDeviceOemUnlocked(); 203 } 204 enableOemUnlockPreference()205 private boolean enableOemUnlockPreference() { 206 return !isBootloaderUnlocked() && isOemUnlockAllowedByUserAndCarrier(); 207 } 208 209 210 @VisibleForTesting showKeyguardConfirmation(Resources resources, int requestCode)211 boolean showKeyguardConfirmation(Resources resources, int requestCode) { 212 final ChooseLockSettingsHelper.Builder builder = 213 new ChooseLockSettingsHelper.Builder(mActivity, mFragment); 214 return builder.setRequestCode(requestCode) 215 .setTitle(resources.getString(com.android.settingslib.R.string.oem_unlock_enable)) 216 .show(); 217 } 218 219 @VisibleForTesting confirmEnableOemUnlock()220 void confirmEnableOemUnlock() { 221 EnableOemUnlockSettingWarningDialog.show(mFragment); 222 } 223 224 /** 225 * Returns whether OEM unlock is allowed by the user and carrier. 226 * 227 * This does not take into account any restrictions imposed by the device policy. 228 */ 229 @VisibleForTesting isOemUnlockAllowedByUserAndCarrier()230 boolean isOemUnlockAllowedByUserAndCarrier() { 231 final UserHandle userHandle = UserHandle.of(UserHandle.myUserId()); 232 return mOemLockManager.isOemUnlockAllowedByCarrier() 233 && !mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, 234 userHandle); 235 } 236 237 @VisibleForTesting isOemUnlockedAllowed()238 boolean isOemUnlockedAllowed() { 239 return mOemLockManager.isOemUnlockAllowed(); 240 } 241 242 } 243