Android13充电动画实现

充电动画

以MTK平台为例,实现充电动画

充电电压达到6V,显示快充文本,否则显示Charging

效果图

在这里插入图片描述

修改文件清单
  1. system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/BubbleBean.java
  2. system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/BubbleViscosity.java
  3. system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/WiredChargingAnimation.java
  4. system/vendor/mediatek/proprietary/packages/apps/SystemUI/res/layout/wired_charging_layout.xml
  5. system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/power/PowerUI.java
  6. system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/util/Utils.java
具体实现
1、新增布局

system/vendor/mediatek/proprietary/packages/apps/SystemUI/res/layout/.xml**

<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright (C) 2021 The Android Open Source Project

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/shcy_charge_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#99000000">

    <com.android.systemui.charging.BubbleViscosity
        android:id="@+id/shcy_bubble_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <TextView
        android:id="@+id/charge_text"
        android:layout_marginTop="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#25DA29"
        android:textSize="17sp"
        android:layout_gravity="center"/>

</FrameLayout>

2、新增气泡 bean

**system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/BubbleBean.java **

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.charging;

public class BubbleBean {

	private float randomY = 3;
	private float x;
	private float y;
	private int index;

	public BubbleBean(float x, float y, float randomY, int index){
		this.x = x;
		this.y = y;
		this.randomY = randomY;
		this.index = index;
	}

	public void set(float x, float y, float randomY, int index){
		this.x = x;
		this.y = y;
		this.randomY = randomY;
		this.index = index;
	}

	public void setMove(int screenHeight, int maxDistance){
		if (y - maxDistance < 110){
			this.y -= 2;
			return;
		}

		if (maxDistance <= y && screenHeight -y > 110){
			this.y -= randomY;
		}else {
			this.y -= 0.6;
		}

		if (index == 0){
			this.x -= 0.4;
		}else if (index == 2){
			this.x += 0.4;
		}
	}

	public int getIndex() {
		return index;
	}

	public float getX() {
		return x;
	}

	public void setX(float x) {
		this.x = x;
	}

	public float getY() {
		return y;
	}

	public void setY(float y) {
		this.y = y;
	}
}

3、新增充电动画自定义 view

system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/BubbleViscosity.java

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.charging;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.jar.Attributes;

/**
 * WiredCharging paint
 */
public class BubbleViscosity extends SurfaceView implements SurfaceHolder.Callback,Runnable {

	private static ScheduledExecutorService scheduledThreadPool;
	private Context context;
	private String paintColor = "#25DA29";
	private String centreColor = "#00000000";
	private String minCentreColor = "#9025DA29";
	private int screenHeight;
	private int screenWidth;

	private float lastRadius;
	private float rate = 0.32f;
	private float rate2 = 0.45f;
	private PointF lastCurveStrat = new PointF();
	private PointF lastCurveEnd = new PointF();
	private PointF centreCirclePoint = new PointF();
	private float centreRadius;
	private float bubbleRadius;

	private PointF[] arcPointStrat = new PointF[8];
	private PointF[] arcPointEnd = new PointF[8];
	private PointF[] control = new PointF[8];
	private PointF arcStrat = new PointF();
	private PointF arcEnd = new PointF();
	private PointF controlP = new PointF();

	List<PointF> bubbleList = new ArrayList<>();
	List<BubbleBean> bubbleBeans = new ArrayList<>();

	private int rotateAngle = 0;
	private float controlrate = 1.66f;
	private float controlrateS = 1.3f;
	private int i = 0;
	private SurfaceHolder mHolder;
	private float scale = 0;

	private Paint arcPaint;
	private Paint minCentrePaint;
	private Paint bubblePaint;
	private Paint centrePaint;
	private Paint lastPaint;
	private Path lastPath;
	private Random random;
	private Paint textPaint;
	//private Paint chargerTextPaint;
	private String text = "78 %";
	//private String chargerText = "Charging";
	private Rect rect;

	public BubbleViscosity(Context context) {
		this(context,null);
	}

	public BubbleViscosity(Context context, AttributeSet attrs){
		this(context, attrs, 0);
	}

