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 ---------------------------------- 1.获取LightsService中注册的LightsManager:mLights = LocalServices.getService(LightsManager.class); 2.然后在构造函数中只获取了背光灯:new DisplayPowerState(mBlanker, mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT), new ColorFade(Display.DEFAULT_DISPLAY)); 整个系统中也只有这里获取了背光灯。 DisplayPowerState.java ----------------------------------- DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) --> mPhotonicModulator = new PhotonicModulator(); --> mPhotonicModulator.start(); --> run() //无限循环执行这个线程 --> mLock.wait(); //睡眠 --> setBrightness(backlight); 在setState()中notifyAll(); //唤醒 在mScreenUpdateRunnable中调用了setState() private final Runnable mScreenUpdateRunnable = new Runnable() { mPhotonicModulator.setState(mScreenState, brightness); } mScreenUpdateRunnable作为一个处理消息的响应线程 postScreenUpdateThreadSafe中mHandler.post(mScreenUpdateRunnable); scheduleScreenUpdate() --> postScreenUpdateThreadSafe(); 由上,也就是调用scheduleScreenUpdate()来触发向消息队列中存放一个消息,消息处理函数中notifyAll()然后在上面无限循环的 run()中设置背光亮度。 DisplayPowerState --> scheduleScreenUpdate setScreenState --> scheduleScreenUpdate setScreenBrightness --> scheduleScreenUpdate setColorFadeLevel --> scheduleScreenUpdate DisplayPowerController.java ------------------------- --> new DisplayPowerState() --> animateScreenStateChange //在updatePowerState中被调用 处理消息: Handler的handleMessage中调用updatePowerState updatePowerState() animateScreenStateChange //这里面设置背光亮度 发送消息: requestPowerState sendUpdatePowerStateLocked //基本上所有操作都是通过它执行的,也就是这个函数对上层做基础支持。 mHandler.sendMessage(msg); //它通过发送消息在Handler的handleMessage中处理 updateDisplayPowerStateLocked requestPowerState 什么时候发消息: PowerManagerService.java ---------------------------- updatePowerStateLocked updateDisplayPowerStateLocked systemReady方法中: (1)注册了4个Receiver eg: filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler); 当数据库中的Intent.ACTION_BATTERY_CHANGED变化的时候,BatteryReceiver的onReceive()就会被调用。 (2)对于背光灯还注册了1个ContentObserver resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver, UserHandle.USER_ALL); 当数据库中Settings.Secure.SCREENSAVER_ENABLED变化的时候,mSettingsObserver中的onChange()方法就会被调用。 Receiver 监听的事件 BatteryReceiver ACTION_BATTERY_CHANGED DreamReceiver ACTION_DREAMING_STARTED UserSwitchedReceiver ACTION_USER_SWITCHED DockReceiver ACTION_DOCK_EVENT mSettingsObserver SCREENSAVER_ENABLED 屏保功能开启 SCREENSAVER_ACTIVATE_ON_SLEEP 在睡眠时屏保启动 SCREENSAVER_ACTIVATE_ON_DOCK 连接底座并且屏保启动 SCREEN_OFF_TIMEOUT 进入dream状态前未活动时间 SLEEP_TIMEOUT 进入sleep状态前未活动时间 STAY_ON_WHILE_PLUGGED_IN 有插入并且屏幕开启 SCREEN_BRIGHTNESS 屏幕亮度 SCREEN_BRIGHTNESS_MODE 屏幕亮度模式 SCREEN_AUTO_BRIGHTNESS_ADJ LOW_POWER_MODE LOW_POWER_MODE_TRIGGER_LEVEL
2.使用到内容观察者模式
使用方法: 1.创建一个 ContentObserver 的子类,实现 onChange() 方法。 private final class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler) { super(handler); } /*目的是复写这个onChange方法*/ @Override public void onChange(boolean selfChange, Uri uri) { synchronized (mLock) { /*它里面也是去调用updatePowerStateLocked*/ handleSettingsChangedLocked(); } } } 2.注册 ContentObserver /* arg1:需要监听的 uri。 arg2:为 false 表示精确匹配,即只匹配该 Uri。为 true 表示可以同时匹配其派生的 Uri,如: content://com.qin.cb/student(精确匹配) content://com.qin.cb/student/# (派生,false 才能匹配到) content://com.qin.cb/student/schoolchild(派生,false 才能匹配到) arg3:ContentObserver 的实例。 */ registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver, UserHandle.USER_ALL); 3.用完后记得取消注册 ContentObserver unregisterContentObserver(myContentObserver) 参考: ContentObserver:https://www.jianshu.com/p/3bc164010b5f
3.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); } }
4.遇到问题
(1) 应用程序执行后闪退,报没有权限“android.permission.WRITE_SETTINGS”,然后在AndroidManifest.xml中添加这个权限:
<manifest ... <uses-permission android:name="android.permission.WRITE_SETTINGS"/> </manifest>
5.Android自带的背光调节程序BrightnessDialog.java分析
Settings --> Display --> Sleep --> Brightness Level 设置背光,对应的系统自带的App是BrightnessDialog.java /*是第一次创建这个对话框的时候被调用*/ protected void onCreate(Bundle savedInstanceState) { ... /*根据ID获得一个控件,只不过这里是ToggleSlider,我们的App里面是Slide bar*/ final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider); /* * 与我们的App不同,它这个slide没有处理函数,而是作为一个参数传入了BrightnessController */ mBrightnessController = new BrightnessController(this, icon, slider); } @Override /*是每一次使用对话框时调用*/ protected void onStart() { super.onStart(); /*这里面设置了监听*/ mBrightnessController.registerCallbacks(); } public void registerCallbacks() { if (mListening) { return; } /*注意: startObserving setOnChangedListener,它两个构成设置滑动块的处理方法*/ /*和之前的非常像,也是去注册ContentObserver,内容观察者, 若是滑动滑动块了最终就会导致这里面的onChanged()方法被调用 */ mBrightnessObserver.startObserving(); mUserTracker.startTracking(); // Update the slider and mode before attaching the listener so we don‘t // receive the onChanged notifications for the initial values. updateMode(); updateSlider(); /*OnChanged 的监听,this里面肯定有一个onChanged方法*/ mControl.setOnChangedListener(this); mListening = true; } /*BrightnessController.java*/ @Override public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) { updateIcon(mAutomatic); if (mExternalChange) return; if (!mAutomatic) { final int val = value + mMinimumBacklight; /*这里有设置背光*/ setBrightness(val); /*如果当前不是一直按着滑动块而是松手了的话就把那些数据写到数据库里面去。 注意在滑动过程中是直接调用setBrightness(),而不是通过数据库来实现的。但是松手后 才写入数据库的。 */ if (!tracking) { AsyncTask.execute(new Runnable() { public void run() { /*这里会写入数据库,最终会导致内容观察者的函数被调用 本文件中的BrightnessObserver中的onChange被调用 */ Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, val, UserHandle.USER_CURRENT); } }); } } else { final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1; setBrightnessAdj(adj); if (!tracking) { AsyncTask.execute(new Runnable() { public void run() { Settings.System.putFloatForUser(mContext.getContentResolver(), Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj, UserHandle.USER_CURRENT); } }); } } for (BrightnessStateChangeCallback cb : mChangeCallbacks) { cb.onBrightnessLevelChanged(); } }