天天看点

Android 铃声多媒体音量、静音、震动(附源码)导读:

导读:

Android提供了可以进行对原生系统进行控制API。AudioManager用来对音量、模式(静音,震动,震动加声音等模式)等进行管理。可以用Vibrator、HapticFeedback进行管理手机震动。本人带着案例进行讲解,先温柔点讲控制系统音量,再说撩人的震动棒...呸..是振荡器。

一、AudioManager (音频管理)

1、音乐的播放方式

//1、自定义音频文件test
 MediaPlayer player = MediaPlayer.create(getApplicationContext(), R.raw.test);

//2、系统电话铃声TYPE_RINGTONE\系统通知铃声TYPE_NOTIFICATION 
Uri  uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);  

MediaPlayer  mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(PlayerService.this, uri);

————————————————————————————————————————————————————————————————               
 mMediaPlayer.setLooping(true); // 设置循环播放
               
 mMediaPlayer.prepare();//准备
               
 mMediaPlayer.start();//播放
           

2、修改音量方式

首先,拿到音频管理实例对象。 AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

然后,设置音量。例如 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 30, 0);

(1)修改音量

adjustVolume(int direction , int  flag) //修改音量
           

direction(方向):顾名思义,就是点击事件发生,往上增加音量,往下减少音量,和保持音量不变。

  •  AudioManager.ADJUST_LOWER(降低) 
  •  AudioManager.ADJUST_RAISE(升高) 
  •  AudioManager.ADJUST_SAME(锁定不变)  

(2) 修改类型、音量

adjustStreamVolume(int  streamType ,int direction , int flag) //修改类型、音量
           

streamType(音频流类型):即指定声音类型,有下述几种声音类型:

STREAM_ALARM:手机闹铃     STREAM_MUSIC:手机音乐

STREAM_RING:电话铃声      STREAM_SYSTEAM:手机系统

STREAM_DTMF:音调         STREAM_NOTIFICATION:系统提示

STREAM_VOICE_CALL:语音电话
           

flag(标志):其实是点击事件发生后,音量的表现形式。

  • AudioManager.FLAG_SHOW_UI :会弹出调节音量的界面
  • AudioManager.FLAG_ALLOW_RINGER_MODES :最低声音会振动

(3)设置音量大小 

setStreamVolume(int streamType, int index, int flags)//直接设置音量大小
           

index(音量的值) ,int类型。

4、实用小案例

XML 写一个SeekBar控件

<android.support.v7.widget.AppCompatSeekBar
    android:id="@+id/play_volume"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="50dp"/>
           

Activiy中的代码

声明变量

private MediaPlayer player;//测试音乐
private int maxVolume, currentVolume;//音量值
private AudioManager audioManager;//音频管理类
private SeekBar mView_sb_play_volume; //控件
           

初始化操作

mView_sb_play_volume = (SeekBar) findViewById(R.id.play_volume);//滑动进度条

        myRegisterReceiver();//注册同步更新的广播
        player = MediaPlayer.create(getApplicationContext(), R.raw.test);//自定义音频文件test
        audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);//实例
        maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  //获取系统最大音量
        mView_sb_play_volume.setMax(maxVolume);
        currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);  //获取当前值
        mView_sb_play_volume.setProgress(currentVolume);

        player.setLooping(true);
        mView_sb_play_volume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                player.pause();
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                player.start();
            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
                seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
//                seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
//                seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);

//HapticFeedbackConstants的常量值,我们要用到的有三个触摸震动方式:
// 一个是LONG_PRESS(长按),
// 第二个是FLAG_IGNORE_VIEW_SETTING(不受Xml里view的属性设置影响,即不受isHapticFeedbackEnabled()的影响),
// 第三个是FLAG_IGNORE_GLOBAL_SETTING(不受系统设置的影响,即不受是否开启震动反馈的影响)
            }
        });
           

 广播监听音量变化

//注册当音量发生变化时接收的广播
    private void myRegisterReceiver(){
        MyVolumeReceiver mVolumeReceiver = new MyVolumeReceiver() ;
        IntentFilter filter = new IntentFilter() ;
        filter.addAction("android.media.VOLUME_CHANGED_ACTION") ;
        registerReceiver(mVolumeReceiver, filter) ;
    }

    //处理音量变化时的界面显示
    private class MyVolumeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //如果音量发生变化则更改seekbar的位置
            if(intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")){
//AudioManager mAm = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);                
                // 当前的媒体音量
                currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) ;
                mView_sb_play_volume.setProgress(currentVolume) ;
            }
        }
    }
           

二、HapticFeedback(震动反馈)

首先,说明该震动方式不需要设置震动权限!!不需要设置震动权限!!不需要设置震动权限!!重要的事情说三遍。

从上面案例中所见,在SeekBar设置改变监听里自定义触发震动,下面先看一下源码讲解。

如下文所示,点击也会触发震动反馈了:

click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);

            }
        });
           

现在我们就去performHapticFeedback源码看下,都执行了什么。View.performHapticFeedback源码:

