ITmob-Ly
发布于 2023-08-26 / 142 阅读
0

Android 中使用 Jetpack Compose 开发时怎样用代码更改屏幕亮度?

Change brightness level in Android

当我们打开需要显示二维码的页面或播放视频时需要增加屏幕的亮度。比如,支付宝、微信之类需要出示二维码进行刷卡的场景,需要提高屏幕亮度。

本文将介绍怎样使用代码调整屏幕亮度。

1. 只改变当前页面的亮度

最简单的方法是只调整当前页面的屏幕亮度,而不影响系统的亮度设置。通过修改当前 Activity 的 window 属性修改屏幕亮度,只会在当前页面生效,退出该 Activity 后亮度会恢复。

1.1 设置窗口的 screenBrightness 属性,如下所示:

class QrCodeActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.attributes.apply {
            screenBrightness = 1F
            window.attributes = this
        }
    }
}

screenBrightness 属性是一个范围从 0 到 1 的 Float 类型值,其中 0.0 表示 0% 亮度,1.0 表示 100% 亮度。

对于大多数应用场景,这种方式修改屏幕亮度已经够用了,不需要修改系统级别的亮度,更不需要申请权限。

1.2 在 Composable 方法中修改亮度

上例是在 Activity 中调用 window 属性来实现亮度调整。而在使用 Jetpack Compose 时,如何在 Composable 可组合函数中来调整屏幕亮度呢?

重点是在可组合函数中获取 Activity 实例,之前的文章:Jetpack Compose 中如何在 Composable 可组合函数中获取当前 Activity?Jetpack Compose 中如何在 Composable 可组合函数中获取 Activity 的 Window 属性? 介绍了在 Jetpack Compose 的可组合项中如何获取和操作 Activity 和 Window。

// 获取 Activity 的扩展函数
internal fun Context.findActivity(): Activity {
    var context = this
    while (context is ContextWrapper) {
        if (context is Activity) return context
        context = context.baseContext
    }
    throw IllegalStateException("Permissions should be called in the context of an Activity")
}

@Composable
fun ScreenBrightnessSample() {
    val window = LocalContext.current.findActivity().window
    Button(
        onClick = {
            // 改变屏幕亮度
            window.attributes.apply {
                screenBrightness = 1F
                window.attributes = this
            }
        },
    ) {
        Text(text = "Change Screen Brightness")
    }
}

2. 改变系统的亮度设置

第二种方法就是修改系统设置从而实现对亮度的修改,这种修改会对系统的所有页面生效。

Android 6(API level 23)开始修改系统设置需要 WRITE_SETTINGS 权限,需要检查是否获得授权,如果没有授权需要弹出授权页面经过用户授权来让我们的应用拥有修改系统设置的权限。或者我们的应用拥有系统签名,默认就拥有 WRITE_SETTINGS 权限。

2.1 在 Android Manifest 中添加 WRITE_SETTINGS 权限

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

2.2 申请用户授权

判断当前设备是否是 Android 6 及更高版本,如果没有权限则申请授权

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (!Settings.System.canWrite(context)) {
        val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
        intent.data = Uri.parse("package:" + context.packageName)
        context.startActivity(intent)
    }
}

Request permission to modify system settings

2.3 如果已经获取授权,修改系统设置:

// 判断是否是 Android 6 及更高版本,判断是否授权
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (!Settings.System.canWrite(context)) {
        val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
        intent.data = Uri.parse("package:" + context.packageName)
        context.startActivity(intent)
    } else {
        changeScreenBrightness(context)
    }
}

// 修改系统的亮度值设置,由系统处理设备亮度
private fun changeScreenBrightness(context: Context) {
    Settings.System.putInt(
        context.contentResolver,
        Settings.System.SCREEN_BRIGHTNESS,
        200,
    )
    val uriForBrightness = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)
    context.contentResolver.notifyChange(uriForBrightness, null)
}

brightness 值应在 0–255 范围内

2.4 Android 5 及更低版本

Android 5(API level 22)及更低版本中怎样修改系统的亮度设置呢?

