Android13充电动画实现

news2024/10/6 14:36:18

充电动画

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

效果图

在这里插入图片描述

修改文件清单
  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
具体实现
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"/>
</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(20f, 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(),
				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, String charger){
		this.text = level+"%";
		this.chargerText = charger;
		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 com.android.systemui.R;
import com.android.systemui.util.Utils;

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;
		android.util.Log.d(TAG,"makeWiredChargingAnimation batteryLevel="+batteryLevel);
		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);
        }
	}

	private static class WiredChargingView {

		private static final String CHARGE = "Charging";
		private static final String FASTCHARGE = "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;

		public WiredChargingView(Context context, @Nullable Looper looper, int batteryLevel, boolean isDozing) {
			//mNextView = new WirelessChargingLayout(context, batteryLevel, isDozing);
			mNextView = LayoutInflater.from(context).inflate(R.layout.wired_charging_layout, null, false);
			BubbleViscosity shcyBubbleViscosity = mNextView.findViewById(R.id.shcy_bubble_view);
			if (Utils.isFastCharge()){
				chargeText = FASTCHARGE;
			}else {
				chargeText = CHARGE;
			}
			shcyBubbleViscosity.setBatteryLevel(batteryLevel+"", chargeText);

			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()
							mNextView = null;
							mShowingWiredChargingAnimation = false;
							break;
						}
					}
				}
			};
		}

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

   ......
       
}

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

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

相关文章

2023年【道路运输企业安全生产管理人员】考试资料及道路运输企业安全生产管理人员考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员考试资料根据新道路运输企业安全生产管理人员考试大纲要求&#xff0c;安全生产模拟考试一点通将道路运输企业安全生产管理人员模拟考试试题进行汇编&#xff0c;组成一套道路运输企业安…

浅谈新能源汽车充电桩的选型与安装

叶根胜 安科瑞电气股份有限公司 上海嘉定201801 摘要&#xff1a;电动汽车的大力发展和推广是国家为应对日益突出的燃油供需矛盾和环境污染&#xff0c;加强生态环境保护和治理而开发新能源和清洁能源的措施之一&#xff0c;加快了电动汽车的发展。如今&#xff0c;电动汽车已…

Pure-Pursuit 跟踪双移线 Gazebo 仿真

Pure-Pursuit 跟踪双移线 Gazebo 仿真 主要参考学习下面的博客和开源项目 自动驾驶规划控制&#xff08;&#xff21;*、pure pursuit、LQR算法&#xff0c;使用c在ubuntu和ros环境下实现&#xff09; https://github.com/NeXTzhao/planning Pure-Pursuit 的理论基础见今年六月…

如何在 Endless OS 上安装 ONLYOFFICE 桌面编辑器 7.5

ONLYOFFICE 桌面编辑器是一款基于依据 AGPL v.3 许可进行分发的开源办公套件。使用这款应用&#xff0c;您无需保持网络连接状态即可处理存储在计算机上的文档。本指南会向您介绍&#xff0c;如何在 Endless OS 上安装 ONLYOFFICE 桌面编辑器 7.5。 ONLYOFFICE 桌面版是什么 O…

Ansible中的任务执行控制

循环 简单循环 {{item}} 迭代变量名称 loop: - value1 - value2 - ... //赋值列表{{item}} //迭代变量名称循环散列或字典列表 - name: create filehosts: host1tasks:- name: file moudleservice:name: "{{ item.name }}"state: "{{…

实验记录之——git push

平时做开发的时候经常push代码不成功&#xff0c;如下图 经好友传授经验&#xff0c;有如下方法 Win cmd使用Clash&#xff08;端口是7890&#xff09;代理操作&#xff0c;在cmd中输入&#xff1a; set http_proxy127.0.0.1:7890 set https_proxy127.0.0.1:7890Linux export …

防火墙日志记录和分析

防火墙监控进出网络的流量&#xff0c;并保护部署防火墙的网络免受恶意流量的侵害。它是一个网络安全系统&#xff0c;它根据一些预定义的规则监控传入和传出的流量&#xff0c;它以日志的形式记录有关如何管理流量的信息&#xff0c;日志数据包含流量的源和目标 IP 地址、端口…

可视化流程编排(Bpmn.js)介绍及实践

作者:罗强 为将内部系统打通并规范流程定义&#xff0c;基于统一的平台实现工单自动化流转,从而使用无界山工单系统帮助公司内部人员统一管理和处理来自企业内部提交的工单需求。而在系统中流程编排及节点设计主要是使用bpmn.js实现精细化配置。从而满足各种复杂的业务需求。目…