/**
     * BZZZTT!!1!
     *
     * <p>Provide haptic feedback to the user for this view.
     *
     * <p>The framework will provide haptic feedback for some built in actions,
     * such as long presses, but you may wish to provide feedback for your
     * own widget.
     *
     * <p>The feedback will only be performed if
     * {@link #isHapticFeedbackEnabled()} is true.
     *
     * @param feedbackConstant One of the constants defined in
     * {@link HapticFeedbackConstants}
     */
    public boolean performHapticFeedback(int feedbackConstant) {
        return performHapticFeedback(feedbackConstant, 0);
    }
           

这里解释三个知识点:

1、只有在isHapticFeedbackEnabled()为true的情况下,才会触发震动。之后会解释在为false的情况下,为何不会触发震动。

      在xml里,可以通过android:hapticFeedbackEnabled=”false|true”来进行设置

      在java代码里,可以通过view.setHapticFeedbackEnabled(boolean)来设置,不过默认是true哦。

2、HapticFeedbackConstants的常量值,我们要用到的有三个:

  • LONG_PRESS(长按);
  • FLAG_IGNORE_VIEW_SETTING(不受view的设置影响,即不受isHapticFeedbackEnabled()的影响);
  • FLAG_IGNORE_GLOBAL_SETTING(不受系统设置的影响,即不受是否开启震动反馈的影响);

3、最终是返回的performHapticFeedback(int feedbackConstant, int flags)这个方法。

    View.performHapticFeedback(int feedbackConstant, int flags)源码:

/**
     * BZZZTT!!1!
     *
     * <p>Like {@link #performHapticFeedback(int)}, with additional options.
     *
     * @param feedbackConstant One of the constants defined in
     * {@link HapticFeedbackConstants}
     * @param flags Additional flags as per {@link HapticFeedbackConstants}.
     */
    public boolean performHapticFeedback(int feedbackConstant, int flags) {
        if (mAttachInfo == null) {
            return false;
        }
        //noinspection SimplifiableIfStatement
        if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
                && !isHapticFeedbackEnabled()) {
            return false;
        }
        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
                (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
    }
           

看第15行的if语句,当flags=0时,flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING为0,又isHapticFeedbackEnabled()为false,整个条件为真,所以会执行17行,直接return。这也是为什么performHapticFeedback(int feedbackConstant)方法一定要在isHapticFeedbackEnabled()为ture的情况下才会触发震动。 在这里说一下,&是按位与,返回数值,&&逻辑与,返回布尔值。 第19-20行,就是触发底层震动的代码了,之后代码不做分析。

案例:

在单击事件,会触发震动:

click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);//长按
            }
        });
           

如果xml加上 android:hapticFeedbackEnabled=”false”这句话,单击事件没有震动效果了。如下所示:

<Button
        android:layout_width="wrap_content"
        android:id="@+id/click"
        android:layout_height="wrap_content"
        android:hapticFeedbackEnabled="false"
        android:text="make" />
           

如果这时,想让其震动,可以用如下方法来做:

click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS
			 ,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);//忽略view属性设置
            }
        });
           

还记得本篇文章之前,说去设置里打开触摸时震动的开关吗,其实,用户不打开,照样可以让其震动,只需要用如下的方法:

click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS
			 ,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
            }
        });
           

三、Vibrator(振荡器)

震动的系统权限

<uses-permission android:name="android.permission.VIBRATE"/>

获取实例:

Vibrator  vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
           

两种震动方式:

1、按照指定的模式去震动:

vibrator.vibrate(new long[]{100,1000,1000,1000}, -1);
           

数组参数意义:

  • 第一个参数为等待指定时间后开始震动,震动时间为第二个参数; 后边的参数依次为等待震动和震动的时间;
  • 第二个参数为重复次数,-1为不重复,0为一直震动;

2、指定震动的时间,数据类型long,单位为毫秒,一毫秒为1/1000秒

vibrator.vibrate(2000);
           

取消震动:

注意:震动为一直震动的话,如果不取消震动,就算退出,也会一直震动

vibrator.cancel();
           

案例:

XML 

<Button
    android:id="@+id/vibrator1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="35dp"
    android:text="震动模式一间断性"/>


<Button
    android:id="@+id/vibrator2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="震动模式二独立性"/>
           

Activity

private Button vibrator1,vibrator2;//控件
private Vibrator vibrator;//震动
           
vibrator1 = (Button) findViewById(R.id.vibrator1);
 vibrator2 =(Button)findViewById(R.id.vibrator2);
 vibrator1.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
         vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
         vibrator.vibrate(new long[]{100,1000,1000,1000}, -1);
         //按照指定的模式去震动。数组参数意义:
         // 第一个参数为等待指定时间后开始震动,震动时间为第二个参数; 后边的参数依次为等待震动和震动的时间;
         // 第二个参数为重复次数,-1为不重复,0为一直震动;
     }
 });
 vibrator2.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
         vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
         vibrator.vibrate(2000);//震动指定时间 ,数据类型long,单位为毫秒,一毫秒为1/1000秒
     }
 });
// vibrator.cancel();//取消震动,立即停止震动震动为一直震动的话,如果不取消震动,就算退出,也会一直震动
           

源码:安卓系统音频震动demohttp://download.csdn.net/download/csdn_aiyang/9970166

加群一起学习,我们不是一个人战斗:

Android 铃声多媒体音量、静音、震动(附源码)导读: