在android8.0以上的代碼在設置 ---> 聲音 ---> 高級 中 有一個充電提示音的開關,當我們打開後,插入充電器後,設備顯示在充電但並沒有觸發提示音。其實這並不是android原生的bug,這裏的充電提示音指的是無線充電提示音,當只有無線充電的時候纔會響起,然而android有三種充電方式,分別是:電源充電(充電寶和電源充電器),無線充電,USB充電(電腦USB等設備)。如果要修改哪種充電有聲音最好修改是按照Android源碼的的邏輯來走,而網上很多文章都是監聽充電廣播,再播放提示音。本文講解如何在 framework按照源碼的邏輯來修改提示音,這樣將風險降到最低。
首先我們來看frameworks/base/core/java/android/os/BatteryManager.java這個類,這是電池的Manager,在這裏我們可以看到android定義的三種充電方式:
/** Power source is an AC charger. */
public static final int BATTERY_PLUGGED_AC = 1;
/** Power source is a USB port. */
public static final int BATTERY_PLUGGED_USB = 2;
/** Power source is wireless. */
public static final int BATTERY_PLUGGED_WIRELESS = 4;
然後在來看frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java這個類,PMS是負責Andorid系統中電源管理方面的工作。作爲系統核心服務之一,和PKMS,AMS一樣,由SyetemServer run 出來的,比如設備的常見功能如亮滅屏、亮度調節、低電量模式、保持CPU喚醒,還有充電等一系列電池相關的操作都是由它來完成的,這裏主要講解修改充電提示音的過程,所以不深入講解PMS的流程和功能。在這個類中的 private void updateIsPoweredLocked(int dirty) 方法是中,是當設備進行充電或者充電模式發生改變時調用的,
private void updateIsPoweredLocked(int dirty) {
1698 if ((dirty & DIRTY_BATTERY_STATE) != 0) {
1699 final boolean wasPowered = mIsPowered;
1700 final int oldPlugType = mPlugType;
1701 final boolean oldLevelLow = mBatteryLevelLow;
1702 mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
1703 mPlugType = mBatteryManagerInternal.getPlugType();
1704 mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
1705 mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
1706
1707 if (DEBUG_SPEW) {
1708 Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
1709 + ", mIsPowered=" + mIsPowered
1710 + ", oldPlugType=" + oldPlugType
1711 + ", mPlugType=" + mPlugType
1712 + ", mBatteryLevel=" + mBatteryLevel);
1713 }
1714
1715 if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
1716 mDirty |= DIRTY_IS_POWERED;
1717
1718 // Update wireless dock detection state.
1719 final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
1720 mIsPowered, mPlugType, mBatteryLevel);
1721
1722 // Treat plugging and unplugging the devices as a user activity.
1723 // Users find it disconcerting when they plug or unplug the device
1724 // and it shuts off right away.
1725 // Some devices also wake the device when plugged or unplugged because
1726 // they don't have a charging LED.
1727 final long now = SystemClock.uptimeMillis();
1728 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
1729 dockedOnWirelessCharger)) {
1730 wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
1731 mContext.getOpPackageName(), Process.SYSTEM_UID);
1732 }
1733 userActivityNoUpdateLocked(
1734 now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
1735
1736 // Tell the notifier whether wireless charging has started so that
1737 // it can provide feedback to the user.
1738 if (dockedOnWirelessCharger) {
1739 mNotifier.onWirelessChargingStarted();
1740 }
1741 /*#Begin Add by shaochun.wan for add Charging sound on 20180626*/
1742 else if(mIsPowered && mPlugType == BatteryManager.BATTERY_PLUGGED_AC){
1743 mNotifier.onAcChargingStarted();
1744 }
1745 /*#Ended Add by shaochun.wan for add Charging sound on 20180626*/
1746 }
1747
1748 if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
1749 if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
1750 if (DEBUG_SPEW) {
1751 Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
1752 }
1753 mAutoLowPowerModeSnoozing = false;
1754 }
1755 updateLowPowerModeLocked();
1756 }
1757 }
1758 }
注意1738處的代碼:dockedOnWirelessCharger 是當無線充電器鏈接的時候,就調用mNotifier.onWirelessChargingStarted() 這個方法,1742到1744是我添加的電源充電也有充電提示音的代碼,其中mPlugType 是充電的類型,mIsPowered 表示在充電,onAcChargingStarted() 是在 Notifier.java 這個類自定義的方法,當然,如果你想不這麼麻煩,簡單點,可直接調用onWirelessChargingStarted()這個方法。
接下來我們看/frameworks/base/services/core/java/com/android/server/power/Notifier.java 這個類中的方法:onWirelessChargingStarted()
public void onWirelessChargingStarted() {
556 if (DEBUG) {
557 Slog.d(TAG, "onWirelessChargingStarted");
558 }
559
560 mSuspendBlocker.acquire();
561 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
562 msg.setAsynchronous(true);
563 mHandler.sendMessage(msg);
564 }
只是發了一條消息,然後看消息接受的地方:
public void handleMessage(Message msg) {
741 switch (msg.what) {
742 case MSG_USER_ACTIVITY:
743 sendUserActivity();
744 break;
745
746 case MSG_BROADCAST:
747 sendNextBroadcast();
748 break;
749
750 case MSG_WIRELESS_CHARGING_STARTED:
751 /*#Begin Add by shaochun.wan for add Charging sound on 20180626*/
752 case MSG_AC_CHARGING_STARTED:
753 /*#Ended Add by shaochun.wan for add Charging sound on 20180626*/
754 playWirelessChargingStartedSound();
755 break;
756 case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
757 sendBrightnessBoostChangedBroadcast();
758 break;
759 }
760 }
可以看到750處的消息是調用了playWirelessChargingStartedSound() 這個函數。752處的代碼是我添加的自定義的消息,在發送onAcChargingStarted()的,和onWirelessChargingStarted()是一樣的。
最後我們可以看playWirelessChargingStartedSound() 這個方法
private void playWirelessChargingStartedSound() {
716 final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
717 Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
718 final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
719 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
720 if (enabled && soundPath != null) {
721 final Uri soundUri = Uri.parse("file://" + soundPath);
722 if (soundUri != null) {
723 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
724 if (sfx != null) {
725 sfx.setStreamType(AudioManager.STREAM_SYSTEM);
726 sfx.play();
727 }
728 }
729 }
730
731 mSuspendBlocker.release();
732 }
這裏只是播放提示音,如果想修改電源充電的提示音和無線充電的提示音不同,修改 soundPath 即可。到最後充電提示音已經講解完了,想要怎麼定製都很簡單了。