Android 勿扰模式【Do Not Disturb】

前言

最近使用客户的launcher设置音量时,会弹出一个界面,用于授权,用于给【勿扰模式】进行授权。

授权界面的源码

通过adb shell 指令获取当前的包名和界面,发现显示如下:

com.android.Settings.Settings$ZenAccessSettingsActivity

明显界面已经跳转到了原生setting app,一番搜索,该界面的实现源码如下:

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

在这里,主要通过如下方法获取所有需要勿扰权限的app:

private void reloadList() {
    final PreferenceScreen screen = getPreferenceScreen();
    screen.removeAll();
    final ArrayList<ApplicationInfo> apps = new ArrayList<>();
    final ArraySet<String> requesting = getPackagesRequestingNotificationPolicyAccess();
    if (!requesting.isEmpty()) {
        final List<ApplicationInfo> installed = mPkgMan.getInstalledApplications(0);
        if (installed != null) {
            for (ApplicationInfo app : installed) {
                if (requesting.contains(app.packageName)) {
                    apps.add(app);
                }
            }
        }
    }
    ArraySet<String> autoApproved = new ArraySet<>();
    autoApproved.addAll(mNoMan.getEnabledNotificationListenerPackages());
    requesting.addAll(autoApproved);
    Collections.sort(apps, new PackageItemInfo.DisplayNameComparator(mPkgMan));
    for (ApplicationInfo app : apps) {
        final String pkg = app.packageName;
        final CharSequence label = app.loadLabel(mPkgMan);
        final SwitchPreference pref = new AppSwitchPreference(getPrefContext());
        pref.setKey(pkg);
        pref.setPersistent(false);
        pref.setIcon(app.loadIcon(mPkgMan));
        pref.setTitle(label);
        pref.setChecked(hasAccess(pkg));
        if (autoApproved.contains(pkg)) {
            pref.setEnabled(false);
            pref.setSummary(getString(R.string.zen_access_disabled_package_warning));
        }
        pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                final boolean access = (Boolean) newValue;
                if (access) {
                    new ScaryWarningDialogFragment()
                            .setPkgInfo(pkg, label)
                            .show(getFragmentManager(), "dialog");
                } else {
                    new FriendlyWarningDialogFragment()
                            .setPkgInfo(pkg, label)
                            .show(getFragmentManager(), "dialog");
                }
                return false;
            }
        });
        screen.addPreference(pref);
    }
}

这里可以获取到所有需要授权的app,接着需要用户去点击开关进行授权,这里授权的主要方法如下:

private static void setAccess(final Context context, final String pkg, final boolean access) {
    logSpecialPermissionChange(access, pkg, context);
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            final NotificationManager mgr = context.getSystemService(NotificationManager.class);
            mgr.setNotificationPolicyAccessGranted(pkg, access);
        }
    });
}

该方法的关键实现是如下函数:

mgr.setNotificationPolicyAccessGranted(pkg, access);

通过搜索发现,mgr定义如下“

final NotificationManager mgr = context.getSystemService(NotificationManager.class);

这么看来,想要不弹出授权界面,在系统起来的时候,给该应用进行授权即可。这次选择在自己开发的系统服务中进行授权;

final NotificationManager mgr = context.getSystemService(NotificationManager.class);
mgr.setNotificationPolicyAccessGranted(pkg, access);

到此可解决该问题。

需要注意的是,应用需要先在AndroidManifest.xml中申请如下权限:

android.permission.ACCESS_NOTIFICATION_POLICY
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 以形势为身体,以泉水为血脉,以土地为皮肉,以草木为毛发,以屋舍为衣服,以门户为冠带,是事严稚,乃为上吉。 理气派:...
    vivy_c96e阅读 3,966评论 0 2
  • 准备工作:(推荐写法) 标签中没有包含传统的type="text/java script"。因为这里脚本默认了。 ...
    Chenkann阅读 864评论 0 0
  • es6 的解构赋值 - 1.解构的理解就是:解析结构。也就是被解析一方和被赋值一方的形式要相同。
    人生不过尔尔阅读 1,618评论 0 0
  • “被围困的城堡,城外的人想进去,城里的人想逃出来。”这句话出自钱钟书先生所著的《围城》。小说的主干是围绕...
    zxyw0447见安阅读 2,642评论 1 1