AR 眼镜之-充电动画定制-实现方案

news2024/11/27 17:40:24

目录

📂 前言

AR 眼镜系统版本

充电动画

1. 🔱 技术方案

1.1 方案介绍

1.2 实现方案

关机充电动画

亮屏/锁屏充电动画

2. 💠 关机充电动画

2.1 关机充电动画核心处理类与路径

2.2 实现细节

步骤一:1)定制 ui.c 文件,适配分辨率

步骤一:2)定制 ui.c 文件,定制动画 UI

步骤二:新增定制的动画 UI 相关png图片

3. ⚛️ 亮屏/锁屏充电动画

3.1 亮屏/锁屏充电动画时序图

3.2 实现细节

步骤一:注册广播 Action 监听充电接通/断开/充满电等状态

步骤二:开发充电接通/断开/充满电的系统弹窗,显示对应动画

4. ✅ 小结


📂 前言

AR 眼镜系统版本

        W517 Android9。

充电动画

        Android 充电动画分为:关机充电动画 与 亮屏/锁屏充电动画,而且据了解 Android 原生系统只提供了关机充电动画,并未提供亮屏/锁屏充电动画,所以对于关机情况下需要定制,亮屏/锁屏情况下需要增加。

1. 🔱 技术方案

1.1 方案介绍

        技术方案概述:对于关机充电动画,是通过 minui 开发的,主要定制 ui.c 文件以及 /images/*.png 图片;对于亮屏/锁屏充电动画,主要通过监听系统充电连接、断开和充满电的广播去实现。

1.2 实现方案

关机充电动画
  1. 定制 ui.c 文件,适配分辨率,定制动画 UI;

  2. 新增定制的动画 UI 相关png图片。

亮屏/锁屏充电动画
  1. 注册 ACTION_POWER_CONNECTED、ACTION_POWER_DISCONNECTED、ACTION_BATTERY_OKAY 等广播 Action 监听充电接通/断开/充满电等状态;

  2. 开发充电接通/断开/充满电的系统弹窗,显示对应动画。

2. 💠 关机充电动画

2.1 关机充电动画核心处理类与路径

  1. 关机充电动画 UI 处理类:w517\vendor\sprd\proprietories-source\charge\ui.c

  2. 关机充电动画图片存放路径:w517\vendor\sprd\proprietories-source\charge\images\

  3. AR 眼镜上的充电动画图片存放路径:/vendor/etc/res/images/

2.2 实现细节

步骤一:1)定制 ui.c 文件,适配分辨率

步骤一:2)定制 ui.c 文件,定制动画 UI

步骤二:新增定制的动画 UI 相关png图片

3. ⚛️ 亮屏/锁屏充电动画

3.1 亮屏/锁屏充电动画时序图

3.2 实现细节

步骤一:注册广播 Action 监听充电接通/断开/充满电等状态
class BatteryListener(context: Context) {

    private val TAG = BatteryListener::class.java.simpleName
    private val mContext: Context
    private val mReceiver: BatteryBroadcastReceiver
    private val mBatteryChargeWindow: BatteryChargeWindow

    init {
        mContext = context
        mReceiver = BatteryBroadcastReceiver()
        mBatteryChargeWindow = BatteryChargeWindow()
    }

    fun register() {
        Log.e(TAG, "register: ")
        val filter = IntentFilter()
//        filter.addAction(Intent.ACTION_BATTERY_CHANGED) // 电量发生改变
        filter.addAction(Intent.ACTION_BATTERY_LOW) // 电量低
        filter.addAction(Intent.ACTION_BATTERY_OKAY) // 电量充满
        filter.addAction(Intent.ACTION_POWER_CONNECTED) // 接通电源
        filter.addAction(Intent.ACTION_POWER_DISCONNECTED) // 拔出电源
        mContext.registerReceiver(mReceiver, filter)

        mBatteryChargeWindow.init(mContext)
    }

    fun unregister() {
        Log.e(TAG, "unregister: ")
        mContext.unregisterReceiver(mReceiver)
    }

    private inner class BatteryBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Log.e(TAG, "onReceive: ${intent.action}")

            when (intent.action) {
//                Intent.ACTION_BATTERY_CHANGED -> {
//
//                }

                Intent.ACTION_BATTERY_LOW -> {

                }

                Intent.ACTION_BATTERY_OKAY -> {
                    mBatteryChargeWindow.finishCharge()
                }

                Intent.ACTION_POWER_CONNECTED -> {
                    SoundPoolTools.play(
                        context, SoundPoolTools.MUSIC, R.raw.notification_power_connected
                    )
                    mBatteryChargeWindow.startCharge()
                }

                Intent.ACTION_POWER_DISCONNECTED -> {

                }
            }
        }
    }

}
步骤二:开发充电接通/断开/充满电的系统弹窗,显示对应动画
class BatteryChargeWindow {

    private lateinit var mContext: Context
    private lateinit var mWindowManager: WindowManager
    private lateinit var mBatteryChargeView: View
    private lateinit var mChargingAnimation: LottieAnimationView
    private lateinit var mFinishedChargingAnimation: LottieAnimationView
    private lateinit var mBattery: AGGTextView
    private var mLayoutParams: WindowManager.LayoutParams? = null
    private var mIsBarWindowAdded = false
    private val mUiHandler = Handler(Looper.getMainLooper())

    fun init(context: Context) {
        mContext = context.applicationContext
        mWindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        initLayoutParams()
        initView()
    }

    fun startCharge() {
        initLayoutParams()
        addBarWindow()

        mChargingAnimation.visibility = View.VISIBLE
        mChargingAnimation.playAnimation()
        mBattery.text = getBatteryLevel()
        mUiHandler.postDelayed({
            mChargingAnimation.cancelAnimation()
            mChargingAnimation.visibility = View.GONE
            removeBarWindow()
        }, BATTERY_CHARGE_TIME_OUT)
    }

    @SuppressLint("SetTextI18n")
    fun finishCharge() {
        initLayoutParams()
        addBarWindow()

        mFinishedChargingAnimation.visibility = View.VISIBLE
        mFinishedChargingAnimation.playAnimation()
        mBattery.text = "100%"
        mUiHandler.postDelayed({
            mFinishedChargingAnimation.cancelAnimation()
            mFinishedChargingAnimation.visibility = View.GONE
            removeBarWindow()
        }, BATTERY_CHARGE_TIME_OUT)
    }

    private fun initLayoutParams() {
        mLayoutParams = WindowManager.LayoutParams().apply {
            type = WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
            val density = mContext.resources.displayMetrics.density
            width = (640 * density).toInt()
            height = (640 * density).toInt()
            flags =
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
            format = PixelFormat.RGBA_8888 // 去除默认时有的黑色背景,设置为全透明
            gravity = Gravity.CENTER
            title = Constants.AGG_SYSUI_BATTERY_CHARGE
            x = 0
            y = 0
            dofIndex = 1 //  默认为1。 为0,则表示窗口为0DOF模式;为1,则表示窗口为3DOF模式;为2,则表示窗口为6DOF模式。
            setTranslationZ(Constants.TRANSLATION_Z_150CM)

            setRotationXAroundOrigin(-XrEnvironment.getInstance().headPose.roll)
            setRotationYAroundOrigin(-XrEnvironment.getInstance().headPose.yaw)
            setRotationZAroundOrigin(-XrEnvironment.getInstance().headPose.pitch)
        }
    }

    private fun initView() {
        mBatteryChargeView =
            LayoutInflater.from(mContext).inflate(R.layout.battery_charge_layout, null, false)
        mChargingAnimation = mBatteryChargeView.findViewById(R.id.charging)
        mFinishedChargingAnimation = mBatteryChargeView.findViewById(R.id.finishedCharging)
        mBattery = mBatteryChargeView.findViewById(R.id.battery)
    }

    private fun addBarWindow() {
        mUiHandler.post {
            synchronized(this) {
                if (!mIsBarWindowAdded) {
                    try {
                        mWindowManager.addView(mBatteryChargeView, mLayoutParams)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                    mIsBarWindowAdded = true
                }
            }
        }
    }

    private fun removeBarWindow() {
        mUiHandler.post {
            synchronized(this) {
                if (mIsBarWindowAdded) {
                    try {
                        mWindowManager.removeViewImmediate(mBatteryChargeView)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                    mIsBarWindowAdded = false
                }
            }
        }
    }

    /**
     * 获取剩余电池容量占总容量的整数百分比
     */
    private fun getBatteryLevel(): String {
        val batteryManager = mContext.getSystemService(BATTERY_SERVICE) as BatteryManager
        return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
            .toString() + "%"
    }

}