MapStruct的用法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、依赖导入二、简单使用2.1、定义转换的接口2.2、创建实体类2.3、测试2.4、底层实现 三、常用的注解3.1、Mapping(target "xxx1",source "x…

你还在用System.currentTimeMillis()打印代码执行时间?

文章目录 前言一、开发环境二、使用步骤1. 创建Springboot项目2. 引入hutool3. 使用TimeInterval 总结 前言 Hutool是一个小而全的Java工具类库&#xff0c;里面集成了很多实用的工具类&#xff0c;比如文件、流、加密解密、转码、正则、线程、XML等&#xff0c;通过这些工具类…

探索 Java 8 中的 Stream 流:构建流的多种方式

人嘛&#xff0c;要懂得避嫌… 开篇引入 Java 8引入了Stream流作为一项新的特性&#xff0c;它是用来处理集合数据的一种函数式编程方式。Stream流提供了一种更简洁、高效和易于理解的方法来操作集合数据&#xff0c;同时也能够实现并行处理&#xff0c;以提高性能。 以下是St…

在 GORM 中定义模型

为实现与数据库的无缝交互而打造有效模型的全面指南 在使用 GORM 进行数据库管理时&#xff0c;定义模型是基础。模型是您的应用程序的面向对象结构与数据库的关系世界之间的桥梁。本文深入探讨了在 GORM 中打造有效模型的艺术&#xff0c;探讨如何创建结构化的 Go 结构体&…

第十二章,集合类例题

例题1 package 例题;import java.util.*;public class 例题 {public static void main(String[] args) {// TODO Auto-generated method stub//实例化集合类对象Collection<String> list new ArrayList<>();//调用方法&#xff0c;向集合添加数据list.add("…

Java——java.time包使用方法详解

Java——time包使用方法详解 java.time 包是 Java 8 引入的新日期和时间 API&#xff08;JSR 310&#xff09;&#xff0c;用于替代旧的 java.util.Date 和 java.util.Calendar 类。它提供了一组全新的类来处理日期、时间、时间间隔、时区等&#xff0c;具有更好的设计和易用性…

什么是消息队列

什么是消息队列 消息队列是一种通信机制&#xff0c;用于在不同的应用程序或组件之间传递消息。它允许应用程序之间异步地发送和接收消息&#xff0c;而无需直接依赖彼此的可用性或性能。消息队列通常用于解耦不同组件&#xff0c;提高系统的可伸缩性和可维护性&#xff0c;以…

【Python入门一】Python及PyCharm安装教程

Python及PyCharm安装教程 1 Python简介1.1 Python下载及安装 2 PyCharm简介2.1 PyCharm下载及安装 参考 1 Python简介 Python是一种开源的高级编程语言&#xff0c;由Guido van Rossum于1991年创建。Python易于学习、阅读和编写&#xff0c;具有丰富的标准库和第三方模块&…

智慧校园管理云平台电子班牌系统源码,数据管理、信息发布、家校互通、物联控制、教务管理、日常办公、人脸识别

智慧校园平台源码 智慧校园云平台电子班牌系统源码 一款全功能智慧校园管理云平台电子班牌系统源码&#xff0c;融合了多媒体信息发布、家校互通、物联控制、教务管理、日常办公等一系列应用&#xff0c;是校园管理的现代手段。 电子班牌系统的主要功能包括&#xff1a;数据信…

电源管理(PMIC)MAX20428ATIA/VY、MAX20428ATIC/VY、MAX20428ATIE/VY适合汽车ADAS应用的开关稳压器

一、概述 MAX20428是一款高效率、八路输出、低压PMIC。OUT1将输入电源升压至5V&#xff0c;电流高达500mA&#xff0c;而三个同步降压转换器的输入电压范围为3.0V至4.2V&#xff0c;输出电压范围为0.8V至3.9875V&#xff0c;峰值电流分别高达1.3A、1.3A和3.5A。三个300mA pMOS…

c++实现建造者模式

代码 director.h #pragma once #include<vector> #include<string> #include<iostream>class Product { private:std::vector<std::string> _parts;public:void Add(const std::string& part) {_parts.push_back(part);}void show(){std::cout &…

L1和L2正则化通俗理解

机器学习中&#xff0c;如果参数过多&#xff0c;模型过于复杂&#xff0c;容易造成过拟合&#xff08;overfit&#xff09;。即模型在训练样本数据上表现的很好&#xff0c;但在实际测试样本上表现的较差&#xff0c;不具备良好的泛化能力。为了避免过拟合&#xff0c;最常用的…