Android之调节屏幕亮度

一、需求分析

在使用微信或者支付宝的付款码支付时,若是你点击放大付款码,就会跳转到一个新的页面去显示大尺寸的付款码,并且你会发现屏幕变亮了,这样会便于扫码机识别你的付款码。当你付款成功退出付款码放大的界面后,屏幕就会恢复到原先的亮度。我很早就注意到了这点,因此当我本身的项目须要作二维码点击放大功能时,我也在放大的同时把屏幕的界面调亮一点。尽管我当时比较轻松地实现了这个功能,可是当我编写屏幕亮度工具类时,发现里面其实内有乾坤。如今就让咱们来系统学习一下。java

首先咱们要明确“屏幕亮度”是什么。它其实包含了两种状况:android

  1. 当前窗口的亮度。若是只改变当前窗口的亮度的话,当你退出该窗口(好比销毁了当前的Activity或者干脆退出了应用),那么屏幕就会恢复原先的亮度。也就是说,此处的改变只对当前的窗口有效。微信或支付宝在点击放大付款码后,改变的就是这个。
  2. 改变系统屏幕亮度。在下拉的手机设置面板中,有一个改变屏幕亮度的进度条(下图中的红框),这里改变的就是系统的屏幕亮度,适用于全部的窗口。

下来设置面板

二、准备工做

建立一个BrightnessActivity,而后在里面放置两个进度条,一个改变系统亮度,一个改变窗口亮度。为了便于之后使用,咱们会把用到的方法都封装到一个工具类中。因此再建立一个名称为BrightnessUtil的Kotlin文件,可是不要建立类,由于咱们会使用扩展成员的方式来编写工具类。git

舒适提示:最近大半年都在使用Kotlin,这实在是一门很棒的语言,推荐你们学习。之后的博客我通常都会使用Kotlin了。

三、改变当前窗口亮度

首先来看看怎么改变窗口亮度。十分简单,只需改变窗口属性中的屏幕亮度(screenBrightness)一项。让咱们直接来看代码:github

/**
 * 当前窗口亮度
 * 范围为0~1.0,1.0时为最亮,-1为系统默认设置
 */
var Activity.windowBrightness
    get() = window.attributes.screenBrightness
    set(brightness) {
        //小于0或大于1.0默认为系统亮度
        window.attributes = window.attributes.apply {
            screenBrightness = if (brightness > 1.0 || brightness < 0) -1.0F else brightness
        }
    }

改变窗口亮度的上下文必须是Activity,因此我给Activity加了一个扩展属性windowBrightness,它的值就是当前的窗口亮度,改变它的值就能够改变窗口亮度。它的范围是0~1.0,从0到1.0亮度逐渐增大;若是赋值为-1,那就表示跟随系统的亮度。segmentfault

使用起来也很简单:微信

tvWindowBright.text = "当前窗口亮度=$windowBrightness"
        sbWindowBright.progress = if (windowBrightness > 0) (windowBrightness * 100).toInt() else 0
        sbWindowBright.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                windowBrightness = progress.toFloat() / 100F
                tvWindowBright.text = "当前窗口亮度=$windowBrightness"
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
            }

        })

没有接触过Kotlin的小伙伴们可能会不知道这属性在Java中怎么用?毕竟咱们连类名都没有看到。其实Kotlin会默认为Java生成一个“类名+kt”的类,属性则会生成getter和setter静态方法。因此在Java代码中只须要 这么写:app

BrightnessUtilKt.getWindowBrightness(Activity);
        BrightnessUtilKt.setWindowBrightness(Activity,brightness);

四、改变系统亮度

比起改变窗口亮度,改变系统亮度就要麻烦一点了。做为我的,咱们改变世界都是不容易的,那么一个应用想要改变系统天然也不会垂手可得。ide

4.1 清单文件申请权限

第一步,咱们须要到AndroidManifest.xml中申请权限:函数

<uses-permission android:name="android.permission.WRITE_SETTINGS"
        tools:ignore="ProtectedPermissions" />

之因此加上tools:ignore="ProtectedPermissions"是由于改变系统设置的权限通常只归系统App全部,因此编译器会报一个警告,加上这个能够忽略警告。工具

4.2 申请动态权限

若是你的手机系统是Android6.0以上的,那么还得动态申请权限。系统设置权限的动态申请有点特别,它须要跳转到系统的“可修改系统设置”界面,让用户决定是否容许当前应用修改系统设置,而后再在onActivityResult中处理回调结果。

咱们在进入BrightnessActivity时就动态申请权限,代码以下:

