欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

android?原生安全音量配置邏輯設(shè)計(jì)詳解

 更新時(shí)間:2023年01月04日 10:13:36   作者:咚門吹水  
這篇文章主要為大家介紹了android?原生安全音量配置邏輯設(shè)計(jì)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

接到一個(gè)開發(fā)需求,需要定制化開發(fā)一個(gè)安全音量功能;此前有了解過為了符合歐盟等有關(guān)國家和地區(qū)的規(guī)定,原生Android是有自帶一個(gè)安全音量功能的,想要定制則先要了解這個(gè)功能原先長什么樣子,下面我們就從一個(gè)系統(tǒng)工程師的角度出發(fā)去探尋一下,原生Android的安全音量功能是如何實(shí)現(xiàn)的。

安全音量配置

安全音量的相關(guān)配置都在framework的config.xml里面,可以直接修改或者overlay配置修改其默認(rèn)值。

<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">true</bool>
<!-- Safe headphone volume index. When music stream volume is below this index
the SPL on headphone output is compliant to EN 60950 requirements for portable music
players. -->
<integer name="config_safe_media_volume_index">10</integer>

config_safe_media_volume_enabled是安全音量功能的總開關(guān),config_safe_media_volume_index則是表明觸發(fā)安全音量彈框的音量大小值。

安全音量相關(guān)流程

安全音量的主要流程都在AudioService里面,其大致流程如下圖所示:

onSystemReady 初始化

系統(tǒng)啟動(dòng)過程略去不表,在系統(tǒng)啟動(dòng)完成后會(huì)調(diào)用onSystemReady;在onSystemReady中,service會(huì)發(fā)送一個(gè)MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED的msg,強(qiáng)制配置安全音量。

public void onSystemReady() {
    ...
    sendMsg(mAudioHandler,
    MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
    SENDMSG_REPLACE,
    0,
    0,
    TAG,
    SystemProperties.getBoolean("audio.safemedia.bypass", false) ?
        0 : SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
    ...
}

發(fā)送的MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED會(huì)調(diào)用onConfigureSafeVolume()來進(jìn)行安全音量的配置

onConfigureSafeVolume() 安全音量配置

    private void onConfigureSafeVolume(boolean force, String caller) {
        synchronized (mSafeMediaVolumeStateLock) {
            //Mobile contry code,國家代碼,主要用來區(qū)分不同國家,部分國家策略可能會(huì)不一致
            int mcc = mContext.getResources().getConfiguration().mcc;
            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
                //從config_safe_media_volume_index中獲取回來的安全音量觸發(fā)閾值
                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
                mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
                //根據(jù)audio.safemedia.force屬性值或者value配置的值來決定是否使能安全音量
                boolean safeMediaVolumeEnabled =
                        SystemProperties.getBoolean("audio.safemedia.force", false)
                        || mContext.getResources().getBoolean(
                                com.android.internal.R.bool.config_safe_media_volume_enabled);
                //確認(rèn)是否需要bypass掉安全音量功能
                boolean safeMediaVolumeBypass =
                        SystemProperties.getBoolean("audio.safemedia.bypass", false);
                // The persisted state is either "disabled" or "active": this is the state applied
                // next time we boot and cannot be "inactive"
                int persistedState;
                if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE; //這個(gè)值只能是disable或者active,不能是inactive,主要用于下次啟動(dòng)。
                    // The state can already be "inactive" here if the user has forced it before
                    // the 30 seconds timeout for forced configuration. In this case we don't reset
                    // it to "active".
                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
                        if (mMusicActiveMs == 0) { //mMusicActiveMs主要用于計(jì)數(shù),當(dāng)安全音量彈框彈出時(shí),如果按了確定,這個(gè)值便開始遞增,當(dāng)其達(dá)到UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX時(shí),則重新使能安全音量
                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
                            enforceSafeMediaVolume(caller);
                        } else {
                            //跑到這里則表示已經(jīng)彈過安全音量警示了,并且按了確定,所以把值設(shè)置為inactive
                            // We have existing playback time recorded, already confirmed.
                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
                        }
                    }
                } else {
                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
                }
                mMcc = mcc;
                //持久化當(dāng)前安全音量的狀態(tài)
                sendMsg(mAudioHandler,
                        MSG_PERSIST_SAFE_VOLUME_STATE,
                        SENDMSG_QUEUE,
                        persistedState,
                        0,
                        null,
                        0);
            }
        }
    }

由上可知,onConfigureSafeVolume()主要用于配置和使能安全音量功能,并且通過發(fā)送MSG_PERSIST_SAFE_VOLUME_STATE來持久化安全音量配置的值,這個(gè)持久化的值只能是active或者disabled。

case MSG_PERSIST_SAFE_VOLUME_STATE:
    onPersistSafeVolumeState(msg.arg1);
    break;
....
....
private void onPersistSafeVolumeState(int state) {
    Settings.Global.putInt(mContentResolver,
            Settings.Global.AUDIO_SAFE_VOLUME_STATE,
            state);
}

