思路:监听音量的上下按键,显示自定义的音量键盘,然后通过异步线程调整声音的大小,因为这是一个耗时的过程,
/**
* 音量显示面板
*
*/
public class VolumePanel extends Handler implements OnKeyListener, OnSeekBarChangeListener {
/**
* 日志标签
*/
public static final String TAG = VolumePanel.class.getSimpleName();
/**
* 面板自动关闭延迟时间({@value} ms)
*/
public static final long DIALOG_DISMISS_DELAY = 5 * 1000;
/**
* 显示面板消息
*/
public static final int MSG_SHOW = 0;
/**
* 关闭面板消息
*/
public static final int MSG_DISMISS = 1;
/**
* 弹出框
*/
private Dialog mDialog;
/**
* 弹出框视图
*/
private View mView;
/**
* 进度条视图
*/
private SeekBar mSeekbarView;
/**
* 面板
*/
private ViewGroup mPanel;
/**
* 用于放置音量显示条的视图
*/
private ViewGroup mSliderGroup;
/**
* 音量显示条视图
*/
private ViewGroup mGroupView;
/**
* 音量条前面的图标
*/
private ImageView mStreamIcon;
/**
* Android上下文
*/
private Context mContext;
/**
* 音量进度
*/
private int mProgress;
/**
* 声音流枚举
*
*
*/
private enum StreamResources {
RingerStream(AudioManager.STREAM_RING, R.string.volume_icon_description_ringer, R.drawable.ic_audio_ring_notif,
R.drawable.ic_audio_ring_notif_mute, false), VoiceStream(AudioManager.STREAM_VOICE_CALL,
`R.string.volume_icon_description_incall, R.drawable.ic_audio_phone, R.drawable.ic_audio_phone, false), MediaStream(
AudioManager.STREAM_MUSIC, R.string.volume_icon_description_media, R.drawable.ic_audio_vol,
R.drawable.ic_audio_vol_mute, true);
int streamType;
int descRes;
int iconRes;
int iconMuteRes;
// RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly
// requested
boolean show;
/**
* 声音流枚举
*
* @param streamType
* 声音流类型
* @param descRes
* 声音流描述
* @param iconRes
* 声音流图标
* @param iconMuteRes
* 声音流静音图标
* @param show
* 是否显示
*/
StreamResources(int streamType, int descRes, int iconRes, int iconMuteRes, boolean show) {
this.streamType = streamType;
this.descRes = descRes;
this.iconRes = iconRes;
this.iconMuteRes = iconMuteRes;
this.show = show;
}
};
/**
* 声音流列表
*/
private final StreamResources[] STREAMS = { StreamResources.RingerStream, StreamResources.VoiceStream,
StreamResources.MediaStream };
/**
* 当前的流
*/
private StreamResources currentStream;
/**
* 构造方法
*
* @param context
* Android上下文,必须是Application
* @param itemOnly
* 只显示音量进度条
*/
public VolumePanel(Context context, boolean itemOnly) {
super(context.getMainLooper());
LayoutInflater inflater = LayoutInflater.from(context);
// 初始化音量进度条
mGroupView = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
mSeekbarView = (SeekBar) mGroupView.findViewById(R.id.seekbar);
mSeekbarView.setOnSeekBarChangeListener(this);
mStreamIcon = (ImageView) mGroupView.findViewById(R.id.stream_icon);
if (itemOnly) {
mView = mGroupView;
} else {
// 初始化音量面板
mView = inflater.inflate(R.layout.volume_adjust, null);
mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
mSliderGroup.addView(mGroupView);
}
// 初始化弹出框
mDialog = new Dialog(context) {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
}
return super.onTouchEvent(event);
}
};
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setContentView(mView);
// 初始化窗口
Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
window.setGravity(Gravity.TOP);
LayoutParams lp = window.getAttributes();
lp.token = null;
// Offset from the top
lp.y = context.getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
lp.width = LayoutParams.WRAP_CONTENT;
lp.height = LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
mDialog.setOnKeyListener(this);
// 保存Android上下文
mContext = context;
}
/**
* 显示面板
*/
public void show() {
Log.i(TAG, "show volume panel");
sendEmptyMessage(MSG_SHOW);
}
/**
* 关闭面板
*/
public void dismiss() {
Log.i(TAG, "dismiss volume panel");
sendEmptyMessage(MSG_DISMISS);
}
@Override
public void handleMessage(Message msg) {
// 获取音频管理器
AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
switch (msg.what) {
// 显示面板
case MSG_SHOW:
// 获取调整的声音模式
int stream = RtpStreamReceiver.getjStream();
// 判断是否在振铃,如果振铃则调整振铃音量
Ringtone ringtone = JAudioLauncher.oRingtone;
if (ringtone != null && ringtone.isPlaying()) {
stream = ringtone.getStreamType();
}
// 获取音量最大值
int max = manager.getStreamMaxVolume(stream);
// 最大声音和音量面板不匹配时重新设置
if (max != mSeekbarView.getMax()) {
mSeekbarView.setMax(max);
}
// 获取音量,设置进度
int volume = manager.getStreamVolume(stream);
Log.d(TAG, "volume : " + volume);
mProgress = volume;
mSeekbarView.setProgress(volume);
// 获取流信息,设置进度条
for (StreamResources streamResources : STREAMS) {
if (streamResources.streamType == stream) {
// 设置音量图标
if (volume == 0) {
mStreamIcon.setImageResource(streamResources.iconMuteRes);
} else {
mStreamIcon.setImageResource(streamResources.iconRes);
}
streamResources.show = true;
currentStream = streamResources;
break;
}
currentStream = null;
streamResources.show = false;
}
// 显示面板
mDialog.show();
// 移除关闭消息
removeMessages(MSG_DISMISS);
// 设置关闭消息,延迟DIALOG_DISMISS_DELAY
sendEmptyMessageDelayed(MSG_DISMISS, DIALOG_DISMISS_DELAY);
break;
// 关闭面板
case MSG_DISMISS:
// 移除关闭消息
removeMessages(MSG_DISMISS);
// 如果显示,则关闭
if (mDialog.isShowing()) {
mDialog.dismiss();
}
break;
}
super.handleMessage(msg);
}
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
// 监听按键,继续调用调整声音方法
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
JAudioLauncher.adjust(keyCode, true, mContext);
return true;
}
}
return false;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mProgress = seekBar.getProgress();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (mProgress != progress && currentStream != null) {
RtpStreamReceiver.setStreamVolume(currentStream.streamType, progress, AudioManager.FLAG_PLAY_SOUND
| AudioManager.FLAG_VIBRATE, mContext);
}
}
}
自定义的音量键盘布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dip"
android:orientation="horizontal"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip"
android:gravity="left|center_vertical">
<ImageView
android:id="@+id/stream_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dip"
android:background="?android:attr/selectableItemBackground"
/>
<SeekBar
style="?android:attr/seekBarStyle"
android:id="@+id/seekbar"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="16dip"
android:layout_marginRight="16dip" />
</LinearLayout>
///修改声音的方法
static void setStreamVolume(final int stream, final int vol, final int flags,
final Context context) {
if (setVolumeService != null) {
// 使用线程池调整声音
setVolumeService.execute(new Runnable() {
public void run() {
if (debug) {
Log.d(TAG, "setStreamVolume : (stream : " + stream + ", vol : " + vol + ", flags : "
+ flags + ")");
}
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(stream, vol, flags);
});
} else {
Log.w(TAG, "setStreamVolume setVolumeService is null");
}
}
//开启一个异步线程
/**
* 用于设置音量大小操作的线程池
*/
static ExecutorService setVolumeService = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "setStreamVolume");
}
});