4. ✅ 小结

        对于充电动画定制,本文只是一个基础实现方案,更多业务细节请参考产品逻辑去实现。

        另外,由于本人能力有限,如有错误,敬请批评指正,谢谢。


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

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

相关文章

Javascript前端面试基础5【每日更10】

let与var的区别 let命令不存在变量提升,如果在let前使用,会导致报错(var存在变量提升)如果块区中存在let和const命令,就会形成封闭作用域不允许重复声明,因此,不能在函数内部重新声明参数 m…

Pcl读取stl文件,并转换成pcd文件,同时显示stl模型和pcd点云

由于不同版本的pcl兼容范围不一样&#xff0c;这里有2个版本的代码&#xff0c;里面的文件路径需要实际情况修改即可&#xff0c;希望对您有所参考或帮助 pcl1.8.1和vs2015版本代码 #include <iostream> #include <pcl/io/io.h> #include <pcl/io/pcd_io.h>…

序列化与反序列化的本质

1. 将对象存储到本地 假如有一个student类&#xff0c;我们定义了好几个对象&#xff0c;想要把这些对象存储下来&#xff0c;该怎么办呢 from typing import List class Student:name: strage: intphones: List[str] s1 Student("xiaoming",10,["huawei&quo…

大模型微调部署实战及类GPT工具的高效使用

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委&#xff0c;编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二…

