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