	public BubbleViscosity(Context context, AttributeSet attrs, int defStyleAttr){
		super(context, attrs, defStyleAttr);
		this.context = context;
		initTool();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		screenHeight = getMeasuredHeight();
		screenWidth = getMeasuredWidth();
	}

	private void initTool() {
		rect = new Rect();
		mHolder = getHolder();
		mHolder.addCallback(this);
		setFocusable(true);
		mHolder.setFormat(PixelFormat.TRANSPARENT);
		setZOrderOnTop(true);
		lastRadius = dip2Dimension(40f, context);
		centreRadius = dip2Dimension(100f, context);
		bubbleRadius = dip2Dimension(15f, context);
		random = new Random();
		lastPaint = new Paint();
		lastPaint.setAntiAlias(true);
		lastPaint.setStyle(Paint.Style.FILL);
		lastPaint.setColor(Color.parseColor(paintColor));
		lastPaint.setStrokeWidth(2);

		lastPath = new Path();

		centrePaint = new Paint();
		centrePaint.setAntiAlias(true);
		centrePaint.setStyle(Paint.Style.FILL);
		centrePaint.setStrokeWidth(2);
		centrePaint
				.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
		centrePaint.setColor(Color.parseColor(centreColor));
		arcPaint = new Paint();
		arcPaint.setAntiAlias(true);
		arcPaint.setStyle(Paint.Style.FILL);
		arcPaint.setColor(Color.parseColor(paintColor));
		arcPaint.setStrokeWidth(2);
		minCentrePaint = new Paint();
		minCentrePaint.setAntiAlias(true);
		minCentrePaint.setStyle(Paint.Style.FILL);
		minCentrePaint.setColor(Color.parseColor(minCentreColor));
		minCentrePaint.setStrokeWidth(2);
		bubblePaint = new Paint();
		bubblePaint.setAntiAlias(true);
		bubblePaint.setStyle(Paint.Style.FILL);
		bubblePaint.setColor(Color.parseColor(minCentreColor));
		bubblePaint.setStrokeWidth(2);
		textPaint = new Paint();
		textPaint.setAntiAlias(true);
		textPaint.setStyle(Paint.Style.FILL);
		textPaint.setColor(Color.parseColor("#FFFFFF"));
		textPaint.setStrokeWidth(2);
		textPaint.setTextSize(dip2Dimension(40f, context));
		/*chargerTextPaint = new Paint();
		chargerTextPaint.setStyle(Paint.Style.FILL);
		chargerTextPaint.setColor(Color.parseColor(paintColor));
		chargerTextPaint.setStrokeWidth(2);
		chargerTextPaint.setTextSize(dip2Dimension(15f, context));*/
	}

	public void onMDraw(){
		Canvas canvas = mHolder.lockCanvas();
		canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
		bubbleDraw(canvas);
		lastCircleDraw(canvas);
		centreCircleDraw(canvas);
		textPaint.getTextBounds(text, 0, text.length(), rect);
		//chargerTextPaint.getTextBounds(chargerText, 0, text.length(), rect);
		canvas.drawText(text, centreCirclePoint.x - rect.width() / 2,
				centreCirclePoint.y - rect.height() / 2, textPaint);
		/*canvas.drawText(chargerText, centreCirclePoint.x - rect.width() - rect.width() / 3,
				centreCirclePoint.y + rect.height() * 2, chargerTextPaint);*/
		mHolder.unlockCanvasAndPost(canvas);
	}

	public void setBatteryLevel(String level){
		this.text = level+"%";
		postInvalidate();
	}

	private void centreCircleDraw(Canvas canvas){
		centreCirclePoint.set(screenWidth / 2, screenHeight / 2);
		circleInCoordinateDraw(canvas);
		canvas.drawCircle(centreCirclePoint.x, centreCirclePoint.y, centreRadius, centrePaint);
	}

