现在的位置: 首页 > 综合 > 正文

android4.0新功能之—- 打开最近的应用程序出现缩略图的分析

2013年01月30日 ⁄ 综合 ⁄ 共 9398字 ⁄ 字号 评论关闭

本人对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<TaskDescription> 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<TaskDescription> getRecentTasks() {       
        cancelLoadingThumbnails();

        ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
        final PackageManager pm = mContext.getPackageManager();
        final ActivityManager am = (ActivityManager)
                mContext.getSystemService(Context.ACTIVITY_SERVICE);

        final List<ActivityManager.RecentTaskInfo> recentTasks =
                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);

        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
                    .resolveActivityInfo(pm, 0);

        HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
        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<TaskDescription>(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<mWindows.size(); i++) {
                    Slog.i(TAG, mWindows.get(i) + ": " + mWindows.get(i).mLayer
                            + " animLayer=" + mWindows.get(i).mAnimLayer
                            + " surfaceLayer=" + mWindows.get(i).mSurfaceLayer);
                }
            }
            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
        }

        if (rawss == null) {
            Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
                    + ") to layer " + maxLayer);
            return null;
        }

        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
        Matrix matrix = new Matrix();
        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
        matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
        Canvas canvas = new Canvas(bm);
        canvas.drawBitmap(rawss, matrix, null);
        canvas.setBitmap(null);

        rawss.recycle();
        return bm;
    }

由于我需要的是将缩略图翻转相应的度数,修改7中rot的值即可。

 

抱歉!评论已关闭.