Android背光灯控制实现

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));
        ...
    }
  • 获取LightsService中注册的LightsManager:mLights = LocalServices.getService(LightsManager.class);
  • 然后在构造函数中只获取了背光灯: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    }

构造函数中

  • mBacklight = backlight //这里将上述拿到的LightImpl,赋值给mBacklight
  • 创建一个线程mPhotonicModulator = new PhotonicModulator()

下面分析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        }
  • 创建了一个PhotonicModulator 线程,此线程大部分事件是睡眠的,通过notifyAll()来唤醒,具体唤醒流程如下:
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);
    }
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值