Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之通知使用權

Android之通知使用權

編輯:關於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

詳細講解:

/packages/apps/Settings/src/com/android/settings/notification/NotificationAccessSettings.java
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 mEnabledServices = new HashSet();
    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中
                                    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中。*/
    private void loadEnabledServices() {
        mEnabledServices.clear();//首先清空HashSet,確保數據最新從數據庫讀取
        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 adapter, PackageManager pm) {
        int services = 0;
        if (adapter != null) {
            adapter.clear();
        }
        final int user = ActivityManager.getCurrentUser();

        List 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 {
        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;
    }

}

 

數據庫相關信息

\

數據庫字段對應應用信息格式:包名/service:包名/service。兩應用間信息用”:“隔開。

  1. 上一頁:
  2. 下一頁: