Home | History | Annotate | Download | only in applications
      1 /*
      2  * Copyright (C) 2017 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.settingslib.applications;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.BroadcastReceiver;
     21 import android.content.ComponentName;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.ResolveInfo;
     28 import android.content.pm.ServiceInfo;
     29 import android.database.ContentObserver;
     30 import android.net.Uri;
     31 import android.os.Handler;
     32 import android.provider.Settings;
     33 import android.util.Slog;
     34 
     35 import com.android.settingslib.wrapper.PackageManagerWrapper;
     36 
     37 import java.util.ArrayList;
     38 import java.util.HashSet;
     39 import java.util.List;
     40 
     41 /**
     42  * Class for managing services matching a given intent and requesting a given permission.
     43  */
     44 public class ServiceListing {
     45     private final ContentResolver mContentResolver;
     46     private final Context mContext;
     47     private final String mTag;
     48     private final String mSetting;
     49     private final String mIntentAction;
     50     private final String mPermission;
     51     private final String mNoun;
     52     private final HashSet<ComponentName> mEnabledServices = new HashSet<>();
     53     private final List<ServiceInfo> mServices = new ArrayList<>();
     54     private final List<Callback> mCallbacks = new ArrayList<>();
     55 
     56     private boolean mListening;
     57 
     58     private ServiceListing(Context context, String tag,
     59             String setting, String intentAction, String permission, String noun) {
     60         mContentResolver = context.getContentResolver();
     61         mContext = context;
     62         mTag = tag;
     63         mSetting = setting;
     64         mIntentAction = intentAction;
     65         mPermission = permission;
     66         mNoun = noun;
     67     }
     68 
     69     public void addCallback(Callback callback) {
     70         mCallbacks.add(callback);
     71     }
     72 
     73     public void removeCallback(Callback callback) {
     74         mCallbacks.remove(callback);
     75     }
     76 
     77     public void setListening(boolean listening) {
     78         if (mListening == listening) return;
     79         mListening = listening;
     80         if (mListening) {
     81             // listen for package changes
     82             IntentFilter filter = new IntentFilter();
     83             filter.addAction(Intent.ACTION_PACKAGE_ADDED);
     84             filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
     85             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
     86             filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
     87             filter.addDataScheme("package");
     88             mContext.registerReceiver(mPackageReceiver, filter);
     89             mContentResolver.registerContentObserver(Settings.Secure.getUriFor(mSetting),
     90                     false, mSettingsObserver);
     91         } else {
     92             mContext.unregisterReceiver(mPackageReceiver);
     93             mContentResolver.unregisterContentObserver(mSettingsObserver);
     94         }
     95     }
     96 
     97     private void saveEnabledServices() {
     98         StringBuilder sb = null;
     99         for (ComponentName cn : mEnabledServices) {
    100             if (sb == null) {
    101                 sb = new StringBuilder();
    102             } else {
    103                 sb.append(':');
    104             }
    105             sb.append(cn.flattenToString());
    106         }
    107         Settings.Secure.putString(mContentResolver, mSetting,
    108                 sb != null ? sb.toString() : "");
    109     }
    110 
    111     private void loadEnabledServices() {
    112         mEnabledServices.clear();
    113         final String flat = Settings.Secure.getString(mContentResolver, mSetting);
    114         if (flat != null && !"".equals(flat)) {
    115             final String[] names = flat.split(":");
    116             for (String name : names) {
    117                 final ComponentName cn = ComponentName.unflattenFromString(name);
    118                 if (cn != null) {
    119                     mEnabledServices.add(cn);
    120                 }
    121             }
    122         }
    123     }
    124 
    125     public void reload() {
    126         loadEnabledServices();
    127         mServices.clear();
    128         final int user = ActivityManager.getCurrentUser();
    129 
    130         final PackageManagerWrapper pmWrapper =
    131                 new PackageManagerWrapper(mContext.getPackageManager());
    132         List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
    133                 new Intent(mIntentAction),
    134                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
    135                 user);
    136 
    137         for (ResolveInfo resolveInfo : installedServices) {
    138             ServiceInfo info = resolveInfo.serviceInfo;
    139 
    140             if (!mPermission.equals(info.permission)) {
    141                 Slog.w(mTag, "Skipping " + mNoun + " service "
    142                         + info.packageName + "/" + info.name
    143                         + ": it does not require the permission "
    144                         + mPermission);
    145                 continue;
    146             }
    147             mServices.add(info);
    148         }
    149         for (Callback callback : mCallbacks) {
    150             callback.onServicesReloaded(mServices);
    151         }
    152     }
    153 
    154     public boolean isEnabled(ComponentName cn) {
    155         return mEnabledServices.contains(cn);
    156     }
    157 
    158     public void setEnabled(ComponentName cn, boolean enabled) {
    159         if (enabled) {
    160             mEnabledServices.add(cn);
    161         } else {
    162             mEnabledServices.remove(cn);
    163         }
    164         saveEnabledServices();
    165     }
    166 
    167     private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
    168         @Override
    169         public void onChange(boolean selfChange, Uri uri) {
    170             reload();
    171         }
    172     };
    173 
    174     private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
    175         @Override
    176         public void onReceive(Context context, Intent intent) {
    177             reload();
    178         }
    179     };
    180 
    181     public interface Callback {
    182         void onServicesReloaded(List<ServiceInfo> services);
    183     }
    184 
    185     public static class Builder {
    186         private final Context mContext;
    187         private String mTag;
    188         private String mSetting;
    189         private String mIntentAction;
    190         private String mPermission;
    191         private String mNoun;
    192 
    193         public Builder(Context context) {
    194             mContext = context;
    195         }
    196 
    197         public Builder setTag(String tag) {
    198             mTag = tag;
    199             return this;
    200         }
    201 
    202         public Builder setSetting(String setting) {
    203             mSetting = setting;
    204             return this;
    205         }
    206 
    207         public Builder setIntentAction(String intentAction) {
    208             mIntentAction = intentAction;
    209             return this;
    210         }
    211 
    212         public Builder setPermission(String permission) {
    213             mPermission = permission;
    214             return this;
    215         }
    216 
    217         public Builder setNoun(String noun) {
    218             mNoun = noun;
    219             return this;
    220         }
    221 
    222         public ServiceListing build() {
    223             return new ServiceListing(mContext, mTag, mSetting, mIntentAction, mPermission, mNoun);
    224         }
    225     }
    226 }
    227