您的位置:首页 > 移动开发 > Android开发

Android FrameWork深入分析DreamManagerService实现自己的系统屏保

2017-07-03 18:23 585 查看

Framework分析DreamService,实现自己的系统屏保

现在有一个需求是在手机一段时间不用的情况下,显示自己的系统屏保功能

下面是涉及到的代码

/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java 显示屏保功能的入口

/frameworks/base/services/core/java/com/android/server/dreams/DreamManagerService.java 管理屏保APP

/frameworks/base/services/core/java/com/android/server/dreams/DreamController.java 屏保具体的呼起

/packages/apps/DeskClock/src/com/android/deskclock/Screensaver.java 闹钟模块默认的屏保

首先需要熟悉PowerManagerService的主要逻辑

这边个人推荐blog:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=30510400&id=5569393

接着上面的博客介绍,大概画了一个流程,其实我们只要在系统启动屏保的时候绑定到自己的APP就行了

![主要过程](http://img.blog.csdn.net/20170703170434850?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3pxc2Rx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


现在我们主要分析DreamManagerService的逻辑

DreamManagerService怎么找到屏保APP?

找到入口了,那么DreamManagerService怎么启动屏保app呢?

private final class LocalService extends DreamManagerInternal {

@Override

public void startDream(boolean doze) {

startDreamInternal(doze);

}

}

private void startDreamInternal(boolean doze) {

final int userId = ActivityManager.getCurrentUser();

//获得屏保指定的app

final ComponentName dream = chooseDreamForUser(doze, userId);

if (dream != null) {

synchronized (mLock) {

startDreamLocked(dream, false /isTest/, doze, userId);

}

}

}

我们分析一下chooseDreamForUser()做了什么处理

//doze是系统另外一种状态了,系统处于节电状态,网络什么都会禁止掉

//我们让PowerMangerService调用startDream()的时候传入doze = false;

//可以看出这边是找到所有的屏保app默认使用第一个

private ComponentName chooseDreamForUser(boolean doze, int userId) {

Slog.w(TAG, “Dream 0 ” + doze + userId);

if (doze) {

ComponentName dozeComponent = getDozeComponent(userId);

return validateDream(dozeComponent) ? dozeComponent : null;

}

ComponentName[] dreams = getDreamComponentsForUser(userId);

return dreams != null && dreams.length != 0 ? dreams[0] : null;

}

看一下getDreamComponentsForUser()做了什么处理

private ComponentName[] getDreamComponentsForUser(int userId) {

//这里是从settings.db获得默认的屏保app中dreameService的包名

String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),

Settings.Secure.SCREENSAVER_COMPONENTS,

userId);

//我们这边写死定义为自己的app这

names = “com.ucon.displaydream/com.ucon.displaydream.”;

Slog.w(TAG, “names 1 : ” + names);

ComponentName[] components = componentsFromString(names);

Slog.w(TAG, “names 2 : ” + components);

// first, ensure components point to valid services
List<ComponentName> validComponents = new ArrayList<ComponentName>();
if (components != null) {
for (ComponentName component : components) {
if (validateDream(component)) {
validComponents.add(component);
}
}
}


}

**Settings.Secure.getStringForUser(mContext.getContentResolver(),Settings.Secure.SCREENSAVER_COMPONENTS, userId);获得默认的componentName

是 com.android.deskclock/com.android.deskclock.Screensaver**

然后打开screensaver的代码

package com.android.deskclock;

import android.app.AlarmManager;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.content.res.Configuration;

import android.os.Handler;

import android.preference.PreferenceManager;

import android.service.dreams.DreamService;

import android.util.Log;

import android.view.View;

import android.widget.TextClock;

import com.android.deskclock.Utils.ScreensaverMoveSaverRunnable;

public class Screensaver extends DreamService {

public static final int ORIENTATION_CHANGE_DELAY_MS = 250;

private static final boolean DEBUG = false;
private static final String TAG = "DeskClock/Screensaver";

private View mContentView, mSaverView;
private View mAnalogClock, mDigitalClock;
private String mDateFormat;
private String mDateFormatForAccessibility;

private final Handler mHandler = new Handler();

private final ScreensaverMoveSaverRunnable mMoveSaverRunnable;

// Thread that runs every midnight and refreshes the date.
private final Runnable mMidnightUpdater = new Runnable() {
@Override
public void run() {
Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
}
};

/**
* Receiver to handle time reference changes.
*/
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (DEBUG) Log.v(TAG, "Screensaver onReceive, action: " + action);

if (action == null) {
return;
}

if (action.equals(Intent.ACTION_TIME_CHANGED)
|| action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
Utils.refreshAlarm(Screensaver.this, mContentView);
Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
} else if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
Utils.refreshAlarm(Screensaver.this, mContentView);
}
}
};

