在使用微信或者支付寶的付款碼支付時,若是你點擊放大付款碼,就會跳轉到一個新的頁面去顯示大尺寸的付款碼,並且你會發現屏幕變亮了,這樣會便於掃碼機識別你的付款碼。當你付款成功退出付款碼放大的界面後,屏幕就會恢復到原先的亮度。我很早就注意到了這點,因此當我本身的項目須要作二維碼點擊放大功能時,我也在放大的同時把屏幕的界面調亮一點。儘管我當時比較輕鬆地實現了這個功能,可是當我編寫屏幕亮度工具類時,發現裏面其實內有乾坤。如今就讓咱們來系統學習一下。java
首先咱們要明確「屏幕亮度」是什麼。它其實包含了兩種狀況:android
建立一個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
第一步,咱們須要到AndroidManifest.xml中申請權限:函數
<uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />
之因此加上tools:ignore="ProtectedPermissions"
是由於改變系統設置的權限通常只歸系統App全部,因此編譯器會報一個警告,加上這個能夠忽略警告。工具
若是你的手機系統是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("你拒絕了權限") } } } } }
代碼很簡單,就不作過多解釋了。
前面咱們雖然解決了權限問題,可是還要考慮到一個實際狀況,那就是用戶可能會設置了自動亮度,在這個前提下是沒法改變系統屏幕亮度的。因此這裏要作兩步處理:
咱們在工具類中添加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 }
前面咱們獲取了系統亮度模式,經過設置它的值,咱們就能夠控制自動亮度模式的開關了。
在工具類中建立一個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 )
如今咱們總算能夠編寫修改系統亮度的代碼了。跟修改窗口亮度同樣,咱們這裏也使用了一個屬性,命名爲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?) { } }) }
實現的效果以下:
視頻錄製看不出亮度的變化,但真機上是沒有問題的。
本文分析了屏幕亮度的類型,並給出了設置的方法。其中,設置系統屏幕亮度時要格外注意動態權限申請和自動亮度模式的影響。
最後給一下主要的源碼: