• Android之通知使用权


    通知使用权打开方式

    设置——提示音和通知——通知使用权。

    具体界面如图:

    存在须要拥有通知使用权应用时:

    存在须要拥有通知使用权应用时:

    用户为应用勾选复选框后系统弹dialog须要用户进一步确认时:

    主要涉及文件:

    /packages/apps/Settings/src/com/android/settings/notification/NotificationAccessSettings.java

     /packages/apps/Settings/src/com/android/settings/notification/ManagedServiceSettings.java

    涉及数据库:

    data/data/com.android.providers.settings

    具体解说:

    public class NotificationAccessSettings extends ManagedServiceSettings {
        private static final String TAG = NotificationAccessSettings.class.getSimpleName();
        private static final Config CONFIG = getNotificationListenerConfig();
    
        private static Config getNotificationListenerConfig() {
            final Config c = new Config();
            c.tag = TAG;
            /*Settings.Secure.ENABLED_NOTIFICATION_LISTENERS = 
             *数据库字段。通过读取数据库中字段推断应用是否有通知使用权。有则界面中应用相应的checkbox为勾选状态,
             *应用相应checkbox不勾选时,时用户勾选后会有提示框弹出。确定后通过此字段向数据库写入此应用信息。
             * */
            c.setting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
            c.intentAction = NotificationListenerService.SERVICE_INTERFACE;
            /*
             * 应用须要在manifest文件里声明这个服务权限才会被检測到, 才会显示到同一时候使用权界面
             * */
            c.permission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
            c.noun = "notification listener";
            /*用户勾选后弹出的dialog中的标题*/
            c.warningDialogTitle = R.string.notification_listener_security_warning_title;
            /*用户勾选后弹出的dialog中的内容*/
            c.warningDialogSummary = R.string.notification_listener_security_warning_summary;
            /*当前系统中不存在不论什么须要使用通知使用权的应用时,通知使用权界面会有相应提示*/
            c.emptyText = R.string.no_notification_listeners;
            return c;
        }
    
        @Override
        protected Config getConfig() {
            return CONFIG;
        }
    
        public static int getListenersCount(PackageManager pm) {
            return getServicesCount(CONFIG, pm);
        }
    
        public static int getEnabledListenersCount(Context context) {
            return getEnabledServicesCount(CONFIG, context);
        }
    }


    /packages/apps/Settings/src/com/android/settings/notification/ManagedServiceSettings.java

    public abstract class ManagedServiceSettings extends ListFragment {
        private static final boolean SHOW_PACKAGE_NAME = false;
    
        private final Config mConfig;
        private PackageManager mPM;
        private ContentResolver mCR;
    
        private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>();
        private ServiceListAdapter mListAdapter;
    
        abstract protected Config getConfig();
    
        public ManagedServiceSettings() {
            mConfig = getConfig();
        }
    
        private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                updateList();
            }
        };
        /*监听到应用的数量增减等改变时须要更新应用列表*/
        private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateList();
            }
        };
        /*用户勾选后弹出相应dialog等待用户进一步确认要为此应用打开通知使用权*/
        public class ScaryWarningDialogFragment extends DialogFragment {
            static final String KEY_COMPONENT = "c";
            static final String KEY_LABEL = "l";
    
            public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label) {
                Bundle args = new Bundle();
                args.putString(KEY_COMPONENT, cn.flattenToString());
                args.putString(KEY_LABEL, label);
                setArguments(args);
                return this;
            }
    
            @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                final Bundle args = getArguments();
                final String label = args.getString(KEY_LABEL);
                final ComponentName cn = ComponentName.unflattenFromString(args.getString(KEY_COMPONENT));
    
                final String title = getResources().getString(mConfig.warningDialogTitle, label);
                final String summary = getResources().getString(mConfig.warningDialogSummary, label);
                return new AlertDialog.Builder(getActivity())
                        .setMessage(summary)
                        .setTitle(title)
                        .setCancelable(true)
                        .setPositiveButton(android.R.string.ok,//
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        mEnabledServices.add(cn);//加入应用信息到HashSet<ComponentName>中
                                        saveEnabledServices();//数据库写操作
                                    }
                                })
                        .setNegativeButton(android.R.string.cancel,
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        // pass
                                    }
                                })
                        .create();
            }
        }
    
        @Override
        public void onCreate(Bundle icicle) {
            super.onCreate(icicle);
    
            mPM = getActivity().getPackageManager();
            mCR = getActivity().getContentResolver();
            mListAdapter = new ServiceListAdapter(getActivity());
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View v =  inflater.inflate(R.layout.managed_service_settings, container, false);
            TextView empty = (TextView) v.findViewById(android.R.id.empty);
            empty.setText(mConfig.emptyText);
            return v;
        }
    
        @Override
        public void onResume() {
            super.onResume();
            updateList();
    
            // listen for package changes
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_ADDED);//应用加入
            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);//应用改变
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);//应用卸载
            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);//应用更新
            filter.addDataScheme("package");
            getActivity().registerReceiver(mPackageReceiver, filter);
    
            mCR.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting),
                    false, mSettingsObserver);
        }
    
        @Override
        public void onPause() {
            super.onPause();
    
            getActivity().unregisterReceiver(mPackageReceiver);
            mCR.unregisterContentObserver(mSettingsObserver);
        }
        
        /*从数据库中载入拥有通知使用权的应用,并将其信息存入到HashSet<ComponentName>中。*/
        private void loadEnabledServices() {
            mEnabledServices.clear();//首先清空HashSet<ComponentName>。确保数据最新从数据库读取
            final String flat = Settings.Secure.getString(mCR, mConfig.setting);//数据库读操作
            if (flat != null && !"".equals(flat)) {
                final String[] names = flat.split(":");
                for (int i = 0; i < names.length; i++) {
                    final ComponentName cn = ComponentName.unflattenFromString(names[i]);
                    if (cn != null) {
                        mEnabledServices.add(cn);
                    }
                }
            }
        }
        /*数据库存操作*/
        private void saveEnabledServices() {
            StringBuilder sb = null;
            for (ComponentName cn : mEnabledServices) {
                if (sb == null) {
                    sb = new StringBuilder();
                } else {
                    sb.append(':');
                }
                sb.append(cn.flattenToString());
            }
            /*数据库存操作*/
            Settings.Secure.putString(mCR,
                    mConfig.setting,
                    sb != null ? sb.toString() : "");
        }
        /*更新应用显示列表*/
        private void updateList() {
            loadEnabledServices();
    
            getServices(mConfig, mListAdapter, mPM);
            mListAdapter.sort(new PackageItemInfo.DisplayNameComparator(mPM));
    
            getListView().setAdapter(mListAdapter);
        }
    
        protected static int getEnabledServicesCount(Config config, Context context) {
            final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting);
            if (flat == null || "".equals(flat)) return 0;
            final String[] components = flat.split(":");
            return components.length;
        }
    
        protected static int getServicesCount(Config c, PackageManager pm) {
            return getServices(c, null, pm);
        }
    
        private static int getServices(Config c, ArrayAdapter<ServiceInfo> adapter, PackageManager pm) {
            int services = 0;
            if (adapter != null) {
                adapter.clear();
            }
            final int user = ActivityManager.getCurrentUser();
    
            List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                    new Intent(c.intentAction),
                    PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                    user);
    
            for (int i = 0, count = installedServices.size(); i < count; i++) {
                ResolveInfo resolveInfo = installedServices.get(i);
                ServiceInfo info = resolveInfo.serviceInfo;
    
                if (!c.permission.equals(info.permission)) {
                    Slog.w(c.tag, "Skipping " + c.noun + " service "
                            + info.packageName + "/" + info.name
                            + ": it does not require the permission "
                            + c.permission);
                    continue;
                }
                if (adapter != null) {
                    adapter.add(info);
                }
                services++;
            }
            return services;
        }
    
        private boolean isServiceEnabled(ServiceInfo info) {
            final ComponentName cn = new ComponentName(info.packageName, info.name);
            return mEnabledServices.contains(cn);
        }
    
        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            ServiceInfo info = mListAdapter.getItem(position);
            final ComponentName cn = new ComponentName(info.packageName, info.name);
            if (mEnabledServices.contains(cn)) {
            	//取消勾选
                // the simple version: disabling
                mEnabledServices.remove(cn);
                saveEnabledServices();
            } else {
            	//选择勾选后填出dialog
                // show a scary dialog
                new ScaryWarningDialogFragment()
                    .setServiceInfo(cn, info.loadLabel(mPM).toString())
                    .show(getFragmentManager(), "dialog");
            }
        }
    
        private static class ViewHolder {
            ImageView icon;
            TextView name;
            CheckBox checkbox;
            TextView description;
        }
        
        /*用于应用列表载入显示*/
        private class ServiceListAdapter extends ArrayAdapter<ServiceInfo> {
            final LayoutInflater mInflater;
    
            ServiceListAdapter(Context context) {
                super(context, 0, 0);
                mInflater = (LayoutInflater)
                        getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            }
    
            public boolean hasStableIds() {
                return true;
            }
    
            public long getItemId(int position) {
                return position;
            }
    
            public View getView(int position, View convertView, ViewGroup parent) {
                View v;
                if (convertView == null) {
                    v = newView(parent);
                } else {
                    v = convertView;
                }
                bindView(v, position);
                return v;
            }
    
            public View newView(ViewGroup parent) {
                View v = mInflater.inflate(R.layout.managed_service_item, parent, false);
                ViewHolder h = new ViewHolder();
                h.icon = (ImageView) v.findViewById(R.id.icon);//应用图标
                h.name = (TextView) v.findViewById(R.id.name);//应用名
                h.checkbox = (CheckBox) v.findViewById(R.id.checkbox);//勾选框
                h.description = (TextView) v.findViewById(R.id.description);//应用描写叙述
                v.setTag(h);
                return v;
            }
    
            public void bindView(View view, int position) {
                ViewHolder vh = (ViewHolder) view.getTag();
                ServiceInfo info = getItem(position);
    
                vh.icon.setImageDrawable(info.loadIcon(mPM));
                vh.name.setText(info.loadLabel(mPM));
                if (SHOW_PACKAGE_NAME) {
                    vh.description.setText(info.packageName);
                    vh.description.setVisibility(View.VISIBLE);
                } else {
                    vh.description.setVisibility(View.GONE);
                }
                vh.checkbox.setChecked(isServiceEnabled(info));
            }
        }
    
        protected static class Config {
            String tag;
            String setting;
            String intentAction;
            String permission;
            String noun;
            int warningDialogTitle;
            int warningDialogSummary;
            int emptyText;
        }
    <p>}
    </p>

    数据库相关信息

    数据库字段相应应用信息格式:包名/service:包名/service。两应用间信息用”:“隔开。

  • 相关阅读:
    从IL角度彻底理解回调_委托_指针
    微信个人机器人开发
    个人微信接口开发
    淘客微信接口
    python爬虫添加请求头代码实例
    用 Django 开发一个 Python Web API
    Common encryption methods and implementation in Python Python中常用的加密方法及实现
    python aes加密
    # Python语言程序设计基础
    Python语言程序设计基础——4 程序的控制结构
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8729055.html
Copyright © 2020-2023  润新知