Android 5 及更低版本中不需要申请 WRITE_SETTINGS 权限,直接设置即可。

但是在低版本中如果想通过修改系统设置改变设备的屏幕亮度,需要先将屏幕亮度自动调节关闭,调整到手动调节亮度的模式,对系统亮度的更改才会生效

// 判断屏幕亮度是否为手动调节模式,如果是自动模式,修改为手动调节
private fun changeBrightnessToManualMode(context: Context) {
    val brightnessMode = Settings.System.getInt(
        context.contentResolver,
        Settings.System.SCREEN_BRIGHTNESS_MODE,
    )
    if (Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC == brightnessMode) {
        Settings.System.putInt(
            context.contentResolver,
            Settings.System.SCREEN_BRIGHTNESS_MODE,
            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
        )
        val uriForBrightnessMode = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE)
        context.contentResolver.notifyChange(uriForBrightnessMode, null)
    }
}

修改屏幕亮度的调节模式也是对系统设置的修改,在 Android 5 及以前版本中不需要申请权限

2.5 在 Android 5 中调节系统的屏幕亮度设置

这里的代码与 2.3 介绍的在高版本中的代码一样

// 修改系统的亮度值设置,由系统处理设备亮度
private fun changeScreenBrightness(context: Context) {
    Settings.System.putInt(
        context.contentResolver,
        Settings.System.SCREEN_BRIGHTNESS,
        200,
    )
    val uriForBrightness = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)
    context.contentResolver.notifyChange(uriForBrightness, null)
}

3. 完整代码(修改屏幕亮度系统设置)

下面是上面第二节中介绍的怎样修改系统级别的屏幕亮度的完整代码。本适配了 Android 6 (API level 23) 及以上的高版本和 Android 6 (API level 23) 一下的低版本(本例对低版本的适配是在 Android 5 中测试的)。

@Composable
fun ChangeBrightnessSetting() {
    val context = LocalContext.current
    Button(
        onClick = {
            // 判断是否是 Android 6 及更高版本,判断是否授权
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.System.canWrite(context)) {
                    val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
                    intent.data = Uri.parse("package:" + context.packageName)
                    context.startActivity(intent)
                } else {
                    changeScreenBrightness(context)
                }
            } else {
                // 判断屏幕亮度是否为手动调节模式,如果是自动模式,修改为手动调节
                changeBrightnessToManualMode(context)
                // 修改系统的亮度值设置,由系统处理设备亮度
                changeScreenBrightness(context)
            }
        },
    ) {
        Text(text = "Change Screen Brightness Setting")
    }
}

private fun changeScreenBrightness(context: Context) {
    Settings.System.putInt(
        context.contentResolver,
        Settings.System.SCREEN_BRIGHTNESS,
        200,
    )
    // 调用 notifyChange, 部分设备只对 Settings 的修改并不生效
    val uriForBrightness = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)
    context.contentResolver.notifyChange(uriForBrightness, null)
}

private fun changeBrightnessToManualMode(context: Context) {
    val brightnessMode = Settings.System.getInt(
        context.contentResolver,
        Settings.System.SCREEN_BRIGHTNESS_MODE,
    )
    if (Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC == brightnessMode) {
        Settings.System.putInt(
            context.contentResolver,
            Settings.System.SCREEN_BRIGHTNESS_MODE,
            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
        )
        val uriForBrightnessMode = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE)
        context.contentResolver.notifyChange(uriForBrightnessMode, null)
    }
}

上面代码实现了对屏幕亮度和亮度调节模式的修改,真实项目开发中可能还会需要考虑缓存修改前的模式和亮度值,完成业务逻辑后将亮度和模式恢复。

总结

本文介绍了 Android 中使用 Jetpack Compose 开发时怎样改变屏幕亮度(当前页面的亮度和系统级别的亮度设置),并且对于系统级别的亮度设置,在低版本的 Android 系统中怎样适配也做了介绍。

本文的开发环境时 Jetpack Compose,如果使用传统的视图时一样的,只修改当前也的亮度时获取 Activity 的 Window 属性更方便。