記事のマスターリンクのこのシリーズ:テーマ別のサブディレクトリのAndroid Frameworkクラスオーディオ・サブシステム
この章の要点の概要と説明:
この章では、onに焦点を当てます。上記のマインドマップの左上の音量調整プロセスのプロセス分析の設定インターフェイスで音量を調整するプロセスで十分です。主に、スライダーのボリューム値がレイヤーごとに転送される方法を説明します。
1 notification_settings.xmlからプログラムエントリを見つけます。
設定アプリケーションで、ファイル(packages / apps / Settings / res / xml / notification_settings.xml)を介して音量スライダーを定義します。
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/notification_settings"
android:key="notification_settings"
settings:keywords="@string/keywords_sounds_and_notifications">
<PreferenceCategory
android:key="sound"
android:title="@string/sound_settings" >
<!-- Media volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="media_volume"
android:icon="@*android:drawable/ic_audio_vol"
android:title="@string/media_volume_option_title" />
<!-- Alarm volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="alarm_volume"
android:icon="@*android:drawable/ic_audio_alarm"
android:title="@string/alarm_volume_option_title" />
...
</PreferenceCategory>
</PreferenceScreen>
このファイルは複数のVolumeSeekBarPreferenceを定義しています。ここでの各VolumeSeekBarPreferenceはSeekBarにバインドされています。VolumeSeekBarPreferenceのバインディング関数onBindViewで、対応するSeekBar SeekBarChangeListener(SeekBarVolumizerオブジェクト)が設定されています。コードは次のとおりです:
@Override
protected void onBindView(View view) {
super.onBindView(view);
if (mStream == 0) {
Log.w(TAG, "No stream found, not binding volumizer");
return;
}
mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
init();
}
2 init関数の分析からメッセージMSG_SET_DEVICE_VOLUMEをAudioServiceに送信するまで
最後にinit関数がここで呼び出され、コードは次のように実装されます。
private void init() {
if (mSeekBar == null) return;
getPreferenceManager().registerOnActivityStopListener(this);
final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
@Override
public void onSampleStarting(SeekBarVolumizer sbv) {
if (mCallback != null) {
mCallback.onSampleStarting(sbv);
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
if (mCallback != null) {
mCallback.onStreamValueChanged(mStream, progress);
}
}
@Override
public void onMuted(boolean muted) {
if (mMuted == muted) return;
mMuted = muted;
updateIconView();
}
};
final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
if (mVolumizer == null) {
//创建SeekBarVolumizer
mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc);
}
mVolumizer.start();
//设置mSeekBar
mVolumizer.setSeekBar(mSeekBar);
updateIconView();
mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress());
updateSuppressionText();
}
SeekBarがスライドされると、SeekBarオブジェクトのonProgressRefreshが呼び出され、コードは次のようになります。
public class SeekBar extends AbsSeekBar {
//...
@Override
void onProgressRefresh(float scale, boolean fromUser) {
super.onProgressRefresh(scale, fromUser);
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
}
}
//...
}
この関数は、mOnSeekBarChangeListener.onProgressChangedを呼び出して音量を設定します。このmOnSeekBarChangeListenerは、SeekBarVolumizerのsetSeekBarfanメソッドで設定されます。コードは次のとおりです:
public void setSeekBar(SeekBar seekBar) {
if (mSeekBar != null) {
mSeekBar.setOnSeekBarChangeListener(null);
}
mSeekBar = seekBar;
mSeekBar.setOnSeekBarChangeListener(null);
mSeekBar.setMax(mMaxStreamVolume);
updateSeekBar();
mSeekBar.setOnSeekBarChangeListener(this);
}
ここでのsetOnSeekBarChangeListenerは、SeekBarVolumizer自体でSeekBarのmOnSeekBarChangeListenerに設定されるため、ここではSeekBarVolumizerのonProgressChanged実装について懸念しています。
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
if (fromTouch) {
postSetVolume(progress);
}
if (mCallback != null) {
mCallback.onProgressChanged(seekBar, progress, fromTouch);
}
}
ここでpostSetVolumeの分析を続けます。コードの実装は次のとおりです。
private void postSetVolume(int progress) {
if (mHandler == null) return;
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
}
ここでメッセージ処理フローの分析を続けます。ハンドラーに対応するhandleMessageコードは次のように実装されます。
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_STREAM_VOLUME:
mAudioManager.setStreamVolume(mStreamType, mLastProgress,
AudioManager.FLAG_SHOW_UI_WARNINGS);
break;
//..
default:
Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
}
return true;
}
ここでオーディオサブシステムに入り始め、mAudioManagerのsetStreamVolumeコードは次のように実装されます。
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
if (mUseMasterVolume) {
service.setMasterVolume(index, flags, mContext.getOpPackageName());
} else {
service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
AUdioServiceのsetStreamVolumeがここで呼び出され、コードは次のように実装されます。
public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
}
setStreamVolumeの分析を続けます。コードの実装は次のとおりです。
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
int uid) {
//...
synchronized (mSafeMediaVolumeState) {
// reset any pending volume command
//...
if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
mVolumeController.postDisplaySafeVolumeWarning(flags);
mPendingVolumeCommand = new StreamVolumeCommand(
streamType, index, flags, device);
} else {
//checkSafeMediaVolume为真时
onSetStreamVolume(streamType, index, flags, device);
index = mStreamStates[streamType].getIndex(device);
}
}
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
ここでonSetStreamVolumeの分析を続けます。コードの実装は次のとおりです。
private void onSetStreamVolume(int streamType, int index, int flags, int device) {
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
//...
}
setStreamVolumeIntの分析を続けます。コードの実装は次のとおりです。
private void setStreamVolumeInt(int streamType,
int index,
int device,
boolean force) {
VolumeStreamState streamState = mStreamStates[streamType];
if (streamState.setIndex(index, device) || force) {
//最终都会调用AudioService.java的代码发出MSG
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
最後に、MSG_SET_DEVICE_VOLUMEがmAudioHandlerに送信されて処理さ れ、処理の流れは、Android Frameworkオーディオサブシステムのボリューム調整のためのボリュームキー処理フローのパート3で分析されました(14)。
注:各SeekBarはストリームに対応します。SeekBarをスライドすると、ストリームの音量が設定され、同じエイリアス(同じグループ)に属する他のストリームの音量も設定されます。