屏幕保护有两个设置可选:默认为插入基座充电时
通过DreamBackend启用屏保,并且保存选择的时机
//QSSI.13\packages\apps\Settings\src\com\android\settings\dream\WhenToDreamPicker.java
@Override
protected boolean setDefaultKey(String key) {mBackend.setWhenToDream(DreamSettings.getSettingFromPrefKey(key));return true;
}
//QSSI.13\frameworks\base\packages\SettingsLib\src\com\android\settingslib\dream\DreamBackend.java
//启用屏保:
public void startDreaming() {logd("startDreaming()");if (mDreamManager == null) {return;}try {mDreamManager.dream();} catch (RemoteException e) {Log.w(TAG, "Failed to dream", e);}
}
//记录启用时机
public void setWhenToDream(@WhenToDream int whenToDream) {setEnabled(whenToDream != NEVER);switch (whenToDream) {case WHILE_CHARGING:setActivatedOnDock(false);setActivatedOnSleep(true);break;case WHILE_DOCKED:setActivatedOnDock(true);setActivatedOnSleep(false);break;case EITHER:setActivatedOnDock(true);setActivatedOnSleep(true);break;case NEVER:default:break;}
}public void setActivatedOnDock(boolean value) {logd("setActivatedOnDock(%s)", value);setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, value);
}public void setActivatedOnSleep(boolean value) {logd("setActivatedOnSleep(%s)", value);setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, value);
}
DreamBackend是对屏保管理的类,最终会通过IDreamManager来执行到DreamManagerService
启动屏保时,先获取系统安装的所有屏保,通过下列代码可以得到我们自己的开发的屏保
PackageManager pm = mContext.getPackageManager();
Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE);
List<ResolveInfo> resolveInfos = pm.queryIntentServices(dreamIntent,PackageManager.GET_META_DATA);
然后再将屏保设置我们自己开发的
//QSSI.13\frameworks\base\services\core\java\com\android\server\dreams\DreamManagerService.java
public void setActiveDream(ComponentName dream) {logd("setActiveDream(%s)", dream);if (mDreamManager == null)return;try {ComponentName[] dreams = { dream };mDreamManager.setDreamComponents(dream == null ? null : dreams);} catch (RemoteException e) {Log.w(TAG, "Failed to set active dream to " + dream, e);}}
如果没有设置,系统会有一个默认的屏保,使用以下方法可以获取默认屏保
//QSSI.13\frameworks\base\services\core\java\com\android\server\dreams\DreamManagerService.java
public ComponentName getDefaultDream() {if (mDreamManager == null)return null;try {return mDreamManager.getDefaultDreamComponent();} catch (RemoteException e) {Log.w(TAG, "Failed to get default dream", e);return null;}}
然后用户有任何操作,屏保都会停止,实现逻辑是在DreamService里面的
//QSSI.13\frameworks\base\core\java\android\service\dreams\DreamService.java
/** {@inheritDoc} */
@Override
public boolean dispatchTouchEvent(MotionEvent event) {// TODO: create more flexible version of mInteractive that allows clicks// but finish()es on any other kind of activityif (!mInteractive && event.getActionMasked() == MotionEvent.ACTION_UP) {if (mDebug) Slog.v(mTag, "Waking up on touchEvent");wakeUp();return true;}return mWindow.superDispatchTouchEvent(event);
}
public final void wakeUp() {wakeUp(false);
}private void wakeUp(boolean fromSystem) {if (mDebug) {Slog.v(mTag, "wakeUp(): fromSystem=" + fromSystem + ", mWaking=" + mWaking+ ", mFinished=" + mFinished);}if (!mWaking && !mFinished) {mWaking = true;if (mActivity != null) {// During wake up the activity should be translucent to allow the application// underneath to start drawing. Normally, the WM animation system takes care of// this, but here we give the dream application some time to perform a custom exit// animation. If it uses a view animation, the WM doesn't know about it and can't// make the activity translucent in the normal way. Therefore, here we ensure that// the activity is translucent during wake up regardless of what animation is used// in onWakeUp().mActivity.convertToTranslucent(null, null);}// As a minor optimization, invoke the callback first in case it simply// calls finish() immediately so there wouldn't be much point in telling// the system that we are finishing the dream gently.onWakeUp();// Now tell the system we are waking gently, unless we already told// it we were finishing immediately.if (!fromSystem && !mFinished) {if (mActivity == null) {Slog.w(mTag, "WakeUp was called before the dream was attached.");} else {try {mDreamManager.finishSelf(mDreamToken, false /*immediate*/);} catch (RemoteException ex) {// system server died}}}}
}
屏保实现充电显示的逻辑在PowerManagerService里面
//QSSI.13\frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
系统设置启用和时机
//是否打开屏保
mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,Settings.Secure.SCREENSAVER_ENABLED,mDreamsEnabledByDefaultConfig ? 1 : 0,UserHandle.USER_CURRENT) != 0);
//仅充电时设置此值为1
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,UserHandle.USER_CURRENT) != 0);//基座充电时,此值为1
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,UserHandle.USER_CURRENT) != 0);
PowerManagerService里面主要是处理电源相关的逻辑,所以updatePowerStateLocked()方法会时时调用,更新电源状态,然后根据不同状态进行不同处理
private void updatePowerStateLocked() {if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {return;}if (!Thread.holdsLock(mLock)) {Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");}Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");mUpdatePowerStateInProgress = true;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 = mClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);updateAttentiveStateLocked(now, dirtyPhase1);if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// Phase 2: Lock profiles that became inactive/not kept awake.updateProfilesLocked(now);// Phase 3: Update power state of all PowerGroups.final boolean powerGroupsBecameReady = updatePowerGroupsLocked(dirtyPhase2);// Phase 4: Update dream state (depends on power group ready signal).updateDreamLocked(dirtyPhase2, powerGroupsBecameReady);// Phase 5: Send notifications, if needed.finishWakefulnessChangeIfNeededLocked();// Phase 6: 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);mUpdatePowerStateInProgress = false;}
}private boolean updateWakefulnessLocked(int dirty) {....if (shouldNapAtBedTimeLocked()) {//判断是否需要屏保changed = dreamPowerGroupLocked(powerGroup, time,Process.SYSTEM_UID, /* allowWake= */ false);} ...
}@GuardedBy("mLock")
private boolean shouldNapAtBedTimeLocked() {return mDreamsActivateOnSleepSetting|| (mDreamsActivateOnDockSetting&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
在updatePowerStateLocked方法里面,会更新屏保状态,调用updateDreamLocked方法
private void updateDreamLocked(int dirty, boolean powerGroupBecameReady) {if ((dirty & (DIRTY_WAKEFULNESS| DIRTY_USER_ACTIVITY| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED| DIRTY_ATTENTIVE| DIRTY_WAKE_LOCKS| DIRTY_BOOT_COMPLETED| DIRTY_SETTINGS| DIRTY_IS_POWERED| DIRTY_STAY_ON| DIRTY_PROXIMITY_POSITIVE| DIRTY_BATTERY_STATE)) != 0 || powerGroupBecameReady) {if (areAllPowerGroupsReadyLocked()) {scheduleSandmanLocked();}}
}
scheduleSandmanLocked方法里面会发送一个消息
private void scheduleSandmanLocked() {if (!mSandmanScheduled) {mSandmanScheduled = true;for (int idx = 0; idx < mPowerGroups.size(); idx++) {final PowerGroup powerGroup = mPowerGroups.valueAt(idx);if (powerGroup.supportsSandmanLocked()) {Message msg = mHandler.obtainMessage(MSG_SANDMAN);msg.arg1 = powerGroup.getGroupId();msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());}}}
}
在PowerManagerHandler里面处理MSG_SANDMAN消息
private final class PowerManagerHandlerCallback implements Handler.Callback {@Overridepublic boolean handleMessage(Message msg) {switch (msg.what) {case MSG_USER_ACTIVITY_TIMEOUT:handleUserActivityTimeout();break;case MSG_SANDMAN:handleSandman(msg.arg1);break;case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:handleScreenBrightnessBoostTimeout();break;case MSG_CHECK_FOR_LONG_WAKELOCKS:checkForLongWakeLocks();break;case MSG_ATTENTIVE_TIMEOUT:handleAttentiveTimeout();break;}return true;}
}
主要处理逻辑是在handleSandman里面
private void handleSandman(int groupId) { // runs on handler thread// Handle preconditions.final boolean startDreaming;final int wakefulness;synchronized (mLock) {mSandmanScheduled = false;if (!mPowerGroups.contains(groupId)) {// Group has been removed.return;}final PowerGroup powerGroup = mPowerGroups.get(groupId);wakefulness = powerGroup.getWakefulnessLocked();// 首先判断是否可以启动屏保// 如果可以启动屏保且当前锁状态为WAKEFULNESS_NAPPING时,由表示需要启动屏保if (powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup);powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false);} else {startDreaming = false;}}// Start dreaming if needed.// We only control the dream on the handler thread, so we don't need to worry about// concurrent attempts to start or stop the dream.final boolean isDreaming;if (mDreamManager != null) {// Restart the dream whenever the sandman is summoned.//启动屏保if (startDreaming) {mDreamManager.stopDream(/* immediate= */ false,"power manager request before starting dream" /*reason*/);mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING,"power manager request" /*reason*/);}isDreaming = mDreamManager.isDreaming();} else {isDreaming = false;}// At this point, we either attempted to start the dream or no attempt will be made,// so stop holding the display suspend blocker for Doze.mDozeStartInProgress = false;// Update dream state.synchronized (mLock) {if (!mPowerGroups.contains(groupId)) {// Group has been removed.return;}// Remember the initial battery level when the dream started.//如果屏保正在运行且相关设置允许启动屏保,将状态设置为WAKEFULNESS_DREAMINGif (startDreaming && isDreaming) {mDreamsBatteryLevelDrain = 0;if (wakefulness == WAKEFULNESS_DOZING) {Slog.i(TAG, "Dozing...");} else {Slog.i(TAG, "Dreaming...");}}// If preconditions changed, wait for the next iteration to determine// whether the dream should continue (or be restarted).final PowerGroup powerGroup = mPowerGroups.get(groupId);if (powerGroup.isSandmanSummonedLocked()|| powerGroup.getWakefulnessLocked() != wakefulness) {return; // wait for next cycle}
....// Stop dream.if (isDreaming) {mDreamManager.stopDream(/* immediate= */ false, "power manager request" /*reason*/);}
}
从代码可以看出mWakefulness变量与是否启动屏保密切相关,当启动屏保时,mWakefulness状态发生变化
@GuardedBy("mLock")
int recalculateGlobalWakefulnessLocked() {int deviceWakefulness = WAKEFULNESS_ASLEEP;for (int i = 0; i < mPowerGroups.size(); i++) {final int wakefulness = mPowerGroups.valueAt(i).getWakefulnessLocked();if (wakefulness == WAKEFULNESS_AWAKE) {return WAKEFULNESS_AWAKE;} else if (wakefulness == WAKEFULNESS_DREAMING&& (deviceWakefulness == WAKEFULNESS_ASLEEP|| deviceWakefulness == WAKEFULNESS_DOZING)) {//此状态下,屏保会被启动deviceWakefulness = WAKEFULNESS_DREAMING;} else if (wakefulness == WAKEFULNESS_DOZING&& deviceWakefulness == WAKEFULNESS_ASLEEP) {deviceWakefulness = WAKEFULNESS_DOZING;}}return deviceWakefulness;
}
在停止屏保时,会依次调用handleDreamFinishedLocked –>wakeUpNoUpdateLocked
在wakeUpNoUpdateLocked方法里面,mWakefulness 状态发生变化