2、我们的apk有系统签名,这样可以直接操作授权的数据库,此方法也可以触发系统来绑定我们的服务。
public static void registerNotificationListener(Context context) { Log.i(tag, "----registerNotificationListener------"); String pkgName = context.getPackageName(); final String flat = Settings.Secure.getString(context.getContentResolver(), getNotificationListenerConfig().setting); StringBuilder sb = new StringBuilder(); boolean isEnable = false; 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 && TextUtils.equals(pkgName, cn.getPackageName())) { isEnable = true; break; } } } boolean writeSetting = false; if (isEnable) { sb.append(flat); //writeSetting = mNotifyService != null && !isServiceRun(context, NotificationListener.class.getName()); writeSetting = !isServiceRun(context); Log.i(tag, "mNotifyService: "+ mNotifyService + ", wirteSetting:" + writeSetting); } else { if (mNotifyService == null) { mNotifyService = new ComponentName(context, NotificationListener.class); } sb.append(flat).append(":").append(mNotifyService.flattenToString()); writeSetting = true; Log.i(tag, "writeSetting: " + writeSetting); } if (writeSetting) { Log.i(tag, "-----registerNotificationListener-----writeSetting----true-----"); /* * int index = sb.lastIndexOf(":"); if (index != -1) { sb.deleteCharAt(index); } */ // sb = new StringBuilder("com.qihoo.appstore/com.qihoo.appstore.AppStoreNotificationListenerService"); Log.i(tag, "-----registerNotificationListener-----writeSetting----true-----" + sb.toString()); try { Settings.Secure.putString(context.getContentResolver(), getNotificationListenerConfig().setting, sb != null ? sb.toString() : ""); } catch (Exception e) { e.printStackTrace(); // 发生异常,说明无权限(使用普通方法重新绑定服务) enableNotificationListener(context); } } else { Log.i(tag, "-----registerNotificationListener-----writeSetting----false---isrunning--"); } // Intent service = new Intent(context, NotificationMonitor.class); // context.startService(service); } private static Config getNotificationListenerConfig() { final Config c = new Config(); c.setting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; c.intentAction = NotificationListenerService.SERVICE_INTERFACE; c.permission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; c.noun = "notification listener"; return c; } protected static class Config { String tag; String setting; String intentAction; String permission; String noun; int warningDialogTitle; int warningDialogSummary; int emptyText; } 检查服务是否授权: public static boolean isNotificationListenerServiceEnabled(Context context) { Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context); return packageNames.contains(context.getPackageName()); } 判断服务是否启动: public static boolean isServiceRun(Context context) { boolean isRun = false; ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(Integer.MAX_VALUE); if (serviceList != null && serviceList.size() > 0) { for (ActivityManager.RunningServiceInfo info : serviceList) { if (info.service.getClassName().equals(NotificationListener.class.getName())) { isRun = true; break; } } } return isRun; } 另外有些特殊情况,我们的app被系统杀死,或是发生crash后如何使系统再次绑定这个服务呢? 有三种方式可以触发: 1. 重启手机 2. 有卸载更新或覆盖安装 3. Setting数据库变更。 其中我们可以主动去触发方式2,即 主动去触发广播(Service的disable,会有Intent.ACTION_PACKAGE_CHANGED广播) 利用这一特性,把应用的NotificationListenerService实现类disable再enable,即可触发系统onBind操作。 PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(new ComponentName(context, NotificationListener.class), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(new ComponentName(context, NotificationListener.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); 另外一种更特殊的: 一旦我们在执行service的onCreate或是onBind之前发生了crash,那么必须重启手机才能使用该服务。 因为NotificationManagerService会记录该service, 这是个系统服务类,只有再次重启才能清除这个记录标志。