本人对Java可谓是一窍不通,工作主要是用C,C++,但最近工作需要,分析了一下ICS关于打开最近应用的程序如何获得程序的缩略图,要说详细步骤可能没有看仔细,现将分析过程稍作总结如下,供大家参考:
通过logcat分析找打了一个突破口:
1:frameworks/base/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java中
public void refreshRecentTasksList() {
refreshRecentTasksList(null);
}
private void refreshRecentTasksList(ArrayList recentTasksList) {
if (mRecentTasksDirty) {
if (recentTasksList != null) {
mRecentTaskDescriptions = recentTasksList;
} else {
mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks(); //注意mRecentTasksLoader.getRecentTasks
}
mListAdapter.notifyDataSetInvalidated();
updateUiElements(getResources().getConfiguration());
mRecentTasksDirty = false;
}
}
2:frameworks/base/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java中
ArrayList getRecentTasks() {
cancelLoadingThumbnails();
ArrayList tasks = new ArrayList();
final PackageManager pm = mContext.getPackageManager();
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List recentTasks =
am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
HashSet recentTasksToKeepInCache = new HashSet();
int numTasks = recentTasks.size();
// skip the first task - assume it's either the home screen or the current activity.
final int first = 1;
recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
TaskDescription item = createTaskDescription(recentInfo.id,
recentInfo.persistentId, recentInfo.baseIntent,
recentInfo.origActivity, recentInfo.description, homeInfo);分析一下createTaskDescription
if (item != null) {
tasks.add(item);
++index;
}
}
// when we're not using the TaskDescription cache, we load the thumbnails in the
// background
loadThumbnailsInBackground(new ArrayList(tasks)); 个人认为这个函数就是加载缩略图的
return tasks;
}
======
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
ComponentName origActivity, CharSequence description, ActivityInfo homeInfo) {
Intent intent = new Intent(baseIntent);
if (origActivity != null) {
intent.setComponent(origActivity);
}
final PackageManager pm = mContext.getPackageManager();
if (homeInfo == null) {
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
}
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
final ActivityInfo info = resolveInfo.activityInfo;
final String title = info.loadLabel(pm).toString();
Drawable icon = getFullResIcon(resolveInfo, pm);
if (title != null && title.length() > 0 && icon != null) {
if (DEBUG) Log.v(TAG, "creating activity desc for id="
+ persistentTaskId + ", label=" + title);
TaskDescription item = new TaskDescription(taskId,
persistentTaskId, resolveInfo, baseIntent, info.packageName,
description);
item.setLabel(title); //设置标题
item.setIcon(icon); //设置icon
// Don't load the current home activity.
if (homeInfo != null
&& homeInfo.packageName.equals(intent.getComponent().getPackageName())
&& homeInfo.name.equals(intent.getComponent().getClassName())) {
return null;
}
return item;
} else {
if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId);
}
}
return null;
}
======
void loadThumbnail(TaskDescription td) {
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId); //going into ActivityManager.java
if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
+ td + ": " + thumbs.mainThumbnail);
synchronized (td) {
if (thumbs != null && thumbs.mainThumbnail != null) {
td.setThumbnail(thumbs.mainThumbnail);
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
}
}
3:frameworks/base/core/java/android/app/ActivityManager.java
public TaskThumbnails getTaskThumbnails(int id) throws SecurityException {
try {
return ActivityManagerNative.getDefault().getTaskThumbnails(id); 注意此返回值
} catch (RemoteException e) {
// System dead, we will be dead too soon!
return null;
}
}
4:frameworks/base/core/java/android/app/ActivityManagerNative.java
1:static public IActivityManager getDefault() {
return gDefault.get();
} IActivityManager java牛人能否告知IActivityManager什么意思啊,查找android源码没有发现对应的java文件
2: 同时跟踪代码还发现执行了以下的程序,本人所知有限,无法解释:
case GET_TASK_THUMBNAILS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int id = data.readInt();
ActivityManager.TaskThumbnails bm = getTaskThumbnails(id);
reply.writeNoException();
if (bm != null) {
reply.writeInt(1);
bm.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
5:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
关于如何跳到这个函数中执行,还请高手不吝指教
public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
Log.d(TAG,"++++sam debug ActivityManagerService.java----getTaskThumbnails id:" + id );
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
"getTaskThumbnails()");
TaskRecord tr = taskForIdLocked(id);
if (tr != null) {
return mMainStack.getTaskThumbnailsLocked(tr); 注意此函数
}
}
return null;
}
6:frameworks/base/services/java/com/android/server/am/ActivityStack.java
public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
ActivityRecord resumed = mResumedActivity;
if (resumed != null && resumed.thumbHolder == tr) {
info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
} else {
info.mainThumbnail = tr.lastThumbnail; ****通过分析 程序走的是else分支,tr.lastThumbnail从何而来??????
}
return info;
}
7:frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
Bitmap rawss;
int maxLayer = 0;
final Rect frame = new Rect();
float scale;
int dw, dh;
int rot;
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
dw = mAppDisplayWidth;
dh = mAppDisplayHeight;
int aboveAppLayer = mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
aboveAppLayer += TYPE_LAYER_MULTIPLIER;
boolean isImeTarget = mInputMethodTarget != null
&& mInputMethodTarget.mAppToken != null
&& mInputMethodTarget.mAppToken.appToken != null
&& mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
// Figure out the part of the screen that is actually the app.
boolean including = false;
for (int i=mWindows.size()-1; i>=0; i--) {
WindowState ws = mWindows.get(i);
if (ws.mSurface == null) {
continue;
}
if (ws.mLayer >= aboveAppLayer) {
continue;
}
// When we will skip windows: when we are not including
// ones behind a window we didn't skip, and we are actually
// taking a screenshot of a specific app.
if (!including && appToken != null) {
// Also, we can possibly skip this window if it is not
// an IME target or the application for the screenshot
// is not the current IME target.
if (!ws.mIsImWindow || !isImeTarget) {
// And finally, this window is of no interest if it
// is not associated with the screenshot app.
if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
continue;
}
}
}
// We keep on including windows until we go past a full-screen
// window.
including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
if (maxLayer < ws.mAnimLayer) {
maxLayer = ws.mAnimLayer;
}
// Don't include wallpaper in bounds calculation
if (!ws.mIsWallpaper) {
final Rect wf = ws.mFrame;
final Rect cr = ws.mContentInsets;
int left = wf.left + cr.left;
int top = wf.top + cr.top;
int right = wf.right - cr.right;
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
}
}
Binder.restoreCallingIdentity(ident);
// Constrain frame to the screen size.
frame.intersect(0, 0, dw, dh);
if (frame.isEmpty() || maxLayer == 0) {
return null;
}
// The screenshot API does not apply the current screen rotation.
rot = mDisplay.getRotation();
int fw = frame.width();
int fh = frame.height();
// Constrain thumbnail to smaller of screen width or height. Assumes aspect
// of thumbnail is the same as the screen (in landscape) or square.
float targetWidthScale = width / (float) fw;
float targetHeightScale = height / (float) fh;
if (dw <= dh) {
scale = targetWidthScale;
// If aspect of thumbnail is the same as the screen (in landscape),
// select the slightly larger value so we fill the entire bitmap
if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
scale = targetHeightScale;
}
} else {
scale = targetHeightScale;
// If aspect of thumbnail is the same as the screen (in landscape),
// select the slightly larger value so we fill the entire bitmap
if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
scale = targetWidthScale;
}
}
// The screen shot will contain the entire screen.
dw = (int)(dw*scale);
dh = (int)(dh*scale);
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
int tmp = dw;
dw = dh;
dh = tmp;
rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
}
if (DEBUG_SCREENSHOT) {
Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
for (int i=0; i
由于我需要的是将缩略图翻转相应的度数,修改7中rot的值即可。