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