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