1 /* 2 * Copyright (C) 2015 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.notification; 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.settings.notification.ManagedServiceSettings.Config; 36 37 import java.util.ArrayList; 38 import java.util.HashSet; 39 import java.util.List; 40 41 public class ServiceListing { 42 private final ContentResolver mContentResolver; 43 private final Context mContext; 44 private final Config mConfig; 45 private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>(); 46 private final List<ServiceInfo> mServices = new ArrayList<ServiceInfo>(); 47 private final List<Callback> mCallbacks = new ArrayList<Callback>(); 48 49 private boolean mListening; 50 ServiceListing(Context context, Config config)51 public ServiceListing(Context context, Config config) { 52 mContext = context; 53 mConfig = config; 54 mContentResolver = context.getContentResolver(); 55 } 56 addCallback(Callback callback)57 public void addCallback(Callback callback) { 58 mCallbacks.add(callback); 59 } 60 removeCallback(Callback callback)61 public void removeCallback(Callback callback) { 62 mCallbacks.remove(callback); 63 } 64 setListening(boolean listening)65 public void setListening(boolean listening) { 66 if (mListening == listening) return; 67 mListening = listening; 68 if (mListening) { 69 // listen for package changes 70 IntentFilter filter = new IntentFilter(); 71 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 72 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 73 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 74 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 75 filter.addDataScheme("package"); 76 mContext.registerReceiver(mPackageReceiver, filter); 77 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting), 78 false, mSettingsObserver); 79 } else { 80 mContext.unregisterReceiver(mPackageReceiver); 81 mContentResolver.unregisterContentObserver(mSettingsObserver); 82 } 83 } 84 getEnabledServicesCount(Config config, Context context)85 public static int getEnabledServicesCount(Config config, Context context) { 86 final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting); 87 if (flat == null || "".equals(flat)) return 0; 88 final String[] components = flat.split(":"); 89 return components.length; 90 } 91 getServicesCount(Config c, PackageManager pm)92 public static int getServicesCount(Config c, PackageManager pm) { 93 return getServices(c, null, pm); 94 } 95 findService(Context context, Config config, final ComponentName cn)96 public static ServiceInfo findService(Context context, Config config, final ComponentName cn) { 97 final ServiceListing listing = new ServiceListing(context, config); 98 final List<ServiceInfo> services = listing.reload(); 99 for (ServiceInfo service : services) { 100 final ComponentName serviceCN = new ComponentName(service.packageName, service.name); 101 if (serviceCN.equals(cn)) { 102 return service; 103 } 104 } 105 return null; 106 } 107 getServices(Config c, List<ServiceInfo> list, PackageManager pm)108 private static int getServices(Config c, List<ServiceInfo> list, PackageManager pm) { 109 int services = 0; 110 if (list != null) { 111 list.clear(); 112 } 113 final int user = ActivityManager.getCurrentUser(); 114 115 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( 116 new Intent(c.intentAction), 117 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 118 user); 119 120 for (int i = 0, count = installedServices.size(); i < count; i++) { 121 ResolveInfo resolveInfo = installedServices.get(i); 122 ServiceInfo info = resolveInfo.serviceInfo; 123 124 if (!c.permission.equals(info.permission)) { 125 Slog.w(c.tag, "Skipping " + c.noun + " service " 126 + info.packageName + "/" + info.name 127 + ": it does not require the permission " 128 + c.permission); 129 continue; 130 } 131 if (list != null) { 132 list.add(info); 133 } 134 services++; 135 } 136 return services; 137 } 138 saveEnabledServices()139 private void saveEnabledServices() { 140 StringBuilder sb = null; 141 for (ComponentName cn : mEnabledServices) { 142 if (sb == null) { 143 sb = new StringBuilder(); 144 } else { 145 sb.append(':'); 146 } 147 sb.append(cn.flattenToString()); 148 } 149 Settings.Secure.putString(mContentResolver, mConfig.setting, 150 sb != null ? sb.toString() : ""); 151 } 152 loadEnabledServices()153 private void loadEnabledServices() { 154 mEnabledServices.clear(); 155 final String flat = Settings.Secure.getString(mContentResolver, mConfig.setting); 156 if (flat != null && !"".equals(flat)) { 157 final String[] names = flat.split(":"); 158 for (int i = 0; i < names.length; i++) { 159 final ComponentName cn = ComponentName.unflattenFromString(names[i]); 160 if (cn != null) { 161 mEnabledServices.add(cn); 162 } 163 } 164 } 165 } 166 reload()167 public List<ServiceInfo> reload() { 168 loadEnabledServices(); 169 getServices(mConfig, mServices, mContext.getPackageManager()); 170 for (Callback callback : mCallbacks) { 171 callback.onServicesReloaded(mServices); 172 } 173 return mServices; 174 } 175 isEnabled(ComponentName cn)176 public boolean isEnabled(ComponentName cn) { 177 return mEnabledServices.contains(cn); 178 } 179 setEnabled(ComponentName cn, boolean enabled)180 public void setEnabled(ComponentName cn, boolean enabled) { 181 if (enabled) { 182 mEnabledServices.add(cn); 183 } else { 184 mEnabledServices.remove(cn); 185 } 186 saveEnabledServices(); 187 } 188 189 private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { 190 @Override 191 public void onChange(boolean selfChange, Uri uri) { 192 reload(); 193 } 194 }; 195 196 private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { 197 @Override 198 public void onReceive(Context context, Intent intent) { 199 reload(); 200 } 201 }; 202 203 public interface Callback { onServicesReloaded(List<ServiceInfo> services)204 void onServicesReloaded(List<ServiceInfo> services); 205 } 206 } 207