安全音量觸發(fā)

從實(shí)際操作可知,安全音量觸發(fā)條件是:音量增大到指定值。 從調(diào)節(jié)音量的代碼出發(fā),在調(diào)用mAudioManager.adjustStreamVolume和mAudioManager.setStreamVolume時(shí),最終會(huì)調(diào)用到AudioService中的同名方法,在執(zhí)行該方法的內(nèi)部:

protected void adjustStreamVolume(int streamType, int direction, int flags,
        String callingPackage, String caller, int uid) {
    ...
    ...
    ...
    } else if ((direction == AudioManager.ADJUST_RAISE) &&
            !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
        Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
        mVolumeController.postDisplaySafeVolumeWarning(flags);
    ....
    ...
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
            String caller, int uid) {
    ....
    ....
        if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumeController.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
            } else {
                onSetStreamVolume(streamType, index, flags, device, caller);
                index = mStreamStates[streamType].getIndex(device);
            }
    ....
    ....

由以上代碼可以看出,其安全音量彈框警告的觸發(fā)地方就在checkSafeMediaVolume方法附近處,并且都是通過mVolumeController這個(gè)遠(yuǎn)程服務(wù)去調(diào)用UI顯示安全音量彈框警告,但兩種調(diào)節(jié)音量的方法,觸發(fā)效果略有不同:

  • adjustStreamVolume:當(dāng)音量步進(jìn)方向是上升并且checkSafeMediaVolume返回false時(shí),直接彈出警告框;由于警告框占據(jù)了焦點(diǎn),此時(shí)無法進(jìn)行UI操作,并且再按音量+鍵時(shí),會(huì)繼續(xù)觸發(fā)這個(gè)彈框,導(dǎo)致無法實(shí)質(zhì)性地調(diào)整音量;
  • setStreamVolume:當(dāng)傳入的音量形參大于安全音量閾值,會(huì)觸發(fā)checkSafeMediaVolume返回false,彈出安全音量警告框;并且會(huì)通過mPendingVolumeCommand保存設(shè)置的音量值,待關(guān)掉安全音量后再賦回來。
private boolean checkSafeMediaVolume(int streamType, int index, int device) {
        synchronized (mSafeMediaVolumeStateLock) {
            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &amp;&amp;
                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &amp;&amp;
                    ((device &amp; mSafeMediaVolumeDevices) != 0) &amp;&amp;
                    (index &gt; safeMediaVolumeIndex(device))) {
                return false;
            }
            return true;
        }
    }

以上是安全音量判斷條件checkSafeMediaVolume,可以看出其判斷主要根據(jù)以下條件:

  • mSafeMediaVolumeState是否為active,這個(gè)是安全音量功能的開關(guān)變量;
  • 音頻流是否為STREAM_MUSIC,只針對(duì)該音頻流做安全音量;
  • 設(shè)備類型,默認(rèn)mSafeMediaVolumeDevices值如下:
    /*package*/ final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET
            | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
            | AudioSystem.DEVICE_OUT_USB_HEADSET;

由上可知,只針對(duì)耳機(jī)播放或者USB耳機(jī)才做安全音量功能,如有需要系統(tǒng)工程師可自行配置其他設(shè)備;

  • 音量大小,只有音量index超過safeMediaVolumeIndex獲取的值,才需要彈出安全音量警示框,而safeMediaVolumeIndex的值則是本文開頭在config.xml中配置的config_safe_media_volume_index所得出的;

UI部分

上面有提到,當(dāng)滿足安全音量警示框的觸發(fā)條件時(shí),會(huì)通過mVolumeController這個(gè)遠(yuǎn)程服務(wù)去調(diào)用UI顯示安全音量彈框警告,其調(diào)用鏈條有點(diǎn)長,中途略過不表,其最終會(huì)走到VolumeDialogImpl.java的showSafetyWarningH,如下:

