我們在android手機長按HOME鍵,會彈出一個近期任務欄。近期任務欄會顯示你訪問過的app的截圖。
實現過程分爲如下幾步:
Activiyty開始pause時截圖
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity);
completePauseLocked(false);
}
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (!resuming) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
mStackSupervisor.resumeTopActivitiesLocked();
}
return false;
}
if (mActivityContainer.mParentActivity == null) {
// Top level stack, not a child. Look for child stacks.
mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
}
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
prev.updateThumbnailLocked(screenshotActivities(prev), null);
}
代碼路徑:frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
上述代碼中有兩個主要的函數:
1)prev.updateThumbnailLocked 用於更新Activity的縮略圖,即在近期任務欄看到的縮略圖
2)screenshotActivities 用於截圖
先分析screenshotActivities
public final Bitmap screenshotActivities(ActivityRecord who) {
if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who);
if (who.noDisplay) {
if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tNo display");
return null;
}
if (isHomeStack()) {
// This is an optimization -- since we never show Home or Recents within Recents itself,
// we can just go ahead and skip taking the screenshot if this is the home stack.
if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tHome stack");
return null;
}
int w = mService.mThumbnailWidth;
int h = mService.mThumbnailHeight;
if (w > 0) {
if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tTaking screenshot");
return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
w, h, SCREENSHOT_FORCE_565);
}
Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
return null;
}
代碼路徑:frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
截圖調用的是WindowManagerService的screenShotApplications。
public Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
int height, boolean force565) {
if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
final DisplayContent displayContent = getDisplayContentLocked(displayId);
....
bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
inRotation, rot);
截圖最終call到SurfaceControl.screenshot函數。
另外一個函數:
void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
if (newThumbnail != null) {
if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
"Setting thumbnail of " + this + " to " + newThumbnail);
boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
if (thumbnailUpdated && isPersistable()) {
mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
}
}
task.lastDescription = description;
}
代碼路徑:frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java
邏輯比較簡單,不在描述。