Android最近任务显示的图片

news2024/11/29 2:46:07

Android最近任务显示的图片

  • 1、TaskSnapshot截图
    • 1.1 snapshotTask
    • 1.2 drawAppThemeSnapshot
  • 2、导航栏显示问题
  • 3、Recentan按键进入最近任务

1、TaskSnapshot截图

frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java
frameworks/base/core/java/android/view/SurfaceControl.java
frameworks/base/core/jni/android_view_SurfaceControl.cpp
frameworks/native/libs/gui/SurfaceComposerClient.cpp
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

截图保存路径:data/system_ce/0/snapshots

TaskSnapshot captureTaskSnapshot(Task task, boolean snapshotHome) {
    final TaskSnapshot snapshot;
    if (snapshotHome) {
        snapshot = snapshotTask(task);
    } else {
        switch (getSnapshotMode(task)) {
            case SNAPSHOT_MODE_NONE:
                return null;
            case SNAPSHOT_MODE_APP_THEME:
                snapshot = drawAppThemeSnapshot(task);
                break;
            case SNAPSHOT_MODE_REAL:
                snapshot = snapshotTask(task);
                break;
            default:
                snapshot = null;
                break;
        }
    }
    return snapshot;
}

1.1 snapshotTask

SNAPSHOT_MODE_REAL:截图一张真实的屏幕截图作为快照。
实际截图缓存 SurfaceControl.captureLayersExcluding -> ScreenshotClient::captureLayers -> SurfaceFlinger::captureLayers

TaskSnapshot snapshotTask(Task task, int pixelFormat) {
    TaskSnapshot.Builder builder = new TaskSnapshot.Builder();

    if (!prepareTaskSnapshot(task, pixelFormat, builder)) {
        // Failed some pre-req. Has been logged.
        return null;
    }

    final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
            createTaskSnapshot(task, builder);

    if (screenshotBuffer == null) {
        // Failed to acquire image. Has been logged.
        return null;
    }
    builder.setSnapshot(screenshotBuffer.getHardwareBuffer());
    builder.setColorSpace(screenshotBuffer.getColorSpace());
    return builder.build();
}

SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
        TaskSnapshot.Builder builder) {
    Point taskSize = new Point();
    final SurfaceControl.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
            mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize, builder);
    builder.setTaskSize(taskSize);
    return taskSnapshot;
}

SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
        float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
    if (task.getSurfaceControl() == null) {
        if (DEBUG_SCREENSHOT) {
            Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
        }
        return null;
    }
    task.getBounds(mTmpRect);
    mTmpRect.offsetTo(0, 0);

    SurfaceControl[] excludeLayers;
    final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
    // Exclude IME window snapshot when IME isn't proper to attach to app.
    final boolean excludeIme = imeWindow != null && imeWindow.getSurfaceControl() != null
            && !task.getDisplayContent().shouldImeAttachedToApp();
    final WindowState navWindow =
            task.getDisplayContent().getDisplayPolicy().getNavigationBar();
    // If config_attachNavBarToAppDuringTransition is true, the nav bar will be reparent to the
    // the swiped app when entering recent app, therefore the task will contain the navigation
    // bar and we should exclude it from snapshot.
    final boolean excludeNavBar = navWindow != null;
    if (excludeIme && excludeNavBar) {
        excludeLayers = new SurfaceControl[2];
        excludeLayers[0] = imeWindow.getSurfaceControl();
        excludeLayers[1] = navWindow.getSurfaceControl();
    } else if (excludeIme || excludeNavBar) {
        excludeLayers = new SurfaceControl[1];
        excludeLayers[0] =
                excludeIme ? imeWindow.getSurfaceControl() : navWindow.getSurfaceControl();
    } else {
        excludeLayers = new SurfaceControl[0];
    }
    builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isVisible());

    final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
            SurfaceControl.captureLayersExcluding(
                    task.getSurfaceControl(), mTmpRect, scaleFraction,
                    pixelFormat, excludeLayers);
    if (outTaskSize != null) {
        outTaskSize.x = mTmpRect.width();
        outTaskSize.y = mTmpRect.height();
    }
    final HardwareBuffer buffer = screenshotBuffer == null ? null
            : screenshotBuffer.getHardwareBuffer();
    if (isInvalidHardwareBuffer(buffer)) {
        return null;
    }
    return screenshotBuffer;
}

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
                                       const sp<IScreenCaptureListener>& captureListener) {
    ATRACE_CALL();

    status_t validate = validateScreenshotPermissions(args);
    if (validate != OK) {
        return validate;
    }

    ui::Size reqSize;
    sp<Layer> parent;
    Rect crop(args.sourceCrop);
    std::unordered_set<sp<Layer>, SpHash<Layer>> excludeLayers;
    ui::Dataspace dataspace;

    // Call this before holding mStateLock to avoid any deadlocking.
    bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();

    {
        Mutex::Autolock lock(mStateLock);

        parent = fromHandle(args.layerHandle).promote();
        if (parent == nullptr) {
            ALOGE("captureLayers called with an invalid or removed parent");
            return NAME_NOT_FOUND;
        }

        if (!canCaptureBlackoutContent &&
            parent->getDrawingState().flags & layer_state_t::eLayerSecure) {
            ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
            return PERMISSION_DENIED;
        }

        Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState());
        if (args.sourceCrop.width() <= 0) {
            crop.left = 0;
            crop.right = parentSourceBounds.getWidth();
        }

        if (args.sourceCrop.height() <= 0) {
            crop.top = 0;
            crop.bottom = parentSourceBounds.getHeight();
        }

        if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) {
            // Error out if the layer has no source bounds (i.e. they are boundless) and a source
            // crop was not specified, or an invalid frame scale was provided.
            return BAD_VALUE;
        }
        reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);

        for (const auto& handle : args.excludeHandles) {
            sp<Layer> excludeLayer = fromHandle(handle).promote();
            if (excludeLayer != nullptr) {
                excludeLayers.emplace(excludeLayer);
            } else {
                ALOGW("Invalid layer handle passed as excludeLayer to captureLayers");
                return NAME_NOT_FOUND;
            }
        }

        // The dataspace is depended on the color mode of display, that could use non-native mode
        // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
        // and failed if display is not in native mode. This provide a way to force using native
        // colors when capture.
        dataspace = args.dataspace;
    } // mStateLock

    // really small crop or frameScale
    if (reqSize.width <= 0 || reqSize.height <= 0) {
        ALOGW("Failed to captureLayes: crop or scale too small");
        return BAD_VALUE;
    }

    Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height);
    bool childrenOnly = args.childrenOnly;
    RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
        return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
                                                 childrenOnly, layerStackSpaceRect,
                                                 args.captureSecureLayers);
    });

    auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) {
        parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
            if (!layer->isVisible()) {
                return;
            } else if (args.childrenOnly && layer == parent.get()) {
                return;
            } else if (args.uid != CaptureArgs::UNSET_UID && args.uid != layer->getOwnerUid()) {
                return;
            }

            sp<Layer> p = layer;
            while (p != nullptr) {
                if (excludeLayers.count(p) != 0) {
                    return;
                }
                p = p->getParent();
            }

            visitor(layer);
        });
    };

    if (captureListener == nullptr) {
        ALOGE("capture screen must provide a capture listener callback");
        return BAD_VALUE;
    }

    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
                                      args.pixelFormat, args.allowProtected, args.grayscale,
                                      captureListener);
    return fenceStatus(future.get());
}

1.2 drawAppThemeSnapshot

SNAPSHOT_MODE_APP_THEME:不允许截图真实的屏幕截图,但我们应该尝试使用应用程序主题来创建应用程序的虚假表示。

/**
 * If we are not allowed to take a real screenshot, this attempts to represent the app as best
 * as possible by using the theme's window background.
 */
private TaskSnapshot drawAppThemeSnapshot(Task task) {
    final ActivityRecord topChild = task.getTopMostActivity();
    if (topChild == null) {
        return null;
    }
    final WindowState mainWindow = topChild.findMainWindow();
    if (mainWindow == null) {
        return null;
    }
    final int color = ColorUtils.setAlphaComponent(
            task.getTaskDescription().getBackgroundColor(), 255);
    final LayoutParams attrs = mainWindow.getAttrs();
    final Rect taskBounds = task.getBounds();
    final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride();
    final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
    final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
            attrs.privateFlags, attrs.insetsFlags.appearance, task.getTaskDescription(),
            mHighResTaskSnapshotScale, insetsState);
    final int taskWidth = taskBounds.width();
    final int taskHeight = taskBounds.height();
    final int width = (int) (taskWidth * mHighResTaskSnapshotScale);
    final int height = (int) (taskHeight * mHighResTaskSnapshotScale);

    final RenderNode node = RenderNode.create("TaskSnapshotController", null);
    node.setLeftTopRightBottom(0, 0, width, height);
    node.setClipToBounds(false);
    final RecordingCanvas c = node.start(width, height);
    c.drawColor(color);
    decorPainter.setInsets(systemBarInsets);
    decorPainter.drawDecors(c /* statusBarExcludeFrame */);
    node.end(c);
    final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
    if (hwBitmap == null) {
        return null;
    }
    final Rect contentInsets = new Rect(systemBarInsets);
    final Rect letterboxInsets = topChild.getLetterboxInsets();
    InsetUtils.addInsets(contentInsets, letterboxInsets);

    // Note, the app theme snapshot is never translucent because we enforce a non-translucent
    // color above
    return new TaskSnapshot(
            System.currentTimeMillis() /* id */,
            topChild.mActivityComponent, hwBitmap.getHardwareBuffer(),
            hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
            mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
            contentInsets, letterboxInsets, false /* isLowResolution */,
            false /* isRealSnapshot */, task.getWindowingMode(),
            getAppearance(task), false /* isTranslucent */, false /* hasImeSurface */);
}

2、导航栏显示问题

应用设置导航栏可避免图片底部黑条

<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:navigationBarColor">@android:color/transparent</item>

3、Recentan按键进入最近任务

<!-- Component name for the activity that will be presenting the Recents UI, which will receive
     special permissions for API related to fetching and presenting recent tasks. The default
     configuration uses Launcehr3QuickStep as default launcher and points to the corresponding
     recents component. When using a different default launcher, change this appropriately or
     use the default systemui implementation: com.android.systemui/.recents.RecentsActivity -->
<string name="config_recentsComponentName" translatable="false"
        >com.android.launcher3/com.android.quickstep.RecentsActivity</string>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1902726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++ primer plus 第15章友,异常和其他: 15.2.1 嵌套类和访问权限系

c primer plus 第15章友&#xff0c;异常和其他&#xff1a; 15.2.1 嵌套类和访问权限系 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;c primer plus 第15章友&#xff0c;异常和其他&#xff1a; 15.2.1 嵌套类和…

详解Amivest 流动性比率

详解Amivest 流动性比率 Claude-3.5-Sonnet Poe Amivest流动性比率是一个衡量证券市场流动性的重要指标。这个比率主要用于评估在不对价格造成重大影响的情况下,市场能够吸收多少交易量。以下是对Amivest流动性比率的详细解释: 定义: Amivest流动性比率是交易额与绝对收益率的…

柯桥职场英语学习商务英语口语生活英语培训生活口语学习

辣妹用英语怎么说&#xff1f; 辣妹在英语中通常被翻译为“hot girl”或“spicy girl”&#xff0c;但更常见和直接的是“hot chick”或简单地使用“hot”来形容。 举个例子: Shes a real hot girl with her trendy outfit and confident attitude. 她真是个辣妹&#xff0…

Linux:进程终止和进程替换

Linux&#xff1a;Linux&#xff1a;进程终止和进程替换 一、进程终止1.1 进程退出场景和创建退出方式 1.2 exit 和 _exit区别二、进程程序替换2.1 进程替换函数2.2 函数解释及命名解释函数解释命名解释 2.3 单进程程序替换&#xff08;无子进程&#xff09;2.3.1 带l函数进程替…

Ubuntu配置GitHub(第一次clone/push)

文章目录 1. 安装Git&检查连接2. 注册GitHub3. 生成&GitHub添加SSH3.1. 检查&删除已有id_rsa3.2. 生成SSH3.3. GitHub添加id_rsa.pub SSH3.4. 检查SSH 4. 继续开发可以参考参考 1. 安装Git&检查连接 安装 sudo apt-get install git检查SSH连接 ssh -T gitgi…

C++——stack和queue类用法指南

一、stack的介绍和使用 1.1 stack的介绍 1、stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行插入与提取操作 2、stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&am…

clickhouse高可用可拓展部署

clickhouse高可用&可拓展部署 1.部署架构 1.1高可用架构 1.2硬件资源 部署服务 节点名称 节点ip 核数 内存 磁盘 zookeeper zk-01 / 4c 8G 100G zk-02 / 4c 8G 100G zk-03 / 4c 8G 100G clikehouse ck-01 / 32c 128G 2T ck-02 / 32c 128G 2T ck-03 / 32c 128G 2T ck-04 /…

设计模式之模版方法

模版方法介绍 模版方法&#xff08;Template Method&#xff09;模式是一种行为型设计模式&#xff0c;它定义了一个操作&#xff08;模板方法&#xff09;的基本组合与控制流程&#xff0c;将一些步骤&#xff08;抽象方法&#xff09;推迟到子类中&#xff0c;使得子类可以在…

LeetCode热题100刷题8:54. 螺旋矩阵、73. 矩阵置零、48. 旋转图像