public class VolumeDialog {
    ...
    private void showSafetyWarningH(int flags) {
        if ((flags &amp; (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0
                || mShowing) {
            synchronized (mSafetyWarningLock) {
                if (mSafetyWarning != null) {
                    return;
                }
                mSafetyWarning = new SafetyWarningDialog(mContext, mController.getAudioManager()) {
                    @Override
                    protected void cleanUp() {
                        synchronized (mSafetyWarningLock) {
                            mSafetyWarning = null;
                        }
                        recheckH(null);
                    }
                };
                mSafetyWarning.show();
            }
            recheckH(null);
        }
        rescheduleTimeoutH();
    }
    ...
}

UI配置部分主要在SafetyWarningDialog.java,代碼就不貼了,可自行查看,其本質(zhì)是一個(gè)對(duì)話框,在彈出時(shí)會(huì)搶占UI焦點(diǎn),如果不點(diǎn)擊確定或取消,則無法操作其他UI;

點(diǎn)擊確定后,會(huì)調(diào)用mAudioManager.disableSafeMediaVolume()來暫時(shí)關(guān)閉安全音量警告功能,但上面有提到,當(dāng)點(diǎn)擊確定之后其實(shí)是啟動(dòng)了一個(gè)變量mMusicActiveMs的計(jì)數(shù),當(dāng)這個(gè)計(jì)數(shù)到達(dá)一定值(默認(rèn)是20個(gè)小時(shí)),安全音量會(huì)重新啟動(dòng);

但如果點(diǎn)擊了取消,再繼續(xù)調(diào)大音量時(shí),安全音量彈框還是會(huì)繼續(xù)彈出;

disableSafeMediaVolume()

上面有提到,在安全音量彈框彈出后,點(diǎn)擊確定可以暫時(shí)關(guān)閉安全音量警告功能,其實(shí)最終會(huì)調(diào)用到AudioService中的disableSafeMediaVolume(),代碼如下:

public void disableSafeMediaVolume(String callingPackage) {
        enforceVolumeController("disable the safe media volume");
        synchronized (mSafeMediaVolumeStateLock) {
            setSafeMediaVolumeEnabled(false, callingPackage);
            if (mPendingVolumeCommand != null) {
                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
                                  mPendingVolumeCommand.mIndex,
                                  mPendingVolumeCommand.mFlags,
                                  mPendingVolumeCommand.mDevice,
                                  callingPackage);
                mPendingVolumeCommand = null;
            }
        }
    }

一方面是調(diào)用setSafeMediaVolumeEnabled來暫時(shí)關(guān)閉安全音量功能,另一方面會(huì)把此前臨時(shí)掛起的設(shè)置音量mPendingVolumeCommand重新設(shè)置回去。

小結(jié)

簡(jiǎn)單來講,Android原生的安全音量功能默認(rèn)強(qiáng)制打開,在插入耳機(jī)后,音量調(diào)節(jié)到指定閾值時(shí),會(huì)觸發(fā)音量警告彈框,該彈框會(huì)搶走焦點(diǎn),不點(diǎn)擊確定或取消無法進(jìn)行其他操作;在點(diǎn)擊確定后,默認(rèn)操作者本人允許設(shè)備音量繼續(xù)往上調(diào),但此時(shí)系統(tǒng)會(huì)開始一個(gè)默認(rèn)為20分鐘的倒計(jì)時(shí),在這20分鐘內(nèi)音量隨意調(diào)節(jié)都不會(huì)觸發(fā)安全音量彈框,但20分鐘結(jié)束后,音量大于閾值時(shí)會(huì)繼續(xù)觸發(fā)安全音量彈框,提醒使用者注意。

以上就是android 原生安全音量配置邏輯設(shè)計(jì)詳解的詳細(xì)內(nèi)容,更多關(guān)于android 原生安全音量邏輯的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android創(chuàng)建和使用數(shù)據(jù)庫SQLIte

    Android創(chuàng)建和使用數(shù)據(jù)庫SQLIte

    這篇文章主要為大家詳細(xì)介紹了Android創(chuàng)建和使用數(shù)據(jù)庫SQLIte的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android高效安全加載圖片的方法詳解

    Android高效安全加載圖片的方法詳解

    Android開發(fā)中消耗內(nèi)存較多一般都是在圖像上面,下面這篇文章主要給大家介紹了關(guān)于Android如何高效安全加載圖片的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Android自定義View實(shí)現(xiàn)LayoutParams的方法詳解

    Android自定義View實(shí)現(xiàn)LayoutParams的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)LayoutParams,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-02-02
  • Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法

    Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法

    這篇文章主要介紹了Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Android Studio ADB網(wǎng)絡(luò)調(diào)試匯總

    Android Studio ADB網(wǎng)絡(luò)調(diào)試匯總

    這篇文章主要為大家詳細(xì)介紹了Android Studio ADB網(wǎng)絡(luò)調(diào)試的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 新手必看Android Studio入門詳解

    新手必看Android Studio入門詳解

    上篇文章已經(jīng)說過了Android Studio的安裝配置,這篇文章主要介紹了Android Studio入門詳解以及一些常見的報(bào)錯(cuò),新手同學(xué)一起從這里開始完成我們的第一個(gè)Android項(xiàng)目吧!
    2021-08-08
  • 適配Android 8.0版本更新安裝與通知欄的一些坑

    適配Android 8.0版本更新安裝與通知欄的一些坑

    這篇文章主要給大家介紹了關(guān)于Android適配8.0版本更新安裝與通知欄的一些坑,文中通過示例代碼將這些坑介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • Android實(shí)現(xiàn)調(diào)用攝像頭和相冊(cè)的方法

    Android實(shí)現(xiàn)調(diào)用攝像頭和相冊(cè)的方法

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)調(diào)用攝像頭和相冊(cè)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Android Studio kotlin生成編輯類注釋代碼

    Android Studio kotlin生成編輯類注釋代碼

    這篇文章主要介紹了Android Studio kotlin生成編輯類注釋代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Android自定義彈框Dialog效果

    Android自定義彈框Dialog效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義彈框Dialog效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評(píng)論