《RMT: Retentive Networks Meet Vision Transformers》CVPR2024

论文&#xff1a;RMT: Retentive Networks Meet Vision Transformers - AMiner 摘要 这篇论文探讨了将Retentive Network&#xff08;RetNet&#xff09;的概念引入到计算机视觉领域&#xff0c;并与Vision Transformer结合&#xff0c;提出了一种新的模型RMT&#xff08;Ret…

牛津剑桥等发现:AI 训 AI 惨遭投毒 9 次大崩溃

【新智元导读】9 次迭代后&#xff0c;模型开始出现诡异乱码&#xff0c;直接原地崩溃&#xff01;牛津、剑桥等机构的一篇论文登上了 Nature 封面&#xff0c;称合成数据就像近亲繁殖&#xff0c;效果无异于投毒。有无破解之法&#xff1f;那就是 —— 更多使用人类数据&#…

护眼灯有没有护眼的效果?一文揭秘用护眼灯到底好不好

护眼灯有没有护眼的效果&#xff1f;在现在这个时代&#xff0c;无论是在学习还是办公&#xff0c;都很难离开一款好用的台灯&#xff0c;所以&#xff0c;为了避免会挑选到质量不好的台灯&#xff0c;我们应该要先避开一些网红小品牌&#xff0c;优先选择有专业技术支持的&…

ClickHouse 24.6 版本发布说明

本文字数&#xff1a;14127&#xff1b;估计阅读时间&#xff1a;36 分钟 作者&#xff1a;ClickHouse team 本文在公众号【ClickHouseInc】首发 又到了发布新版本的时间&#xff01; 发布概要 本次ClickHouse 24.6 版本包含了23个新功能&#x1f381;、24项性能优化&#x1f6…

maven介绍 搭建Nexus3(maven私服搭建)

Maven是一个强大的项目管理工具&#xff0c;它基于项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;的概念&#xff0c;通过XML格式的配置文件&#xff08;pom.xml&#xff09;来管理项目的构建 Maven确实可以被视为一种工程管理工具或项目自动化构…

使用flutter做圆形进度条 (桌面端)

