android系统音量界面相关

来源:互联网 发布:cf挂源码 编辑:程序博客网 时间:2024/05/16 11:33

    • 涉及到的代码
      • 什么是AudioManger
      • AudioManger和AudioService的关系
    • 题外话
      • 关于源码中引用资源文件编译报错cannot be resolved or is not a field
      • 关于Dialog是否依附Activity的问题
      • 关于外放和耳机音量统一问题

涉及到的代码:

framework/base/media/
AudioManager.java
AudioService.java

framework/base/package/SystemUI/
VolumeDialogController.java ——- 界面逻辑处理
VolumeDialog.java ——— UI显示
volume_dialog.xml ——— UI布局文件

什么是AudioManger

AudioManager简介

AudioManger和AudioService的关系:

AudioManager 封装了AudioService的服务,并通过getservice()方法获取AudioService的 Service 实例,涉及到普遍使用的aidl.

调用的通用方式:
import android.media.AudioManager;
private AudioManager mAudioManager;
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
各种public方法随你用,当然也包括系统音量的各种接口。

关于系统音量界面的调用将走到SystemUI中,涉及的关键文件如下,看命名就能看出来:
framework/base/package/SystemUI/
VolumeDialogController.java ——- 界面逻辑处理
VolumeDialog.java ——— UI显示
volume_dialog.xml ——— UI布局文件

关于系统音量的修改,一般情况下局限于UI上的修改,那么关注的文件是VolumeDialog.java和volume_dialog.xml,至于如何修改,看能力和需求了。

CallbackHandler的使用 以及VolumeDialogController.java中C,VC,W这三个类的作用都是相当关键的,下面这篇博客介绍比较多

Android 上的「安全音量」

题外话:

关于源码中引用资源文件编译报错:cannot be resolved or is not a field

源码中添加额外的图片,直接在代码中引用类似这样的设置背景操作:
ImageView.setBackground(getContext().getDrawable(R.drawable.android_ic_music_0));

编译时会报:cannot be resolved or is not a field错误,检查代码没有问题,各种分辨率的资源路径中也有图片资源,R文件中有对应的id,也是需要导R包的,编译前touch *和git clean,仍然无法解决问题。

原理不明,解决方法如下:
在xml中先引用一下图片(如果加入一批图片,只需引用一张即可),这样就能解决问题,之后在将xml中的引用去除,只在代码中引用,也能编译通过,
貌似一上来直接在代码中引用图片是不行的,只有在xml中有引用图片,那么新加入的一批图片才会在更多的R文件中注册(全局搜索图片名而得,个人臆想,不作数),此后才能在代码中引用。问题能解决,原因还是不明。

关于Dialog是否依附Activity的问题

Dialog一般情况下是依附于activity存在的,否则会报出Android.view.WindowManager$BadTokenException:Unable to add window的错误
特例情况(或者说解决上述报错的办法):
1.显示一个系统界别的dialog,即全局性质的dialog。这种dialog在任何界面下都可以弹出来。但是,这种dialog不相应home键和返回键,即强制用户必须对dialog作出操作后。
使用方法是在dialog.show()语句之前设置dialog的window的type是system alert型。
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mDialog.show();
如需要,同时在AndroidManifast中申请权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

2.在dialog的背后加一个透明的activity。即先显示一个透明的activity,在使用activity的context显示dialog。需要注意的是,activity在destroy的时候一定要把dialog给dismiss掉,
否则activity消失但dialog还在,会crash。
以上是两种特例情况,源码中的非activity下的dialog弹窗一般会使用特例1的方法(通话时长显示等),但是并无法确认所有的弹窗都是Dialog。

关于外放和耳机音量统一问题

  • 前言:android源生的代码是将两者的音量值独立开来,这是很人性化的设计,毕竟人对耳机音量和外放音量的需求是不一样的
  • 此处的统一音量值是特殊项目(无外放设备的项目)的特殊需求,此处记录一下完成思路,万一忘了就尴尬了。。。
  • 其实还有一个方法就是驱动修改默认的音频通道,但是有可能影响到其他的音量,比如蓝牙耳机连接时的音量,所以还是在上层修改比较容易控制

    思路:不去强行修改原本正确的输出设备,以免导致其他bug,在做音量调节(多媒体音量)的时候,保持外放和耳机音量同步

  • 涉及代码:AudioManager.java,AudioService.java,AudioSystem.java

  • 关键方法:AudioService.java中的adjustStreamVolume(int streamType, int direction, int flags,String callingPackage, String caller, int uid)
  • 保持两者音量同步的关键是在音量调节的时候能找到耳机和外放的设备值,很幸运,关键方法中就找到了,通过下面的方法获取到当前的输出设备(设备的标志位定义在Audioystem.java中)
    final int device = getDeviceForStream(streamTypeAlias);
    AudioSystem.DEVICE_OUT_SPEAKER:外放
    AudioSystem.DEVICE_OUT_WIRED_HEADSET:耳机
  • 那么在关键方法的最后加上同步音量的代码就好了,注意,添加的同步音量的代码不可以弹出音量调节UI(VolumeDialog)
    添加如下:
if ((streamType == AudioSystem.STREAM_MUSIC)){    if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {        setStreamVolumeInt(streamType,index,AudioSystem.DEVICE_OUT_WIRED_HEADSET,false,caller);    } else if((device & AudioSystem.DEVICE_OUT_WIRED_HEADSET) != 0){        setStreamVolumeInt(streamType,index,AudioSystem.DEVICE_OUT_SPEAKER,false,caller);    }}

思路明确,其实并不难

1 0