1 /* 2 * Copyright (C) 2019 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.car.settings.security; 18 19 import android.annotation.Nullable; 20 import android.app.admin.DevicePolicyManager; 21 import android.bluetooth.BluetoothDevice; 22 import android.car.Car; 23 import android.car.drivingstate.CarUxRestrictions; 24 import android.car.trust.CarTrustAgentEnrollmentManager; 25 import android.car.trust.TrustedDeviceInfo; 26 import android.car.userlib.CarUserManagerHelper; 27 import android.content.Context; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceGroup; 32 33 import com.android.car.settings.R; 34 import com.android.car.settings.common.FragmentController; 35 import com.android.car.settings.common.Logger; 36 import com.android.car.settings.common.PreferenceController; 37 import com.android.internal.widget.LockPatternUtils; 38 39 import java.util.ArrayList; 40 import java.util.List; 41 42 /** 43 * Business logic of trusted device list page 44 */ 45 public class TrustedDeviceListPreferenceController extends PreferenceController<PreferenceGroup> { 46 private static final Logger LOG = new Logger(TrustedDeviceListPreferenceController.class); 47 private final CarUserManagerHelper mCarUserManagerHelper; 48 private final LockPatternUtils mLockPatternUtils; 49 private final Car mCar; 50 @Nullable 51 private CarTrustAgentEnrollmentManager mCarTrustAgentEnrollmentManager; 52 private final CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback 53 mCarTrustAgentEnrollmentCallback = 54 new CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback() { 55 56 @Override 57 public void onEnrollmentHandshakeFailure(BluetoothDevice device, int errorCode) { 58 } 59 60 @Override 61 public void onAuthStringAvailable(BluetoothDevice device, String authString) { 62 } 63 64 @Override 65 public void onEscrowTokenAdded(long handle) { 66 } 67 68 @Override 69 public void onEscrowTokenRemoved(long handle) { 70 refreshUi(); 71 } 72 73 @Override 74 public void onEscrowTokenActiveStateChanged(long handle, boolean active) { 75 if (active) { 76 refreshUi(); 77 } 78 } 79 }; 80 81 @VisibleForTesting 82 final ConfirmRemoveDeviceDialog.ConfirmRemoveDeviceListener mConfirmRemoveDeviceListener = 83 new ConfirmRemoveDeviceDialog.ConfirmRemoveDeviceListener() { 84 public void onConfirmRemoveDevice(long handle) { 85 mCarTrustAgentEnrollmentManager.removeEscrowToken(handle, 86 mCarUserManagerHelper.getCurrentProcessUserId()); 87 } 88 }; 89 TrustedDeviceListPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)90 public TrustedDeviceListPreferenceController(Context context, String preferenceKey, 91 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 92 super(context, preferenceKey, fragmentController, uxRestrictions); 93 mCarUserManagerHelper = new CarUserManagerHelper(context); 94 mLockPatternUtils = new LockPatternUtils(context); 95 mCar = Car.createCar(context); 96 mCarTrustAgentEnrollmentManager = (CarTrustAgentEnrollmentManager) mCar.getCarManager( 97 Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE); 98 99 } 100 101 @Override checkInitialized()102 protected void checkInitialized() { 103 if (mCarTrustAgentEnrollmentManager == null) { 104 throw new IllegalStateException("mCarTrustAgentEnrollmentManager is null."); 105 } 106 } 107 108 @Override getPreferenceType()109 protected Class<PreferenceGroup> getPreferenceType() { 110 return PreferenceGroup.class; 111 } 112 113 114 @Override updateState(PreferenceGroup preferenceGroup)115 protected void updateState(PreferenceGroup preferenceGroup) { 116 if (!hasPassword()) { 117 preferenceGroup.removeAll(); 118 preferenceGroup.addPreference(createAuthenticationReminderPreference()); 119 return; 120 } 121 List<Preference> updatedList = createTrustDevicePreferenceList(); 122 if (!isEqual(preferenceGroup, updatedList)) { 123 preferenceGroup.removeAll(); 124 for (Preference trustedDevice : updatedList) { 125 preferenceGroup.addPreference(trustedDevice); 126 } 127 } 128 preferenceGroup.setVisible(preferenceGroup.getPreferenceCount() > 0); 129 } 130 hasPassword()131 private boolean hasPassword() { 132 return mLockPatternUtils.getKeyguardStoredPasswordQuality( 133 mCarUserManagerHelper.getCurrentProcessUserId()) 134 != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 135 } 136 137 @Override onStartInternal()138 protected void onStartInternal() { 139 mCarTrustAgentEnrollmentManager.setEnrollmentCallback(mCarTrustAgentEnrollmentCallback); 140 141 } 142 143 @Override onStopInternal()144 protected void onStopInternal() { 145 mCarTrustAgentEnrollmentManager.setEnrollmentCallback(null); 146 } 147 148 /** 149 * Method to compare two lists of preferences, used only by updateState method. 150 * 151 * @param preferenceGroup current preference group 152 * @param trustedDeviceList updated preference list 153 * @return {@code true} when two lists are the same 154 */ isEqual(PreferenceGroup preferenceGroup, List<Preference> trustedDeviceList)155 private boolean isEqual(PreferenceGroup preferenceGroup, List<Preference> trustedDeviceList) { 156 if (preferenceGroup.getPreferenceCount() != trustedDeviceList.size()) { 157 return false; 158 } 159 for (Preference p : trustedDeviceList) { 160 if (preferenceGroup.findPreference(p.getKey()) == null) { 161 return false; 162 } 163 } 164 return true; 165 } 166 createTrustDevicePreferenceList()167 private List<Preference> createTrustDevicePreferenceList() { 168 List<Preference> trustedDevicesList = new ArrayList<>(); 169 List<TrustedDeviceInfo> devices = 170 mCarTrustAgentEnrollmentManager.getEnrolledDeviceInfoForUser( 171 mCarUserManagerHelper.getCurrentProcessUserId()); 172 for (TrustedDeviceInfo deviceInfo : devices) { 173 trustedDevicesList.add( 174 createTrustedDevicePreference(deviceInfo.getName(), deviceInfo.getHandle())); 175 } 176 return trustedDevicesList; 177 } 178 createTrustedDevicePreference(String deviceName, long handle)179 private Preference createTrustedDevicePreference(String deviceName, long handle) { 180 Preference preference = new Preference(getContext()); 181 preference.setIcon(R.drawable.ic_settings_bluetooth); 182 preference.setTitle(deviceName); 183 preference.setKey(String.valueOf(handle)); 184 preference.setOnPreferenceClickListener((Preference pref) -> { 185 ConfirmRemoveDeviceDialog dialog = ConfirmRemoveDeviceDialog.newInstance(deviceName, 186 handle); 187 dialog.setConfirmRemoveDeviceListener(mConfirmRemoveDeviceListener); 188 getFragmentController().showDialog(dialog, ConfirmRemoveDeviceDialog.TAG); 189 return true; 190 }); 191 return preference; 192 } 193 createAuthenticationReminderPreference()194 private Preference createAuthenticationReminderPreference() { 195 Preference preference = new Preference(getContext()); 196 preference.setSummary(R.string.trusted_device_set_authentication_reminder); 197 return preference; 198 } 199 } 200