当前位置: 首页 > article >正文

Lineageos 22.1(Android 15)实现负一屏

一、前言

方案是参考的这位大佬的,大家可以去付费订阅支持一波。我大概理一下Android15的修改。
大佬的方案代码

二、Android15适配调整

1.bp调整,加入aidl引入,这样make之后就可以索引代码了

filegroup {name: "launcher-src",srcs: ["src/**/*.java","src/**/*.kt","src/**/*.aidl"],
}

客户端端按照文章来就行,服务端我微调了一下代码,让切换变得更加平顺,具体还的项目中再调整。其实还差手机重复按的时候停止动画之类的东西处理,遇到的时候再说吧。

package com.google.test;import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;import com.google.android.libraries.launcherclient.ILauncherOverlay;
import com.google.android.libraries.launcherclient.ILauncherOverlayCallback;import androidx.annotation.NonNull;/*** Created by cczheng on 2022/5/25.*/public class ScreenService extends Service {private Context mContext;private WindowManager mWindowManager;private WindowManager.LayoutParams mLayoutParams;private int screenWidth;ILauncherOverlayCallback overlayCallback;private String TAG = "ScreenService";private float progress;@Overridepublic void onCreate() {super.onCreate();mContext = this;mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);mLayoutParams = new WindowManager.LayoutParams();DisplayMetrics outMetrics = new DisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(outMetrics);screenWidth = outMetrics.widthPixels;Log.d(TAG, "onCreate");}@Overridepublic IBinder onBind(Intent intent) {IBinder iBinder = new ILauncherOverlayImpl().asBinder();Log.i(TAG, "onBind");return iBinder;}public class ILauncherOverlayImpl extends ILauncherOverlay.Stub {private Handler mainThreadHandler;@Overridepublic String getVoiceSearchLanguage() throws RemoteException {return null;}@Overridepublic boolean isVoiceDetectionRunning() throws RemoteException {return false;}@Overridepublic void onPause() throws RemoteException {Log.d(TAG, "onPause");}@Overridepublic void onResume() throws RemoteException {Log.d(TAG, "onResume");}@Overridepublic void requestVoiceDetection(boolean start) throws RemoteException {Log.d(TAG, "requestVoiceDetection");}@Overridepublic void openOverlay(int options) throws RemoteException {Log.i(TAG, "openOverlay");}@Overridepublic void closeOverlay(int options) throws RemoteException {Log.i(TAG, "closeOverlay");}@Overridepublic void startScroll() throws RemoteException {Log.e(TAG, "startScroll");Message.obtain(this.mainThreadHandler, OverlayCallback.START_SCROLL).sendToTarget();}@Overridepublic void onScroll(float progress) throws RemoteException {
//            Log.i(TAG,"onScroll=" + progress);Message.obtain(this.mainThreadHandler, OverlayCallback.UPDATE_SCROLL, progress).sendToTarget();}@Overridepublic void endScroll() throws RemoteException {Log.e(TAG, "endScroll");Message.obtain(this.mainThreadHandler, OverlayCallback.END_SCROLL).sendToTarget();}@Overridepublic void windowAttached(WindowManager.LayoutParams attrs, ILauncherOverlayCallback callbacks,int options) throws RemoteException {Log.i(TAG, "windowAttached.....");
//            doWindowAttached(attrs, callbacks, options);overlayCallback = callbacks;Bundle bundle = new Bundle();bundle.putParcelable("layout_params", attrs);bundle.putInt("client_options", options);OverlayCallback overlayCallback = new OverlayCallback(ScreenService.this);mainThreadHandler = new Handler(Looper.getMainLooper(), overlayCallback);Message.obtain(this.mainThreadHandler, OverlayCallback.WINDOW_ATTACHED,Pair.create(bundle, callbacks)).sendToTarget();}@Overridepublic void windowDetached(boolean isChangingConfigurations) throws RemoteException {Log.d(TAG, "windowDetached");Message.obtain(this.mainThreadHandler, OverlayCallback.WINDOW_DETACHCHED, isChangingConfigurations).sendToTarget();}}private void applyScroll(View view)  {try {overlayCallback.overlayScrollChanged(progress);mLayoutParams.x = (int) (-screenWidth*(1-progress));mWindowManager.updateViewLayout(view, mLayoutParams);} catch (RemoteException e) {throw new RuntimeException(e);}}private void startProgressAnimation(boolean open,View view) {ValueAnimator valueAnimator=(open)? ValueAnimator.ofFloat(progress, 1f):ValueAnimator.ofFloat(progress, 0f);valueAnimator.setDuration(500);valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {try {overlayCallback.overlayScrollChanged(0);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {progress= (float) valueAnimator.getAnimatedValue();applyScroll(view);}});valueAnimator.start();}class OverlayCallback implements Handler.Callback {public static final int WINDOW_ATTACHED = 100;public static final int START_SCROLL = 101;public static final int UPDATE_SCROLL = 102;public static final int END_SCROLL = 103;public static final int WINDOW_DETACHCHED = 104;private ScreenService screenService;private LinearLayout mOverlayDecorView;public OverlayCallback(ScreenService screenService) {this.screenService = screenService;}@Overridepublic boolean handleMessage(@NonNull Message msg) {try {if (msg.what == WINDOW_ATTACHED) {
//                bundle.putParcelable("layout_params", attrs);
//                bundle.putInt("client_options", options);Pair<Bundle, ILauncherOverlayCallback> pair = (Pair<Bundle, ILauncherOverlayCallback>) msg.obj;WindowManager.LayoutParams layoutParams = pair.first.getParcelable("layout_params");
//                    overlayCallback = pair.second;doWindowAttached(layoutParams, pair.second, 1);} else if (msg.what == START_SCROLL) {} else if (msg.what == UPDATE_SCROLL) {progress = (float) msg.obj;Log.d(TAG, "progress=" + progress);applyScroll(mOverlayDecorView);} else if (msg.what == END_SCROLL) {startProgressAnimation(progress>0.4f,mOverlayDecorView);}} catch (RemoteException e) {e.printStackTrace();}return false;}public void doWindowAttached(WindowManager.LayoutParams lp, ILauncherOverlayCallback cb,int flags) throws RemoteException {mLayoutParams = new WindowManager.LayoutParams();mLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;mLayoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;mLayoutParams.gravity = Gravity.START;// 负一屏的 Window 层级比 Launcher 的大就可以mLayoutParams.type = lp.type + 1;mLayoutParams.token = lp.token;mLayoutParams.flags = WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;mLayoutParams.x = -screenWidth;Log.d(TAG, "doWindowAttached." + lp.type + "   " + lp.token + "   " + (-screenWidth));mLayoutParams.format = PixelFormat.TRANSLUCENT;mOverlayDecorView = new LinearLayout(mContext);mOverlayDecorView.setGravity(Gravity.CENTER);mOverlayDecorView.setBackgroundColor(Color.RED);TextView textView = new TextView(mContext);textView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));textView.setText("XXXXXXXX");textView.setTextSize(25);textView.setTextColor(Color.WHITE);mOverlayDecorView.addView(textView);mWindowManager.addView(mOverlayDecorView, mLayoutParams);mOverlayDecorView.setOnTouchListener(new OverlayOnTouchListener());if (cb != null) {cb.overlayStatusChanged(1);}}}private boolean isDrag;private class OverlayOnTouchListener implements View.OnTouchListener {private int firstX;private int lastX;@Overridepublic boolean onTouch(View view, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:isDrag = false;firstX = (int) event.getRawX();lastX = (int) event.getRawX();break;case MotionEvent.ACTION_MOVE:isDrag = true;int nowX = (int) event.getRawX();int movedX = nowX - lastX;lastX = nowX;
//                    Log.d(TAG,"movedX=" + movedX);if (movedX < 0) {//只能左滑,滑到launcher中mLayoutParams.x = mLayoutParams.x + movedX;progress=1-((float) -mLayoutParams.x )/((float) screenWidth);applyScroll(view);
//                        mWindowManager.updateViewLayout(view, mLayoutParams);
//                        try {
//                            overlayCallback.overlayScrollChanged();
//                        } catch (RemoteException e) {
//                            throw new RuntimeException(e);
//                        }}break;case MotionEvent.ACTION_UP:int stopX = (int) event.getRawX();int movedFX = stopX - firstX;Log.d(TAG,"lastX=" + lastX + "  isDrag=" + isDrag + "  movedFX=" + movedFX);if (isDrag && movedFX < 0) {progress=1-((float) -mLayoutParams.x )/((float) screenWidth);startProgressAnimation(false,view);}break;}return isDrag || view.onTouchEvent(event);}}}

在这里插入图片描述

相关文章:

Lineageos 22.1(Android 15)实现负一屏

一、前言 方案是参考的这位大佬的&#xff0c;大家可以去付费订阅支持一波。我大概理一下Android15的修改。 大佬的方案代码 二、Android15适配调整 1.bp调整&#xff0c;加入aidl引入&#xff0c;这样make之后就可以索引代码了 filegroup {name: "launcher-src"…...

《深度学习》——YOLOv3详解

文章目录 YOLOv3简介YOLOv3核心原理YOLOv3改进YOLOv3网络结构 YOLOv3简介 YOLOv3&#xff08;You Only Look Once, version 3&#xff09;是一种先进的实时目标检测算法&#xff0c;由 Joseph Redmon 和 Ali Farhadi 开发。它在目标检测领域表现出色&#xff0c;具有速度快、精…...

【设计模式】三十一、状态模式

系列文章|源码 https://github.com/tyronczt/design-mode-learn 文章目录 系列文章|源码一、模式核心思想二、模式结构三、Java代码示例&#xff1a;订单状态管理1. 定义状态接口2. 实现具体状态类3. 上下文类&#xff08;Context&#xff09;4. 客户端调用5. 运行截图 四、状…...

vue 获取当前时间并自动刷新

新增需求&#xff0c;需要在大屏的右上角展示当前时间&#xff0c;并实时按秒刷新&#xff0c;通过通义千问搜索关键js代码后&#xff0c;整理出如下代码。 【效果图】 【HTML】 <div class"time-wrap">{{ formattedDateTime }}<span> {{ weekTime }}&…...

C 语 言 --- 扫 雷 游 戏(初 阶 版)

C 语 言 --- 扫 雷 游 戏 初 阶 版 代 码 全 貌 与 功 能 介 绍扫雷游戏的功能说明游 戏 效 果 展 示游 戏 代 码 详 解game.htest.cgame.c 总结 &#x1f4bb;作 者 简 介&#xff1a;曾 与 你 一 样 迷 茫&#xff0c;现 以 经 验 助 你 入 门 C 语 言 &#x1f4a1;个 人 主…...

WebDeveloper靶机详解

一、主机发现 arp-scan -l靶机ip为192.168.55.163 二、端口扫描、目录枚举、漏洞扫描、指纹识别 2.1端口扫描 nmap --min-rate 10000 -p- 192.168.55.163发现并无特殊端口开放 扫描一下UDP端口 nmap -sU --min-rate 10000 -p- 192.168.55.163没有扫描到UDP端口 2.2目录枚…...

Cursor IDE 入门指南

什么是 Cursor? Cursor 是一款集成了 AI 功能的现代代码编辑器&#xff0c;基于 VSCode 开发&#xff0c;专为提高开发效率而设计。它内置强大的 AI 助手功能&#xff0c;能够理解代码、生成代码、解决问题&#xff0c;帮助开发者更快、更智能地完成编程任务。 基础功能 1.…...

来源于胡椒的亚甲二氧桥CYP450-文献精读119

Piper nigrum CYP719A37 Catalyzes the Decisive Methylenedioxy Bridge Formation in Piperine Biosynthesis 胡椒 (Piper nigrum) CYP719A37 催化胡椒碱生物合成中关键的亚甲二氧桥形成 摘要 胡椒 (Piper nigrum) 是世界上最受欢迎的香料之一。其主要辛辣成分胡椒碱 (piper…...

STM32八股【1】-----启动流程和startup文件理解

启动流程 知识点 MCU 上电复位。MSP从向量表第0个地址读取一个32位&#xff08;2字节&#xff09;的值并保存&#xff0c;该值为栈顶地址。PC计数器从第1个地址读取一个两字节的值并保存&#xff0c;该值为程序入口&#xff0c;一般是Reset_Handler。想了解FLASH地址映射可以…...

Docker与K8S是什么该怎么选?

用了很久的容器化&#xff0c;最近突然看到一个问题问&#xff1a; docker和K8S究竟有什么区别&#xff0c;到底该怎么选&#xff1f;我认真思考了一会&#xff0c;发现一时间还真说不明白&#xff0c;于是就研究了一段时间发布今天的博文&#xff01; Docker vs Kubernetes&a…...

梦回杭州...

她对我说&#xff0c;烟雨中的西湖更别有情趣&#xff0c;我也怀着对‘人间天堂’的憧憬踏上了向往之旅。第一次亲密接触没有感觉中那么好&#xff0c;现在想起来是那时的人和心情都没能安静下来&#xff0c;去慢慢品味它的美。 六下杭州&#xff0c;亲历每一片风景&#xff0c…...

NAT 实验:多私网环境下 NAPT、Easy IP 配置及 FTP 服务公网映射

NAT基本概念 定义&#xff1a;网络地址转换&#xff08;Network Address Translation&#xff0c;NAT&#xff09;是一种将私有&#xff08;保留&#xff09;地址转化为合法公网 IP 地址的转换技术&#xff0c;它被广泛应用于各种类型 Internet 接入方式和各种类型的网络中。作…...

SEED XSS 实验环境搭建步骤《精简版》

目录 1. 启动 SEED Ubuntu VM 2. 配置 /etc/hosts 3. 下载并解压 Labsetup.zip 4. 使用 Docker Compose 启动实验环境 5. 确保容器正常运行 6. 访问 Elgg Web 应用 7. 账户信息 8. 进入容器内部 9.实验环境搭建完成 &#x1f389; 10. 关闭实验 11.&#x1f4a1; 重…...

YOLO数据集分割训练集、测试集和验证集

记录一下自己的分割代码。 注意&#xff1a; 这是在windows环境&#xff0c;请Linux的同学们注意。标签为txt&#xff0c;图像为jpg&#xff0c;其他的我没试过喔。 训练集、验证集、测试集&#xff08;7:2:1&#xff09; import os import shutil import random from tqdm…...

Debug-037-table列表勾选回显方案

效果展示&#xff1a; 图1 图2 最近实现一个支持勾选的el-table可以回显之前勾选项的功能。实现了一个“编辑”的功能&#xff1a; 在图1中的列表中有三行数据&#xff0c;当点击“更换设备”按钮时&#xff0c;打开抽屉显示el-table组件如图2所示&#xff0c;可以直接回显勾选…...

使用 libevent 构建高性能网络应用

使用 libevent 构建高性能网络应用 在现代网络编程中&#xff0c;高性能和可扩展性是开发者追求的核心目标。为了实现这一目标&#xff0c;许多开发者选择使用事件驱动库来管理 I/O 操作和事件处理。libevent 是一个轻量级、高性能的事件通知库&#xff0c;广泛应用于网络服务…...

人脸表情识别系统分享(基于深度学习+OpenCV+PyQt5)

最近终于把毕业大论文忙完了&#xff0c;众所周知硕士大论文需要有三个工作点&#xff0c;表情识别领域的第三个工作点一般是做一个表情识别系统出来&#xff0c;如下图所示。 这里分享一下这个表情识别系统&#xff1a; 采用 深度学习OpenCVPyQt5 构建&#xff0c;主要功能包…...

AtCoder - arc086_d Shift and Decrement分析与实现

分析与思路 可以把操作流程表示成下图 以进行四次除法操作为例&#xff1a; 这里有一个关键点&#xff1a;对于每个p_i (0< i <x-1) &#xff0c;x是除法操作的次数&#xff0c;如果p_i>2&#xff0c;可以将2个p_i的减法操作去掉&#xff0c;在p_(i1)中增加一个减法…...

学习111

项目名称项目简介主要功能技术原理GitHub地址browser-use智能浏览器工具&#xff0c;让AI像人类一样操作浏览器&#xff0c;实现网页自动化网页浏览与操作、多标签页管理、视觉识别与内容提取、操作记录与重复执行、自定义动作支持、主流LLM模型支持为大语言模型服务的创新Pyth…...

Android Jetpack Compose介绍

Android Jetpack Compose Android Jetpack Compose 是 Google 推出的现代 UI 工具包&#xff0c;用于以声明式的方式构建 Android 应用的 UI。它摒弃了传统的 XML 布局方式&#xff0c;完全基于 Kotlin 编写&#xff0c;提供了更简洁、更强大的 UI 开发体验。以下是 Compose 的…...

tcping 命令的使用,ping IP 和端口

1. ‌Windows系统安装‌ ‌下载tcping工具‌&#xff1a;根据系统位数&#xff08;32位或64位&#xff09;下载对应的tcping.exe文件。‌安装步骤‌&#xff1a; 将下载的tcping.exe文件复制到C:\Windows\System32目录下。如果下载的是64位版本&#xff0c;需将文件名改为tcpi…...

天地图InfoWindow插入React自定义组件

截至2025年03月21日天地图的Marker不支持添加Label; 同时Label和Icon是不支持自定义HTMLElement只支持String&#xff1b;目前只有InfoWindow支持自定义HTMLElement; 效果图 React核心api import ReactDOM from react-dom/client const content document.createElement(div);…...

003-掌控命令行-CLI11-C++开源库108杰

首选的现代C风格命令行参数解析器! &#xff08;本课程包含两段教学视频。&#xff09; 以文件对象监控程序为实例&#xff0c;五分钟实现从命令行读入多个监控目标路径&#xff1b;区分两大时机&#xff0c;学习 CLI11 构建与解析参数两大场景下的异常处理&#xff1b;区分三…...

理解 Node.js 中的 process`对象与常用操作

理解 Node.js 中的 process 对象与常用操作 在 Node.js 中&#xff0c;process 是一个全局对象&#xff0c;提供了与当前 Node.js 进程相关的信息和操作。无论是获取进程信息、处理信号、访问环境变量&#xff0c;还是控制进程行为&#xff0c;process 都是不可或缺的工具。 看…...

鸿蒙HarmonyOS NEXT应用崩溃分析及修复

鸿蒙HarmonyOS NEXT应用崩溃分析及修复 如何保证应用的健壮性&#xff0c;其中一个指标就是看崩溃率&#xff0c;如何降低崩溃率&#xff0c;就需要知道存在哪些崩溃&#xff0c;然后对症下药&#xff0c;解决崩溃。那么鸿蒙应用中存在哪些崩溃类型呢&#xff1f;又改如何解决…...

【conda activate无效】 conda: error: argument COMMAND: invalid choice: ‘activate‘

conda activate失效了 在使用conda activate时出现报错&#xff1a; usage: conda [-h] [-v] [--no-plugins] [-V] COMMAND ... conda: error: argument COMMAND: invalid choice: activate (choose from clean, compare, config, create, info, init, install, list, notice…...

Redis + 布隆过滤器解决缓存穿透问题

Redis 布隆过滤器解决缓存穿透问题 1. Redis 布隆过滤器解决缓存穿透问题 &#x1f4cc; 什么是缓存穿透&#xff1f; 缓存穿透指的是查询的数据既不在缓存&#xff0c;也不在数据库&#xff0c;导致每次查询都直接访问数据库&#xff0c;增加数据库压力。 例如&#xff1…...

机器学习——分类、回归、聚类、LASSO回归、Ridge回归(自用)

纠正自己的误区&#xff1a;机器学习是一个大范围&#xff0c;并不是一个小的方向&#xff0c;比如&#xff1a;线性回归预测、卷积神经网络和强化学都是机器学习算法在不同场景的应用。 机器学习最为关键的是要有数据&#xff0c;也就是数据集 名词解释&#xff1a;数据集中的…...

HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错:Error message:is not callable

HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错&#xff1a;Error message:is not callable 最近在鸿蒙开发过程中&#xff0c;UI做好了&#xff0c;根据列表item进行点击跳转&#xff0c;报错了 报错信息如下 Error message:is not callable Stacktrace:at…...

【canvas】一键自动布局:如何让流程图节点自动找到最佳位置

一键自动布局&#xff1a;如何让流程图节点自动找到最佳位置 引言 在流程图、拓扑图和系统架构图设计中&#xff0c;节点布局往往是最令人头疼的问题。如果手动调整每个节点位置&#xff0c;不仅耗时费力&#xff0c;还难以保证美观性和一致性。本文将深入解析如何实现自动布…...