1 /*
2  * Copyright (C) 2018 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.security.trustagent;
18 
19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
20 
21 import android.app.admin.DevicePolicyManager;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.graphics.drawable.Drawable;
28 import android.os.UserHandle;
29 import android.service.trust.TrustAgentService;
30 import android.text.TextUtils;
31 import android.util.ArrayMap;
32 import android.util.ArraySet;
33 import android.util.IconDrawableFactory;
34 
35 import androidx.preference.Preference;
36 import androidx.preference.PreferenceScreen;
37 import androidx.preference.SwitchPreference;
38 
39 import com.android.internal.widget.LockPatternUtils;
40 import com.android.settings.core.BasePreferenceController;
41 import com.android.settings.overlay.FeatureFactory;
42 import com.android.settings.security.SecurityFeatureProvider;
43 import com.android.settingslib.RestrictedLockUtilsInternal;
44 import com.android.settingslib.RestrictedSwitchPreference;
45 import com.android.settingslib.core.lifecycle.LifecycleObserver;
46 import com.android.settingslib.core.lifecycle.events.OnStart;
47 
48 import java.util.List;
49 
50 public class TrustAgentsPreferenceController extends BasePreferenceController
51         implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart {
52 
53     private static final Intent TRUST_AGENT_INTENT =
54             new Intent(TrustAgentService.SERVICE_INTERFACE);
55 
56     private final ArrayMap<ComponentName, TrustAgentInfo> mAvailableAgents;
57     private final ArraySet<ComponentName> mActiveAgents;
58     private final DevicePolicyManager mDevicePolicyManager;
59     private final IconDrawableFactory mIconDrawableFactory;
60     private final LockPatternUtils mLockPatternUtils;
61     private final PackageManager mPackageManager;
62     private final TrustAgentManager mTrustAgentManager;
63 
64     private PreferenceScreen mScreen;
65 
TrustAgentsPreferenceController(Context context, String key)66     public TrustAgentsPreferenceController(Context context, String key) {
67         super(context, key);
68         mAvailableAgents = new ArrayMap<>();
69         mActiveAgents = new ArraySet<>();
70         mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
71         mIconDrawableFactory = IconDrawableFactory.newInstance(context);
72         final SecurityFeatureProvider securityFeatureProvider =
73                 FeatureFactory.getFactory(context).getSecurityFeatureProvider();
74         mTrustAgentManager = securityFeatureProvider.getTrustAgentManager();
75         mLockPatternUtils = securityFeatureProvider.getLockPatternUtils(context);
76         mPackageManager = context.getPackageManager();
77     }
78 
79     @Override
displayPreference(PreferenceScreen screen)80     public void displayPreference(PreferenceScreen screen) {
81         super.displayPreference(screen);
82         mScreen = screen;
83     }
84 
85     @Override
getAvailabilityStatus()86     public int getAvailabilityStatus() {
87         return AVAILABLE;
88     }
89 
90     @Override
onStart()91     public void onStart() {
92         updateAgents();
93     }
94 
updateAgents()95     private void updateAgents() {
96         findAvailableTrustAgents();
97         loadActiveAgents();
98         removeUselessExistingPreferences();
99 
100         final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
101                 mContext, DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, UserHandle.myUserId());
102 
103         for (TrustAgentInfo agent : mAvailableAgents.values()) {
104             final ComponentName componentName = agent.getComponentName();
105             RestrictedSwitchPreference preference = (RestrictedSwitchPreference)
106                     mScreen.findPreference(componentName.flattenToString());
107             if (preference == null) {
108                 preference = new RestrictedSwitchPreference(mScreen.getContext());
109             }
110             preference.setKey(componentName.flattenToString());
111             preference.useAdminDisabledSummary(true);
112             preference.setTitle(agent.getLabel());
113             preference.setIcon(agent.getIcon());
114             preference.setOnPreferenceChangeListener(this);
115             preference.setChecked(mActiveAgents.contains(componentName));
116             if (admin != null && mDevicePolicyManager.getTrustAgentConfiguration(null /* admin */,
117                     componentName) == null) {
118                 preference.setChecked(false);
119                 preference.setDisabledByAdmin(admin);
120             }
121             mScreen.addPreference(preference);
122         }
123     }
124 
loadActiveAgents()125     private void loadActiveAgents() {
126         final List<ComponentName> activeTrustAgents = mLockPatternUtils.getEnabledTrustAgents(
127                 UserHandle.myUserId());
128         if (activeTrustAgents != null) {
129             mActiveAgents.addAll(activeTrustAgents);
130         }
131     }
132 
saveActiveAgents()133     private void saveActiveAgents() {
134         mLockPatternUtils.setEnabledTrustAgents(mActiveAgents, UserHandle.myUserId());
135     }
136 
findAvailableTrustAgents()137     private void findAvailableTrustAgents() {
138         final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(
139                 TRUST_AGENT_INTENT, PackageManager.GET_META_DATA);
140         mAvailableAgents.clear();
141         for (ResolveInfo resolveInfo : resolveInfos) {
142             if (resolveInfo.serviceInfo == null) {
143                 continue;
144             }
145             if (!mTrustAgentManager.shouldProvideTrust(resolveInfo, mPackageManager)) {
146                 continue;
147             }
148             final CharSequence label = resolveInfo.loadLabel(mPackageManager);
149             final ComponentName componentName = mTrustAgentManager.getComponentName(resolveInfo);
150             final Drawable icon = mIconDrawableFactory.getBadgedIcon(
151                     resolveInfo.getComponentInfo().applicationInfo);
152             final TrustAgentInfo agentInfo = new TrustAgentInfo(label, componentName, icon);
153             mAvailableAgents.put(componentName, agentInfo);
154         }
155     }
156 
removeUselessExistingPreferences()157     private void removeUselessExistingPreferences() {
158         final int count = mScreen.getPreferenceCount();
159         if (count <= 0) {
160             return;
161         }
162         for (int i = count - 1; i >= 0; i--) {
163             final Preference pref = mScreen.getPreference(i);
164             final String[] names = TextUtils.split(pref.getKey(), "/");
165             final ComponentName componentName = new ComponentName(names[0], names[1]);
166             if (!mAvailableAgents.containsKey(componentName)) {
167                 mScreen.removePreference(pref);
168                 mActiveAgents.remove(componentName);
169             }
170         }
171     }
172 
173     @Override
onPreferenceChange(Preference preference, Object newValue)174     public boolean onPreferenceChange(Preference preference, Object newValue) {
175         if (!(preference instanceof SwitchPreference)) {
176             return false;
177         }
178         for (TrustAgentInfo agent : mAvailableAgents.values()) {
179             final ComponentName componentName = agent.getComponentName();
180             if (!TextUtils.equals(preference.getKey(), componentName.flattenToString())) {
181                 continue;
182             }
183             if ((Boolean) newValue && !mActiveAgents.contains(componentName)) {
184                 mActiveAgents.add(componentName);
185             } else {
186                 mActiveAgents.remove(componentName);
187             }
188             saveActiveAgents();
189             return true;
190         }
191         return false;
192     }
193 }
194