- 效果
Android_source/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
private int lastBatteryStatus;
private final BroadcastReceiver mBatteryChangedReceiver= new BroadcastReceiver(){
@Override
public 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;
}
};
@Override
public void showWirelessChargingAnimation(int batteryLevel) {
if(!mKeyguardManager.isKeyguardLocked() && !isHome(mContext)){
return;
}
if (mDozing || mKeyguardManager.isKeyguardLocked()) {
// on ambient or lockscreen, hide notification panel
wirelessChargingAnimation = WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
batteryLevel, new WirelessChargingAnimation.Callback() {
@Override
public void onAnimationStarting() {
CrossFadeHelper.fadeOut(mNotificationPanelViewController.getView(), 1);
}
@Override
public void onAnimationEnded() {
CrossFadeHelper.fadeIn(mNotificationPanelViewController.getView());
}
}, mDozing, batteryStatus);
wirelessChargingAnimation.show();
} else {
// workspace
wirelessChargingAnimation = 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, int
batteryLevel, 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() {
@Override
public 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) {
@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;
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 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) {
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() {
@Override
public 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;
}
}
}
}