179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler/* 279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * Copyright (C) 2010 The Android Open Source Project 379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * 479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License"); 579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * you may not use this file except in compliance with the License. 679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * You may obtain a copy of the License at 779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * 879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * http://www.apache.org/licenses/LICENSE-2.0 979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * 1079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * Unless required by applicable law or agreed to in writing, software 1179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS, 1279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * See the License for the specific language governing permissions and 1479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler * limitations under the License. 1579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler */ 1679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 1779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerpackage com.android.settings; 1879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 1979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.app.ActivityManager; 2079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.app.AlertDialog; 2179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.app.Dialog; 2279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.app.DialogFragment; 2379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.BroadcastReceiver; 2479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.ContentResolver; 2579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.DialogInterface; 2679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.IntentFilter; 2779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.pm.PackageItemInfo; 2879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.pm.ServiceInfo; 2979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.database.ContentObserver; 3079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.net.Uri; 3179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.os.Handler; 3279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.service.notification.NotificationListenerService; 3379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.util.Slog; 3479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.widget.ArrayAdapter; 3579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 3679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.app.ListFragment; 3779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.ComponentName; 3879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.Context; 3979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.Intent; 4079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.pm.PackageManager; 4179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.content.pm.ResolveInfo; 4279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.os.Bundle; 4379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.provider.Settings; 4479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.view.LayoutInflater; 4579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.view.View; 4679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.view.ViewGroup; 4779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.widget.CheckBox; 4879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.widget.ImageView; 4979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.widget.ListView; 5079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport android.widget.TextView; 5179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 5279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport java.util.HashSet; 5379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerimport java.util.List; 5479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 5579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandlerpublic class NotificationAccessSettings extends ListFragment { 5679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler static final String TAG = NotificationAccessSettings.class.getSimpleName(); 5779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private static final boolean SHOW_PACKAGE_NAME = false; 5879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 5979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private PackageManager mPM; 6079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private ContentResolver mCR; 6179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 6279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private final HashSet<ComponentName> mEnabledListeners = new HashSet<ComponentName>(); 6379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private ListenerListAdapter mList; 6479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 6579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private final Uri ENABLED_NOTIFICATION_LISTENERS_URI 6679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 6779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 6879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { 6979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 7079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onChange(boolean selfChange, Uri uri) { 7179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler updateList(); 7279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 7379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler }; 7479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 7579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { 7679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 7779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onReceive(Context context, Intent intent) { 7879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler updateList(); 7979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 8079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler }; 8179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 8279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public class ListenerWarningDialogFragment extends DialogFragment { 8379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler static final String KEY_COMPONENT = "c"; 8479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler static final String KEY_LABEL = "l"; 8579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 8679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public ListenerWarningDialogFragment setListenerInfo(ComponentName cn, String label) { 8779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Bundle args = new Bundle(); 8879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler args.putString(KEY_COMPONENT, cn.flattenToString()); 8979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler args.putString(KEY_LABEL, label); 9079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler setArguments(args); 9179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 9279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return this; 9379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 9479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 9579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public Dialog onCreateDialog(Bundle savedInstanceState) { 9679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler super.onCreate(savedInstanceState); 9779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final Bundle args = getArguments(); 9879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final String label = args.getString(KEY_LABEL); 9979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final ComponentName cn = ComponentName.unflattenFromString(args.getString(KEY_COMPONENT)); 10079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 10179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final String title = getResources().getString( 10279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler R.string.notification_listener_security_warning_title, label); 10379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final String summary = getResources().getString( 10479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler R.string.notification_listener_security_warning_summary, label); 10579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return new AlertDialog.Builder(getActivity()) 10679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setMessage(summary) 10779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setTitle(title) 10879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setIconAttribute(android.R.attr.alertDialogIcon) 10979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setCancelable(true) 11079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setPositiveButton(android.R.string.ok, 11179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler new DialogInterface.OnClickListener() { 11279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onClick(DialogInterface dialog, int id) { 11379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mEnabledListeners.add(cn); 11479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler saveEnabledListeners(); 11579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 11679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler }) 11779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setNegativeButton(android.R.string.cancel, 11879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler new DialogInterface.OnClickListener() { 11979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onClick(DialogInterface dialog, int id) { 12079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler // pass 12179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 12279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler }) 12379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .create(); 12479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 12579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 12679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 12779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 12879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onCreate(Bundle icicle) { 12979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler super.onCreate(icicle); 13079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 13179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mPM = getActivity().getPackageManager(); 13279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mCR = getActivity().getContentResolver(); 13379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mList = new ListenerListAdapter(getActivity()); 13479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 13579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 13679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 13779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public View onCreateView(LayoutInflater inflater, ViewGroup container, 13879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Bundle savedInstanceState) { 139b8c4898c64c6e1a0e3d0a1de7c0116d80edb6e44Daniel Sandler return inflater.inflate(R.layout.notification_access_settings, container, false); 14079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 14179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 14279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 14379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onResume() { 14479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler super.onResume(); 14579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler updateList(); 14679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 14779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler // listen for package changes 14879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler IntentFilter filter = new IntentFilter(); 14979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler filter.addAction(Intent.ACTION_PACKAGE_ADDED); 15079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 15179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 15279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 15379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler filter.addDataScheme("package"); 15479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler getActivity().registerReceiver(mPackageReceiver, filter); 15579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 15679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mCR.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, false, mSettingsObserver); 15779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 15879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 15979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 16079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onPause() { 16179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler super.onPause(); 16279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 16379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler getActivity().unregisterReceiver(mPackageReceiver); 16479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mCR.unregisterContentObserver(mSettingsObserver); 16579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 16679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 16779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler void loadEnabledListeners() { 16879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mEnabledListeners.clear(); 16979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final String flat = Settings.Secure.getString(mCR, 17079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 17179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (flat != null && !"".equals(flat)) { 17279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final String[] names = flat.split(":"); 17379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler for (int i = 0; i < names.length; i++) { 17479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final ComponentName cn = ComponentName.unflattenFromString(names[i]); 17579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (cn != null) { 17679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mEnabledListeners.add(cn); 17779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 17879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 17979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 18079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 18179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 18279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler void saveEnabledListeners() { 18379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler StringBuilder sb = null; 18479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler for (ComponentName cn : mEnabledListeners) { 18579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (sb == null) { 18679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler sb = new StringBuilder(); 18779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } else { 18879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler sb.append(':'); 18979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 19079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler sb.append(cn.flattenToString()); 19179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 19279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Settings.Secure.putString(mCR, 19379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 19479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler sb != null ? sb.toString() : ""); 19579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 19679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 19779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler void updateList() { 19879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler loadEnabledListeners(); 19979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 20055dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock getListeners(mList, mPM); 20155dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock mList.sort(new PackageItemInfo.DisplayNameComparator(mPM)); 20255dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock 20355dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock getListView().setAdapter(mList); 20455dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock } 20555dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock 20655dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock static int getListenersCount(PackageManager pm) { 20755dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock return getListeners(null, pm); 20855dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock } 20955dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock 21055dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock private static int getListeners(ArrayAdapter<ServiceInfo> adapter, PackageManager pm) { 21155dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock int listeners = 0; 21255dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock if (adapter != null) { 21355dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock adapter.clear(); 21455dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock } 21579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final int user = ActivityManager.getCurrentUser(); 21679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 21755dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( 21879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler new Intent(NotificationListenerService.SERVICE_INTERFACE), 21979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 22079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler user); 22179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 22279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler for (int i = 0, count = installedServices.size(); i < count; i++) { 22379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ResolveInfo resolveInfo = installedServices.get(i); 22479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ServiceInfo info = resolveInfo.serviceInfo; 22579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 22679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals( 22779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler info.permission)) { 22879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler Slog.w(TAG, "Skipping notification listener service " 22979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler + info.packageName + "/" + info.name 23079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler + ": it does not require the permission " 23179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); 23279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler continue; 23379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 23455dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock if (adapter != null) { 23555dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock adapter.add(info); 23655dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock } 23755dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock listeners++; 23879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 23955dbdf68f966d5218a265086f848f60d5a75c13fJohn Spurlock return listeners; 24079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 24179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 24279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler boolean isListenerEnabled(ServiceInfo info) { 24379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final ComponentName cn = new ComponentName(info.packageName, info.name); 24479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return mEnabledListeners.contains(cn); 24579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 24679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 24779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler @Override 24879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void onListItemClick(ListView l, View v, int position, long id) { 24979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ServiceInfo info = mList.getItem(position); 25079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final ComponentName cn = new ComponentName(info.packageName, info.name); 25179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (mEnabledListeners.contains(cn)) { 25279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler // the simple version: disabling 25379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mEnabledListeners.remove(cn); 25479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler saveEnabledListeners(); 25579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } else { 25679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler // show a scary dialog 25779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler new ListenerWarningDialogFragment() 25879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .setListenerInfo(cn, info.loadLabel(mPM).toString()) 25979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler .show(getFragmentManager(), "dialog"); 26079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 26179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 26279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 26379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler static class ViewHolder { 26479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ImageView icon; 26579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler TextView name; 26679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler CheckBox checkbox; 26779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler TextView description; 26879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 26979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 27079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler class ListenerListAdapter extends ArrayAdapter<ServiceInfo> { 27179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler final LayoutInflater mInflater; 27279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 27379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ListenerListAdapter(Context context) { 27479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler super(context, 0, 0); 27579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler mInflater = (LayoutInflater) 27679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 27779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 27879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 27979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public boolean hasStableIds() { 28079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return true; 28179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 28279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 28379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public long getItemId(int position) { 28479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return position; 28579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 28679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 28779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public View getView(int position, View convertView, ViewGroup parent) { 28879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler View v; 28979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (convertView == null) { 29079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler v = newView(parent); 29179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } else { 29279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler v = convertView; 29379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 29479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler bindView(v, position); 29579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return v; 29679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 29779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 29879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public View newView(ViewGroup parent) { 29979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler View v = mInflater.inflate(R.layout.notification_listener_item, parent, false); 30079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ViewHolder h = new ViewHolder(); 30179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler h.icon = (ImageView) v.findViewById(R.id.icon); 30279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler h.name = (TextView) v.findViewById(R.id.name); 30379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler h.checkbox = (CheckBox) v.findViewById(R.id.checkbox); 30479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler h.description = (TextView) v.findViewById(R.id.description); 30579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler v.setTag(h); 30679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler return v; 30779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 30879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 30979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler public void bindView(View view, int position) { 31079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ViewHolder vh = (ViewHolder) view.getTag(); 31179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler ServiceInfo info = getItem(position); 31279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler 31379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.icon.setImageDrawable(info.loadIcon(mPM)); 31479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.name.setText(info.loadLabel(mPM)); 31579b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler if (SHOW_PACKAGE_NAME) { 31679b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.description.setText(info.packageName); 31779b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.description.setVisibility(View.VISIBLE); 31879b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } else { 31979b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.description.setVisibility(View.GONE); 32079b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 32179b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler vh.checkbox.setChecked(isListenerEnabled(info)); 32279b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 32379b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler } 32479b9bfe56ee4036fbe8d9bcac01260356309ae2fDaniel Sandler} 325