android双屏之副屏待机显示图片

摘要:android原生有双屏的机制,但需要芯片厂商适配框架后在底层实现。本文在基于芯发8766已实现底层适配的基础上,仅针对上层Launcher部分对系统进行改造,从而实现在开机后副屏显示一张待机图片。

副屏布局

由于仅显示一张图片,故布局仅需填充ImageView

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_image.xml
===================================================================
--- vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_image.xml	(不存在的)
+++ vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_image.xml	(版本 1687)
@@ -0,0 +1,6 @@
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/image_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scaleType="centerInside" />

关于android:scaleType的详细说明和用法,可参考官网API
或者以下BLOG:
Android的ImageView scaleType八大属性,你都了解吗?
android学习笔记之ImageView的scaleType属性

准备一张符合副屏分辨率的图片

博主所使用的副屏为320x240,图片格式为JPG

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/res/mipmap-hdpi/presents.jpg

副屏图片管理类

新增图换图片功能,在显示以上图片的基础上,如果所指定路径有替换的图片文件,则使用替换的图片文件。

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/ImagePresentation.java
===================================================================
--- vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/ImagePresentation.java	(不存在的)
+++ vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/ImagePresentation.java	(版本 1687)
@@ -0,0 +1,48 @@
+package com.android.launcher3.presentation;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.Display;
+import android.widget.ImageView;
+
+import com.android.launcher3.R;
+
+import java.io.File;
+
+public class ImagePresentation extends Presentation {
+    private static final String TAG = "ImagePresentation";
+
+    ImageView imageView;
+
+    public ImagePresentation(Context context, Display display) {
+        super(context, display);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.presentation_image);
+
+        imageView = findViewById(R.id.image_view);
+        imageView.setImageResource(R.mipmap.presents);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/presents_replace.jpg";
+        File imageFile = new File(path);
+        if (imageFile.exists()) {
+            imageView.setImageURI(Uri.fromFile(new File(path)));
+        } else {
+            Log.d(TAG, "The replacement image does not exist, use the original image");
+        }
+    }
+}

在Launcher部分的实现

由于需要开机后显示待机的图片,并且副屏的内容默认是投射填充主屏的内容,故开机后会有准备阶段,主要显示一部分Launcher的内容,在完全准备好后,再显示副屏的待机图片。

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
===================================================================
--- vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java	(版本 1678)
+++ vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java	(版本 1687)
@@ -70,6 +70,7 @@import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.PendingIntent;
+import android.app.Presentation;import android.appwidget.AppWidgetHostView;import android.appwidget.AppWidgetManager;import android.content.ActivityNotFoundException;
@@ -86,6 +87,7 @@import android.graphics.Bitmap;import android.graphics.Rect;import android.graphics.RectF;
+import android.hardware.display.DisplayManager;import android.os.Build;import android.os.Bundle;import android.os.CancellationSignal;
@@ -99,6 +101,7 @@import android.text.method.TextKeyListener;import android.util.Log;import android.util.SparseArray;
+import android.view.Display;import android.view.KeyEvent;import android.view.KeyboardShortcutGroup;import android.view.KeyboardShortcutInfo;
@@ -168,6 +171,7 @@import com.android.launcher3.popup.PopupContainerWithArrow;import com.android.launcher3.popup.PopupDataProvider;import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.presentation.ImagePresentation;import com.android.launcher3.qsb.QsbContainerView;import com.android.launcher3.statemanager.StateManager;import com.android.launcher3.statemanager.StateManager.StateHandler;
@@ -387,6 +391,11 @@private StringCache mStringCache;+    // @ + {
+    private DisplayManager mDisplayManager;
+    private Presentation secondaryPresentation;
+    // @ + }
+@Override@TargetApi(Build.VERSION_CODES.S)protected void onCreate(Bundle savedInstanceState) {
@@ -453,6 +462,34 @@super.onCreate(savedInstanceState);+        // @ + {
+        mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                Log.d(TAG, "onDisplayAdded");
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                Log.d(TAG, "onDisplayRemoved");
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {}
+        }, null);
+
+        Display[] displays = mDisplayManager.getDisplays();
+        for (Display display : displays) {
+            if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+                secondaryPresentation = new ImagePresentation(this, display);
+                //secondaryPresentation = new VideoPresentation(this, display);
+                secondaryPresentation.show();
+                break;
+            }
+        }
+        // @ + }
+LauncherAppState app = LauncherAppState.getInstance(this);mOldConfig = new Configuration(getResources().getConfiguration());mModel = app.getModel();
@@ -1718,6 +1755,12 @@mOverlayManager.onActivityDestroyed(this);mUserChangedCallbackCloseable.close();
+
+        // @ + {
+        if (secondaryPresentation != null && secondaryPresentation.isShowing()) {
+            secondaryPresentation.dismiss();
+        }
+        // @ + }}public LauncherAccessibilityDelegate getAccessibilityDelegate() {

