zoukankan      html  css  js  c++  java
  • 系统多任务问题

    1.代码位置:

    frameworks/base/packages/SystemUI/src/com/android/systemui/recent/

    /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    ..../TaskRecord.java
    ../wm/WindowManagerService.java
    ActivityManagerService.java
    @Override public ActivityManager.TaskThumbnail getTaskThumbnail(int id) { synchronized (this) { enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, "getTaskThumbnail()"); TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id); if (tr != null) { return tr.getTaskThumbnailLocked(); } } return null; }
    TaskRecord.java
    public TaskThumbnail getTaskThumbnailLocked() { if (stack != null) { final ActivityRecord resumedActivity = stack.mResumedActivity; if (resumedActivity != null && resumedActivity.task == this) { final Bitmap thumbnail = stack.screenshotActivities(resumedActivity); setLastThumbnail(thumbnail); } } final TaskThumbnail taskThumbnail = new TaskThumbnail(); getLastThumbnail(taskThumbnail); return taskThumbnail; }
    ActivityStack.java  
    public final Bitmap screenshotActivities(ActivityRecord who) { if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who); if (who.noDisplay) { if (DEBUG_SCREENSHOTS) Slog.d(TAG, " No 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, " Home stack"); return null; } int w = mService.mThumbnailWidth; int h = mService.mThumbnailHeight; if (w > 0) { if (DEBUG_SCREENSHOTS) Slog.d(TAG, " Taking 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; }
    WindowManagerService.java
    /** * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. * In portrait mode, it grabs the upper region of the screen based on the vertical dimension * of the target image. * * @param displayId the Display to take a screenshot of. * @param width the width of the target bitmap * @param height the height of the target bitmap * @param force565 if true the returned bitmap will be RGB_565, otherwise it * will be the same config as the surface */ @Override 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); if (displayContent == null) { if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken + ": returning null. No Display for displayId=" + displayId); return null; } final DisplayInfo displayInfo = displayContent.getDisplayInfo(); int dw = displayInfo.logicalWidth; int dh = displayInfo.logicalHeight; if (dw == 0 || dh == 0) { if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken + ": returning null. logical widthxheight=" + dw + "x" + dh); return null; } Bitmap bm = null; int maxLayer = 0; final Rect frame = new Rect(); final Rect stackBounds = new Rect(); float scale = 0; int rot = Surface.ROTATION_0; boolean screenshotReady; int minLayer; if (appToken == null) { screenshotReady = true; minLayer = 0; } else { screenshotReady = false; minLayer = Integer.MAX_VALUE; } int retryCount = 0; WindowState appWin = null; final boolean appIsImTarget = mInputMethodTarget != null && mInputMethodTarget.mAppToken != null && mInputMethodTarget.mAppToken.appToken != null && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken; final int aboveAppLayer = (mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; while (true) { if (retryCount++ > 0) { // Reset max/min layers on retries so we don't accidentally take a screenshot of a // layer based on the previous try. maxLayer = 0; minLayer = Integer.MAX_VALUE; try { Thread.sleep(100); } catch (InterruptedException e) { } } synchronized(mWindowMap) { // Figure out the part of the screen that is actually the app. appWin = null; final WindowList windows = displayContent.getWindowList(); for (int i = windows.size() - 1; i >= 0; i--) { WindowState ws = windows.get(i); if (!ws.mHasSurface) { continue; } if (ws.mLayer >= aboveAppLayer) { continue; } if (ws.mIsImWindow) { if (!appIsImTarget) { continue; } } else if (ws.mIsWallpaper) { if (appWin == null) { // We have not ran across the target window yet, so it is probably // behind the wallpaper. This can happen when the keyguard is up and // all windows are moved behind the wallpaper. We don't want to // include the wallpaper layer in the screenshot as it will coverup // the layer of the target window. continue; } // Fall through. The target window is in front of the wallpaper. For this // case we want to include the wallpaper layer in the screenshot because // the target window might have some transparent areas. } else if (appToken != null) { if (ws.mAppToken == null || ws.mAppToken.token != appToken) { // This app window is of no interest if it is not associated with the // screenshot app. continue; } appWin = ws; } // Include this window. final WindowStateAnimator winAnim = ws.mWinAnimator; if (maxLayer < winAnim.mSurfaceLayer) { maxLayer = winAnim.mSurfaceLayer; } if (minLayer > winAnim.mSurfaceLayer) { minLayer = winAnim.mSurfaceLayer; } // 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); ws.getStackBounds(stackBounds); frame.intersect(stackBounds); } if (ws.mAppToken != null && ws.mAppToken.token == appToken && ws.isDisplayedLw()) { screenshotReady = true; } } if (appToken != null && appWin == null) { // Can't find a window to snapshot. if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: Couldn't find a surface matching " + appToken); return null; } if (!screenshotReady) { if (retryCount > MAX_SCREENSHOT_RETRIES) { Slog.i(TAG, "Screenshot max retries " + retryCount + " of " + appToken + " appWin=" + (appWin == null ? "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState))); return null; } // Delay and hope that window gets drawn. if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState); continue; } // Screenshot is ready to be taken. Everything from here below will continue // through the bottom of the loop and return a value. We only stay in the loop // because we don't want to release the mWindowMap lock until the screenshot is // taken. if (maxLayer == 0) { if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken + ": returning null maxLayer=" + maxLayer); return null; } // Constrain frame to the screen size. frame.intersect(0, 0, dw, dh); // Tell surface flinger what part of the image to crop. Take the top // right part of the application, and crop the larger dimension to fit. Rect crop = new Rect(frame); if (width / (float) frame.width() < height / (float) frame.height()) { int cropWidth = (int)((float)width / (float)height * frame.height()); crop.right = crop.left + cropWidth; } else { int cropHeight = (int)((float)height / (float)width * frame.width()); crop.bottom = crop.top + cropHeight; } // The screenshot API does not apply the current screen rotation. rot = getDefaultDisplayContentLocked().getDisplay().getRotation(); if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; } // Surfaceflinger is not aware of orientation, so convert our logical // crop to surfaceflinger's portrait orientation. convertCropForSurfaceFlinger(crop, rot, dw, dh); if (DEBUG_SCREENSHOT) { Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to " + maxLayer + " appToken=" + appToken); for (int i = 0; i < windows.size(); i++) { WindowState win = windows.get(i); Slog.i(TAG, win + ": " + win.mLayer + " animLayer=" + win.mWinAnimator.mAnimLayer + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer); } } ScreenRotationAnimation screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); final boolean inRotation = screenRotationAnimation != null && screenRotationAnimation.isAnimating(); if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG, "Taking screenshot while rotating"); bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer, inRotation, rot); if (bm == null) { Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh + ") to layer " + maxLayer); return null; } } break; } if (DEBUG_SCREENSHOT) { // TEST IF IT's ALL BLACK int[] buffer = new int[bm.getWidth() * bm.getHeight()]; bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight()); boolean allBlack = true; final int firstColor = buffer[0]; for (int i = 0; i < buffer.length; i++) { if (buffer[i] != firstColor) { allBlack = false; break; } } if (allBlack) { Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" + Integer.toHexString(firstColor) + ")! mSurfaceLayer=" + (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") + " minLayer=" + minLayer + " maxLayer=" + maxLayer); } } // Copy the screenshot bitmap to another buffer so that the gralloc backed // bitmap will not have a long lifetime. Gralloc memory can be pinned or // duplicated and might have a higher cost than a skia backed buffer. Bitmap ret = bm.copy(bm.getConfig(),true); bm.recycle(); return ret; }
    frameworks/base/core/java/android/view/SurfaceControl.java

    ComponentName(组件名称)是用来打开其他应用程序中的Activity或服务的。

    在Android应用程序中如果要详细描述一个组件我们需要知道该组件所在的应用包名,也就是在AndroidManifest.xml文件中manifest根结点下的package=“XXX.XXXXX.XXXXX",还有组件在应用程序中的完整路径名,拿Activity来说,也就是activity节点中name属性的值。因此到这里我们也就明白了可以使用ComponentName来封装一个组件的应用包名和组件的名字

    Intent it=new Intent();
    it.setComponent(new ComponentName(String packageName,String activityName ));
    startActivity(it);
    RecentPanelView.java
    public void handleOnClick(View view) { Log.d(TAG,"handleOnClick"); ViewHolder holder = (ViewHolder) view.getTag(); TaskDescription ad = holder.taskDescription; final Context context = view.getContext(); final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); Bitmap bm = null; boolean usingDrawingCache = true; if (holder.thumbnailViewDrawable instanceof BitmapDrawable) { bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap(); if (bm.getWidth() == holder.thumbnailViewImage.getWidth() && bm.getHeight() == holder.thumbnailViewImage.getHeight()) { usingDrawingCache = false; } } if (usingDrawingCache) { holder.thumbnailViewImage.setDrawingCacheEnabled(true); bm = holder.thumbnailViewImage.getDrawingCache(); } Bundle opts = (bm == null) ? null : ActivityOptions.makeThumbnailScaleUpAnimation( holder.thumbnailViewImage, bm, 0, 0, null).toBundle(); show(false); if (ad.taskId >= 0) { // This is an active task; it should just go to the foreground. /*am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME, opts);*/ boolean successful; try { Method method = Class.forName("android.app.ActivityManager") .getMethod("moveTaskToFrontWithResult", int.class, int.class, Bundle.class); successful = (Boolean) method.invoke(am, ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME, opts); Log.d(TAG, "invoke moveTaskToFrontWithResult successful: " + successful); if(!successful) { startActivityFromRecent(ad, context, opts); } } catch (NoSuchMethodException e) { am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME, opts); } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "invoke moveTaskToFrontWithResult failed: " + e); // TODO: handle exception } Log.v(TAG, "Move Task To Front for " + ad.taskId); } else { startActivityFromRecent(ad, context, opts); } if (usingDrawingCache) { holder.thumbnailViewImage.setDrawingCacheEnabled(false); } } private void startActivityFromRecent(TaskDescription ad, final Context context, Bundle opts) { Intent intent = ad.intent; intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK); if (DEBUG) Log.v(TAG, "Starting activity " + intent); try { context.startActivityAsUser(intent, opts, new UserHandle(ad.userId)); } catch (SecurityException e) { Log.e(TAG, "Recents does not have the permission to launch " + intent, e); } catch (ActivityNotFoundException e) { Log.e(TAG, "Error launching activity " + intent, e); } }
     /**
         * Version of {@link #startActivity(Intent)} that allows you to specify the
         * user the activity will be started for.  This is not available to applications
         * that are not pre-installed on the system image.  Using it requires holding
         * the INTERACT_ACROSS_USERS_FULL permission.
         * @param intent The description of the activity to start.
         * @param user The UserHandle of the user to start this activity for.
         * @throws ActivityNotFoundException &nbsp;
         * @hide
         */
        public void startActivityAsUser(Intent intent, UserHandle user) {
            throw new RuntimeException("Not implemented. Must override in a subclass.");
        }
  • 相关阅读:
    android 多线程
    android调用 .net webService
    android apk程序升级
    android连数据库
    android事件
    android 服务
    android 活动
    (12)android控件-Advanced
    (11)android控件-Transitions
    (10) android控件-date
  • 原文地址:https://www.cnblogs.com/zhengtu2015/p/5125302.html
Copyright © 2011-2022 走看看