1. 程式人生 > >Android背光亮度調節

Android背光亮度調節

最近在做一個App的設定項,亮度調節。真正做時,發現Android亮度調節比預想要複雜一些。其實目前網上已有不少這方面的資料,但有些博文具有一定誤導性。在此將這塊內容按照自己理解整理一下。

整體上看,Android亮度調節分為三個層次,分別是:Android系統亮度調節、Android App亮度調節和Android當前螢幕(Window)亮度調節。

1.Android系統亮度調節

Android系統亮度調節全域性性最高,常見於系統設定中的亮度設定項。Android中提供了獲取和設定系統亮度值(“手動模式下的亮度值”)的介面,具體如下:

1 // 獲取系統亮度
2 Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
1 // 設定系統亮度
2 Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,systemBrightness);

其中,需要注意的是,返回的亮度值是處於0-255之間的整型數值。

Android 2.1以後的系統中,系統亮度調節中新增了“自動亮度”選項。“自動亮度”是依據外界光源來自動的改變系統亮度,目前大部分手機中對“自動亮度”還可以進行小幅度的調節其值。與自動亮度相對應的是“手動亮度”,當處於“手動亮度”下,設定拖動亮度進度條會大幅度的改變Android系統亮度。“手動亮度”和“自動亮度”分別稱之為Android系統的“亮度模式”。

與之相對應的,Android系統中也提供了獲取和設定“亮度模式”的介面。

1 // 獲取系統亮度模式
2 Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
1 // 設定系統亮度模式
2 Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, systemMode);

可是遺憾的是,Android中並未提供處於“自動亮度”模式下的亮度值介面。上面所說的獲取系統亮度值介面實際上都是指“手動亮度”模式下的亮度值。

一般而言,通過手動亮度值以及設定系統亮度模式介面,可以滿足常規的大部分針對Android系統亮度設定編碼需求,以完成系統亮度調節。

2.Android App亮度調節

與系統亮度不同的是,Android中並未直接提供針對於App層面的亮度調節方式。因此,對於需要進行App的亮度調節,可以通過系統亮度調節或當前螢幕的亮度調節方式間接來實現。

3.Android當前螢幕(Window)亮度調節

Android針對當前螢幕(Window)提供了設定亮度的介面,常見寫法如下:

1 Window window = activity.getWindow();
2 WindowManager.LayoutParams lp = window.getAttributes();
3 lp.screenBrightness = brightness;
4 window.setAttributes(lp);

其中,需要注意的是此處的brightness是一個0.0-1.0之間的一個float型別數值。

預設情況下,當我們直接修改了系統亮度值後,當前Window中是可以即時反應出來亮度效果的,這是因為預設情況下,WindowManager.LayoutParams的screenBrightness的預設值為WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE。

即表示Window沒有自己的亮度引數,將依隨系統亮度效果的變化而變化。這也就是我們最常見的:當調整系統亮度後,所有Window都即時反應出系統亮度設定效果。

當時,實際專案中我們還會遇到此類需求:系統設定亮度時只針對當前Window或App內生效,而不影響到系統本身的亮度設定。

假設當前Window內有一個SeekBar,UI與系統亮度調節UI基本類似,使用者可以滑動此SeekBar,使得當前Window亮度即時發生變化,且不影響到系統亮度效果。如何實現呢?

此時我們需要啟用WindowManager.LayoutParams的screenBrightness引數,使之具有自動的特定亮度值,設定此值後在當前Window範圍內,其將覆蓋掉系統亮度設定。

因此,有必要將使用者選擇的亮度值轉換為相應的Window亮度值(為與系統亮度值相一致,假設SeekBar的最大值為255)。

複製程式碼
 1 // 根據亮度值修改當前window亮度
 2 public void changeAppBrightness(Context context, int brightness) {
 3     Window window = ((Activity) context).getWindow();
 4     WindowManager.LayoutParams lp = window.getAttributes();
 5     if (brightness == -1) {
 6         lp.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
 7     } else {
 8         lp.screenBrightness = (brightness <= 0 ? 1 : brightness) / 255f;
 9     }
10     window.setAttributes(lp);
11 }
複製程式碼

其中,brightness形參為使用者選擇的亮度值。

那麼,上述程式碼中為什麼有一個"brightness == -1"的判斷呢?在此主要是考慮到App設定項中可能出現的“跟隨系統亮度”或“恢復系統預設亮度”此類設定,當用戶進行此類操作時,直接將screenBrightness引數還原成預設引數值即可。因為由前文描述“自動亮度”模式下系統亮度值是不能直接得到的,那麼當系統處於“自動亮度”模式下,此時brightness引數值將無法準確確定,因此,將screenBrightness引數還原成預設引數值成為一個行之有效的方法。

4.Android App亮度調節可行方案分析

目前網上有不少博文中提到App亮度調節時,提出的方案是在App設定項中,首先記錄下設定之前的系統亮度值和亮度模式,使用者在App設定項進行亮度調節時,直接修改系統亮度值,當用戶退出此App,或App至於後臺(如按下Home按鍵等),再將系統亮度還原。初看起來貌似一個可行的方案。但是主要存在如下幾個問題:

1.如何獲取到設定之前的系統亮度值和亮度模式(因為之後在此App外部要恢復系統亮度值到此初始值)?當用戶每次進入到設定頁時獲取?嚴格意義上來說,是沒法準確記錄的。因為Android的使用者操作不可預知性,如進入到設定頁,拖動SeekBar設定了一個亮度值,此時直接修改了系統的亮度值,如果此時使用者在未將應用至於後臺或未將應用退出的情況下直接在App外部修改了系統亮度設定,如小米中可以通過下拉標題欄,直接就可以設定系統亮度。因此,App亮度設定之前的系統亮度初始值獲取存在困難。

2.如何判斷使用者來到了App外部?因為此時需要恢復系統亮度設定到初始系統亮度。如使用者可以按下Home按鍵,長按Home按鍵直接切換App,直接Back按鍵等一步步退出此App,下拉標題欄直接點選其他App通知資訊進入到其他App,手機自動鎖屏後解鎖時使用者直接進入其他應用等等,此類操作場景也具有不可預知性,因此,判斷使用者來到了App外部以恢復系統亮度到初始值的時機上也存在一定困難。

由此,App亮度調節方案推薦通過設定當前螢幕(Window)方式進行。

大致思路如下:使用者在設定項中進行亮度調節時,呼叫changeAppBrightness()方法,將改變當前螢幕(Window)的亮度,此時對系統亮度無任何影響,接下來存在的問題終於要就集中於當用戶來到本App其他Activity中,如果使得剛剛設定的亮度值得以即時反應出來。

 當用戶進行亮度調節後,將當前亮度設定值儲存起來(如儲存到SharedPreferences中),在基類Activity中的onResume方法中,可以取出SharedPreferences中的使用者所設定的App亮度值,然後changeAppBrightness()方法以實現每個當前螢幕的亮度調節。

 總體說來,通過設定當前螢幕(Window)的方式來設定App亮度更加簡單有效。