[Android Framework] Android實現充電時振動
阿新 • • 發佈:2019-01-29
概述
在Android原生程式碼中,當插入USB充電時,不會有充電提示音或者振動,因此,在平時專案中,有這種需求,這裡總結一下。
原理
當電池狀態改變時,BatterService都會發出ACTION_BATTERY_CHANGED
廣播,在PowerManagerService中對該廣播也進行了監聽,PowerManagerService負責協調整個電源狀態,其中有一個方法updateIsPoweredLocked()
專門負責處理電池狀態改變的邏輯,因此,可以在PowerManagerService中實現該功能,同時,在Power模組中,有一個類————Notifier類專門負責向其他模組通知PMS的變化,如亮屏廣播ACTION_SCREEN_ON
實現
PowerManagerService.java中:
private void updateIsPoweredLocked(int dirty) {
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
// ......
if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
mDirty |= DIRTY_IS_POWERED;
// .......
if (dockedOnWirelessCharger) {
mNotifier.onWirelessChargingStarted();
// Add Vibrate when Charging BEG
} else if (mBootCompleted && mIsPowered) {
mNotifier.onUsbChargingStarted(true);
}
// Add Vibrate when Charging END
}
// ......
}
}
當PowerManagerService中接收到ACTION_BATTERY_CHANGED
廣播後,如果充電狀態改變,則進入Notifier中:
Notifier.java:
import android.os.VibrationEffect;
import android.os.Vibrator;
private Vibrator mVibrator;
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
private VibrationEffect mVibrationEffect;
//獲取Vibrator例項
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
IAppOpsService appOps, SuspendBlocker suspendBlocker,
WindowManagerPolicy policy) {
// ......
//獲取Vibrator服務例項
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
//VibrationEffect描述了由振動器執行的觸覺效果
mVibrationEffect = VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE);
}
public void onUsbChargingStarted(boolean virbate) {
//申請一個SuspendBlocker鎖,以防止CPU休眠
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_USB_CHARGING_STARTED,virbate);
//非同步處理振動
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
//Handler中:
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// ......
case MSG_USB_CHARGING_STARTED:
boolean virbate = (boolean) msg.obj;
playUsbChargingStartedSound(virbate);
break;
}
}
}
private void playUsbChargingStartedSound(boolean virbate) {
//TODO play usb music if need.
//這裡沒有實現插入usb的鈴聲,引數表示是否振動
if (virbate) chargeVirbate();
//釋放SuspendBlocker鎖
mSuspendBlocker.release();
}
//進行振動
private void chargeVirbate() {
if (mVibrator != null && mVibrator.hasVibrator()) {
mVibrator.vibrate(mVibrationEffect, VIBRATION_ATTRIBUTES);
}
}
相關類
Vibrator
Vibrator用於操作裝置振動機器,其作為一個系統服務,通過getSystemService()獲取其例項:
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
常用API
boolean hasVibrator (): 檢測當前裝置是否有振動器
void cancel (): 取消當前振動
boolean hasAmplitudeControl (): 檢測當前裝置是否有振幅控制器
void vibrate (VibrationEffect vibe): 開始振動,VibrationEffect用於描述振動效果
void vibrate (VibrationEffect vibe, AudioAttributes attributes): 開始振動,AudioAttributes是一個封裝了音訊流資訊屬性集合的類,每種振動對應一種AudioAttributes
VibrationEffect
VibrationEffect用於描述Vibrator的振動效果,獲取其例項時,有兩種方式:
VibrationEffect.createOneShot ():建立一次性振動,一次振動將以指定的振幅在指定的時間段內持續振動,然後停止。
VibrationEffect.createWaveform():建立波形振動,波形振動是一系列可重複的定時和振幅對,振幅陣列決定振動的強烈程度,定時陣列決定振動的時長,若振幅為0,則意味著不會有振動。
常用API
public static VibrationEffect createOneShot (long milliseconds, int amplitude):建立一次性振動。
long milliseconds:振動時長
int amplitude:振幅
public static VibrationEffect createWaveform (long[] timings, int[] amplitudes, int repeat)
long[] timings:一對時長陣列
int[] amplitudes:一對振幅陣列,必須大小在1和255之間;
int repeat: 要重複的timings的索引,-1表示不重複;
public static VibrationEffect createWaveform (long[] timings, int repeat)//獲取VibrationEffect常用形式
long[] timings:振動開始時間和結束時間,以結束時間開始。
int repeat: 要重複的timings的索引,-1表示不重複;
public static final int DEFAULT_AMPLITUDE:預設振幅,值為-1