	private void lastCircleDraw(Canvas canvas){
		lastCurveStrat.set(screenWidth / 2 - lastRadius, screenHeight);
		lastCurveEnd.set((screenWidth / 2), screenHeight);

		float k = (lastRadius / 2) / lastRadius;

		float aX = lastRadius - lastRadius * rate2;
		float aY = lastCurveStrat.y - aX * k;
		float bX = lastRadius - lastRadius * rate;
		float bY = lastCurveEnd.y - bX * k;

		lastPath.rewind();
		lastPath.moveTo(lastCurveStrat.x, lastCurveStrat.y);
		lastPath.cubicTo(lastCurveStrat.x + aX, aY, lastCurveEnd.x - bX, bY, lastCurveEnd.x, lastCurveEnd.y - lastRadius / 2);
		lastPath.cubicTo(lastCurveEnd.x + bX, bY, lastCurveEnd.x + lastRadius - aX, aY, lastCurveEnd.x + lastRadius, lastCurveEnd.y);

		lastPath.lineTo(lastCurveStrat.x, lastCurveStrat.y);
		canvas.drawPath(lastPath, lastPaint);
	}

	private int bubbleIndex = 0;

	private void bubbleDraw(Canvas canvas){
		for (int i = 0; i < bubbleBeans.size(); i++) {
			if (bubbleBeans.get(i).getY() <= (int) (screenHeight / 2 + centreRadius)){
				bubblePaint.setAlpha(000);
				canvas.drawCircle(bubbleBeans.get(i).getX(), bubbleBeans.get(i).getY(), bubbleRadius, bubblePaint);
			} else {
				bubblePaint.setAlpha(150);
				canvas.drawCircle(bubbleBeans.get(i).getX(), bubbleBeans.get(i).getY(), bubbleRadius, bubblePaint);
			}
		}
	}

	/**
	 * @param dip
	 * @param context
	 * @return
	 */
	public float dip2Dimension(float dip, Context context){
		DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
		return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
	}

	/**
	 * @param canvas
	 */
	public void circleInCoordinateDraw(Canvas canvas) {
		int angle;
		for (int i = 0; i < arcPointStrat.length; i++) {
			if (i > 3 && i < 6) {
				if (i == 4) {
					angle = rotateAngle + i * 60;

				} else {
					angle = rotateAngle + i * 64;
				}
			} else if (i > 5) {
				if (i == 6) {
					angle = rotateAngle + i * 25;
				} else {
					angle = rotateAngle + i * 48;
				}

			} else {
				angle = rotateAngle + i * 90;
			}

			float radian = (float) Math.toRadians(angle);
			float adjacent = (float) Math.cos(radian) * centreRadius;
			float right = (float) Math.sin(radian) * centreRadius;
			float radianControl = (float) Math.toRadians(90 - (45 + angle));
			float xStrat = (float) Math.cos(radianControl) * centreRadius;
			float yEnd = (float) Math.sin(radianControl) * centreRadius;
			if (i == 0 || i == 1) {
				if (i == 1) {
					arcStrat.set(centreCirclePoint.x + adjacent - scale,
							centreCirclePoint.y + right + scale);
					arcEnd.set(centreCirclePoint.x - right, centreCirclePoint.y
							+ adjacent);

				} else {
					arcStrat.set(centreCirclePoint.x + adjacent,
							centreCirclePoint.y + right);
					arcEnd.set(centreCirclePoint.x - right - scale,
							centreCirclePoint.y + adjacent + scale);

				}
				controlP.set(centreCirclePoint.x + yEnd * controlrate,
						centreCirclePoint.y + xStrat * controlrate);
			} else {
				arcStrat.set(centreCirclePoint.x + adjacent,
						centreCirclePoint.y + right);
				arcEnd.set(centreCirclePoint.x - right, centreCirclePoint.y
						+ adjacent);
				if (i > 5) {
					controlP.set(centreCirclePoint.x + yEnd * controlrateS,
							centreCirclePoint.y + xStrat * controlrateS);
				} else {
					controlP.set(centreCirclePoint.x + yEnd * controlrate,
							centreCirclePoint.y + xStrat * controlrate);
				}
			}
			arcPointStrat[i] = arcStrat;
			arcPointEnd[i] = arcEnd;
			control[i] = controlP;

			lastPath.rewind();
			lastPath.moveTo(arcPointStrat[i].x, arcPointStrat[i].y);
			lastPath.quadTo(control[i].x, control[i].y, arcPointEnd[i].x,
					arcPointEnd[i].y);

			if (i > 3 && i < 6) {
				canvas.drawPath(lastPath, minCentrePaint);
			} else {
				canvas.drawPath(lastPath, arcPaint);
			}
			lastPath.rewind();
		}
	}

