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

目录

📂 前言

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. ✅ 小结

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

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


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值