/* * Copyright (C) 2017 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.development; import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_ENABLE_OEM_UNLOCK; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.service.oemlock.OemLockManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.development.DeveloperOptionsPreferenceController; public class OemUnlockPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin, OnActivityResultListener { private static final String PREFERENCE_KEY = "oem_unlock_enable"; private static final String TAG = "OemUnlockPreferenceController"; private static final String OEM_UNLOCK_SUPPORTED_KEY = "ro.oem_unlock_supported"; private static final String UNSUPPORTED = "-9999"; private static final String SUPPORTED = "1"; private final OemLockManager mOemLockManager; private final UserManager mUserManager; private final TelephonyManager mTelephonyManager; private final Activity mActivity; private final DevelopmentSettingsDashboardFragment mFragment; private RestrictedSwitchPreference mPreference; public OemUnlockPreferenceController(Context context, Activity activity, DevelopmentSettingsDashboardFragment fragment) { super(context); if (!TextUtils.equals(SystemProperties.get(OEM_UNLOCK_SUPPORTED_KEY, UNSUPPORTED), SUPPORTED)) { mOemLockManager = null; Log.w(TAG, "oem_unlock not supported."); } else { mOemLockManager = (OemLockManager) context.getSystemService(Context.OEM_LOCK_SERVICE); } mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); mActivity = activity; mFragment = fragment; } @Override public boolean isAvailable() { return mOemLockManager != null; } @Override public String getPreferenceKey() { return PREFERENCE_KEY; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean isUnlocked = (Boolean) newValue; if (isUnlocked) { if (!showKeyguardConfirmation(mContext.getResources(), REQUEST_CODE_ENABLE_OEM_UNLOCK)) { confirmEnableOemUnlock(); } } else { mOemLockManager.setOemUnlockAllowedByUser(false); OemLockInfoDialog.show(mFragment); } return true; } @Override public void updateState(Preference preference) { super.updateState(preference); mPreference.setChecked(isOemUnlockedAllowed()); updateOemUnlockSettingDescription(); // Showing mEnableOemUnlock preference as device has persistent data block. mPreference.setDisabledByAdmin(null); mPreference.setEnabled(enableOemUnlockPreference()); if (mPreference.isEnabled()) { // Check restriction, disable mEnableOemUnlock and apply policy transparency. mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET); } } @Override public boolean onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_ENABLE_OEM_UNLOCK) { if (resultCode == Activity.RESULT_OK) { if (mPreference.isChecked()) { confirmEnableOemUnlock(); } else { mOemLockManager.setOemUnlockAllowedByUser(false); } } return true; } return false; } @Override protected void onDeveloperOptionsSwitchEnabled() { handleDeveloperOptionsToggled(); } public void onOemUnlockConfirmed() { mOemLockManager.setOemUnlockAllowedByUser(true); } public void onOemUnlockDismissed() { if (mPreference == null) { return; } updateState(mPreference); } private void handleDeveloperOptionsToggled() { mPreference.setEnabled(enableOemUnlockPreference()); if (mPreference.isEnabled()) { // Check restriction, disable mEnableOemUnlock and apply policy transparency. mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET); } } private void updateOemUnlockSettingDescription() { int oemUnlockSummary = R.string.oem_unlock_enable_summary; if (isBootloaderUnlocked()) { oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_bootloader_unlocked; } else if (isSimLockedDevice()) { oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_sim_locked_device; } else if (!isOemUnlockAllowedByUserAndCarrier()) { // If the device isn't SIM-locked but OEM unlock is disallowed by some party, this // means either some other carrier restriction is in place or the device hasn't been // able to confirm which restrictions (SIM-lock or otherwise) apply. oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_connectivity_or_locked; } mPreference.setSummary(mContext.getResources().getString(oemUnlockSummary)); } /** Returns {@code true} if the device is SIM-locked. Otherwise, returns {@code false}. */ private boolean isSimLockedDevice() { int phoneCount = mTelephonyManager.getPhoneCount(); for (int i = 0; i < phoneCount; i++) { if (mTelephonyManager.getAllowedCarriers(i).size() > 0) { return true; } } return false; } /** * Returns {@code true} if the bootloader has been unlocked. Otherwise, returns {code false}. */ @VisibleForTesting boolean isBootloaderUnlocked() { return mOemLockManager.isDeviceOemUnlocked(); } private boolean enableOemUnlockPreference() { return !isBootloaderUnlocked() && isOemUnlockAllowedByUserAndCarrier(); } @VisibleForTesting boolean showKeyguardConfirmation(Resources resources, int requestCode) { final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(mActivity, mFragment); return builder.setRequestCode(requestCode) .setTitle(resources.getString(R.string.oem_unlock_enable)) .show(); } @VisibleForTesting void confirmEnableOemUnlock() { EnableOemUnlockSettingWarningDialog.show(mFragment); } /** * Returns whether OEM unlock is allowed by the user and carrier. * * This does not take into account any restrictions imposed by the device policy. */ @VisibleForTesting boolean isOemUnlockAllowedByUserAndCarrier() { final UserHandle userHandle = UserHandle.of(UserHandle.myUserId()); return mOemLockManager.isOemUnlockAllowedByCarrier() && !mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, userHandle); } @VisibleForTesting boolean isOemUnlockedAllowed() { return mOemLockManager.isOemUnlockAllowed(); } }