	private void setAnimation() {
		setScheduleWithFixedDelay(this, 0, 5);
		setScheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				if (bubbleIndex > 2)
					bubbleIndex = 0;
				if (bubbleBeans.size() < 8) {
					bubbleBeans.add(new BubbleBean(
							bubbleList.get(bubbleIndex).x, bubbleList
							.get(bubbleIndex).y, random.nextInt(4) + 2,
							bubbleIndex));
				} else {
					for (int i = 0; i < bubbleBeans.size(); i++) {
						if (bubbleBeans.get(i).getY() <= (int) (screenHeight / 2 + centreRadius)) {
							bubbleBeans.get(i).set(
									bubbleList.get(bubbleIndex).x,
									bubbleList.get(bubbleIndex).y,
									random.nextInt(4) + 2, bubbleIndex);
							if (random.nextInt(bubbleBeans.size()) + 3 == 3 ? true
									: false) {
							} else {
								break;
							}
						}
					}
				}
				bubbleIndex++;
			}
		}, 0, 300);
	}

	private static ScheduledExecutorService getInstence() {
		if (scheduledThreadPool == null) {
			synchronized (BubbleViscosity.class) {
				if (scheduledThreadPool == null) {
					scheduledThreadPool = Executors
							.newSingleThreadScheduledExecutor();
				}
			}
		}
		return scheduledThreadPool;
	}

	private static void setScheduleWithFixedDelay(Runnable var1, long var2,
												  long var4) {
		getInstence().scheduleWithFixedDelay(var1, var2, var4,
				TimeUnit.MILLISECONDS);

	}

	public static void onDestroyThread() {
		getInstence().shutdownNow();
		if (scheduledThreadPool != null) {
			scheduledThreadPool = null;
		}
	}

	@Override
	public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
		bubbleList.clear();
		setBubbleList();
		startBubbleRunnable();
		setAnimation();
	}

	@Override
	public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {

	}

	@Override
	public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
		onDestroyThread();
	}

	@Override
	public void run() {
		i++;
		rotateAngle = i;
		if (i > 90 && i < 180) {
			scale += 0.25;
			if (controlrateS < 1.66)
				controlrateS += 0.005;
		} else if (i >= 180) {
			scale -= 0.12;
			if (i > 300)
				controlrateS -= 0.01;
		}
		onMDraw();
		if (i == 360) {
			i = 0;
			rotateAngle = 0;
			controlrate = 1.66f;
			controlrateS = 1.3f;
			scale = 0;
		}
	}

	public void setBubbleList() {
		float radian = (float) Math.toRadians(35);
		float adjacent = (float) Math.cos(radian) * lastRadius / 3;
		float right = (float) Math.sin(radian) * lastRadius / 3;
		if (!bubbleList.isEmpty())
			return;
		bubbleList.add(new PointF(screenWidth / 2 - adjacent, screenHeight
				- right));
		bubbleList.add(new PointF(screenWidth / 2, screenHeight - lastRadius
				/ 4));
		bubbleList.add(new PointF(screenWidth / 2 + adjacent, screenHeight
				- right));
		startBubbleRunnable();
	}

	public void startBubbleRunnable(){
		setScheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < bubbleBeans.size(); i++) {
					bubbleBeans.get(i).setMove(screenHeight,
							(int) (screenHeight / 2 + centreRadius));
				}
			}
		}, 0, 4);
	}
}

4、新增动画管理类

system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/WiredChargingAnimation.java

package com.android.systemui.charging;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.util.Slog;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.TextView;

import com.android.systemui.R;
import com.android.systemui.util.Utils;
import com.tinno.feature.TinnoFeature;

