FMPlay.java
public void onCreate(Bundle savedInstanceState) {
Log.d(LOGTAG,"onCreate");
super.onCreate(savedInstanceState);
//设置全屏模式
setVolumeControlStream(AudioManager.STREAM_FM);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.radio);
//得到FM台列表
mStationList = FMPlaySharedPreferences.getInstance(this);
if (!getComponents()) {
return;
}
setUiPower(false, true);
//new 一个Service的作用? 普通的类
mService = new RadioServiceStub(this, this); --------important4
//设置FM存储位置,SDcard首先
m_recorder = new Recorder();
m_recorder.setOnStateChangedListener(mOnStateChangedListener);
registerExternalStorageListener();
/* changed by qiaozw begin*/ //定义一个轻量级存储perfs?
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mIsSpeaker = prefs.getBoolean("mIsSpeaker", false); ------------------10.1---------------- 此处模糊,根据api 此时prefs应该应该时没有数据,所以猜返回false
/* changed by qiaozw end */
mReady = false;
mOver = true;
mOpenResult = true;
mDialogs = new Dialog[DIALOG_COUNT];
mCurrentDialog = NO_DIALOG;
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
filter.addAction(Intent.ACTION_FM);
filter.addAction(Intent.ACTION_HEADSET_PLUG);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction("android.intent.action.TIME_SET");
//注册广播
registerReceiver(mReceiver, filter);
//mm04 fix bug 2706
tmgr = (TelephonyManager) getSystemService("phone");
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
protected void onStart() {
Log.d(LOGTAG,"onStart");
super.onStart();
//onCreate -> onStart
if (!mService.bindToService()) { -----------------important6
Log.d(LOGTAG, "fail to bindToService");
mService = null;
return;
}
//判断FM是否已经打开
if(mPowerChecked && !isFmOn()){
mHandler.sendMessage(mHandler.obtainMessage(MSG_OPEN)); --------important1
}
//mm04 fix bug 3183
Intent i = new Intent("com.android.fm.stopmusicservice");
i.putExtra("playingfm", true);
this.sendBroadcast(i);
}
FMPlay.java
private boolean isFmOn(){
boolean value = false;
try {
value = mService.isFmOn();
} catch (NullPointerException e){
Log.d(LOGTAG,"mService NullPointerException");
mService = new RadioServiceStub(this, this);
if (!mService.bindToService()) {
Log.d(LOGTAG, "resetMService fail to bindToService");
mService = null;
return true;
}
isFmOn();
Log.d(LOGTAG,"mService ok");
} catch (Exception e) {
// TODO Auto-generated catch block
Log.d(LOGTAG,"mService Exception");
e.printStackTrace();
return true;
}
return value;
}
RadioServiceStub.java
public boolean isFmOn() {
boolean value = false;
if (mService != null) {
try {
value = mService.isFmOn();
} catch (RemoteException e) {
e.printStackTrace();
}
}
return value;
}
IRadioService.aidl
interface IRadioService
{
-------------------
boolean isFmOn();
-------------------
}
FMplayService.java
static class ServiceStub extends IRadioService.Stub{
WeakReference<FMplayService> mService;
public ServiceStub(FMplayService service) {
mService = new WeakReference<FMplayService>(service);
}
public boolean fmOn() throws RemoteException {
if(mService != null){
if(mService.get() != null){
return mService.get().fmOn();
}
}
return false;
}
-------------------------------------
public boolean isFmOn() throws RemoteException {
if(mService != null){
if(mService.get() != null){
return mService.get().isFmOn();
}
}
return false;
}
----------------------------------------
public boolean routeAudio(int device) { -----------------------13.2----------------------
return mService.get().routeAudio(device);
}
}
WeakReference<FMplayService> mService;
WeakReference.java
public class WeakReference<T> extends Reference<T> {}
Reference.java
/**
* Returns the referent of the reference object.
*
* @return the referent to which reference refers, or {@code null} if the
* object has been cleared.
*/
public T get() {
return referent;
}
FMplayService.java
public boolean isFmOn() {
Log.d(LOGTAG, "isFmOn" + mFmOn);
return (mReceiver != null) && mFmOn;
}
接-----------important1
frameworks\base\core\java\anrdoid\os\Handler.java
/**
* Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
*
* @param what Value to assign to the returned Message.what field.
* @return A Message from the global message pool.
*/
public final Message obtainMessage(int what) //what = MSG_OPEN
{
return Message.obtain(this, what);
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0); //msg.what = MSG_OPEN
}
frameworks\base\core\java\anrdoid\os\Message.java
public static Message obtain(Handler h, int what) {
Message m = obtain();
m.target = h;
m.what = what;
return m;
}
FMPlay.java
private Handler mHandler = new Handler(){ ------------------------important2 mHandler.sendMessage - > handleMessage
public void handleMessage(Message msg) {
Log.d(LOGTAG, "msg.what: " +msg.what+" mOver: "+mOver);
switch(msg.what) { //msg.what = MSG_OPEN
case MSG_ROUTE:
removeMessages(MSG_ROUTE);
if (mReady) {
showAudioDevice(); ------------10.1-----mIsSpeaker=false------------
mService.routeAudio(mIsSpeaker ? FMplayService.RADIO_AUDIO_DEVICE_SPEAKER -----------12--------------
: FMplayService.RADIO_AUDIO_DEVICE_WIRED_HEADSET);
} else {
Message message = mHandler.obtainMessage(MSG_ROUTE);
sendMessageDelayed(message, CHECK_DELAY);
}
break;
...........................................
case MSG_UPDATE: ---------------------14------------------------
removeMessages(MSG_UPDATE);
if (mReady) {
if (!isFmOn()) { //isFmOn() = true
mIsFromScratch = (FMPlaySharedPreferences.getStationCount(0) == 0);
} else {
setUiEnabled(true);
if (mService.getAudioDevice() == FMplayService.RADIO_AUDIO_DEVICE_SPEAKER) { //RADIO_AUDIO_DEVICE_WIRED_HEADSET=0
//---------------------RadioServiceStub.java----------------
public int getAudioDevice() {
int device = FMplayService.RADIO_AUDIO_DEVICE_SPEAKER;
if (mService != null) {
try {
device = mService.getAudioDevice();
//--------------FMplayService.java----------------
static class ServiceStub extends IRadioService.Stub {
WeakReference<FMplayService> mService;
public int getAudioDevice() {
return mService.get().getAudioDevice();
}
}
//------------------真的调用之处---------
public int getAudioDevice() {
return mAudioDevice;
}
//--------------------
public void onCreate() {
............................
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean mIsSpeaker = prefs.getBoolean("mIsSpeaker", false); //根据上次分析应该是false(最好还是根据真机打印)
mAudioDevice = mIsSpeaker ? RADIO_AUDIO_DEVICE_SPEAKER : RADIO_AUDIO_DEVICE_WIRED_HEADSET;
}
//--------------------
//---------------------------
//------------------------------
} catch (RemoteException e) {
e.printStackTrace();
}
}
return device;
}
//------------------------------------
mIsSpeaker = true;
} else {
mIsSpeaker = false;
}
if (mIsFromScratch) {
mIsFromScratch = false;
if (FMPlaySharedPreferences.getStationCount(0) > 0) {
FMPlaySharedPreferences.setTunedFreq(FMPlaySharedPreferences.getStation(0, 0).getFreq());
}
}
}
float freq;
if(searchfreq){
freq = mService.getFreq();
searchfreq = false;
}else{
freq = FMPlaySharedPreferences.getTunedFreq(); ---------------------14.2----------DEFAULT_NO_FREQUENCY--------
}
String name = FMPlaySharedPreferences.getStationName(0, freq);
//---------------FMPlaySharedPreferences.java-------------
public static String getStationName(int list, float freq) {
if (checkIndex(list)) {
//----------------------
private static boolean checkIndex(int list) {
int count = mListOfPlist.size();
if (list == count) {
createPresetList(String.valueOf(list));
//---------------------
public static int createPresetList(String name) {
int list = getListIndex(name);
//----------------------
public static int getListIndex(String name) {
if (mNameMap.containsKey(name)) { //一直以来分析以没搜索到台为基础,所以map中没有加入值,mNameMap在开始的load处会初始化
return Integer.parseInt(mNameMap.get(name));
}
return -1;
}
//----------------------
if (list != -1) {
return list;
}
int count = mListOfPlist.size();
mListOfPlist.add(new PresetStationList(name));
mNameMap.put(name, String.valueOf(count));
return count;
}
//---------------------
}
count = mListOfPlist.size();
if (list >= count || list < 0) {
return false;
}
return true;
}
//----------------------
PresetStation tmp = mListOfPlist.get(list).getStation(freq);
if (tmp != null) {
return tmp.getStationName();
}
}
return null;
}
//----------------------------
if (name == null) {
name = ""; //到这里
}
Log.d(LOGTAG,"MSG_UPDATE: entering showRadioInfo");
setFreqForUi(freq);
showAudioDevice();
if (mService.isFmOn()) {
mService.setFreq(freq); //此时设置默认值为DEFAULT_NO_FREQUENCY 87.5(很多东西靠分析很难得出结论,需要拿真机打断点)
}
} else {
Message message = mHandler.obtainMessage(MSG_UPDATE);
sendMessageDelayed(message, CHECK_DELAY);
}
break;
case MSG_OPEN:
removeMessages(MSG_OPEN);
if (!mReady) { //mReady =true
sendMessageDelayed(obtainMessage(MSG_OPEN), OPEN_DELAY);
} else { ----------------important7
if (!isFmOn()) {//fix bug 11354,11420
if (System.getInt(getContentResolver(), System.AIRPLANE_MODE_ON, 0) != 0) {
showAlertDialog(AIRPLANE_DIALOG);
return;
}
TelephonyManager pm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (pm.getCallState() == TelephonyManager.CALL_STATE_RINGING || pm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {
showAlertDialog(PHONE_DIALOG);
return;
}
if (!SystemProperties.getBoolean("ro.device.support.antenna", false)) {
if (isHeadsetExists()) {
if (mCurrentDialog == HEADSET_DIALOG) { //NO_DIALOG
closeAlertDialog(HEADSET_DIALOG);
}
if (mOver == true) { //mOver = true;
Log.d(LOGTAG, "showAlertDialog:STARTUP_DIALOG");
showAlertDialog(STARTUP_DIALOG); //mCurrentDialog = STARTUP_DIALOG
mOpenThread = createOpenThread(); ------------------- 8
Log.d(LOGTAG, " create thread when use ");
mOpenThread.start();
}
} else {
if (mCurrentDialog != HEADSET_DIALOG) {
if (mCurrentDialog != NO_DIALOG) {
closeAlertDialog(mCurrentDialog);
}
showAlertDialog(HEADSET_DIALOG);
}
return;
}
}
} else {
setUiPower(true, false);
}
}
break;
case MSG_PROGRESS:
removeMessages(MSG_PROGRESS);
if (!mOver) { //mOver = false ---------9.2
sendMessageDelayed(obtainMessage(MSG_PROGRESS), PROGRESS_DELAY);
} else {
closeAlertDialog(STARTUP_DIALOG); -------------9.4
if (!SystemProperties.getBoolean("ro.device.support.antenna", false)) {
if (isHeadsetExists()) {
if (!mOpenResult) { //mOpenResult=true
showAlertDialog(OPENERROR_DIALOG);
} else { --------------------------9.5
Message message = mHandler.obtainMessage(MSG_ROUTE);
mHandler.sendMessage(message);
if (FMPlaySharedPreferences.getStationCount(0) <= 0) {
Intent req = new Intent(FMPlay.this, StationSearch.class);
startActivity(req);
} else {
message = mHandler.obtainMessage(MSG_UPDATE);
mHandler.sendMessage(message);
}
setUiPower(true, false);
setUiEnabled(true); // Users can do whatever
// they want once we are
// prepared.
}
} else {
Intent intent = new Intent(FMplayService.ACTION_SHUTDOWN);
sendBroadcast(intent);
}
}
}
break;
...................................................
default:
}
}
};
frameworks\base\core\java\anrdoid\os\Handler.java
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) -----------------------important3
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this; ----------------走这边
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
frameworks\base\core\java\anrdoid\os\Looper.java
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
具体看Looper.java,
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
.............................
所以important3中queue != null
在onCeate()时important4
mService = new RadioServiceStub(this, this); ----------------------5
if (!mService.bindToService()) { -----------------6
public boolean bindToService() {
mContext.startService(new Intent(mContext, FMplayService.class));
mBinder = new BinderCallback(mCallback);
return mContext.bindService((new Intent()).setClass(mContext, FMplayService.class), mBinder,
Context.BIND_AUTO_CREATE);
}
private class BinderCallback implements ServiceConnection {
private ServiceConnection mCallback;
public void onServiceDisconnected(ComponentName name) {
if (mCallback != null) {
mCallback.onServiceDisconnected(name);
}clmps
mService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IRadioService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(name, service); -------------------------????
}
}
public BinderCallback(ServiceConnection callback) {
mCallback = callback;
}
}
public RadioServiceStub(Context context, ServiceConnection callback) {
mContext = context;
mCallback = callback; ---------------------important5回归 -> 5
mService = null;
mBinder = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mReady = true;
Log.d(LOGTAG, "mReady = true");
}
所以此时mReady = true;
case MSG_OPEN:
走 -> ----------------important7
FMPlayer.java
private Thread createOpenThread() {
return new Thread(new Runnable() {
public void run() {
Log.d(LOGTAG, "tring open fm");
mOver = false;
mHandler.sendMessage(mHandler.obtainMessage(MSG_PROGRESS)); ------9.1
mOpenResult = mService.fmOn(); //true
Log.d(LOGTAG, "tring open fm result = " + mOpenResult);
mOver = true; -----------9.3
}
});
}
protected void showAlertDialog(int id) {
if(!FMPlay.this.isFinishing()){
showDialog(id);
mCurrentDialog = id;
}
}
private void showAudioDevice() {
mHeadsetToggle.setChecked(!mIsSpeaker, false); //mIsSpeaker=false ----------------11.1-------------------
if(mIsSpeaker){
mHeadsetIndicator.setImageResource(R.drawable.headset_indicator_spk);
}else {
mHeadsetIndicator.setImageResource(R.drawable.headset_indicator);
}
}
PreferenceManager.java
public static SharedPreferences getDefaultSharedPreferences(Context context) { ----------------------10.2---------------
return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
getDefaultSharedPreferencesMode());
}
Context.java
public abstract SharedPreferences getSharedPreferences(String name,
int mode); ----------------10.3------------------ 没有找到实现这个函数的地方
PreferenceManager.java
public SharedPreferences getSharedPreferences() {
if (mSharedPreferences == null) {
mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
mSharedPreferencesMode);
}
return mSharedPreferences;
}
CheckableImageButton.java
public void setChecked(boolean checked, boolean notifyToListener) { // checked=true notifyToListener=false -----------------11.2-------------------
if (checked != mChecked) {
boolean isAllowed = true;
if (mListener != null && notifyToListener) {
isAllowed = mListener.onCheckedChanged(this, checked);
}
if (isAllowed) {
mChecked = checked;
updateImageSource();
}
}
}
RadioServiceStub.java
public boolean routeAudio(int device) { //FMplayService.RADIO_AUDIO_DEVICE_WIRED_HEADSET
boolean value = false;
try {
value = mService.routeAudio(device); -------------------------13.1---------------------
} catch (RemoteException e) {
e.printStackTrace();
}
return value;
}
FMplayService.java
public boolean routeAudio(int device) { ----------------------13.3----------------------
return routeAudio(device, true);
}
public boolean routeAudio(int device, boolean audioFocus) { //FMplayService.RADIO_AUDIO_DEVICE_WIRED_HEADSET , true
if (audioFocus && device != RADIO_AUDIO_DEVICE_NONE && !requestAudioFocus()) {
return false;
}
if (device == RADIO_AUDIO_DEVICE_SPEAKER || device == RADIO_AUDIO_DEVICE_WIRED_HEADSET) {
mAudioDevice = device;
mFmOn = true;//mFmOn should be set before setVolume().
// add for bug158083 start
if (device == RADIO_AUDIO_DEVICE_SPEAKER) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, AudioSystem.DEVICE_STATE_AVAILABLE, "");
} else if (device == RADIO_AUDIO_DEVICE_WIRED_HEADSET) { ----------------13.4-----------------------
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_AVAILABLE, "");
}
// add for bug158083 end
setVolume();
Log.d(LOGTAG, "route audio:" + device);
Intent intent = new Intent(Intent.ACTION_FM);
intent.putExtra("state", 1);
intent.putExtra("speaker", device);
sendBroadcast(intent);
} else if (mFmOn ==true && device == RADIO_AUDIO_DEVICE_NONE){
mFmOn = false;
// add for bug158083 start
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,AudioSystem.DEVICE_STATE_UNAVAILABLE,"");
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,AudioSystem.DEVICE_STATE_UNAVAILABLE,"");
// add for bug158083 end
Log.d(LOGTAG, "route audio:" + device);
Intent intentaudio = new Intent(Intent.ACTION_FM);
intentaudio.putExtra("FM", 0);
intentaudio.putExtra("state", 0);
sendBroadcast(intentaudio);
} else {
Log.e(LOGTAG, "ignore device: " + device);
}
return true;
}
========================================================================================================================================
FMPlay.java
protected void onResume() {
Log.d(LOGTAG,"onResume");
super.onResume();
mStationList.load(); //在onCreate里有 mStationList = FMPlaySharedPreferences.getInstance(this);
if(refresh){ //开始的时候refresh=false
getComponents();
refresh = false;
}
if (mDigitalClockUpdater != null) { //开始的时候 mDigitalClockUpdater = null
mDigitalClockUpdater.run();
}
if(StationSearch.isSearching()){ //开始的时候 mSearcher = null public static boolean isSearching(){
boolean result = (mSearcher != null) && (mSearcher.isSearching());
return result;
}//
Log.d(LOGTAG,"isSearching = true!");
Intent req = new Intent(getBaseContext(), StationSearch.class);
startActivity(req);
} else {
Log.d(LOGTAG,"isSearching = false!");
Message msg = mHandler.obtainMessage(MSG_UPDATE); ---------------------14.1------------------------
mHandler.sendMessage(msg);
}
}
public void load() {
if (mContext == null) {
return;
}
if (mListOfPlist.size() != 0) {
mListOfPlist.clear();
mNameMap.clear();
}
SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES,
Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
mTunedFreq = sp.getFloat(LAST_TUNED_FREQUENCY, DEFAULT_NO_FREQUENCY);
int listNumber = sp.getInt(NUMBER_OF_LIST, 0);
int listIndex = 0;
int stationIndex = 0;
while (listIndex < listNumber) {
String listName = sp.getString(NAME_OF_LIST + listIndex, "FM - " + (listIndex + 1));
int stationNumber = sp.getInt(NUMBER_OF_STATION + listIndex, 0);
int list = createPresetList(listName);
PresetStationList stationList = mListOfPlist.get(list);
stationIndex = 0;
while (stationIndex < stationNumber) {
String stationName = sp.getString(NAME_OF_STATION + listIndex + "x" + stationIndex,
DEFAULT_NO_NAME);
float stationFreq = sp.getFloat(STATION_FREQUENCY + listIndex + "x" + stationIndex,
DEFAULT_NO_FREQUENCY);
boolean stationEditStatus = sp.getBoolean(EDIT_STATUS_OF_STATION + listIndex + "x" + stationIndex,
DEFAULT_EDIT_STATUS);
stationList.addStation(stationName, stationFreq, stationEditStatus);
++stationIndex;
}
++listIndex;
}
mListIndex = sp.getInt(LAST_LIST_INDEX, 0);
if (mListIndex >= listNumber) {
mListIndex = 0;
}
}