Android設定でボリュームバーをドラッグしてボリュームを調整するフロー(android 5.1)

11245 ワード

前言:問題は、お客様がSoundPoolを通じてヒント音を再生し、音量を大きくしたいと考えているため、ハードウェアはQCTでオーディオパラメータを見ることができず、音源を大きくする方法しかありませんが、お客様は軽く感じています.途中でDEMO実験を書く必要がありますが、上層部はどのようにハードウェアにQCTを通じてオーディオパラメータを見ることができますか?私は本当に知りません.知っている学生は伝言を残して私を指導することができます.それから駆動していろいろな言い訳をして、私に上層部の音量を調節する流れを提供して、設定の中で音量バーをドラッグすることでQCTを通じてパラメータを見ることができて、しかも短いオーディオです.だから私はコードを追うのに苦労して、今メモしておきます.(最后に駆动して1つのリストを通じてSoundPool方法を调べて放送したのは低遅延オーディオでDSPを通らないで、明らかに駆动して一目で见ることができるものは私达の上层に调べなければならなくて、本当にいらいらします!)
上位レイヤはUIを設定してレイアウトファイルnotificationを検索します.settings.xml
notification_settings.xml(/packages/apps/Settings/res/xml)

<com.android.settings.notification.VolumeSeekBarPreference
        android:key="media_volume"
        android:icon="@*android:drawable/ic_audio_vol"
        android:title="@string/media_volume_option_title" />


<com.android.settings.notification.VolumeSeekBarPreference
        android:key="alarm_volume"
        android:icon="@*android:drawable/ic_audio_alarm"
        android:title="@string/alarm_volume_option_title" />


<com.android.settings.notification.VolumeSeekBarPreference
        android:key="ring_volume"
        android:icon="@*android:drawable/ic_audio_ring_notif"
        android:title="@string/ring_volume_option_title" />

UIをコードで構築すると、初期化時にonProgressChangedメソッドが書き換えられます.
VolumeSeekBarPreference.java(/packages/apps/Settings/src/com/android/settings/notification)
private void init() {
    ...
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
        if (mCallback != null) {                    
            mCallback.onStreamValueChanged(mStream, progress);
            }
        }
    ...
}

次のcallbackは長い間探していましたが、実は簡単です.
SeekBarVolumizer.java(/frameworks/base/core/java/android/preference)
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {        
    if (fromTouch) {
        postSetVolume(progress);
    }
    if (mCallback != null) {
        mCallback.onProgressChanged(seekBar, progress, fromTouch);
    }
}

public void onStopTrackingTouch(SeekBar seekBar) {        
    postStartSample();
}

private void postStartSample() {
    if (mHandler == null) return;
    mHandler.removeMessages(MSG_START_SAMPLE);
    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
                isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
}

@Override
public boolean handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_START_SAMPLE:
            onStartSample();
            break;
    }
}

private void onStartSample() {
    if (!isSamplePlaying()) {
        if (mCallback != null) {
            mCallback.onSampleStarting(this);
        }
        if (mRingtone != null) {
            try {
                mRingtone.play(); //   
            } catch (Throwable e) {
                Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
            }
        }
    }
}

Ringtone.java(/frameworks/base/media/java/android/media)
/**
 * Plays the ringtone.
 */
public void play() {
    if (mLocalPlayer != null) {
        // do not play ringtones if stream volume is 0
        // (typically because ringer mode is silent).
        if (mAudioManager.getStreamVolume(
                AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
            mLocalPlayer.start(); //   
        }
    } else if (mAllowRemote && (mRemotePlayer != null)) {
        final Uri canonicalUri = mUri.getCanonicalUri();
        try {
            mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes);
        } catch (RemoteException e) {
            if (!playFallbackRingtone()) {
                Log.w(TAG, "Problem playing ringtone: " + e);
            }
        }
    } else {
        if (!playFallbackRingtone()) {
            Log.w(TAG, "Neither local nor remote playback available");
        }
    }
}

MediaPlayer.java(/frameworks/base/media/java/android/media)
public void start() throws IllegalStateException {
    if (isRestricted()) {
        _setVolume(0, 0);
    }
    stayAwake(true);      
    _start();
}

private native void _start() throws IllegalStateException;

android_media_MediaPlayer.cpp(/frameworks/base/media/jni)
{"_start",      "()V",        (void *)android_media_MediaPlayer_start},

static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{    
    sp mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    process_media_player_call( env, thiz, mp->start(), NULL, NULL ); //mp->start()
}

以降の流れは、[Android]AudioTrack::start
また、音量バーをドラッグするとサンプル音が再生され、メディア、目覚まし時計、ベルの音が異なり、リソースをロードする場所はSeekBarVolumizerを構築する際に決まります.
SeekBarVolumizer.java(/frameworks/base/core/java/android/preference)
public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
    mContext = context;
    mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    mStreamType = streamType;
    mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
    mNotificationOrRing = isNotificationOrRing(mStreamType);
    if (mNotificationOrRing) {
        mRingerMode = mAudioManager.getRingerModeInternal();
    }
    mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
    mCallback = callback;
    mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
    mMuted = mAudioManager.isStreamMute(mStreamType);
    if (mCallback != null) {
        mCallback.onMuted(mMuted);
    }
    if (defaultUri == null) { //         Uri  
        if (mStreamType == AudioManager.STREAM_RING) {
            defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
        } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
            defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
        } else {
            defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
        }
    }
    mDefaultUri = defaultUri;
}