public class WiredChargingAnimation {
	public static final long DURATION = 5555;
	private static final String TAG = "WiredChargingAnimation";
	private static final boolean DEBUG = true || Log.isLoggable(TAG, Log.DEBUG);

	private final WiredChargingView mCurrentWirelessChargingView;
	private static WiredChargingView mPreviousWirelessChargingView;
	private static boolean mShowingWiredChargingAnimation;

	public StatusBarManager statusBarManager;

	public static boolean isShowingWiredChargingAnimation(){
		return mShowingWiredChargingAnimation;
	}

	public WiredChargingAnimation(@NonNull Context context, @Nullable Looper looper, int
			batteryLevel, boolean isDozing) {
		statusBarManager = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
		mCurrentWirelessChargingView = new WiredChargingView(context, looper,
				batteryLevel, isDozing);
	}

	public static WiredChargingAnimation makeWiredChargingAnimation(@NonNull Context context,
																	@Nullable Looper looper, int batteryLevel, boolean isDozing) {
		mShowingWiredChargingAnimation = true;
		return new WiredChargingAnimation(context, looper, batteryLevel, isDozing);
	}

	/**
	 * Show the view for the specified duration.
	 */
	public void show() {
		if (mCurrentWirelessChargingView == null ||
				mCurrentWirelessChargingView.mNextView == null) {
			throw new RuntimeException("setView must have been called");
		}

        /*if (mPreviousWirelessChargingView != null) {
            mPreviousWirelessChargingView.hide(0);
        }*/
		statusBarManager.disable(StatusBarManager.DISABLE_BACK | StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT);
		mPreviousWirelessChargingView = mCurrentWirelessChargingView;
		mCurrentWirelessChargingView.show();
		mCurrentWirelessChargingView.hide(DURATION);
	}

	public void hide(){
		if (mPreviousWirelessChargingView != null) {
            mPreviousWirelessChargingView.hide(0);
			statusBarManager.disable(StatusBarManager.DISABLE_NONE);
        }
	}

	public static class WiredChargingView {

		private static String CHARGE = "";
		private static String FASTCHARGE = "";
		private String chargeText;

		private static final int SHOW = 0;
		private static final int HIDE = 1;

		private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
		private final Handler mHandler;

		private int mGravity;
		private View mView;
		private View mNextView;
		private WindowManager mWM;

		private TextView charge_text;

		private static final int MSG_SHOW = 0x88;

		private Context mContext;
		
        //实时读取电压,显示是否快充文本
		private Handler handler = new Handler(Looper.myLooper()){
			@Override
			public void handleMessage(@NonNull Message msg) {
				super.handleMessage(msg);
				switch (msg.what){
					case MSG_SHOW:
						showText();
						sendEmptyMessageDelayed(MSG_SHOW, 500);
						break;
				}
			}
		};

		public WiredChargingView(Context context, @Nullable Looper looper, int batteryLevel, boolean isDozing) {
			//mNextView = new WirelessChargingLayout(context, batteryLevel, isDozing);
			this.mContext = context;
			mNextView = LayoutInflater.from(context).inflate(R.layout.wired_charging_layout, null, false);
			BubbleViscosity shcyBubbleViscosity = mNextView.findViewById(R.id.shcy_bubble_view);
			charge_text = mNextView.findViewById(R.id.charge_text);

			shcyBubbleViscosity.setBatteryLevel(batteryLevel+"");

			showText();
			handler.sendEmptyMessageDelayed(MSG_SHOW, 500);

			mNextView.setOnTouchListener(new OnTouchListener() {

				@Override
				public boolean onTouch(View v, MotionEvent event) {
					switch (event.getAction()){
						case MotionEvent.ACTION_DOWN:
							hide(0);
							break;
					}
					return false;
				}
			});

			mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;

			final WindowManager.LayoutParams params = mParams;
			params.height = WindowManager.LayoutParams.MATCH_PARENT;
			params.width = WindowManager.LayoutParams.MATCH_PARENT;
			params.format = PixelFormat.TRANSLUCENT;

			params.type = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;

			params.flags =  WindowManager.LayoutParams.FLAG_DIM_BEHIND
					| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
					| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
					| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
			params.systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
					| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
					| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;

			params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;

			params.dimAmount = 1.0f;

			if (looper == null) {
				// Use Looper.myLooper() if looper is not specified.
				looper = Looper.myLooper();
				if (looper == null) {
					throw new RuntimeException(
							"Can't display wireless animation on a thread that has not called "
									+ "Looper.prepare()");
				}
			}

			mHandler = new Handler(looper, null) {
				@Override
				public void handleMessage(Message msg) {
					switch (msg.what) {
						case SHOW: {
							handleShow();
							break;
						}
						case HIDE: {
							handleHide();
							// Don't do this in handleHide() because it is also invoked by
							// handleShow()
							handler.removeMessages(MSG_SHOW);
							mNextView = null;
							mShowingWiredChargingAnimation = false;
							break;
						}
					}
				}
			};
		}