前言 最近收到一个需求&#xff0c;需要使用flutter 来做一个圆形进度条&#xff0c;这可难倒我了&#xff0c;毕竟我是做前端的&#xff0c;flutter 之前接触的也少&#xff0c;但没办法&#xff0c;既然需求有了&#xff0c;也得硬着头皮上了&#xff0c;先来看看做的效果。…

简过网:大学生考公,一定要先好好看看这篇文章!

大家好&#xff0c;我是简过网&#xff0c;今天这篇文章我们来聊聊关于大学生考公的那些事儿&#xff0c;希望能给大学生们一点点的帮助&#xff01; 首先&#xff0c;可能有朋友会问了&#xff0c;大学生一般从什么时候开始备考公务员呢&#xff0c;在这里小编建议大家从大三…

《昇思25天学习打卡营第24天|基于MindSpore通过GPT实现情感分类》

基于MindSpore通过GPT实现情感分类 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mind…

yolov5-7环境搭建训练自己的模型

1.下载代码 git clone https://github.com/ultralytics/yolov5 # clone可以切到5-7版本&#xff0c;也可以去github选标签下载 2.配置好conda环境&#xff0c;网上教程比较多&#xff0c;不做讲解&#xff0c;python3.8即可。 3.在环境里安装pyrtorch 按自己的需求选取&am…

每日一练,java05

目录 题目知识点&#xff1a;1.12.13.1 题目 选自牛客网 1.下列表述错误的是&#xff1f;&#xff08;&#xff09; A.int是基本类型&#xff0c;直接存数值&#xff0c;Integer是对象&#xff0c;用一个引用指向这个对象。 B.在子类构造方法中使用super()显示调用父类的构造…

第T6周:使用TensorFlow实现好莱坞明星识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文章目录 一、前期工作1.设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据 二、数据预处理1、加载数据2、数据可视化3、再…

【论文速读】| LLMCloudHunter:利用大语言模型(LLMs)从基于云的网络威胁情报(CTI)中自动提取检测规则

本次分享论文&#xff1a;LLMCloudHunter: Harnessing LLMs for Automated Extraction of Detection Rules from Cloud-Based CTI 基本信息 原文作者&#xff1a;Yuval Schwartz, Lavi Benshimol, Dudu Mimran, Yuval Elovici, Asaf Shabtai 作者单位&#xff1a;Ben-Gurion…

mfc100u.dll 文件缺失?两种方法快速修复丢失mfc100u.dll 文件难题

您的电脑是否遭遇了 mfc100u.dll 文件缺失的问题&#xff1f;这种情况通常由多种原因引起。在本文中&#xff0c;我们将介绍两种修复 mfc100u.dll 文件丢失问题的策略——一种是手动方法&#xff0c;另一种是自动修复的使用。我们将探讨如何有效地解决 mfc100u.dll 文件缺失的几…

Linux下git入门操作

0.创建仓库 可以按这个配置来&#xff0c;.gitignore中存放了上传时忽略的文件类型后缀。 1.clone仓库 在gitee上创建好仓库&#xff0c;点击克隆/下载&#xff0c; 复制地址fyehong/Linux_notes 。 在所需的文件夹中放置仓库。比如我在文件夹lesson9下存储仓库。就在less…

Python爬虫技术 第18节 数据存储

Python 爬虫技术常用于从网页上抓取数据&#xff0c;并将这些数据存储起来以供进一步分析或使用。数据的存储方式多种多样&#xff0c;常见的包括文件存储和数据库存储。下面我将通过一个简单的示例来介绍如何使用 Python 爬取数据&#xff0c;并将其存储为 CSV 和 JSON 文件格…

【数据结构】二叉树链式结构——感受递归的暴力美学

前言&#xff1a; 在上篇文章【数据结构】二叉树——顺序结构——堆及其实现中&#xff0c;实现了二叉树的顺序结构&#xff0c;使用堆来实现了二叉树这样一个数据结构&#xff1b;现在就来实现而二叉树的链式结构。 一、链式结构 链式结构&#xff0c;使用链表来表示一颗二叉树…