Android最近任务显示的图片

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>

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Blazor SPA 的本质是什么以及服务器端渲染如何与 Blazor 的新 Web 应用程序配合使用

Blazor 通常被称为单页应用程序 (SPA) 框架。当我第一次开始使用 Blazor 时&#xff0c;我对 SPA 的含义、组件如何为 SPA 架构做出贡献以及所有这些如何与交互性联系在一起感到困惑。 今天&#xff0c;我将解答大家可能关心的三个问题&#xff1a; 什么是 SPA&#xff1f;了…

Sentinel-1 Level 1数据处理的详细算法定义(一)

《Sentinel-1 Level 1数据处理的详细算法定义》文档定义和描述了Sentinel-1实现的Level 1处理算法和方程&#xff0c;以便生成Level 1产品。这些算法适用于Sentinel-1的Stripmap、Interferometric Wide-swath (IW)、Extra-wide-swath (EW)和Wave模式。 今天介绍的内容如下&…

14-42 剑和诗人16 - 如何从一个技术人员到CTO再到投资人的角色转变

​​​​​​ 我清楚地记得我的职业轨迹发生转变的那个关键时刻。当时&#xff0c;我正向整个执行领导团队和董事会成员介绍我们部门的技术路线图&#xff0c;感到说服这些有影响力的利益相关者资助一系列雄心勃勃的计划的压力。我知道他们的支持&#xff08;和资金&#xff09…

英语学习交流小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;每日打卡管理&#xff0c;备忘录管理&#xff0c;学习计划管理&#xff0c;学习资源管理&#xff0c;论坛交流 微信端账号功能包括&#xff1a;系统首页&#xff0c;学习资源&…

基于最大相邻夹角的边缘点提取(matlab)

1、背景介绍 边缘点是指点云数据中代表物体或场景几何形状突变的那些点。在三维点云中&#xff0c;边缘点通常标志着不同表面或物体的分界&#xff0c;或者是物体表面上的不规则性&#xff0c;如裂缝、棱角、突起等。点云边缘检测的作用非常重要&#xff0c;最常见是进行特征点…

应用监控SkyWalking调研

参考&#xff1a; 链路追踪( Skyworking )_skywalking-CSDN博客 企业级监控项目Skywalking详细介绍&#xff0c;来看看呀-CSDN博客 SkyWalking 极简入门 | Apache SkyWalking 使用 SkyWalking 监控 ClickHouse Server | Apache SkyWalking https://zhuanlan.zhihu.com/p/3…

45 mysql truncate 的实现

前言 truncate 是一个我们也经常会使用到的命令 其作用类似于 delete from $table; 但是 他会比 delete 块很多&#xff0c;这里我们来看一下 它的实现 delete 的时候会逐行进行处理, 打上 删除标记, 然后 由后台任务 进行数据处理 truncate table 的实现 执行 sql 如下 …

【测试专题】软件总体计划方案(2024原件word)

测试目标&#xff1a;确保项目的需求分析说明书中的所有功能需求都已实现&#xff0c;且能正常运行&#xff1b;确保项目的业务流程符合用户和产品设计要求&#xff1b;确保项目的界面美观、风格一致、易学习、易操作、易理解。 获取&#xff1a;软件全套文档过去进主页。 一、…

Go语言--工程管理、临时/永久设置GOPATH、main函数以及init函数

工作区 Go 代码必须放在工作区中。工作区其实就是一个对应于特定工程的目录&#xff0c;它应包含3个子目录:src 目录、pkg目录和bin 目录。 src 目录:用于以代码包的形式组织并保存 Go源码文件。(比如:.go.chs等)pkg 目录:用于存放经由 go install 命令构建安装后的代码包(包…

2.3.2 主程序和外部IO交互 (文件映射方式)----C#调用范例

2.3.2 主程序和外部IO交互 &#xff08;文件映射方式&#xff09;----C#调用范例 效果显示 1 说明 1 .1 Test_IOServer是64bit 程序&#xff0c; BD_SharedIOServerd.dll 在 /Debug文件夹中 1 .2 Test_IOServer是32bit 程序&#xff0c; BD_SharedIOClientd.dll (32bit&#…