54. 螺旋矩阵 class Solution { public:vector<int> spiralOrder(vector<vector<int>>& matrix) {vector<int> vec;if(matrix.empty())return vec;int left0;int right matrix[0].size()-1;int up0;int down matrix.size()-1;while(true) {for(i…

【TB作品】脉搏测量,ATMEGA8单片机,Proteus仿真,ATmega8控制脉搏测量与显示系统

硬件组成&#xff1a; LCD1602脉搏测量电路&#xff08;带灯&#xff09;蜂鸣器报警按键设置AT24C02 功能&#xff1a; &#xff08;1&#xff09;LCD1602主页显示脉搏、报警上限、报警下限&#xff1b; &#xff08;2&#xff09;五个按键&#xff1a;按键1&#xff1a;切换设…

axios的使用,处理请求和响应,axios拦截器

1、axios官网 https://www.axios-http.cn/docs/interceptors 2、安装 npm install axios 3、在onMouunted钩子函数中使用axios来发送请求&#xff0c;接受响应 4.出现的问题&#xff1a; &#xff08;1&#xff09; 但是如果发送请求请求时间过长&#xff0c;回出现请求待处…

RK3568 GPU介绍及使用

一、RK3568简介 RK3568四核64位Cortex-A55 处理器&#xff0c;采用全新ARM v8.2-A架构&#xff0c;主频最高可达2.0GHz&#xff0c;效能有大幅提升&#xff1b;采用22nm先进工艺&#xff0c;具有低功耗高性能的特点RK3568集成了双核心架构 GPU&#xff0c;高性能VPU以及高效能…

YOLOv8_obb数据集可视化[旋转目标检测实践篇]

先贴代码,周末再补充解析。 这个篇章主要是对标注好的标签进行可视化,虽然比较简单,但是可以从可视化代码中学习到YOLOv8是如何对标签进行解析的。 import cv2 import numpy as np import os import randomdef read_obb_labels(label_file_path):with open(label_file_path,…

Linux内存管理--系列文章柒——硬件架构

一、引子 之前文章讲解的是系统的虚拟内存&#xff0c;本章讲述这些硬件的架构和系统怎样统一管理这些硬件的。 二、物理内存模型 物理内存模型描述了计算机系统中的物理内存如何由操作系统组织和管理。它定义了物理内存如何划分为单元&#xff0c;如何寻址这些单元以及如何…

yolov8实战——yolov8TensorRT部署(python推理)(保姆教学)

yolov8实战——yolov8TensorRT部署&#xff08;python推理&#xff09;&#xff08;保姆教学&#xff09; 一 、准备好代码和环境安装TensorRt下载代码和安装环境 部署和推理构建ONNX构建engine无torch推理torch推理 最近用到yolov8&#xff0c;但是寻找了一圈才找到了yolov8最…

Java 自定义集合常量

文章目录 Java 自定义集合常量一、普通方法自定义集合常量信息1、定义 Map 集合信息&#xff08;1&#xff09;方法一&#xff1a;使用静态代码块&#xff08;2&#xff09;方法二&#xff1a;简单定义 Map 常量 2、定义 List 集合信息3、定义 Set 集合信息 二、通过 Collectio…

Node.js-path 模块

path 模块 path 模块提供了 操作路径 的功能&#xff0c;如下是几个较为常用的几个 API&#xff1a; 代码实例&#xff1a; const path require(path);//获取路径分隔符 console.log(path.sep);//拼接绝对路径 console.log(path.resolve(__dirname, test));//解析路径 let pa…

一文学会 BootStrap

文章目录 认识BootStrap历史优缺点使用注意安装CDN源码引入包管理器 媒体查询屏幕尺寸的分割点&#xff08;Breakpoints&#xff09;响应式容器网格系统基本使用底层实现.container.row.col、.col-份数 网格嵌套自动布局列 Auto-layout响应式类 Responsive Class 响应式工具类-…

前端根据目录生成模块化路由routes

根据约定大于配置的逻辑&#xff0c;如果目录结构约定俗成&#xff0c;前端是可以根据目录结构动态生成路由所需要的 route 结构的&#xff0c;这个过程是要在编译时 进行&#xff0c;生成需要的代码&#xff0c;保证运行时的代码正确即可 主流的打包工具都有对应的方法读取文…

Qt(二)弹窗类 颜色对话框 字体对话框 资源文件

文章目录 一、QDebug类和QMessagebox类&#xff08;一&#xff09;QDebug类&#xff1a;打印调试类&#xff08;二&#xff09;QMessagebox类&#xff1a;弹窗类2. 修改组件图标&#xff08;1&#xff09;通过ui界面&#xff08;2&#xff09;通过QIcon的方式&#xff08;3&…