		public void showText(){
			CHARGE = mContext.getString(R.string.charge_slow);

			if (TinnoFeature.TINNO_FEATURE_SPX_PK){
				FASTCHARGE = mContext.getString(R.string.charge_fast_pk);
			}else {
				FASTCHARGE = mContext.getString(R.string.charge_fast_mcl);
			}

			if (Utils.isFastCharge()){
				chargeText = FASTCHARGE;
			}else {
				chargeText = CHARGE;
			}
			charge_text.setText(chargeText);
		}

		public void show() {
			if (DEBUG) Slog.d(TAG, "SHOW: " + this);
			mHandler.obtainMessage(SHOW).sendToTarget();
		}

		public void hide(long duration) {
			mHandler.removeMessages(HIDE);

			if (DEBUG) Slog.d(TAG, "HIDE: " + this);
			mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);
		}

		private void handleShow() {
			if (DEBUG) {
				Slog.d(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView="
						+ mNextView);
			}

			if (mView != mNextView) {
				// remove the old view if necessary
				handleHide();
				mView = mNextView;
				Context context = mView.getContext().getApplicationContext();
				String packageName = mView.getContext().getOpPackageName();
				if (context == null) {
					context = mView.getContext();
				}
				mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
				mParams.packageName = packageName;
				mParams.hideTimeoutMilliseconds = DURATION;

				if (mView.getParent() != null) {
					if (DEBUG) Slog.d(TAG, "REMOVE! " + mView + " in " + this);
					mWM.removeView(mView);
				}
				if (DEBUG) Slog.d(TAG, "ADD! " + mView + " in " + this);

				try {
					mWM.addView(mView, mParams);
				} catch (WindowManager.BadTokenException e) {
					Slog.d(TAG, "Unable to add wireless charging view. " + e);
				}
			}
		}

		private void handleHide() {
			if (DEBUG) Slog.d(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
			if (mView != null) {
				if (mView.getParent() != null) {
					if (DEBUG) Slog.d(TAG, "REMOVE! " + mView + " in " + this);
					mWM.removeViewImmediate(mView);
				}

				mView = null;
			}
		}
	}
}

5、动画触发(电源插入时且在锁屏下显示气泡动画)

system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/power/PowerUI.java

@SysUISingleton
public class PowerUI extends CoreStartable implements CommandQueue.Callbacks {
    private final BroadcastDispatcher mBroadcastDispatcher;
    private final CommandQueue mCommandQueue;
    private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;

    //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 start
    private KeyguardManager mKeyguardManager;
    //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 end

    @Inject
    public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
            CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
            WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
            PowerManager powerManager) {
        super(context);
        mBroadcastDispatcher = broadcastDispatcher;
        mCommandQueue = commandQueue;
        mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
        mWarnings = warningsUI;
        mEnhancedEstimates = enhancedEstimates;
        mPowerManager = powerManager;
        //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 start
        mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
        //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 end
    }
    
    .....
    
    public void init() {
            // Register for Intent broadcasts for...
            IntentFilter filter = new IntentFilter();
            ....
            filter.addAction(Intent.ACTION_USER_SWITCHED);
            //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 start
            filter.addAction(Intent.ACTION_POWER_CONNECTED);
            filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
            //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 end
            mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
            ....
    }
    
    ....
        
    @Override
    public void onReceive(Context context, Intent intent) {
        .....
         	} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                mWarnings.userSwitched();
            //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 start
            } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
                boolean isCharging = Settings.Secure.getInt(mContext.getContentResolver(),
                        Settings.Secure.CHARGING_ANIMATE_SWITCH, 0) == 1;
                android.util.Log.d("zhang", "onReceive: -> Settings -> " + isCharging);
                if (mKeyguardManager.isKeyguardLocked() && isCharging){
                    WiredChargingAnimation.makeWiredChargingAnimation(context, null, mBatteryLevel, false).show();
                }
            } else if(Intent.ACTION_POWER_DISCONNECTED.equals(action)){
                WiredChargingAnimation.makeWiredChargingAnimation(context, null, mBatteryLevel, false).hide();
            //TN modify for bug VFFASMCLZAA-1040 by xin.wang 2023/10/30 end
            } else {
                Slog.w(TAG, "unknown intent: " + intent);
            }
   }

   ......
       
}
6、读取充电电压,判断是否达到6V快充条件

system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/util/Utils.java

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.android.systemui.util;

import static android.view.Display.DEFAULT_DISPLAY;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.provider.Settings;
import android.view.DisplayCutout;

import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
import com.android.systemui.shared.system.QuickStepContract;

//TN modify for bug VFFASMCLZAA-1040 2023/10/31 start {
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import android.util.Log;
import android.text.TextUtils;
//TN modify for bug VFFASMCLZAA-1040 2023/10/31 start }

import java.util.List;
import java.util.function.Consumer;

public class Utils {

    private static Boolean sUseQsMediaPlayer = null;

    /**
     * Allows lambda iteration over a list. It is done in reverse order so it is safe
     * to add or remove items during the iteration.  Skips over null items.
     */
    public static <T> void safeForeach(List<T> list, Consumer<T> c) {
        for (int i = list.size() - 1; i >= 0; i--) {
            T item = list.get(i);
            if (item != null) {
                c.accept(item);
            }
        }
    }

    .....

    /**
     * Gets the {@link R.dimen#status_bar_header_height_keyguard}.
     */
    public static int getStatusBarHeaderHeightKeyguard(Context context) {
        final int statusBarHeight = SystemBarUtils.getStatusBarHeight(context);
        final DisplayCutout cutout = context.getDisplay().getCutout();
        final int waterfallInsetTop = cutout == null ? 0 : cutout.getWaterfallInsets().top;
        final int statusBarHeaderHeightKeyguard = context.getResources()
                .getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard);
        return Math.max(statusBarHeight, statusBarHeaderHeightKeyguard + waterfallInsetTop);
    }

    /**
     * @author:xin.wang
     * @deprecated TN modify for bug VFFASMCLZAA-1040
     * @result true->FastCharge false->Charge
     */
    public static boolean isFastCharge(){
        final String CHARGING_VOLTAGE = "/sys/class/power_supply/mtk-master-charger/voltage_now";
        String result = readFile(CHARGING_VOLTAGE);
        if (!TextUtils.isEmpty(result)){
            float currentCharVol = (float) (Float.parseFloat(result) / 1000.0);
            if (currentCharVol > 6.0){
                return true;
            }else {
                return false;
            }
        }
        return false;
    }

    public static String readFile(final String filepath) {
        File file = new File(filepath);
        if (!file.exists()) {
            return null;
        }
        String content = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            byte[] buffer = new byte[(int) file.length()];
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                byte[] result = new byte[length];
                System.arraycopy(buffer, 0, result, 0, length);
                content = new String(result);
                break;
            }
        } catch (Exception e) {
            return null;
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            } catch (IOException e) {
                Log.d("Utils", "readFile: " + e.getMessage());
            }
        }
        return content;
    }
}

https://blog.youkuaiyun.com/qq_40446718/article/details/83445363

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值