1. 程式人生 > >[Android Framework] Android實現充電時振動

[Android Framework] Android實現充電時振動

概述

在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