1 /*
2  * Copyright (C) 2016 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 package com.android.settings.utils;
17 
18 import android.app.ActivityManager;
19 import android.content.ComponentName;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.content.pm.ServiceInfo;
26 import android.provider.Settings;
27 import android.text.TextUtils;
28 import android.util.ArraySet;
29 import android.util.Slog;
30 
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.Set;
35 
36 public class ZenServiceListing {
37 
38     private final ContentResolver mContentResolver;
39     private final Context mContext;
40     private final ManagedServiceSettings.Config mConfig;
41     private final Set<ServiceInfo> mApprovedServices = new ArraySet<ServiceInfo>();
42     private final List<Callback> mZenCallbacks = new ArrayList<>();
43 
ZenServiceListing(Context context, ManagedServiceSettings.Config config)44     public ZenServiceListing(Context context, ManagedServiceSettings.Config config) {
45         mContext = context;
46         mConfig = config;
47         mContentResolver = context.getContentResolver();
48     }
49 
findService(final ComponentName cn)50     public ServiceInfo findService(final ComponentName cn) {
51         for (ServiceInfo service : mApprovedServices) {
52             final ComponentName serviceCN = new ComponentName(service.packageName, service.name);
53             if (serviceCN.equals(cn)) {
54                 return service;
55             }
56         }
57         return null;
58     }
59 
addZenCallback(Callback callback)60     public void addZenCallback(Callback callback) {
61         mZenCallbacks.add(callback);
62     }
63 
removeZenCallback(Callback callback)64     public void removeZenCallback(Callback callback) {
65         mZenCallbacks.remove(callback);
66     }
67 
reloadApprovedServices()68     public void reloadApprovedServices() {
69         mApprovedServices.clear();
70         String[] settings = {mConfig.setting, mConfig.secondarySetting};
71 
72         for (String setting : settings) {
73             if (!TextUtils.isEmpty(setting)) {
74                 final String flat = Settings.Secure.getString(mContentResolver, setting);
75                 if (!TextUtils.isEmpty(flat)) {
76                     final List<String> names = Arrays.asList(flat.split(":"));
77                     List<ServiceInfo> services = new ArrayList<>();
78                     getServices(mConfig, services, mContext.getPackageManager());
79                     for (ServiceInfo service : services) {
80                         if (matchesApprovedPackage(names, service.getComponentName())) {
81                             mApprovedServices.add(service);
82                         }
83                     }
84                 }
85             }
86         }
87         if (!mApprovedServices.isEmpty()) {
88             for (Callback callback : mZenCallbacks) {
89                 callback.onServicesReloaded(mApprovedServices);
90             }
91         }
92     }
93 
94     // Setting could contain: the component name of the condition provider, the package name of
95     // the condition provider, the component name of the notification listener.
matchesApprovedPackage(List<String> approved, ComponentName serviceOwner)96     private boolean matchesApprovedPackage(List<String> approved, ComponentName serviceOwner) {
97         String flatCn = serviceOwner.flattenToString();
98         if (approved.contains(flatCn) || approved.contains(serviceOwner.getPackageName())) {
99             return true;
100         }
101         for (String entry : approved) {
102             if (!TextUtils.isEmpty(entry)) {
103                 ComponentName approvedComponent = ComponentName.unflattenFromString(entry);
104                 if (approvedComponent != null && approvedComponent.getPackageName().equals(
105                         serviceOwner.getPackageName())) {
106                     return true;
107                 }
108             }
109         }
110         return false;
111     }
112 
getServices(ManagedServiceSettings.Config c, List<ServiceInfo> list, PackageManager pm)113     private static int getServices(ManagedServiceSettings.Config c, List<ServiceInfo> list,
114             PackageManager pm) {
115         int services = 0;
116         if (list != null) {
117             list.clear();
118         }
119         final int user = ActivityManager.getCurrentUser();
120 
121         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
122                 new Intent(c.intentAction),
123                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
124                 user);
125 
126         for (int i = 0, count = installedServices.size(); i < count; i++) {
127             ResolveInfo resolveInfo = installedServices.get(i);
128             ServiceInfo info = resolveInfo.serviceInfo;
129 
130             if (!c.permission.equals(info.permission)) {
131                 Slog.w(c.tag, "Skipping " + c.noun + " service "
132                         + info.packageName + "/" + info.name
133                         + ": it does not require the permission "
134                         + c.permission);
135                 continue;
136             }
137             if (list != null) {
138                 list.add(info);
139             }
140             services++;
141         }
142         return services;
143     }
144 
145     public interface Callback {
onServicesReloaded(Set<ServiceInfo> services)146         void onServicesReloaded(Set<ServiceInfo> services);
147     }
148 }
149