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.pswp.cn/news/906327.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906327.shtml
英文地址,請注明出處:http://en.pswp.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;具有高度可移植性和跨平…