//修改系统屏幕亮度须要修改系统设置的权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //若是当前平台版本大于23平台
            if (!Settings.System.canWrite(mContext)) {
                val intent = with(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)) {
                    data = Uri.parse("package:$packageName")
                    this
                }
                startActivityForResult(intent, RQ_WRITE_SETTINGS)
            } else {
                changeSystemBrightness()
            }
        } else {
            //Android6.0如下的系统则直接修改亮度
            changeSystemBrightness()
        }

首先调用Settings.System.canWrite(Context)判断手机系统,Android6.0如下的直接容许修改亮度的操做;Android6.0以上的则要进一步判断是否已经得到了修改系统设置的权限,没有的话就要打开以下界面去设置。

修改系统设置界面

不管用户是否受权,咱们都须要一个回调,这时onActivityResult就能够派上用场了:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            RQ_WRITE_SETTINGS -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (Settings.System.canWrite(mContext)) {
                        shortToast("已获取权限")
                        changeSystemBrightness()
                    } else {
                        shortToast("你拒绝了权限")
                    }
                }
            }
        }
    }

代码很简单,就不作过多解释了。

4.3 去除自动亮度

前面咱们虽然解决了权限问题,可是还要考虑到一个实际状况,那就是用户可能会设置了自动亮度,在这个前提下是没法改变系统屏幕亮度的。因此这里要作两步处理:

  1. 判断用户是否开启了自动亮度;
  2. 若是当前开启了自动亮度,则须要将其关闭。

4.3.1 判断是否自动亮度

咱们在工具类中添加isAutoBrightness属性,它只有Getter方法,返回一个布尔值。这里调用Settings.System.getInt()方法,第二个参数传入 Settings.System.SCREEN_BRIGHTNESS_MODE表示咱们要获取系统屏幕亮度模式,若是是Settings.System.SCREEN_BRIGHTNESS_MODE,则表示当前自动亮度模式。

val isAutoBrightness:Boolean
    get() = try {
        Settings.System.getInt(
            AndUtil.appContext.contentResolver,
            Settings.System.SCREEN_BRIGHTNESS_MODE
        ) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
    } catch (e: Settings.SettingNotFoundException) {
        e.printStackTrace()
        false
    }

4.3.2 设置开启和关闭自动亮度

前面咱们获取了系统亮度模式,经过设置它的值,咱们就能够控制自动亮度模式的开关了。
在工具类中建立一个setAutoBrightness()函数,若是设置成功就返回true。这里用到的是Settings.System.putInt(),第二个参数即为咱们要设置的亮度模式。当参数enable为true时就是自动模式了。

/**
 * 设置是否开启自动亮度
 * @param enable : 为true时开启,false时关闭
 * @return 设置成功返回true
 */
fun setAutoBrightness(enable: Boolean) = Settings.System.putInt(
    AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
    if (enable) Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC else Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
)

4.4 封装改变系统屏幕亮度属性

如今咱们总算能够编写修改系统亮度的代码了。跟修改窗口亮度同样,咱们这里也使用了一个属性,命名为systemBrightness

/**
 * 系统屏幕亮度,须要WRITE_SETTINGS权限,并在代码中申请系统设置权限
 * 范围为0~255
 */
var systemBrightness
    get() = try {
        Settings.System.getInt(AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS)
    } catch (e: Settings.SettingNotFoundException) {
        e.printStackTrace()
        -1
    }
    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
    set(@IntRange(from = 0, to = 255) brightness) {
        if (isAutoBrightness) {
            //若是当前是自动亮度,则关闭自动亮度
            setAutoBrightness(false)
        }
        val uri = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)
        Settings.System.putInt(AndUtil.appContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness)
        AndUtil.appContext.contentResolver.notifyChange(uri, null)
    }

这里咱们重点来看设置系统亮度,也就是set()里面的代码。首先判断当前是否开启了自动亮度模式,若是是则将其关闭。后面的代码相似于setAutoBrightness(),都是在Settings.System.putInt()中赋值,不一样的是还要调用Context.contentResolver.notifyChange()方法去通知系统咱们已经修改了屏幕亮度,这样设置的值才会起做用。另外,要注意系统屏幕亮度的取值范围是0~255。

最后固然是设置SeekBar的监听了:

private fun changeSystemBrightness() {
        sbSystemBright.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                systemBrightness = progress * 255 / 100
                tvSystemBright.text = "系统亮度=$systemBrightness"
            }


            override fun onStartTrackingTouch(seekBar: SeekBar?) {
            }


            override fun onStopTrackingTouch(seekBar: SeekBar?) {
            }

        })
    }

实现的效果以下:

效果

视频录制看不出亮度的变化,但真机上是没有问题的。

五、后记

本文分析了屏幕亮度的类型,并给出了设置的方法。其中,设置系统屏幕亮度时要格外注意动态权限申请和自动亮度模式的影响。

最后给一下主要的源码:

BrightnessUtil

BrightnessActivity

相关文章
相关标签/搜索