public Screensaver() {
if (DEBUG) Log.d(TAG, "Screensaver allocated");
mMoveSaverRunnable = new ScreensaverMoveSaverRunnable(mHandler);
}

@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Screensaver created");
super.onCreate();

setTheme(R.style.DeskClockParentTheme);

mDateFormat = getString(R.string.abbrev_wday_month_day_no_year);
mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
if (DEBUG) Log.d(TAG, "Screensaver configuration changed");
super.onConfigurationChanged(newConfig);
mHandler.removeCallbacks(mMoveSaverRunnable);
layoutClockSaver();
mHandler.postDelayed(mMoveSaverRunnable, ORIENTATION_CHANGE_DELAY_MS);
}

@Override
public void onAttachedToWindow() {
if (DEBUG) Log.d(TAG, "Screensaver attached to window");
super.onAttachedToWindow();

// We want the screen saver to exit upon user interaction.
setInteractive(false);

setFullscreen(true);

layoutClockSaver();

// Setup handlers for time reference changes and date updates.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(mIntentReceiver, filter);
Utils.setMidnightUpdater(mHandler, mMidnightUpdater);

mHandler.post(mMoveSaverRunnable);
}

@Override
public void onDetachedFromWindow() {
if (DEBUG) Log.d(TAG, "Screensaver detached from window");
super.onDetachedFromWindow();

mHandler.removeCallbacks(mMoveSaverRunnable);

// Tear down handlers for time reference changes and date updates.
Utils.cancelMidnightUpdater(mHandler, mMidnightUpdater);
unregisterReceiver(mIntentReceiver);
}

private void setClockStyle() {
Utils.setClockStyle(this, mDigitalClock, mAnalogClock,
ScreensaverSettingsActivity.KEY_CLOCK_STYLE);
mSaverView = findViewById(R.id.main_clock);
boolean dimNightMode = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(ScreensaverSettingsActivity.KEY_NIGHT_MODE, false);
Utils.dimClockView(dimNightMode, mSaverView);
setScreenBright(!dimNightMode);
}

private void layoutClockSaver() {
setContentView(R.layout.desk_clock_saver);
mDigitalClock = findViewById(R.id.digital_clock);
mAnalogClock = findViewById(R.id.analog_clock);
setClockStyle();
Utils.setTimeFormat((TextClock)mDigitalClock,
(int)getResources().getDimension(R.dimen.main_ampm_font_size));

mContentView = (View) mSaverView.getParent();
mSaverView.setAlpha(0);

mMoveSaverRunnable.registerViews(mContentView, mSaverView);

Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
Utils.refreshAlarm(Screensaver.this, mContentView);
}


}

我们就知道DreamService与系统屏保的关系了,但是怎么bind启动屏保的dreameService的呢?

DreamManagerService的实现代码在DreamController中实现的

public void startDream(Binder token, ComponentName name,

boolean isTest, boolean canDoze, int userId) {

stopDream(true /immediate/);

Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try {
// Close the notification shade. Don't need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);

Slog.i(TAG, "Starting dream: name=" + name
+ ", isTest=" + isTest + ", canDoze=" + canDoze
+ ", userId=" + userId);

mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);

try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
} catch (RemoteException ex) {
Slog.e(TAG, "Unable to add window token for dream.", ex);
stopDream(true /*immediate*/);
return;
}

Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
try {
//这边就是怎么启动屏保的service了
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
Slog.e(TAG, "Unable to bind dream service: " + intent);
stopDream(true /*immediate*/);
return;
}


}

我们看一下DreamService显示屏保的时候怎么退出和唤醒屏幕

@Override

public boolean dispatchKeyEvent(KeyEvent event) {

// TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK

if (!mInteractive) {

if (mDebug) Slog.v(TAG, “Waking up on keyEvent”);

wakeUp();

return true;

} else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {

if (mDebug) Slog.v(TAG, “Waking up on back key”);

//唤醒屏幕

wakeUp();

return true;

}

return mWindow.superDispatchKeyEvent(event);

}

/** {@inheritDoc} */
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
if (!mInteractive) {
if (mDebug) Slog.v(TAG, "Waking up on keyShortcutEvent");
wakeUp();
return true;
}
return mWindow.superDispatchKeyShortcutEvent(event);
}


public void onWakeUp() {

//屏幕唤醒后消灭自己

finish();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: