Android 11 连续插拔充电,出现充电提示音消失

现象: 连续插拔充电器,出现充电提示音消失,只能重启

插上充电器,PowerManagerService就会调用updatePowerStateLocked()方法来更新整个电源状态的改变,并进行重新计算。当电源状态发生改变时,如亮灭屏、电池状态改变、暗屏…都会调用该方法,在该方法中调用了其他同级方法进行更新。

  • 源码路径: frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
	private void updatePowerStateLocked() {
        if (!mSystemReady || mDirty == 0) {
            return;
        }
        if (!Thread.holdsLock(mLock)) {
            Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
        }

        Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
        try {
            // Phase 0: Basic state updates.
            updateIsPoweredLocked(mDirty);
            updateStayOnLocked(mDirty);
            updateScreenBrightnessBoostLocked(mDirty);
            
            // Phase 1: Update wakefulness.
            // Loop because the wake lock and user activity computations are influenced
            // by changes in wakefulness.
            final long now = mClock.uptimeMillis();
            int dirtyPhase2 = 0;
            for (;;) {
                int dirtyPhase1 = mDirty;
                dirtyPhase2 |= dirtyPhase1;
                mDirty = 0;

                updateWakeLockSummaryLocked(dirtyPhase1);
                updateUserActivitySummaryLocked(now, dirtyPhase1);
                updateAttentiveStateLocked(now, dirtyPhase1);
                if (!updateWakefulnessLocked(dirtyPhase1)) {
                    break;
                }
            }
            
            // Phase 2: Lock profiles that became inactive/not kept awake.
            updateProfilesLocked(now);

            // Phase 3: Update display power state.
            final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);

            // Phase 4: Update dream state (depends on display ready signal).
            updateDreamLocked(dirtyPhase2, displayBecameReady);

            // Phase 5: Send notifications, if needed.
            finishWakefulnessChangeIfNeededLocked();

            // Phase 6: Update suspend blocker.
            // Because we might release the last suspend blocker here, we need to make sure
            // we finished everything else first!
            updateSuspendBlockerLocked();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
    }

然后调用updateIsPoweredLocked(),此方法中会判断是否充电,充电类型,电池电量等级,会去唤醒屏幕,设置电池状态。

	/**
     * Updates the value of mIsPowered.
     * Sets DIRTY_IS_POWERED if a change occurred.
     */
	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();
            mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
            mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
                        + ", mIsPowered=" + mIsPowered
                        + ", oldPlugType=" + oldPlugType
                        + ", mPlugType=" + mPlugType
                        + ", mBatteryLevel=" + mBatteryLevel);
            }
            
            if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
                mDirty |= DIRTY_IS_POWERED;

                // Update wireless dock detection state.
                // 更新无线充电头检测状态
                final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
                        mIsPowered, mPlugType);

                // Treat plugging and unplugging the devices as a user activity.
                // Users find it disconcerting when they plug or unplug the device
                // and it shuts off right away.
                // Some devices also wake the device when plugged or unplugged because
                // they don't have a charging LED.
                final long now = mClock.uptimeMillis();
                // 插拔充电线是否唤醒屏幕PluggedOrUnplugged
                if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
                        dockedOnWirelessCharger)) {
                    wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
                            "android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
                            mContext.getOpPackageName(), Process.SYSTEM_UID);
                }
                userActivityNoUpdateLocked(
                        now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);

                // only play charging sounds if boot is completed so charging sounds don't play
                // with potential notification sounds
                // 播放充电提示音
                if (mBootCompleted) {
                    if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType)
                            && BatteryManager.isPlugWired(mPlugType)) {
                        mNotifier.onWiredChargingStarted(mUserId);
                    } else if (dockedOnWirelessCharger) {
                        mNotifier.onWirelessChargingStarted(mBatteryLevel, mUserId);
                    }
                }
            }
            // 设置电池状态
            mBatterySaverStateMachine.setBatteryStatus(mIsPowered, mBatteryLevel, mBatteryLevelLow);
        }
    }

充电提示音在Notifier.java中控制

  • 源码路径:frameworks/base/services/core/java/com/android/server/power/Notifier.java
	// 无线充电
	private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) {
        // play sounds + haptics
        playChargingStartedFeedback(userId, true /* wireless */);

        // show animation
        if (mShowWirelessChargingAnimationConfig && mStatusBarManagerInternal != null) {
            mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
        }
        mSuspendBlocker.release();
    }
    
    //有线充电
    private void showWiredChargingStarted(@UserIdInt int userId) {
        playChargingStartedFeedback(userId, false /* wireless */);
        mSuspendBlocker.release();
    }
    
    private void playChargingStartedFeedback(@UserIdInt int userId, boolean wireless) {
        if (!isChargingFeedbackEnabled(userId)) {
            return;
        }
        
        // vibrate
		final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
        if (vibrate) {
            mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
        }
        // play sound
        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND
                        : Settings.Global.CHARGING_STARTED_SOUND);
        final Uri soundUri = Uri.parse("file://" + soundPath);
        if (soundUri != null) {
            final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
            if (sfx != null) {
                sfx.setStreamType(AudioManager.STREAM_SYSTEM);
                sfx.play();
            }
        }
    }

上面的代码存在mediaPlayer未释放资源的问题,会导致其它模块播放media时出现(1,-19)

Ringtone 持有一个对应的mediaplayer,虽然Ringtone 每次播放前都释放资源,但是因为RingtoneManager每次返回的是一个新的Ringtone 对象,所以上面代码中,会不断的创建新的nediaplayer,导致出现无法播放问题。

最后处理:

	private Ringtone mRingtone; // add 
	...
	public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
            SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
            ...
        initChargingStartedSound(); // add       
	}
	// add start 
    private void initChargingStartedSound(){
        // play sound
        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                Settings.Global.CHARGING_STARTED_SOUND);
        if (soundPath != null) {
            final Uri soundUri = Uri.parse("file://" + soundPath);
            if (soundUri != null) {
                mRingtone = RingtoneManager.getRingtone(mContext, soundUri);
                if (mRingtone != null) {
                    mRingtone.setStreamType(AudioManager.STREAM_SYSTEM);
                }
            }
        }
    }
	// add end 
	
	private void playChargingStartedFeedback(@UserIdInt int userId, boolean wireless) {
        if (!isChargingFeedbackEnabled(userId)) {
            return;
        }
        // add start
        // vibrate
		/* final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
        if (vibrate) {
            mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
        }
		*/
        // play sound
        /*final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND
                        : Settings.Global.CHARGING_STARTED_SOUND);
        final Uri soundUri = Uri.parse("file://" + soundPath);
        if (soundUri != null) {
            final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
            if (sfx != null) {
                sfx.setStreamType(AudioManager.STREAM_SYSTEM);
                sfx.play();
            }
        }*/
        if (mRingtone != null) {
            mRingtone.stop();
            mRingtone.play();
        }
		// add end
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值