Android系统屏保功能开发
1 AndroidManifest.xml 文件配置
需要先配置为系统应用
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.xxx.xxx"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.BIND_DREAM_SERVICE" />
...
<!--屏保服务类-->
<service
android:name=".display.xxx.MyDream"
android:enabled="true"
android:exported="true"
android:icon="@drawable/bg_screensaver_clock"
android:label="@string/display_dream_clock"
android:permission="android.permission.BIND_DREAM_SERVICE">
<intent-filter>
<action android:name="android.service.dreams.DreamService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</manifest>
实现 DreamService
在这里,我实现了一个基类,方便扩展多种屏保。
public abstract class BaseDream extends DreamService {
public static final String TAG = BaseDream.class.getName();
public boolean mLowProfile;
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
wakeUp();
return true;
}
@Override
public void onWakeUp() {
super.onWakeUp();
wakeupDream();
}
protected void wakeupDream() {
PowerManager pm = getSystemService(PowerManager.class);
pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:NODOZE");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
init();
hideBar();
}
@Override
public void onDreamingStarted() {
super.onDreamingStarted();
}
@Override
public void onDreamingStopped() {
super.onDreamingStopped();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
release();
}
@Override
public void onDestroy() {
super.onDestroy();
}
protected abstract void init();
protected abstract void release();
private void hideBar() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
public void setLowProfile(boolean lowProfile) {
if (mLowProfile != lowProfile) {
mLowProfile = lowProfile;
int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
}
}
private void applySystemUiVisibilityFlags(int flags, int mask) {
View v = getWindow() == null ? null : getWindow().getDecorView();
if (v != null) {
v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask));
}
}
private int applyFlags(int oldFlags, int flags, int mask) {
return (oldFlags&~mask) | (flags&mask);
}
}
实现时钟屏保类,不外乎就是在这个服务里自定义自己的UI。
/**
* 系统默认屏保:时钟屏保
* 详情见 device\rockchip\rk3399\PRODUCT\overlay\frameworks\base\core\res\res\values\config.xml
* <string name="config_dreamsDefaultComponent"
* translatable="false">com.XXX.XXX/com.XXX.XXX.display.screensaver.dream.MyDream</string>
*/
public class ClockDream extends BaseDream {
public static final String TAG = ClockDream.class.getSimpleName();
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
refreshLayoutParams();
}
private void refreshLayoutParams() {
}
@Override
protected void init() {
setInteractive(false);
setFullscreen(true);
setLowProfile(true);
// 设置布局文件
setContentView(R.layout.view_dream_screensaver);
...
}
@Override
protected void release() {
...
}
...
}
到这里开发基本完成,那怎么才能把我们定义好的屏保设置为当前屏保呢,其实在系统启动的时候,会加载 AndroidManifest.xml 清单文件,解析并将配置为屏保的服务存储起来,通过系统服务来向应用层提供屏保列表的遍历、设置接口。
2 PowerManagerService 分析
屏保从何时启动,在系统SystemServer startOtherServices 服务启动阶段, PowerManagerService 系统服务准备就绪时,调用 systemReady() 方法,注册了更新屏保的系统广播,通过接收 Intent.ACTION_DREAMING_STARTED、Intent.ACTION_DREAMING_STOPPED 广播来对外提供控制屏保的启动与停止, 另一种方式就是通过接口来控制,上述两种方式最后调用的接口最后都会调用到 DeamManagerService 服务的接口。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
// Message: 当发生用户活动超时(界面无操作)以更新电源状态时发送.
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
// Message: 当设备进入或退出dreaming或dozing状态时发送
private static final int MSG_SANDMAN = 2;
// Message: 当屏幕亮度提升到期时发送
private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3;
// Message: 轮询以查找长期持有的唤醒锁.
private static final int MSG_CHECK_FOR_LONG_WAKELOCKS = 4;
public void systemReady(IAppOpsService appOps) {
mSystemReady = true;
mAppOps = appOps;
mDreamManager = getLocalService(DreamManagerInternal.class);
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
mPolicy = getLocalService(WindowManagerPolicy.class);
//省略代码...
ilter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
}
private final class DreamReceiver extends