摘要: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的内容,在完全准备好后,再显示副屏的待机图片。
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();
+ }
+ }
+}
+