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();
}
相关文章推荐
- Android系统启动流程分析之启动应用 - ActivityManagerService
- Android framework 应用安装流程 分析 PackageManagerService(Android5.1)
- Android5.1 PowerManagerService深入分析
- Android Framework 之PackageManagerService详细分析
- [Android 系统源代码研究] ActivityManagerService情景分析
- Android PackageManagerService流程详细分析(六)之优化系统库
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(1)
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android framework源码之JNI实现过程分析
- Android 核心分析 之七------Service深入分析
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(5)
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android 核心分析 之六 -----IPC框架分析 Binder,Service,Service manager .
- Android Service学习之IntentService 深入分析
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android Service学习之IntentService 深入分析
- Android Service学习之IntentService 深入分析
- Android 核心分析 之七------Service深入分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析 (下)