Android FM 模块学习之四 源码解析(1)
Normal
0
7.8 磅
0
2
false
false
false
EN-US
ZH-CN
X-NONE
MicrosoftInternetExplorer4
前一章我们了解了FM手动调频,接下来我们要分析FM模块用到的源码。此源码是基于高通平台的,别的平台都大同小异,只不过是平台自己作了些小改动而已。
首先要看的当然是主activity,
FMRadio.java
fmradio 类启动FMRadioService.java 类调用FmSharedPreferences类进行存储数据,PresetStation调整频率
setVolumeControlStream(AudioManager.STREAM_MUSIC); 音乐回放即媒体音量
LoadedDataAndState 加载数据状态
HorizontalNumberPicker 水平刻度盘类继承LinearLayout
mPicker.setTextSize(mDisplayWidth/ TEXTSIZE_PARAMETER_FOR_NUMBER_PICKER); 设置字体的大小,屏幕宽度除以20
mPicker.setDensity(outMetrics.densityDpi); 设置控件密度
mPicker.setOnValueChangedListener 设置监听事件
valueToFrequency(newVal); 刻度滑动选中的值,上升下降调整限制值FmConfig 配置文件里setLowerLimit(int lowLimit)在设置里选中地区时候的频率取值范围
mPrefs.getFrequencyStepSize() ,获得设置的步长大小
mHandler.post(mRadioChangeFrequency); 更新在刻度盘上显示频率信息、
tuneRadio(int frequency) 调整fm 频率
FMRadioService.java 类isFmOn() 方法:
registerCallbacks 注册回调IFMRadioServiceCallbacks 的对象、
ServiceStub 继承IFMRadioService.Stub 使用到WeakReferenc弱引用, WeakReference 是弱于 SoftReference 的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)。
IBindermBinder = new ServiceStub(this); bindService IBinder 等于serviceStub 对象。
fmOn() 部分代码:
/**
* 当来电话不是闲置的时候就返回false
*/
if (TelephonyManager.CALL_STATE_IDLE != getCallState() ) {
return bStatus;
}
mReceiver= new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);
FmReceiver 接受广播类继承FmTransceiver
/ * * * 构造函数接收方对象,
路径
电台和事件回调。
* @param devicePath 调频设备路径字符串。
回调事件回调处理
从调频接收机* 事件。
* /
public FmReceiver(String devicePath, FmRxEvCallbacksAdaptorcallback)
throws InstantiationException {
mControl = new FmRxControls();
mRxEvents = new FmRxEventListner();
//registerClient(callback);
mCallback = callback;
}
获得FM 现在的状态
public int getFMState()
{
/* Current State of FM device */
int currFMState =FmTransceiver.getFMPowerState();
return currFMState;
}
滑动刻度盘动画效果:
mAnimation= AnimationUtils.loadAnimation(this,R.anim.preset_select);
静音控件监听,点击控件有声无声切换。
mMuteButton.setOnClickListener(mMuteModeClickListener);
喇叭与耳机监听切换
mSpeakerButton.setOnClickListener(mSpeakerClickListener);
开启关闭fm 控件切换
mOnOffButton.setOnClickListener(mTurnOnOffClickListener);
向右调频控件监听
mForwardButton.setOnClickListener(mForwardClickListener);
mForwardButton.setOnLongClickListener(mForwardLongClickListener);
向左调频控件监听
mBackButton.setOnClickListener(mBackClickListener);
mBackButton.setOnLongClickListener(mBackLongClickListener);
单击收藏按钮把收藏频率定位调频到刻度盘上,长期按钮将刻度盘频率收藏到按钮上存储到data 分区下的fmradio_prefs.xml文件 key是tation_name0x1
频率显示控件
mTuneStationFrequencyTV= (TextView)findViewById(R.id.prog_frequency_tv);
长按频率显示控件监听方法:
mTuneStationFrequencyTV.setOnLongClickListener(mFrequencyViewClickListener);
录音视图显示与监听事件
mRecordingMsgTV= (TextView)findViewById(R.id.record_msg_tv);
if (mRecordingMsgTV != null) {
mRecordingMsgTV.setOnClickListener(mRecordButtonListener);
}
自动关掉FM 时间显示
mSleepMsgTV= (TextView)findViewById(R.id.sleep_msg_tv);
fm 信号强度
mRSSI =(ImageView)findViewById(R.id.signal_level);
if (mRSSI != null) {
mRSSI.setVisibility(View.INVISIBLE);
}
显示控件显示信息等数据显示
protectedvoid setDisplayvalue()
onRestart()
获取 IFMRadioService 请求焦点
onStop 中方法调用private boolean
isSleepTimerActive() 是否是睡眠。
if(isSleepTimerActive()){
mSleepUpdateHandlerThread.interrupt();
}
如果是睡眠活动就睡眠更新线程中断线程
当录音开始,走onStop() 方法时候就停止录音更新线程
private boolean isRecording()
if (null!= mRecordUpdateHandlerThread) {
mRecordUpdateHandlerThread.interrupt();
}
public void onStart()
用户选择高清晰多媒体显示创建命令失败.
1 、如果未保存则调用onCreateDialog(int) ,然后再调用onPrepareDialog(int, Dialog)
(2) 如果保存了对话框对象,则直接调用onPrepareDialog(int,Dialog),
不会再去create,所以有时候当你再输入框里无论如何输入什么内容,对话框的内容都是第一次产生的。
removeDialog(int) 是用来清除Activity 保存下来的Dialog对象,如果不加removeDialog将会导致无论在对话框里输入什么内容,
弹出来的对话框始终都是第一次保留下来的,这里所以要加上它
创建搜索dialog
createSearchDlg(id,dlgBuilder)
FMConfig.java 类
public int getRdsStd () {
return mRdsStd;
}
registerFMSettingListner(); 注册收音机设置配置文件
mPrefs.Load(); 调用FmSharedPreferences
的Load()方法获取fmradio_prefs.xml数据
遇见bug: 将设置地区自动选择印度(外单项目)
/* LoadConfiguration */
if(Locale.getDefault().equals(Locale.CHINA)) {
setCountry(sp.getInt(FMCONFIG_COUNTRY,REGIONAL_BAND_CHINA));
} else {
setCountry(sp.getInt(FMCONFIG_COUNTRY, REGIONAL_BAND_NORTH_AMERICA));
}
/* Last list the user was navigating */
Local.getDafault() 在第一次刷机后设置本地语言后
protected void onPause() 的时候,将信息保存mPrefs.Save();
ScrollerText 控件继承Handler 、
/ * * * 移动一个字符留下的文字和文章
*SCROLLER_UPDATE_DELAY_MS 后延迟下更新消息。 * 如果滚动整个字符串, 然后它会显示整个字符串 * 并等待SCROLLER_RESTART_DELAY_MS
滚动重启 * /
voidupdateText() 更新录音时间
停止录音时间跟新
void stopScroll() {
mStatus = SCROLLER_STOPPED;
removeMessages(SCROLLER_MSG_TICK);
removeMessages(SCROLLER_MSG_RESTART);
removeMessages(SCROLLER_MSG_START);
resetScroll();
}
重新设置录音时间显示
private void resetScroll()
启动录音时间
void startScroll() {
初始化搜索
private void initiateSearch(int pty)
resetSearch() 重新收索
private void cancelSearch() 关闭收索
初始化搜索列表
private void initiateSearchList()
初始化睡眠定时器
private void initiateSleepTimer(long seconds) {
mSleepAtPhoneTime =(SystemClock.elapsedRealtime()) + (seconds * 1000);
Log.d(LOGTAG, "Sleep in seconds:" + seconds);
initiateSleepThread();
}
初始化睡眠线程
private void initiateSleepThread()
在
Intent launchPreferencesIntent = new Intent().setClass(this,
Settings.class);
launchPreferencesIntent.putExtra(Settings.RX_MODE,true);
startActivityForResult(launchPreferencesIntent,
ACTIVITY_RESULT_SETTINGS);
private void enableSpeaker() 扬声器可用
private void updateExpiredRecordTime() 更新录音时间
private Runnable doRecordProcessing = new Runnable() 录音进度
public void onResume()
mService.registerCallbacks(mServiceCallbacks); 注册回调service
mService.cancelDelayedStop(FMRadioService.STOP_SERVICE); 延迟关闭FMRadioService
public boolean bindToService(Context context,ServiceConnection
callback) 启动在FMRadio 的onStart()方法判断条件启动FMRadioService
if((mService == null ) && (false == bindToService(this, osc)))
onDestroy() 方法中解绑nRegisterReceiver(mFmSettingReceiver);
boolean isWiredHeadsetAvailable() 判断耳机是否可用,在FMRadioService 类里添加public void
registerHeadsetListener()注册耳机监听事件,mHeadsetPlugged =
(intent.getIntExtra("state", 0) == 1);状态监听
Intent 里的public static final String
ACTION_HEADSET_PLUG =
"android.intent.action.HEADSET_PLUG"; 耳机静态常量定义。
再启动FMRadioService 监听 registerHeadsetListener();耳机
/ * *
确定是否一个内部天线。
* FMOn
返回缓存的值初始化。
*
* @return
真正的如果内部天线可用或连线
*
耳机插入,如果内部天线是错误的
*没有和有线耳机不是插入。
* /
public boolean isAntennaAvailable()FMRadioService 类
public void readInternalAntennaAvailable() 确定是否有内部天线,调用类FMReceivce 的父类FMTransceiver类发送接收信号类
public boolean getInternalAntenna() 方法,通过FmReceiverJNI 类调用getControlNative方法。
恢复设置默认地区设置private voidRestoreDefaults()
当天线可以用的时候就调用UI 界面可用显示
private void enableRadioOnOffUI() {
boolean bEnable = isFmOn();
/* Disable if no antenna/headset isavailable */
if (!isAntennaAvailable()) {
bEnable = false;
}
enableRadioOnOffUI(bEnable);
}
调用此方法private void enableRadioOnOffUI(boolean bEnable) 显示FMRadio.java UI界面
boolean isCallActive() 电话呼叫活动,FMRadioService
类isCallActive当状态不为零表示在通话中
public boolean isCallActive()
{
//Non-zero: Call state is RINGING orOFFHOOK on the available subscriptions
//zero: Call state is IDLE on all theavailable subscriptions
if(0 != getCallState()) return true;
return false;
}
private void enableRadio() 可使用收音机
private void disableRadio() 不可用收音机
private void resetRadio() 重新设置收音机
public void clearStationList() 清除电台列表信息
public boolean fmConfigure() 收音机配置
/ *
设置调频模块自动切换到另一个频率
*
站如果一个频率的信号强度比
*目前调谐频率。
*
*布尔bEnable:真:自动切换到更强的交替频率。
*假:不要切换到备用频率。
* @return真实如果设置自动对焦模式api调用成功,错误如果api失败了。
*注:回调FmRxEvRadioTuneStatus时将调用
*完成不同的频率。
* /
调用FMRadioService 类 publicboolean
enableAutoAF(boolean bEnable)方法。
public void fmAudioOutputMode() 输出立体声音
private void startRecording() 录音开始
private void setRecordingStopImage() 录音停止图片设置
private void setRecordingStartImage() 录音开始图片设置、
private void startRecordingTimer() 录音启动的时间
private void stopRecording() 停止录音
private boolean isRecording() 判断是否在录音
private boolean isSpeakerEnabled() 判断扬声器是可用
private boolean stationExists(PresetStationstation ) 长按收藏按钮式电台频率是都存在
private void addToPresets() 添加电台频率显示到按钮上
FmSharedPreferences.addStation(selectedStation.getName(),selectedStation.getFrequency(),currentList);
setupPresetLayout();
调用FmSharedPreferences 类的addStation方法添加到mListOfPlists列表里
private void resetSearchProgress() 重置搜索进度
updateSearchProgress() 更新搜索进度
setupPresetLayout() 安装频率布局,收藏频率至按钮上初始化
updateStationInfoToUI() 更新电台信息界面信息
private boolean isFmOn() 收音机是否开启
/* 如果启用了模拟路径返回true */
public boolean isAnalogModeEnabled() {
return misAnalogPathEnabled;
}
/ * 返回调频(Soc) 音频硬件是否有限。
* @return真如果调频音频是柔和的,假如果不低调。
* /
public boolean isMuted() {
return mMuted;
}
private boolean isScanActive() 扫描活动布尔值
private boolean isSeekActive() 查找活动布尔值
private boolean isSearchActive() 搜索活动布尔值
public PresetStation getCurrentTunedStation() 获得现在调整电台
private void SeekNextStation() 在搜索查找下一个频率
private void initiateSearch(int pty) 初始化搜索
/** SEEK Station with the matching PI */
private void initiatePISearch(int pi) 需找匹配的频率
private void resetSearch() 从新搜索
private void cancelSearch() 关闭搜索
private void initiateSearchList() 初始化搜索列表
private void initiateSleepTimer(long seconds) 初始化睡眠计时器
private void initiateSleepThread() 初始化睡眠线程
private void endSleepTimer() 结束睡眠计时器时间
private boolean hasSleepTimerExpired() 睡眠计时器停止
private boolean isSleepTimerActive() 睡眠计时器活动是否活动
private void updateExpiredSleepTime() 更新停止睡眠时间
private String makeTimeString(long secs) 时间格式字符串
private void tuneRadio(int frequency) 调整收音机频率
private void resetFMStationInfoUI() 从新设置收音机电台显示界面信息
IFMRadioServiceCallbacks 类回调时候
Runnable mRadioEnabled = new Runnable() 收音机可用
Runnable mRadioDisabled = new Runnable() 收音机不可用
Runnable mRadioReset = new Runnable() 收音机重新设置
Runnable mUpdateStationInfo = new Runnable() 跟新收音机电台信息
Runnable mOnMute = new Runnable() 收音机静音设置
Runnable mOnStereo = new Runnable() 立体声音
Runnable mUpdateRadioText = new Runnable() 更新收音机文本信息
Runnable mRadioChangeFrequency = newRunnable() 调整频率
Runnable mUpdateExtenRadioText = newRunnable() 更新延伸收音机文本信息
Runnable mUpdateProgramService = newRunnable() 跟新service 进度
private void DebugToasts(String str, intduration) 弹出提示信息
private void registerFMSettingListner() 注册设置改变监听
private void unRegisterReceiver(BroadcastReceiver myReceiver) 卸载注册避免重复注册报异常
下面分享的是FM模块的保存方法,即FmSharedPreferences.java
FmSharedPreferences(Context context)在构造方法中加载Load()方法,
public void Load(){
Log.d(LOGTAG, "Load preferences ");
if(mContext == null)
{
return;
}
SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
mTunedFrequency = sp.getInt(PREF_LAST_TUNED_FREQUENCY, DEFAULT_NO_FREQUENCY);
mRecordDuration = sp.getInt(LAST_RECORD_DURATION, RECORD_DUR_INDEX_0_VAL);
mAFAutoSwitch = sp.getBoolean(LAST_AF_JUMP_VALUE, true);
mAudioOutputMode = sp.getBoolean(AUDIO_OUTPUT_MODE, true);
if(sp.getInt(FMCONFIG_COUNTRY, 0) == REGIONAL_BAND_USER_DEFINED) {
mBandMinFreq = sp.getInt(FMCONFIG_MIN, mBandMinFreq);
mBandMaxFreq = sp.getInt(FMCONFIG_MAX, mBandMaxFreq);
mChanSpacing = sp.getInt(FMCONFIG_STEP, mChanSpacing);
}
int num_lists = sp.getInt(LIST_NUM, 1);
if (mListOfPlists.size() == 0) {
for (int listIter = 0; listIter < num_lists; listIter++) {
String listName = sp.getString(LIST_NAME + listIter, "FM - " + (listIter+1));
int numStations = sp.getInt(STATION_NUM + listIter, 1);
if (listIter == 0) {
createFirstPresetList(listName);
} else {
createPresetList(listName);
}
PresetList curList = mListOfPlists.get(listIter);
for (int stationIter = 0; stationIter < numStations; stationIter++) {
String stationName = sp.getString(STATION_NAME + listIter + "x" + stationIter,
DEFAULT_NO_NAME);
int stationFreq = sp.getInt(STATION_FREQUENCY + listIter + "x" + stationIter,
DEFAULT_NO_FREQUENCY);
PresetStation station = curList.addStation(stationName, stationFreq);
int stationId = sp.getInt(STATION_ID + listIter + "x" + stationIter,
DEFAULT_NO_STATIONID);
station.setPI(stationId);
int pty = sp.getInt(STATION_PTY + listIter + "x" + stationIter, DEFAULT_NO_PTY);
station.setPty(pty);
int rdsSupported = sp.getInt(STATION_RDS + listIter + "x" + stationIter,
DEFAULT_NO_RDSSUP);
if (rdsSupported != 0) {
station.setRDSSupported(true);
} else {
station.setRDSSupported(false);
}
/* Load Configuration */
setCountry(sp.getInt(FMCONFIG_COUNTRY, REGIONAL_BAND_NORTH_AMERICA));
/* Last list the user was navigating */
mListIndex = sp.getInt(LAST_LIST_INDEX, 0);
if(mListIndex >= num_lists)
{mListIndex=0;
}
}
初始化取出sp一些数据
根据系统初始化地区设置当地频率
/*Load Configuration */
if (Locale.getDefault().equals(Locale.CHINA)) {
setCountry(sp.getInt(FMCONFIG_COUNTRY, REGIONAL_BAND_CHINA));
} else {
setCountry(sp.getInt(FMCONFIG_COUNTRY, REGIONAL_BAND_NORTH_AMERICA));
}
/* Last list the user was navigating */
保存频率
public void Save()
设置默认的地区
public static void SetDefaults()
设置调整频率
public static void setTunedFrequency(intfrequency)
获取调整频率
public static int getTunedFrequency()
获取下一个频率
public static int getNextTuneFrequency(intfrequency)
获取上一个频率
public static int getPrevTuneFrequency(intfrequency)
/ * *
* @param mFMConfiguration mFMConfiguration设置
* /
public static void setFMConfiguration(FmConfig mFMConfig)
/**
*@return the mFMConfiguration
*/
public static FmConfig getFMConfiguration() {
return mFMConfiguration;
}
设置fm播放的频率范围
public static void setRadioBand(int band)
获取fm频率范围限制
public static int getRadioBand()
获取间隔
public static int getChSpacing()
设置远程数据服务
public static void setRdsStd(int std)
mFMConfiguration.setRdsStd(std);
获取远程数据服务
public static int getRdsStd()
mFMConfiguration.getRdsStd();
设置国家地区
public static void setCountry(intnCountryCode)
获取国家地区
public static int getCountry()
设置声音输出模板
setAudioOutputMode
设置录音是否持续
public static void setRecordDuration(intdurationIndex)
总结:个人认为以上只能作为参考,但是大体框架变化不大。
Android FM 模块学习之四 源码解析(1)的更多相关文章
- Android FM模块学习之四源码解析(一)
转自:http://blog.csdn.net/tfslovexizi/article/details/41516149?utm_source=tuicool&utm_medium=refer ...
- Android FM模块学习之四源码分析(3)
接着看FM模块的其他几个次要的类的源码.这样来看FM上层的东西不是太多. 请看android\vendor\qcom\opensource\fm\fmapp2\src\com\caf\fmradio\ ...
- Android FM模块学习之四源码学习(2)
前几章我们分析了FM模块的几个主要的类文件,今天要分析的是:FMTransceiver.java // 某些工程中名称为FMRadioService.java public class FmTra ...
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- Android Handler机制(四)---Handler源码解析
Handler的主要用途有两个:(1).在将来的某个时刻执行消息或一个runnable,(2)把消息发送到消息队列. 主要依靠post(Runnable).postAtTime(Runnable, l ...
- 【Android应用开发】EasyDialog 源码解析
示例源码下载 : http://download.csdn.net/detail/han1202012/9115227 EasyDialog 简介 : -- 作用 : 用于在界面进行一些介绍, 说明; ...
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- Android Handler机制(二)---MessageQueue源码解析
MessageQueue 1.变量 private final boolean mQuitAllowed;//表示MessageQueue是否允许退出 @SuppressWarnings(" ...
- Android FM模块学习之一 FM启动流程
最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层. 上层就是FM的按扭操作和界面显示,从而调用到FM底层驱动来实现广播收听的功能. FM启动流程:如下图: 先进入FMRadio.jav ...
随机推荐
- Linux常用调优配置
cenos 6.5 文件句柄和网络端口 修改系统所有进程可用句柄数,vi /etc/sysctl.conf fs.file-max=655360net.ipv4.ip_local_port_range ...
- How to install .deb file in Ubuntu
if you have a .deb file: You can install it using sudo dpkg -i /path/to/deb/file followed by sudo ap ...
- 《BI项目笔记》报到信息分析Cube
数据源设置:数据处理逻辑: --处理丢失外键关系数据 SELECT * FROM T_ReportLeafGrade WHERE FSubFID NOT IN ( SELECT FID FROM T_ ...
- Php数据类型之整型详解
php中支持的数据类型 在php中主要支持8种数据类型.和3中伪类型的一个形式.8种数据类型分为以下三3大类,第一个就是我们的标量类型,标量类型它只能存储单一数据,那第二大类就是我们的复合类型,第三个 ...
- Head First 设计模式 --6 命令模式
命令模式:将"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.用到的原则:1.封装变化2.组合优于继承3.针对接口编程,不能针对实现 ...
- Software Engineering: 2. Project management
resources:"Software Engineering" Ian Sommerville For most projects, important goals are: D ...
- 数据库 基础篇2(mysql)
2.1MySQL入门 1)到mysql官网下载. 2)安装mysql软件 3)使用 验证是否成功 打开cmd -> 输入 mysql -u root -p 回车 -> 输入密码 ...
- Oracle系统表整理+常用SQL语句收集
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- CSS3 transform对普通元素的N多渲染影响
一.一入transform深似海 一个普普通通的元素,如果应用了CSS3 transform变换,即便这个transform属性值不会改变其任何表面的变化(如scale(1), translate(0 ...
- 张艾迪(创始人):Hello.世界...
The World No.1 Girl :Eidyzhang The World No.1 Internet Girl :Eidyzhang AOOOiA.global Founder :Eidyzh ...