Home | History | Annotate | Download | only in utils
      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 
     44     public ZenServiceListing(Context context, ManagedServiceSettings.Config config) {
     45         mContext = context;
     46         mConfig = config;
     47         mContentResolver = context.getContentResolver();
     48     }
     49 
     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 
     60     public void addZenCallback(Callback callback) {
     61         mZenCallbacks.add(callback);
     62     }
     63 
     64     public void removeZenCallback(Callback callback) {
     65         mZenCallbacks.remove(callback);
     66     }
     67 
     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.
     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 
    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 {
    146         void onServicesReloaded(Set<ServiceInfo> services);
    147     }
    148 }
    149