扩展 —— 副屏视频布局

能显示图片,自然也能播放视频

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_video.xml
===================================================================
--- vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_video.xml	(不存在的)
+++ vendor/mediatek/proprietary/packages/apps/Launcher3/res/layout/presentation_video.xml	(版本 1687)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<VideoView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/video_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scaleType="centerCrop" />

准备一段符合副屏分辨率的视频

博主所使用的副屏为320x240,视频格式为MP4

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/res/raw/video_320_240.mp4

副屏视频管理类

播放的视频内容需要根据副屏的比例进行缩放,并且根据实际情况实现循环播放。

Index: vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/VideoPresentation.java
===================================================================
--- vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/VideoPresentation.java	(不存在的)
+++ vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/presentation/VideoPresentation.java	(版本 1687)
@@ -0,0 +1,68 @@
+package com.android.launcher3.presentation;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Display;
+import android.view.ViewGroup;
+import android.widget.VideoView;
+
+import com.android.launcher3.R;
+
+public class VideoPresentation extends Presentation {
+    private static final String TAG = "VideoPresentation";
+    private VideoView videoView;
+
+    public VideoPresentation(Context context, Display display) {
+        super(context, display);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.presentation_video);
+        videoView = findViewById(R.id.video_view);
+
+        Uri videoUri = Uri.parse("android.resource://" + getContext().getPackageName() + "/" + R.raw.video_320_240);
+        videoView.setVideoURI(videoUri);
+
+        videoView.setOnPreparedListener(mp -> {
+            int videoWidth = mp.getVideoWidth();
+            int videoHeight = mp.getVideoHeight();
+
+            Point screenSize = new Point();
+            getDisplay().getRealSize(screenSize);
+            int screenWidth = screenSize.x;
+            int screenHeight = screenSize.y;
+
+            float widthRatio = (float) screenWidth / videoWidth;
+            float heightRatio = (float) screenHeight / videoHeight;
+            float scale = Math.min(widthRatio, heightRatio);
+
+            ViewGroup.LayoutParams params = videoView.getLayoutParams();
+            params.width = (int) (videoWidth * scale);
+            params.height = (int) (videoHeight * scale);
+            videoView.setLayoutParams(params);
+        });
+
+        videoView.setOnCompletionListener(mp -> {
+            videoView.start(); // replay
+        });
+
+        
+
+        videoView.start();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (videoView != null) {
+            videoView.stopPlayback();
+        }
+    }
+}
+

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

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

相关文章

STM32之中断

一、提高程序实时性的架构方案 轮询式 指的是在程序运行时&#xff0c;首先对所有的硬件进行初始化&#xff0c;然后在主程序中写一个死循环&#xff0c;需要运行的功能按照顺序进行执行&#xff0c;轮询系统是一种简单可靠的方式&#xff0c;一般适用于在只需要按照顺序执行…

LLM应用开发平台资料

课程和代码资料 放下面了&#xff0c;自取&#xff1a; https://pan.quark.cn/s/57a9d22d61e9

硬盘健康检测与性能测试的实践指南

在日常使用 Windows 系统的过程中&#xff0c;我们常常需要借助各种工具来优化性能、排查问题或管理文件。针对windows工具箱进行实测解析&#xff0c;发现它整合了多种实用功能&#xff0c;能够帮助用户更高效地管理计算机。 以下为测试发现的功能特性&#xff1a; 硬件信息查…

正则表达式进阶(三):递归模式与条件匹配的艺术

在正则表达式的高级应用中&#xff0c;递归模式和条件匹配是处理复杂嵌套结构和动态模式的利器。它们突破了传统正则表达式的线性匹配局限&#xff0c;能够应对嵌套括号、HTML标签、上下文依赖等复杂场景。本文将详细介绍递归模式&#xff08;(?>...)、 (?R) 等&#xff0…

从零开始创建React项目及制作页面

一、React 介绍 React 是一个由 Meta&#xff08;原Facebook&#xff09; 开发和维护的 开源JavaScript库&#xff0c;主要用于构建用户界面&#xff08;User Interface, UI&#xff09;。它是前端开发中最流行的工具之一&#xff0c;广泛应用于单页应用程序&#xff08;SPA&a…

【前端部署】通过 Nginx 让局域网用户访问你的纯前端应用

在日常前端开发中&#xff0c;我们常常需要快速将本地的应用展示给局域网内的同事或测试人员&#xff0c;而传统的共享方式往往效率不高。本文将指导你轻松地将你的纯前端应用&#xff08;无论是 Vue, React, Angular 或原生项目&#xff09;部署到本地&#xff0c;并配置局域网…

【Python装饰器深潜】从语法糖到元编程的艺术

目录 🌟 前言🏗️ 技术背景与价值🩹 当前技术痛点🛠️ 解决方案概述👥 目标读者说明🧠 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🔧 关键技术模块说明⚖️ 技术选型对比🛠️ 二、实战演示⚙️ 环境配置要求💻 核心代码实现案例1:基础计时装饰器案…

