Android中所有系统灯光的定义:lights.h
#define LIGHT_ID_BACKLIGHT “backlight”
JNI: com_android_server_lights_LightsService.cpp
setLight_native:调用HAL去控制背光
Service:LightsService.java
1.它是各种灯光和背光的Service,提供了对背光灯操作的所有方法
2.setLightLocked():是实际调用JNI操作背光灯的函数,所有向应用程序公开的LCD操作接口都使用synchronized (this){… setLightLocked() …}
确保互斥访问硬件。
3.onStart()中:publishLocalService(LightsManager.class, mService);
先分析DisplayPowerController.java
//位于\frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
private void initialize() {
// Initialize the power state object for the default display.
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
new ColorFade(Display.DEFAULT_DISPLAY));
...
}
查看DisplayPowerState构造函数
public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
77 mHandler = new Handler(true /*async*/);
78 mChoreographer = Choreographer.getInstance();
79 mBlanker = blanker;
80 mBacklight = backlight;
81 mColorFade = electronBeam;
82 mPhotonicModulator = new PhotonicModulator();
83 mPhotonicModulator.start();
84
85 // At boot time, we know that the screen is on and the electron beam
86 // animation is not playing. We don't know the screen's brightness though,
87 // so prepare to set it to a known state when the state is next applied.
88 // Although we set the brightness to full on here, the display power controller
89 // will reset the brightness to a new level immediately before the changes
90 // actually have a chance to be applied.
91 mScreenState = Display.STATE_ON;
92 mScreenBrightness = PowerManager.BRIGHTNESS_ON;
93 scheduleScreenUpdate();
94
95 mColorFadePrepared = false;
96 mColorFadeLevel = 1.0f;
97 mColorFadeReady = true;
98 }
构造函数中
下面分析PhotonicModulator线程
private final class PhotonicModulator extends Thread {
341 private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
342 private static final int INITIAL_BACKLIGHT = -1; // unknown
343
344 private final Object mLock = new Object();
345
346 private int mPendingState = INITIAL_SCREEN_STATE;
347 private int mPendingBacklight = INITIAL_BACKLIGHT;
348 private int mActualState = INITIAL_SCREEN_STATE;
349 private int mActualBacklight = INITIAL_BACKLIGHT;
350 private boolean mChangeInProgress;
351
352 public boolean setState(int state, int backlight) {
353 synchronized (mLock) {
354 if (state != mPendingState || backlight != mPendingBacklight) {
355 if (DEBUG) {
356 Slog.d(TAG, "Requesting new screen state: state="
357 + Display.stateToString(state) + ", backlight=" + backlight);
358 }
359
360 mPendingState = state;
361 mPendingBacklight = backlight;
362
363 if (!mChangeInProgress) {
364 mChangeInProgress = true;
365 mLock.notifyAll();
366 }
367 }
368 return !mChangeInProgress;
369 }
370 }
371
384 @Override
385 public void run() {
386 for (;;) {
387 // Get pending change.
388 final int state;
389 final boolean stateChanged;
390 final int backlight;
391 final boolean backlightChanged;
392 synchronized (mLock) {
393 state = mPendingState;
394 stateChanged = (state != mActualState);
395 backlight = mPendingBacklight;
396 backlightChanged = (backlight != mActualBacklight);
397 if (!stateChanged && !backlightChanged) {
398 // All changed applied, notify outer class and wait for more.
399 mChangeInProgress = false;
400 postScreenUpdateThreadSafe();
401 try {
402 mLock.wait();//这里线程会睡眠
403 } catch (InterruptedException ex) { }
404 continue;
405 }
406 mActualState = state;
407 mActualBacklight = backlight;
408 }
409
410 // Apply pending change.
411 if (DEBUG) {
412 Slog.d(TAG, "Updating screen state: state="
413 + Display.stateToString(state) + ", backlight=" + backlight);
414 }
415 boolean suspending = Display.isSuspendedState(state);
416 if (stateChanged && !suspending) {
417 requestDisplayState(state);
418 }
419 if (backlightChanged) {
420 setBrightness(backlight);
421 }
422 if (stateChanged && suspending) {
423 requestDisplayState(state);
424 }
425 }
426 }
scheduleScreenUpdate()
--> postScreenUpdateThreadSafe();
postScreenUpdateThreadSafe中mHandler.post(mScreenUpdateRunnable);
//mScreenUpdateRunnable如下:
private final Runnable mScreenUpdateRunnable = new Runnable() {
mPhotonicModulator.setState(mScreenState, brightness);
}
//setState
public boolean setState(int state, int backlight) {
synchronized (mLock) {
if (state != mPendingState || backlight != mPendingBacklight) {
if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
}
mPendingState = state;
mPendingBacklight = backlight;
if (!mChangeInProgress) {
mChangeInProgress = true;
mLock.notifyAll();
}
}
return !mChangeInProgress;
}
}
由上,也就是调用scheduleScreenUpdate()来触发向消息队列中存放一个消息,消息处理函数中notifyAll()然后在上面无限循环的run()中设置背光亮度。
下面查找scheduleScreenUpdate()的地方:
(1)DisplayPowerState构造方法
–> scheduleScreenUpdate
(2)setScreenState
–> scheduleScreenUpdate
(3)setScreenBrightness
–> scheduleScreenUpdate
(4)setColorFadeLevel
–> scheduleScreenUpdate
综上可以看出,DisplayPowerState.java有三大功能:
设置屏幕状态(setScreenState)、设置屏幕背光(setScreenBrightness)、设置colorfade(setColorFadeLevel)
在frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java的systemReady方法中:
(1)注册了4个广播Receiver:
Receiver 监听的事件
BatteryReceiver ACTION_BATTERY_CHANGED
DreamReceiver ACTION_DREAMING_STARTED
UserSwitchedReceiver ACTION_USER_SWITCHED
DockReceiver ACTION_DOCK_EVENT
当收到这个广播时,都会调用到updatePowerStateLocked()方法
(2)对于背光灯还注册了1个ContentObserver
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
当数据库中Settings.Secure.SCREENSAVER_ENABLED变化的时候,mSettingsObserver中的onChange()方法就会被调用。
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
handleSettingsChangedLocked();
}
}
}
private void handleSettingsChangedLocked() {
updateSettingsLocked();
updatePowerStateLocked();
}
所以触发ContentObserver最终也会调用updatePowerStateLocked();
下面分析一下updatePowerStateLocked
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Update display power state.
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);//下面逻辑调背光
// Phase 3: Update dream state (depends on display ready signal).
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 4: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
// Phase 5: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
private boolean updateDisplayPowerStateLocked(int dirty) {
...
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
...
}
这里有mDisplayManagerInternal中的requestPowerState,mDisplayManagerInternal是一个抽象类,肯定有子类继承它并实现它的requestPowerState方法。
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
//位于frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
private final class LocalService extends DisplayManagerInternal {
...
@Override
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
}
//在onStart中发布了这个类
public void onStart() {
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService());
}
在\frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java中
-->requestPowerState
--> sendUpdatePowerStateLocked()
-->mHandler.sendMessage(msg); //它通过发送消息在Handler的handleMessage中处理
-->handleMessage(Message msg)
-->updatePowerState()
-->animateScreenBrightness(brightness, 0);
--->mScreenBrightnessRampAnimator.animateTo(target, rate) //rate表示收敛速度,要是0表示立即设为targrt值
RampAnimator.java
--->animateTo(target, rate)
--->mProperty.setValue
--->DisplayPowerState.setScreenBrightness
--->scheduleScreenUpdate()
下面分析
mScreenBrightnessRampAnimator.animateTo(target, rate)方法
//在frameworks\base\services\core\java\com\android\server\display\RampAnimator.java
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
下面分析RampAnimator类:
//位于frameworks\base\services\core\java\com\android\server\display\RampAnimator.java
public RampAnimator(T object, IntProperty<T> property) {
mObject = object;
mProperty = property;
mChoreographer = Choreographer.getInstance();
}
public boolean animateTo(int target, int rate) {
// 当rate<=0时,直接将亮度设置为目标值
if (mFirstTime || rate <= 0) {
if (mFirstTime || target != mCurrentValue) {
mFirstTime = false;
mRate = 0;
mTargetValue = target;
mCurrentValue = target;
mProperty.setValue(mObject, target);//这里调用IntProperty的setValue
if (mAnimating) {
mAnimating = false;
cancelAnimationCallback();
}
if (mListener != null) {
mListener.onAnimationEnd();
}
return true;
}
return false;
}
//当rate>0时,这个时候会调用postAnimationCallback函数(这个函数根据VSync信号过来,把亮度慢慢上升的一个过程)
if (!mAnimating
|| rate > mRate
|| (target <= mCurrentValue && mCurrentValue <= mTargetValue)
|| (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
mRate = rate;
}
final boolean changed = (mTargetValue != target);
mTargetValue = target;
// Start animating.
if (!mAnimating && target != mCurrentValue) {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postAnimationCallback();
}
return changed;
}
//位于\frameworks\base\services\core\java\com\android\server\display\DisplayPowerState.java
public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
new IntProperty<DisplayPowerState>("screenBrightness") {
@Override
public void setValue(DisplayPowerState object, int value) {
object.setScreenBrightness(value);
}
@Override
public Integer get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
//位于frameworks\base\services\core\java\com\android\server\display\DisplayPowerState.java
public void setScreenBrightness(int brightness) {
if (mScreenBrightness != brightness) {
if (DEBUG) {
Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
}
mScreenBrightness = brightness;
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
}
}
setting中怎么调节亮度呢
//位于\frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessDialog.java
public class BrightnessDialog extends Activity {
private BrightnessController mBrightnessController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Window window = getWindow();
window.setGravity(Gravity.TOP);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.quick_settings_brightness_dialog);
final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider);
mBrightnessController = new BrightnessController(this, icon, slider);
}
@Override
protected void onStart() {
super.onStart();
mBrightnessController.registerCallbacks();//这里注册callback
MetricsLogger.visible(this, MetricsLogger.BRIGHTNESS_DIALOG);
}
}
//位于frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessController.java
//control:即为滑动块slider
public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
mContext = context;
mIcon = icon;
mControl = control;//赋值control给mControl
mHandler = new Handler();
mUserTracker = new CurrentUserTracker(mContext) {
@Override
public void onUserSwitched(int newUserId) {
updateMode();
updateSlider();
}
};
...
}
public void registerCallbacks() {
//设置监听
mControl.setOnChangedListener(this);
mListening = true;
}
//当滑动条变化时会触发这个onChanged
@Override
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
boolean stopTracking) {
updateIcon(mAutomatic);
if (mExternalChange) return;
if (!mAutomatic) {
final int val = value + mMinimumBacklight;
if (stopTracking) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS, val);
}
setBrightness(val);
//如果一直在滑动时,不用写入数据库;只有挺直时,才需要写入数据库,提高效率
if (!tracking) {
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, val,
UserHandle.USER_CURRENT);
}
});
}
...
}
private void setBrightness(int brightness) {
try {
mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
} catch (RemoteException ex) {
}
}
//位于powermanagerservice.java中
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long ident = Binder.clearCallingIdentity();
try {
setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
//位于powermanagerservice.java中
private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) {
synchronized (mLock) {
if (mTemporaryScreenBrightnessSettingOverride != brightness) {
mTemporaryScreenBrightnessSettingOverride = brightness;
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
}
}
App测试Demo MainActivity.java
package com.example.mm.lcd_brightness;
import android.os.Bundle;
import android.provider.Settings;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.SeekBar;
public class MainActivity extends AppCompatActivity {
final private int LED_NOTIFICATION_ID = 123;
private SeekBar mBacklightSeekBar = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mBacklightSeekBar = (SeekBar)findViewById(R.id.seekBar);
try {
/*将背光调节模式改为手动,无为自动的话手动调节无效*/
Settings.System.putInt(getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
/*让滚动条的初始状态显示在正确的位置*/
int brightness = android.provider.Settings.System.getInt(getContentResolver(),
android.provider.Settings.System.SCREEN_BRIGHTNESS);
mBacklightSeekBar.setProgress(brightness*100/255);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
/*设置滚动条的监听函数*/
mBacklightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener (){
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int brightness = mBacklightSeekBar.getProgress();
/*应用程序传入的是0--100,而底层是0--255*/
brightness = brightness * 255 / 100;
/*设置到数据库中,会导致内容观察者对应的设置屏幕亮度的方法被调用*/
android.provider.Settings.System.putInt(getContentResolver(),
android.provider.Settings.System.SCREEN_BRIGHTNESS, brightness);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
Log.d("App_Brightness: ","==============onStartTrackingTouch===============");
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("App_Brightness: ","==============onStartTrackingTouch===============");
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}