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);}}}

在这里插入图片描述

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

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

相关文章

Java 大视界 -- Java 大数据在智能医疗远程会诊与专家协作中的技术支持(146)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

Sqlite3数据库

工具库的使用&#xff1a;程序编写时#include <库名.h>即可调用库中的函数 编译时链接工具库&#xff1b; 注意&#xff1a;数据库中不区分字母大小写&#xff1b; SQLite 中的事务是数据库操作中非常重要的一个概念&#xff0c;它用于确保数据库操作的完整性和一致性。…

虚拟路由与单页应用(SPA):详解

在单页应用&#xff08;SPA&#xff0c;Single Page Application&#xff09;中&#xff0c;虚拟路由&#xff08;也称为前端路由&#xff09;是一种关键的技术&#xff0c;用于管理页面导航和状态变化&#xff0c;而无需重新加载整个页面。为了帮助你更好地理解这一概念&#…

练习:运动计划

需求&#xff1a;键盘录入星期数&#xff0c;显示今天的减肥活动。 周一&#xff1a;跑步&#xff1b; 周二&#xff1a;游泳&#xff1b; 周三&#xff1a;慢走&#xff1b; 周四&#xff1a;骑动感单车&#xff1b; 周五&#xff1a;拳击&#xff1b; 周六&#xff1a;…

通过webrtc+canvas+css实现简单的电脑滤镜拍照效果

这里我们用的是webrtc中的MediaDevices.getUserMedia()的浏览器api进行的效果实现&#xff0c;MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可&#xff0c;媒体输入会产生一个MediaStream&#xff0c;里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道…

《TCP/IP网络编程》学习笔记 | Chapter 20:Windows 中的线程同步

《TCP/IP网络编程》学习笔记 | Chapter 20&#xff1a;Windows 中的线程同步 《TCP/IP网络编程》学习笔记 | Chapter 20&#xff1a;Windows 中的线程同步用户模式和内核模式用户模式同步内核模式同步 基于 CRITICAL_SECTION 的同步内核模式的同步方法基于互斥量对象的同步基于…

VBA-Excel

VBA 一、数据类型与变量 常用数据类型&#xff1a; Byte&#xff1a;字节型&#xff0c;0~255。Integer&#xff1a;整数型&#xff0c;用于存储整数值&#xff0c;范围 -32768 到 32767。Long&#xff1a;长整型&#xff0c;可存储更大范围的整数&#xff0c;范围 -214748364…

kotlin 内联函数 inline

高阶函数实现的原理&#xff1a;函数类型其实是生成了一个对象 。 inline翻译成中文的意思就是内联&#xff0c;在kotlin里面inline被用来修饰函数&#xff0c;表明当前函数在编译时是以内嵌的形式进行编译的&#xff0c;从而减少了一层函数调用栈&#xff1a; inline fun fun…

PairRE: Knowledge Graph Embeddings via Paired Relation Vectors(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2020年11月 25年3月24日交 目录 一、简介 二、原理 1.整体 2.关系模式 3.优化模型 三、实验性能 四、结论和未来工作 一、简介 将RotatE进行生级&#xff0c;RotatE只对头实体h进行计算&#xff0c;PairRE对头尾实体都进行…

从报错到成功:Mermaid 流程图语法避坑指南✨

&#x1f680; 从报错到成功&#xff1a;Mermaid 流程图语法避坑指南 &#x1f680; &#x1f6a8; 问题背景 在开发文档或技术博客中&#xff0c;我们经常使用 Mermaid 流程图 来可视化代码逻辑。但最近我在尝试绘制一个 Java Stream 转换流程图时&#xff0c;遭遇了以下报错…

深入解析 Redis 实现分布式锁的最佳实践

前言 在分布式系统中&#xff0c;多个进程或线程可能会同时访问同一个共享资源&#xff0c;这就可能导致数据不一致的问题。为了保证数据的一致性&#xff0c;我们通常需要使用分布式锁。Redis 作为高性能的内存数据库&#xff0c;提供了一种简单高效的方式来实现分布式锁。本…

2025年03月10日人慧前端面试(外包滴滴)

目录 普通函数和箭头函数的区别loader 和 plugin 的区别webpack 怎么实现分包&#xff0c;为什么要分包webpack 的构建流程变量提升react 开发中遇到过什么问题什么是闭包vue 开发中遇到过什么问题vue中的 dep 和 watcher 的依赖收集是什么阶段什么是原型链react setState 是同…

Android10 系统截屏功能异常的处理

客户反馈的问题&#xff0c;设备上使用状态栏中“长截屏”功能&#xff0c;截屏失败且出现系统卡死问题。 在此记录该问题的处理 一现象&#xff1a; 设备A10上使用系统“长截屏”功能&#xff0c;出现截屏失败&#xff0c;系统死机。 二复现问题并分析 使用设备操作该功能&…

openvela新时代的国产开源RTOS系统

openvela 简介 openvela 操作系统专为 AIoT 领域量身定制&#xff0c;以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势&#xff0c;已成为众多物联网设备和 AI 硬件的技术首选&#xff0c;涵盖了智能手表、运动手环、智能音箱、耳机、智能家…

ENSP学习day9

ACL访问控制列表实验 ACL&#xff08;Access Control List&#xff0c;访问控制列表&#xff09;是一种用于控制用户或系统对资源&#xff08;如文件、文件夹、网络等&#xff09;访问权限的机制。通过ACL&#xff0c;系统管理员可以定义哪些用户或系统可以访问特定资源&#x…

JVM的组成--运行时数据区

JVM的组成 1、类加载器&#xff08;ClassLoader&#xff09; 类加载器负责将字节码文件从文件系统中加载到JVM中&#xff0c;分为&#xff1a;加载、链接&#xff08;验证、准备、解析&#xff09;、和初始化三个阶段 2、运行时数据区 运行时数据区包括&#xff1a;程序计数…

RAG(Retrieval-Augmented Generation)基建之PDF解析的“魔法”与“陷阱”

嘿&#xff0c;亲爱的算法工程师们&#xff01;今天咱们聊一聊PDF解析的那些事儿&#xff0c;简直就像是在玩一场“信息捉迷藏”游戏&#xff01;PDF文档就像是个调皮的小精灵&#xff0c;表面上看起来规规矩矩&#xff0c;但当你想要从它那里提取信息时&#xff0c;它就开始跟…

Python网络编程入门

一.Socket 简称套接字&#xff0c;是进程之间通信的一个工具&#xff0c;好比现实生活中的插座&#xff0c;所有的家用电器要想工作都是基于插座进行&#xff0c;进程之间要想进行网络通信需要Socket&#xff0c;Socket好比数据的搬运工~ 2个进程之间通过Socket进行相互通讯&a…

人工智能(AI)系统化学习路线

一、为什么需要系统化学习AI&#xff1f; 人工智能技术正在重塑各行各业&#xff0c;但许多初学者容易陷入误区&#xff1a; ❌ 盲目跟风&#xff1a;直接学习TensorFlow/PyTorch&#xff0c;忽视数学与算法基础。 ❌ 纸上谈兵&#xff1a;只看理论不写代码&#xff0c;无法解…

mac calDAV 日历交互

安装Bakal docker https://sabre.io/dav/building-a-caldav-client/ 在Bakal服务器上注册账户 http://localhost:8080/admin/?/users/calendars/user/1/ 在日历端登录账户&#xff1a; Server: http://127.0.0.1:8080/dav.php Server Path: /dav.php/principals/lion No e…