mbed驱动st7789屏幕-硬件选择及连接(1)

目录 1.整体介绍 2. 硬件选择 2.1 mbed L432KC 2.2 ST7789 240*240 1.3寸 3. mbed与st7789的硬件连接 4. 总结 1.整体介绍 我们在使用单片机做一些项目的时候,交互性是最重要的因素。那么对于使用者而言,交互最直接的体现无非就是视觉感知,那么我们希望将项目通过视觉…

SpringBoot集成Jasypt对数据库连接密码进行加密、解密

引入依赖 <!--配置密码加密--><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.3</version></dependency><plugin><groupId>c…

分类器引导的条件生成模型

分类器引导的条件生成模型 分类器引导的条件生成模型1. **基本概念**2. **核心思想**3. **实现步骤&#xff08;以扩散模型为例&#xff09;**4. **优点**5. **挑战与注意事项**6. **应用场景**7. **数学推导**总结 分类器引导的条件生成模型 分类器引导的条件生成模型是一种通…

WPF中的ObjectDataProvider:用于数据绑定的数据源之一

ObjectDataProvider是WPF(Windows Presentation Foundation)中一种强大而灵活的数据绑定源&#xff0c;它允许我们将对象实例、方法结果甚至是构造函数的返回值用作数据源。通过本文&#xff0c;我将深入探讨ObjectDataProvider的工作原理、使用场景以及如何在实际应用中发挥其…

lasticsearch 报错 Document contains at least one immense term 的解决方案

一、问题背景 在使用 Elasticsearch 存储较大字段数据时&#xff0c;出现如下异常&#xff1a; ElasticsearchStatusException: Elasticsearch exception [typeillegal_argument_exception, reasonDocument contains at least one immense term in field"fieldZgbpka"…

[目标检测] YOLO系列算法讲解

前言 目标检测就是做到给模型输入一张图片或者视频&#xff0c;模型可以迅速判断出视频和图片里面感兴趣的目标所有的位置和它 的类别&#xff0c;而当前最热门的目标检测的模型也就是YOLO系列了。 YOLO系列的模型的提出&#xff0c;是为了解决当时目标检测的模型帧率太低而提…

服务器操作系统时间同步失败的原因及修复

服务器操作系统时间同步失败可能导致日志记录不准确、安全证书失效等问题。以下是常见原因及对应的修复方法&#xff1a; ### 一、时间同步失败的常见原因 1. **网络连接问题** - NTP服务器无法访问&#xff08;防火墙阻止、网络中断&#xff09; - DNS解析失败或网…

Cribl 中function 使用过滤的特殊case:Parser + rename

Cribl 利用function 对parser 进行特殊过滤处理: Parser Function – Fields Filter Expression​ When you use the Stream Parser Functions Reserialize option, there is a special option that becomes available, called the Fields Filter Expression. This is basica…

inverse-design-of-grating-coupler-3d

一、设计和优化3D光栅耦合器 1.1 代码讲解 通过预定义的环形间距参数(distances数组),在FDTD中生成椭圆光栅结构,并通过用户交互确认几何正确性后,可进一步执行参数扫描优化。 # os:用于操作系统相关功能(如文件路径操作) import os import sys# lumapi:Lumerical 的…

TuyaOpen横空出世!涂鸦智能如何用开源框架重构AIoT开发范式?

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引子:AIoT开发的“不可能三角”被打破 当AI与物理世界深度融合的浪潮席卷全球,开发者们却始终面临一个“不可能三角”——开发效率、技术深度与商业化落地难以兼得。 …

智慧赋能光伏运维——无人机巡检+地面监控双链路覆盖,打造光伏电站管理新标杆

一、引言&#xff1a;光伏电站运维的挑战与机遇 在全球能源转型浪潮下&#xff0c;光伏电站作为清洁能源的重要载体&#xff0c;其高效运维管理成为行业核心命题。然而&#xff0c;传统光伏电站运维存在覆盖范围广、设备分散、人工巡检效率低、故障响应慢等痛点。为破解这一难…

前端无感登录刷新

前端实现无感登录 在现代的前端开发中&#xff0c;用户体验是非常重要的一环。无感登录&#xff08;也叫自动登录&#xff09;就是其中一个提升用户体验的关键功能。它的目标是让用户在登录后&#xff0c;即使关闭浏览器或长时间不操作&#xff0c;也能在下次访问时自动登录&a…

JAVASE查漏补缺

这段时间学习了很多知识&#xff0c;好多还有疑问不清楚的地方。今天有空总结一下。 javame,javase,javaee 一、Java ME&#xff08;Micro Edition&#xff0c;微型版&#xff09; Java ME是一种适用于移动设备和嵌入式系统的小型Java平台&#xff0c;具有高度可移植性和跨平…