Introduce OemUnlockPreferenceController

- Create new OemUnlockPreferenceController
 - Add new onActivityResult method in DeveloperOptionsController
 - Create controller inside the DashboardFragment
 - Port logic from DevelopmentSettings into the controller

Bug: 34203528
Test: make RunSettingsRoboTests -j40
Change-Id: I0b1387b9547e7c9f2a1a0963421d0ebea55d9ff4
This commit is contained in:
jeffreyhuang
2017-09-15 16:01:34 -07:00
parent 211ea46815
commit 223484ea3c
8 changed files with 642 additions and 6 deletions

View File

@@ -17,6 +17,7 @@
package com.android.settings.development;
import android.content.Context;
import android.content.Intent;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -34,13 +35,29 @@ public abstract class DeveloperOptionsPreferenceController extends
super(context);
}
/**
* Called when an activity returns to the DeveloperSettingsDashboardFragment.
*
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
* @param resultCode The integer result code returned by the child activity
* through its setResult().
* @param data An Intent, which can return result data to the caller
* (various data can be attached to Intent "extras").
* @return true if the controller handled the activity result
*/
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
return false;
}
/**
* Called when developer options is enabled
*/
public abstract void onDeveloperOptionsEnabled();
/**
*Called when developer options is disabled
* Called when developer options is disabled
*/
public abstract void onDeveloperOptionsDisabled();
}

View File

@@ -0,0 +1,24 @@
/*
* 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;
/**
* Interface for storing Activity request codes in development options
*/
public interface DevelopmentOptionsActivityRequestCodes {
int REQUEST_CODE_ENABLE_OEM_UNLOCK = 0;
}

View File

@@ -16,10 +16,13 @@
package com.android.settings.development;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.widget.Switch;
@@ -40,7 +43,7 @@ import java.util.Arrays;
import java.util.List;
public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
implements SwitchBar.OnSwitchChangeListener {
implements SwitchBar.OnSwitchChangeListener, OemUnlockDialogHost {
private static final String TAG = "DevSettingsDashboard";
@@ -103,6 +106,33 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
}
}
@Override
public void onOemUnlockDialogConfirmed() {
final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
OemUnlockPreferenceController.class);
controller.onOemUnlockConfirmed();
}
@Override
public void onOemUnlockDialogDismissed() {
final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
OemUnlockPreferenceController.class);
controller.onOemUnlockDismissed();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
for (AbstractPreferenceController controller : mPreferenceControllers) {
if (controller instanceof DeveloperOptionsPreferenceController) {
if (((DeveloperOptionsPreferenceController) controller).onActivityResult(
requestCode, resultCode, data)) {
return;
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected String getLogTag() {
return TAG;
@@ -121,7 +151,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
mPreferenceControllers = buildPreferenceControllers(context, getLifecycle());
mPreferenceControllers = buildPreferenceControllers(context, getActivity(), getLifecycle(),
this /* devOptionsDashboardFragment */);
return mPreferenceControllers;
}
@@ -140,14 +171,19 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle) {
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new StayAwakePreferenceController(context, lifecycle));
controllers.add(new BluetoothSnoopLogPreferenceController(context));
controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
return controllers;
}
@VisibleForTesting
<T extends AbstractPreferenceController> T getDevelopmentOptionsController(Class<T> clazz) {
return getPreferenceController(clazz);
}
/**
* For Search.
*/
@@ -171,7 +207,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context, null /* lifecycle */);
return buildPreferenceControllers(context, null /* activity */,
null /* lifecycle */, null /* devOptionsDashboardFragment */);
}
};
}

View File

@@ -0,0 +1,82 @@
/*
* 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 android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class EnableOemUnlockSettingWarningDialog extends InstrumentedDialogFragment implements
DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
public static final String TAG = "EnableOemUnlockDlg";
public static void show(Fragment host) {
final FragmentManager manager = host.getActivity().getFragmentManager();
if (manager.findFragmentByTag(TAG) == null) {
final EnableOemUnlockSettingWarningDialog dialog =
new EnableOemUnlockSettingWarningDialog();
dialog.setTargetFragment(host, 0 /* requestCode */);
dialog.show(manager, TAG);
}
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DIALOG_ENABLE_OEM_UNLOCKING;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.confirm_enable_oem_unlock_title)
.setMessage(R.string.confirm_enable_oem_unlock_text)
.setPositiveButton(R.string.enable_text, this /* onClickListener */)
.setNegativeButton(android.R.string.cancel, this /* onClickListener */)
.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
final OemUnlockDialogHost host = (OemUnlockDialogHost) getTargetFragment();
if (host == null) {
return;
}
if (which == DialogInterface.BUTTON_POSITIVE) {
host.onOemUnlockDialogConfirmed();
} else {
host.onOemUnlockDialogDismissed();
}
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
final OemUnlockDialogHost host = (OemUnlockDialogHost) getTargetFragment();
if (host == null) {
return;
}
host.onOemUnlockDialogDismissed();
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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;
/**
* Interface for OemUnlockDialogFragment callbacks.
*/
public interface OemUnlockDialogHost {
/**
* Called when the user presses enable on the warning dialog.
*/
void onOemUnlockDialogConfirmed();
/**
* Called when the user dismisses or cancels the warning dialog.
*/
void onOemUnlockDialogDismissed();
}

View File

@@ -0,0 +1,220 @@
/*
* 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.UserHandle;
import android.os.UserManager;
import android.service.oemlock.OemLockManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.TelephonyManager;
import com.android.settings.R;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.RestrictedSwitchPreference;
public class OemUnlockPreferenceController extends DeveloperOptionsPreferenceController implements
Preference.OnPreferenceChangeListener {
private static final String PREFERENCE_KEY = "oem_unlock_enable";
private final OemLockManager mOemLockManager;
private final UserManager mUserManager;
private final TelephonyManager mTelephonyManager;
private final DevelopmentSettingsDashboardFragment mFragment;
private final ChooseLockSettingsHelper mChooseLockSettingsHelper;
private RestrictedSwitchPreference mPreference;
public OemUnlockPreferenceController(Context context, Activity activity,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mOemLockManager = (OemLockManager) context.getSystemService(Context.OEM_LOCK_SERVICE);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mFragment = fragment;
if (activity != null || mFragment != null) {
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(activity, mFragment);
} else {
mChooseLockSettingsHelper = null;
}
}
@Override
public boolean isAvailable() {
return mOemLockManager != null;
}
@Override
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = (RestrictedSwitchPreference) 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);
}
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
mPreference.setChecked(mOemLockManager.isOemUnlockAllowed());
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
public void onDeveloperOptionsEnabled() {
handleDeveloperOptionsToggled();
}
@Override
public void onDeveloperOptionsDisabled() {
handleDeveloperOptionsToggled();
}
public void onOemUnlockConfirmed() {
mOemLockManager.setOemUnlockAllowedByUser(true);
}
public void onOemUnlockDismissed() {
if (mPreference == null) {
return;
}
updateState(mPreference);
}
private void handleDeveloperOptionsToggled() {
if (mPreference == null) {
return;
}
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}.
*/
private boolean isBootloaderUnlocked() {
return mOemLockManager.isDeviceOemUnlocked();
}
private boolean enableOemUnlockPreference() {
return !isBootloaderUnlocked() && isOemUnlockAllowedByUserAndCarrier();
}
@VisibleForTesting
boolean showKeyguardConfirmation(Resources resources, int requestCode) {
return mChooseLockSettingsHelper.launchConfirmationActivity(
requestCode, resources.getString(R.string.oem_unlock_enable));
}
@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);
}
}