Android M彩蛋图如何修改情景模式的默认值 M

2016年11月
确定要删除当前文章?Android应用设置系统情景模式
* 设置情景模式
* silent//静音状态
* vibrate //震动状态
private void setRingerMode(boolean silent, boolean vibrate) {
if (silent) {
mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE :
AudioManager.RINGER_MODE_SILENT);
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, vibrate ? AudioManager.VIBRATE_SETTING_ON
: AudioManager.VIBRATE_SETTING_OFF);
没有更多推荐了,& 相关文章 &
Android 系统默认音量和最大音量
欢迎大家我分享和推荐好用的代码段~~ 声明
欢迎转载,但请保留文章原始出处:
CSDN:http://www.csdn.net
雨季o莫忧离:链接地址 正文
frameworks\base\media\java\android\media\AudioManager.java
@hide Default volume index values for audio streams
Android XML Shape使用入门
:radius="15dp" /&
&/shape& 效果图 下面是系统源码里的例子,文件为:source/frameworks/base/core/res/res/drawable/progress_horizontal.xml &layer-list xmlns:android="http://schemas.android.com/apk/res/android"&
&item android:id="@android:id/background
android vibrator与alarm
情景模式的类型
//AudioManager.RINGER_MODE_NORMAL 正常模式,有声,是否震动取决于原来系统声音设置中振动的设置
//AudioManager.RINGER_MODE_SILENT 静音模式,无声不震
//AudioManager.RINGER_MODE_VIBRATE 震动模式,无声,震动
前面讲过AudioManager可以修改系统的情景模式,其实看它名字,就知道Android系统的音量也是由它管理的.下面
修改第一次开机时的默认壁纸(静态图片和动态壁纸)
/.nexus.NexusWallpaper&/string& 其中com.android.wallpaper/.nexus.NexusWallpaper,”/”前为包名,后为类名
备注:如果要将内置到系统中的无source code的第三方动态壁纸程序设置为默认动态壁纸,则需要知道该apk中 WallpaperService对应的类名和包名,可以通过Google提供的apk-tool工具来得到该apk的资源文件,那么就可以通过查看AndroidManifest.xml文件去查找到对应的Wallpaper Service的类名和包名。
android静态图片和动态壁纸
/.nexus.NexusWallpaper&/string& 其中com.android.wallpaper/.nexus.NexusWallpaper,”/”前为包名,后为类名
备注:如果要将内置到系统中的无source code的第三方动态壁纸程序设置为默认动态壁纸,则需要知道该apk中 WallpaperService对应的类名和包名,可以通过Google提供的apk-tool工具来得到该apk的资源文件,那么就可以通过查看AndroidManifest.xml文件去查找到对应的Wallpaper Service的类名和包名。
Android的framework层音量控制原理分析--hot(key)处理
其它该当再补充 2.谁负责处理音量显示的? 答:AudioManager调用AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media
Android的framework层音量控制原理分析--hot(key)处理
其它该当再补充 2.谁负责处理音量显示的? 答:AudioManager调用AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media
Android的framework层音量控制原理
音量调整、Home键都在这个类里面做特殊处理,详细内容后面会在其它该当再补充 2.谁负责处理音量显示的? 答:AudioManager调用AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks
Android的framework层音量控制原理分析--hot(key)处理
AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media/AudioService.java /framework/base/core
Android的framework层音量控制原理分析--hot(key)处理 .
AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media/AudioService.java /framework/base/core
Android的framework层音量控制原理分析
AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media/AudioService.java /framework/base/core
Android的framework层音量控制原理分析--hot(key)处理
AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。 源码位置: /frameworks/base/media/java/android/media/AudioManager.java /frameworks/base/media/java/android/media/AudioService.java /framework/base/core
Android的framework层音量控制原理分析--hot(key)处理
:AudioManager调用AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包StatusBarPolicy中接收广播消息来处理的。
源码位置:
/frameworks/base/media/java/android/media/AudioManager.java
/frameworks/base/media/java/android/media/AudioService.java
/framework
Android的frameworks层音量控制原理分析
的 WindowManagerService循环读取下面的消息再做分发到窗口接收,在消息分发前会有一个类做消息过滤处理,就是PhoneWindowManager.interceptKeyBeforeQueueing; 比如音量调整、Home键都在这个类里面做特殊处理,详细内容后面会在其它该当再补充 2.谁负责处理音量显示的? 答:AudioManager调用AudioService来显示的。事件触发在AudioManager,代码的执行实现在AudioService中。状态栏是SystemUI的APK包
Android系统默认值的设置
~255:   frameworks/base/packages/SettingsProvider/res/values/defaults.xml
  def_screen_brightness--&这个值初始化好像是100多 9音量:   frameworks/base/media/java/android/media/AudioManager.java   数组DEFAULT_STREAM_VOLUME第4个值(最大我设置到30但是还是差2格才到最大--默认是11   建议将数组里的所有
Android系统默认值的设置与自定义修改
/AudioManager.java   数组DEFAULT_STREAM_VOLUME第4个值(最大我设置到30但是还是差2格才到最大--默认是11   建议将数组里的所有的数值都设为最大就OK了)   frameworks/base/AudioService.java中定义了每一种音频流的最大音量级别: 10设置Google帐户,左上角提示“正在设置RK2818SDK”,要求改成“正在设置W9”:   out\target\product\sdkDemo\root 中default.prop文件第13行
【android】AudioManager音量控制 当前音量值的获取 1 2 3 4 5 6 //音量控制,初始化定义 AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); //最大音量 int
maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); //当前音量 int
Android中的菜单显示风格
:moreIcon"&@android:drawable/ic_menu_more&/item&
&item name="android:background"&@null&/item&
二、各设置项的定义
2.1 背景 默认是没有背景的
2.2 子菜单背景 每个MenuItem背景的定义通过“android:itemBackground”指向menu_selector,menu_selector定义在frameworks/base/core/res
Android系统默认值的设置
  后面的应该是书签里的   8设定亮度0~255:   frameworks/base/packages/SettingsProvider/res/values/defaults.xml
  def_screen_brightness--&这个值初始化好像是100多 9音量:   frameworks/base/media/java/android/media/AudioManager.java   数组DEFAULT_STREAM_VOLUME第4个值(最大我设置到30但是还是差2格才到最大
Android系统默认值的设置
  后面的应该是书签里的   8设定亮度0~255:   frameworks/base/packages/SettingsProvider/res/values/defaults.xml
  def_screen_brightness--&这个值初始化好像是100多 9音量:   frameworks/base/media/java/android/media/AudioManager.java   数组DEFAULT_STREAM_VOLUME第4个值(最大我设置到30但是还是差2格才到最大
& 2012 - 2016 & aiuxian.com &All Rights Reserved. &
/*爱悠闲图+*/
var cpro_id = "u1888441";浅析Android情景模式流程
此篇是基于MTK平台Android6.0的.情景模式分析,情景模式就是通常手机里面的”标准””静音””会议””户外”这几种模式,这几种模式的区别就在于音量,震动,静音,所以可以说情景模式就是建立在音量改变的基础上的.所以下面就主要的分析情景模式里面的比较重要的两个方面,一是铃声的设置问题,二是音量调节分析,情景模式只是一种覆盖而已,主要还是基于Android设置里面的铃声设置,音量调节,具体还会牵扯到很多地方,这里只是大致介绍下流程,其他还有待继续研究.
(一)铃声设置
手机里面的铃声资源主要分为music,ringtone,alarm,podcast,notification这几类,系统刚启动的时候会去扫描手机里面的多媒体文件,并把这些文件放入数据库中,扫描部分的代码在
frameworks\base\media\java\android\media\MediaScanner.java中
public Uri doScanFile(String path, String mimeType, long lastModified,
long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {
Uri result =
long t1 = System.currentTimeMillis();
try {FileEntry entry = beginFile(path, mimeType, lastModified,
fileSize, isDirectory, noMedia);
// if this file was just inserted via mtp, set the rowid to zero
// (even though it already exists in the database), to trigger
// the correct code path for updating its entry
if (mMtpObjectHandle != 0) {
entry.mRowId = 0;
// rescan for metadata if file was modified since last scan
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
if (noMedia) {
result = endFile(entry, false, false, false, false, false);
String lowpath = path.toLowerCase(Locale.ROOT);
boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) & 0);
boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) & 0);
boolean alarms = (lowpath.indexOf(ALARMS_DIR) & 0);
boolean podcasts = (lowpath.indexOf(PODCAST_DIR) & 0);
boolean music = (lowpath.indexOf(MUSIC_DIR) & 0) ||
(!ringtones && !notifications && !alarms && !podcasts);
boolean isaudio = MediaFile.isAudioFileType(mFileType);
boolean isvideo = MediaFile.isVideoFileType(mFileType);
boolean isimage = MediaFile.isImageFileType(mFileType);
* M: TODO google use new method to generate path, we need test it later.
* because fork process can access external storage
if (isaudio || isvideo || isimage) {
path = Environment.maybeTranslateEmulatedPathToInternal(new File(path))
.getAbsolutePath();
// we only extract metadata for audio and video files
if (isaudio || isvideo) {
processFile(path, mimeType, this);
if (isimage) {
/// M: Decodes OMA DRM 1.0 FL image’s width and height(ALPS)
if (IS_SUPPORT_DRM && lowpath.endsWith(“.dcf”)) {
processDcfImageFile(path);
processImageFile(path);
result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
} catch (RemoteException e) {
Log.e(TAG, “RemoteException in MediaScanner.scanFile()”, e);
long t2 = System.currentTimeMillis();
Log.v(TAG, “scanFile: ” + path + ” took ” + (t2-t1));
private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications,
boolean alarms, boolean music, boolean podcasts){
….. …… ….
if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) {
// Only set these for new entries. For existing entries, they
// may have been modified later, and we want to keep the current
// values so that custom ringtones still show up in the ringtone
// picker.
values.put(Audio.Media.IS_RINGTONE, ringtones);
values.put(Audio.Media.IS_NOTIFICATION, notifications);
values.put(Audio.Media.IS_ALARM, alarms);
values.put(Audio.Media.IS_MUSIC, music);
values.put(Audio.Media.IS_PODCAST, podcasts);
最终扫描进数据库中,数据库的位置在/data/data/com.android.providers.media/databases目录下,里面有SD卡和内存的数据库,现在截内存图如下:
这四个字段同时有且只有一个字段为1,也就是对于一个多媒体文件只能是这四种中的一种,默认为0,如果是某种类型,则android系统默认置为1,所以当要判断是那种类型的媒体资源时只要判断相应字段值哪个是1就可以了.
以上这只是系统刚启动时将媒体文件扫描进数据库中,库里的数据将以contentProvider的形式对外提供服务.接下来就是设置里面的那些铃声的加载问题了.
当点击”手机铃声”或者”通知铃声”或 “闹钟铃声”时就会进入相应的铃声选择界面:
设置里面的”手机铃声”或”默认通知铃声”或”闹钟铃声”选项就是一个Ringtonepreference类控件,此处是DefaultRingtonePreference,在packages\apps\Settings\src\com\mediatek\audioprofile\
DefaultRingtonePreference.java,DefaultRingtonePreference继承了RingtonePreference,当点击时它是会走它里面的onClick()方法,该方法继承了Ringtonepreference里面的onClick()方法,方法如下:
protected void onClick() {
// Launch the ringtone picker
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
onPrepareRingtonePickerIntent(intent);
PreferenceFragment owningFragment = getPreferenceManager().getFragment();
if (owningFragment != null) {
owningFragment.startActivityForResult(intent, mRequestCode);
getPreferenceManager().getActivity().startActivityForResult(intent, mRequestCode);
在该方法里面会开启RingtonePickerActivity.java,同时还会传入一些状态的数据,
protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI,
onRestoreRingtone());
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault);
if (mShowDefault) {
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
RingtoneManager.getDefaultUri(getRingtoneType()));
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent);
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType);
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getTitle());
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_AUDIO_ATTRIBUTES_FLAGS,
AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY);
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_MORE_RINGTONES, true)
这个方法里面就是点击时传入的状态和数据,分别传入了:uri,是否显示默认铃声选项,是否显示静音选项,铃声的type,标题,是否显示更多铃声选项等,此处uri来自于onRestoreRingtone(),该方法的实现在Ringtonepreference的此处子类DefaultRingtonePreference中,如下:
protected Uri onRestoreRingtone() {
int type = getRingtoneType();
Log.d(“@M_” + TAG, “onRestoreRingtone: type = ” + type + ” mKey = ” + mKey
mSimId= ” + mSimId);
Uri uri = mProfileManager.getRingtoneUri(mKey, type, mSimId);
然后追踪到:AudioProfileManager.java里面的getRingtoneUri()-&AudioProfileService.java里面AudioProfileService.getRingtoneUriWithSIM(),该方法里面有两个方法,分别是getProfileState(profileKey, simId)和getDefaultRingtone(type),方法里面会进行判断如果uri不存在或者为空则走getDefaultRingtone(type),其他的走getProfileState(profileKey, simId).
getDefaultRingtone(type)-&实现是在readDefaultRingtones()实现读默认铃声的功能:
private void readDefaultRingtones() {….. ……
String uriString = Settings.System.getStringForUser(mContentResolver,
AudioProfileManager.KEY_DEFAULT_RINGTONE,mUserId);
Uri uri = (uriString == null ? null : Uri.parse(uriString));
mDefaultRingtone.set(DEFAULT_RINGER_INDEX, uri);
Google从6.0以后将铃声相关的数据存储在xml文件里面,文件的位置在data/system/users/0/目录下的settings_system.xml里面,部分截图如下:
所以上面readDefaultRingtones()也是从这里面读的值,至于getProfileState()方法跟踪下去会发现在readPersistedSettings()函数里面实现的.
initValues键值对里面的数来自data/system/audio_profile/[0/XX]/settings.ini里面,是在AudioProfileService.java的内部类AudioProfileSettings里面protected boolean put(final String key, final String value){}方法写入的,settings.ini里面的内容如下:
以上是点击”手机铃声”或者”通知铃声”通过startActivityForResult启动ringtonepickerActivity所传入的状态值.
下面就进入打开的ringtonepickerActivity里面的,该活动的界面就是铃声选择界面,在ringtonepickerActivity的onCreate方法里面去对ringtonepreference所传进来的值进行接收,比如说决定要不要显示”更多铃声”选项等,里面比较重要的是下面这段代码
mCursor = mRingtoneManager.getCursor();
// The volume keys will control the stream that we are choosing a ringtone for
setVolumeControlStream(mRingtoneManager.inferStreamType());
// Get the URI whose list item should have a checkmark
mExistingUri = intent
.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
final AlertController.AlertParams p = mAlertP
p.mCursor = mC
p.mOnClickListener = mRingtoneClickL
p.mLabelColumn = MediaStore.Audio.Media.TITLE;
p.mIsSingleChoice =
p.mOnItemSelectedListener =
p.mPositiveButtonText = getString(com.android.internal.R.string.ok);
p.mPositiveButtonListener =
p.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
p.mPositiveButtonListener =
p.mOnPrepareListViewListener =
p.mTitle = intent.getCharSequenceExtra(RingtoneManager.EXTRA_RINGTONE_TITLE);
if (p.mTitle == null) {
p.mTitle = getString(com.android.internal.R.string.ringtone_picker_title);
这段代码就是利用RingtoneManager的getCursor方法去查询com.android.providers.media数据库,RingtoneManager里面的方法如下:public Cursor getCursor() {
if (mCursor != null && mCursor.requery()) {
Log.v(TAG, “getCursor with old cursor = ” + mCursor);
final Cursor internalCursor = getInternalRingtones();
final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() :
final Cursor mediaCursor = getMediaRingtones();
mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor },
“title”);
return mC分别去查询内存,外存,drm,的音乐,查询的结果给AlertController.AlertParams对象,将结果进行封装从而显示出歌曲姓名列表,上面的setVolumeControlStream(mRingtoneManager.inferStreamType());是设置音量的流类型
当点击后会去播放相应的铃声,通过RingtonePickerActivity中的playRingtone()àrun()里面去播放,点击OK键该Activity会返回一个你选择的歌曲所对应的Uri给RingtonePreference.java.它所做的处理如下:
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == mRequestCode) {
if (data != null) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (callChangeListener(uri != null ? uri.toString() : “”)) {
onSaveRingtone(uri);
所以会去走onSaveRingtone(uri),该方法实现也是在子类DefaultRingtonePreference里面:
protected void onSaveRingtone(Uri ringtoneUri) {
SharedPreferences prefs = this.getContext().getSharedPreferences(
“DefaultRingtonePreference”, Context.MODE_PRIVATE);
mSimId = prefs.getLong(PREF_SIM_ID_VALUME, -1);
mProfileManager.setRingtoneUri(mKey, getRingtoneType(), mSimId, ringtoneUri);继续追踪终到AudioprofileService里面的setRingtoneUri方法,如下:
public void setRingtoneUri(String profileKey, int type, long simId, Uri ringtoneUri) {
….. ….. ……
doRingtoneUriSetting(profileKey, type, simId, newRingtoneUri);
…. …. ….
private void doRingtoneUriSetting(String profileKey, int type, long simid, Uri uri) {
// Firstly, persist to database
persistRingtoneUriToDatabase(profileKey, type, simid, uri);
// Secondly, update the hash map
AudioProfileState state = getProfileState(profileKey);
synchronized (mLock) {
setRingtoneUriInStateMap(state, type, uri, simid);
// Finally, if the profile is active, persist it to system
if (isActiveProfile(profileKey)) {
persistRingtoneUriToSystem(type);
persistRingtoneUriToDatabase方法就是将数据值写到settings.ini里面,这个方法里面会发送消息到handleMessage()里面调用mProfileSettings.put()将数据写入settings.ini
class AudioProfileHandler extends Handler {
public void handleMessage(Message msg) {
…… ……. …….
case MSG_PERSIST_VOICECALL_RINGTONE_TO_DATABASE:
case MSG_PERSIST_NOTIFICATION_RINGTONE_TO_DATABASE:
case MSG_PERSIST_VIDEOCALL_RINGTONE_TO_DATABASE:
case MSG_PERSIST_SIPCALL_RINGTONE_TO_DATABASE:
mProfileSettings.put(name,valueSting);
mProfileSettings.put(AudioProfileManager.getDataKey(name),
getExternalUriData(valueSting));
….. ……. ……}
persistRingtoneUriToSystem();方法则是将数据写到setings.system.xml里面,它也是发送了消息个handlemessage,
case MSG_PERSIST_SIPCALL_RINGTONE_TO_SYSTEM:
RingtoneManager.setActualDefaultRingtoneUri(mContext,
AudioProfileManager.TYPE_SIP_CALL,
(valueSting == null ? null : Uri.parse(valueSting)));
在消息里面调用了RingtoneManager.setActualDefaultRingtoneUri{
String setting = getSettingForType(type);
if (setting == null)
Settings.System.putString(context.getContentResolver(), setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
到此情景模式里面的铃声设置流程分析结束.
(二)音量的调节(参考了&&深入理解Android卷3&&)
音量调节分为两种,一种是按键,一种是设置里面音量条
adjustSuggestedStreamVolume()
onKeyDow() dispatchAdjustVolume() adjustStreamVolume()
setDeviceVolume()
sendVolumeUpdate()
VolumeStreamState. adjustIndex()
按下音量按键系统会将该事件一路传给activity,若没有活动截获处理该事件,承载当前Activity显示的PhoneWindow类的onkeyDown()或onkeyUp()函数将会处理,从而开始通过音量键调整音量的流程.
首先进入PhoneWindow.onKeyDown()方法
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
… …. ….
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
mVolumeControlStreamType, direction,
AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
| AudioManager.FLAG_FROM_KEY);
上面这部分代码主要通过判断mMediaController 是否为空,也就是显示音量的UI是否存在,如果存在就直接调用MediaController.adjustVolume进行音量调整,如果不存在就通过MediaSession去创建UI去调整.追踪sendAdjustVolumeBy()方法最终会追踪到MediaSessionService.java里面的public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
MediaSessionRecord session) {
mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
flags, packageName, TAG);
会发现从PhoneWindow.java的按键处理一直追踪到AudioService.adjustSuggestedStreamVolume方法
frameworks\base\services\core\java\com\android\server\audio\AudioService.java
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller, int uid) {
int streamT
boolean isMute = isMuteAdjust(direction);
if (mVolumeControlStream != -1) {
streamType = mVolumeControlS
streamType = getActiveStreamType(suggestedStreamType);
ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
// Play sounds on STREAM_RING only.
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
resolvedStream != AudioSystem.STREAM_RING) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
// For notifications/ring, show the ui before making any adjustments
// Don't suppress mute/unmute requests
if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
direction = 0;
flags &= ~AudioManager.FLAG_PLAY_SOUND;
flags &= ~AudioManager.FLAG_VIBRATE;
if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
adjustSuggestedStreamVolume()负责接收MeidaSessionService传入的信息,然后针对要修改流类型获取相应的映射,更改是否显示ui的标志,然后将具体的调整音量操作交给adjustStreamVolume()去完成。简单来说这个函数干了以下几件事:一是确定要调整的音量的流类型,二是在某些情况下屏蔽FLAG_PLAY_SOUND,三是调用了adjustStreamVolume()方法
private void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage, String caller, int uid) {
…. …. ….
确定调整音量的方法和流类型
ensureValidDirection(direction);
ensureValidStreamType(streamType);
boolean isMuteAdjust = isMuteAdjust(direction);判断是否静音
获取流的映射和其当前音量
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
final int device = getDeviceForStream(streamTypeAlias);
int aliasIndex = streamState.getIndex(device);
boolean adjustVolume =
…. …. …..
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
// volume is enforced, and max and 0 for the others.
// This is simulated by stepping by the full allowed volume range
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
(device & mSafeMediaVolumeDevices) != 0) {
step = mSafeMediaVolumeI
step = streamState.getMaxIndex();
if (aliasIndex != 0) {
aliasIndex =
// convert one UI step (+/-1) into a number of internal units on the stream alias
不同流类型音量调节范围不同,所以这里进行音量调节范围在不同流之间的转换
step = rescaleIndex(10, streamType, streamTypeAlias);
判断是否要改变情景模式
final int result = checkForRingerModeChange(aliasIndex, direction, step,
streamState.mIsMuted);
是否要改变音量
adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
发送消息将音量值设置到底层和数据库
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
streamState,
VolumeStreamState获取音量值并将音量变化发送更新
int index = mStreamStates[streamType].getIndex(device);
sendVolumeUpdate(streamType, oldIndex, index, flags);
上面的MSG_SET_DEVICE_VOLUME,消息将会传到handleMessage()里面调用
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1)方法,继续追踪会找到在该方法里面做了两件事一是调用streamState.applyDeviceVolume_syncVSS(device)-&AudioSystem.setStreamVolumeIndex(mStreamType, index, device);设置音量到底层的AudioFlinger里面去.二是发送了MSG_PERSIST_VOLUME消息调用persistVolume()将音量写到settings.system.xml文件中.
至于sendVolumeUpdate()方法
private void sendVolumeUpdate()
mVolumeController.postVolumeChanged(streamType, flags);
notifyRingerVolumeChanged()
通过postVolumeChanged可以追踪到IVolumeController,-&在systemUI的VolumeDialogController,java里面要实现了IVolumeController,在VolumeDialogController,java里面追踪到volumeChanged()方法-&onVolumeChangedW()-&onShowRequested()-&VolumeDialog.java里面的onShowRequested()-&showH()-&VolumeDialogMotion.java里面的startShow(){…
mDialog.show();…
这样按下音量键的时候的音量对话框就起来了.
而notifyRingerVolumeChanged()方法则是通知情景模式里面音量发生了改变,情景模式里面的相应的方法接收到通知从而更新音量值并将其保存到情景模式的数据库里面.
具体如下:notifyRingerVolumeChanged()-&AudioProfileService.java里面的onRingerVolumeChanged()-&syncRingerVolumeToProfile()-&persistStreamVolumeToDatabase()-&mProfileSettings.put(name,String.valueOf(valueInt));
接下来就是AudioSevice的内部类VolumeStreamState,VolumeStreamState的功能就是保存了一个流类型所有音量相关的信息,它里面的adjustIndex()方法-&setIndex()方法.
public boolean setIndex(int index, int device, String caller) {
… …. …..
mIndexMap.put(device, index);
…. ….. ….
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
mStreamVolumeAlias[mStreamType]);
sendBroadcastToAll(mVolumeChanged);
这里VolumeStreamState主要就是将音量值保存,和发送一个广播通知系统音量发生了变化,然后在packages\apps\Settings\src\com\mediatek\audioprofile\SeekBarVolumizer.java里面接受通知变化,更新设置里面的音量进度条
在SeekBarVolumizer.java里面接受了广播之后回去走postUpdateSlider()然后在消息处理中更新进度.
同时在systemUI的VolumeDialogController.java里面也接受了这个广播,然后去执行onStateChanged()方法,该方法实现在VolumeDialog.java里面,VolumeDialog.onStateChanged()-&onStateChangedH()-&updateVolumeRowH()-&updateVolumeRowSliderH(){….. …..
row.slider.setProgress(newProgress)
这样systemUI弹框里面的音量条就也更新了.
2.通过设置调整音量
在SeekBarVolumizer里面调用一是调用AudioProfileManager.setStreamVolume(mKey, mStreamType, mOriginalStreamVolume)然后最终到AudioProfileService.setStreamVolume()将数据写到情景模式自己的数据库,二是调用setVolume()方法,在该方法里面将调用AudioManager.setAudioProfileStreamVolume()-&AudioService.setAudioProfileStreamVolume()-&AudioService.setStreamVolumeInt()和sendVolumeUpdate(),在setStreamVolumeInt()方法里面会发送消息,最终将音量值设置到底层的AudioFlinger里面去,以及将音量保存到系统xml数据库中.
没有更多推荐了,

我要回帖

更多关于 豫M 的文章

 

随机推荐