- 效果
Android获取电池充电状态是否为快充可参考.
Android_source/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
private int lastBatteryStatus;private final BroadcastReceiver mBatteryChangedReceiver= new BroadcastReceiver(){@Overridepublic void onReceive(Context context, Intent intent) {int status=intent.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);BatteryManager batteryManager = context.getSystemService(BatteryManager.class);int level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);batteryStatus = com.android.settingslib.Utils.getBatteryStatus(context, intent);Log.d(TAG, "battery status="+status+" level="+level + " batteryStatus = " + batteryStatus);if (status==BatteryManager.BATTERY_STATUS_CHARGING&& lastBatteryStatus!=status){showWirelessChargingAnimation(level);}if (status==BatteryManager.BATTERY_STATUS_DISCHARGING&& lastBatteryStatus!=status){hideWirelessChargingAnimation();}lastBatteryStatus=status;}};@Overridepublic void showWirelessChargingAnimation(int batteryLevel) {if(!mKeyguardManager.isKeyguardLocked() && !isHome(mContext)){return;}if (mDozing || mKeyguardManager.isKeyguardLocked()) {// on ambient or lockscreen, hide notification panelwirelessChargingAnimation = WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,batteryLevel, new WirelessChargingAnimation.Callback() {@Overridepublic void onAnimationStarting() {CrossFadeHelper.fadeOut(mNotificationPanelViewController.getView(), 1);}@Overridepublic void onAnimationEnded() {CrossFadeHelper.fadeIn(mNotificationPanelViewController.getView());}}, mDozing, batteryStatus);wirelessChargingAnimation.show();} else {// workspacewirelessChargingAnimation = WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,batteryLevel, null, false, batteryStatus);wirelessChargingAnimation.show();}}public void hideWirelessChargingAnimation(){try{if(wirelessChargingAnimation != null && wirelessChargingAnimation.isShown()){wirelessChargingAnimation.hide();}}catch(RuntimeException e){}}
Android_source/frameworks/base/packages/SystemUI/src/com/android/systemui/charing/WirelessChargingAnimation.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.charing;import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.provider.Settings;
import android.os.Build;
import android.content.pm.ActivityInfo;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;import com.android.chargeanim.R;/*** A WirelessChargingAnimation is a view containing view + animation for wireless charging.* @hide*/
public class WirelessChargingAnimation {public static final long DURATION = 15133;private static final String TAG = "WirelessChargingView";private final WirelessChargingView mCurrentWirelessChargingView;private static WirelessChargingView mPreviousWirelessChargingView;public interface Callback {void onAnimationStarting();void onAnimationEnded();}/*** Constructs an empty WirelessChargingAnimation object. If looper is null,* Looper.myLooper() is used. Must set* {@link WirelessChargingAnimation#mCurrentWirelessChargingView}* before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}.* @hide*/public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, intbatteryLevel, Callback callback, boolean isDozing, String batteryStatus) {mCurrentWirelessChargingView = new WirelessChargingView(context, looper,batteryLevel, callback, isDozing, batteryStatus);}/*** Creates a wireless charging animation object populated with next view.* @hide*/public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,@Nullable Looper looper, int batteryLevel, Callback callback, boolean isDozing, String batteryStatus) {return new WirelessChargingAnimation(context, looper, batteryLevel, callback, isDozing, batteryStatus);}/*** 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);}mPreviousWirelessChargingView = mCurrentWirelessChargingView;mCurrentWirelessChargingView.show();
// mCurrentWirelessChargingView.hide(DURATION);}public void hide(){if (mCurrentWirelessChargingView == null ||mCurrentWirelessChargingView.mNextView == null) {throw new RuntimeException("setView must have been called");}if (mPreviousWirelessChargingView != null) {mPreviousWirelessChargingView.hide(0);}}private static class WirelessChargingView {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 Callback mCallback;private Context mContext;public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel,Callback callback, boolean isDozing, String batteryStatus) {mContext = context;mCallback = callback;mNextView = LayoutInflater.from(context).inflate(R.layout.activity_main , null, false);BubbleView syberBubbleView = mNextView.findViewById(R.id.syber_bubble_view);syberBubbleView.setBatteryLevel(batteryLevel);
// syberBubbleView.setBatteryStatus(batteryStatus);syberBubbleView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {Log.d(TAG, "onTouch: " + motionEvent.getAction());return true;}});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_WALLPAPER ;params.setTitle("Charging Animation");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {params.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_FULLSCREEN| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;}params.dimAmount = .3f;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) {@Overridepublic 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;break;}}}};}public void show() {Log.d(TAG, "SHOW: " + this);mHandler.obtainMessage(SHOW).sendToTarget();}public void hide(long duration) {mHandler.removeMessages(HIDE);Log.d(TAG, "HIDE: " + this);mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);}private void handleShow() {
// Settings.System.putInt(mContext.getContentResolver(), "show_battery_ui", 1);{Log.d(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView="+ mNextView);}if (mView != mNextView) {// remove the old view if necessaryhandleHide();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) {Log.d(TAG, "REMOVE! " + mView + " in " + this);mWM.removeView(mView);}Log.d(TAG, "ADD! " + mView + " in " + this);try {if (mCallback != null) {mCallback.onAnimationStarting();}int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_FULLSCREEN| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED| WindowManager.LayoutParams.FLAG_FULLSCREEN;mParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;mView.setSystemUiVisibility(visibility);mView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d("sgq", "onTouch: handleHide();" );handleHide();}});mWM.addView(mView, mParams);} catch (WindowManager.BadTokenException e) {Log.d(TAG, "Unable to add wireless charging view. " + e);}}}private void handleHide() {if (mView != null) {if (mView.getParent() != null) {if (mCallback != null) {mCallback.onAnimationEnded();}mWM.removeViewImmediate(mView);}mView = null;}}}
}
资源文件可参考充电动画Demo.