java join与yield方法

join() join() 方法的主要作用是使当前线程&#xff08;调用 join() 方法的线程&#xff09;等待目标线程完成执行。当目标线程执行完毕后&#xff0c;当前线程才会继续执行。 代码示例&#xff1a; public class JoinExample {public static void main(String[] args) {Thr…

在数字化时代,自助BI是数据价值最大化的必经之路

引言&#xff1a;在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;仅仅拥有海量数据并不足以带来竞争优势&#xff0c;关键在于如何有效地分析并利用这些数据以指导决策、优化运营、提升客户体验&#xff0c;并最终实现业务的持续增长。在一章里笔者…

SpringBoot新手快速入门系列教程七:基于一个低配centoos服务器,如何通过宝塔面板部署一个SpringBoot项目

1&#xff0c;如何打包一个项目 通过IDEA自带的命令行&#xff0c;执行 ./gradlew clean build 2&#xff0c;检查生成的JAR文件 进入 build/libs 目录&#xff0c;你应该会看到一个类似 helloredis-0.0.1-SNAPSHOT.jar 的文件。 3&#xff1a;运行生成的JAR文件 你可以使…

springboot服务启动读取不到application.yml中的nacos.config信息

我的版本&#xff1a; 可以添加bootstrap.yml文件&#xff0c;在里面添加nacos.config的配置信息 也可以添加VM参数 -Dspring.cloud.nacos.discovery.server-addr -Dspring.cloud.nacos.config.server-addr -Dspring.cloud.nacos.config.namespace -Dspring.cloud.nacos.discov…

图片管理新纪元:高效批量横向拼接图片,一键生成灰色艺术效果,打造专业视觉体验!

在数字时代&#xff0c;图片已成为我们生活和工作中不可或缺的一部分。但面对海量的图片&#xff0c;如何高效地进行批量管理、拼接和调色&#xff0c;成为许多人面临的难题。今天&#xff0c;我们为您带来了一款颠覆性的图片管理工具&#xff0c;让您轻松实现图片批量横向拼接…

设计模式探索:建造者模式

1. 什么是建造者模式 建造者模式 (Builder Pattern)&#xff0c;也被称为生成器模式&#xff0c;是一种创建型设计模式。 定义&#xff1a;将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 建造者模式要解决的问题&#xff1a; 建造者模…

前端面试题(CSS篇四)

一、CSS 优化、提高性能的方法有哪些&#xff1f; 加载性能&#xff1a; &#xff08;1&#xff09;css压缩&#xff1a;将写好的css进行打包压缩&#xff0c;可以减少很多的体积。 &#xff08;2&#xff09;css单一样式&#xff1a;当需要下边距和左边距的时候&#xff0c;很…

kafka中

Kafka RocketMQ概述 RabbitMQ概述 ActiveMQ概述 ZeroMQ概述 MQ对比选型 适用场景-从公司基础建设力量角度出发 适用场景-从业务场景出发 Kafka配置介绍 运行Kafka 安装ELAK 配置EFAK EFAK界面 KAFKA常用术语 Kafka常用指令 Kafka中消息读取 单播消息 group.id 相同 多播消息 g…

【VUE基础】VUE3第三节—核心语法之ref标签、props

ref标签 作用&#xff1a;用于注册模板引用。 用在普通DOM标签上&#xff0c;获取的是DOM节点。 用在组件标签上&#xff0c;获取的是组件实例对象。 用在普通DOM标签上&#xff1a; <template><div class"person"><h1 ref"title1">…

Vmware环境下ESXi主机 配置上行链路、虚拟交换机、端口组、VMkernel网卡

一、适用场景 1、使用专业服务器跑多种不同的业务&#xff0c;每种业务可能所需运行的server环境不同&#xff0c;有的需要Linux server CentOS7/8、kali、unbuntu……有的需要windows server2008、2003、2016、2019、2022…… 2、本例采用的是VMware ESXi6.7 update 3版本&am…