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);
/* 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;
}
----------------------------------------
}
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();
mService.routeAudio(mIsSpeaker ? FMplayService.RADIO_AUDIO_DEVICE_SPEAKER
: FMplayService.RADIO_AUDIO_DEVICE_WIRED_HEADSET);
} else {
Message message = mHandler.obtainMessage(MSG_ROUTE);
sendMessageDelayed(message, CHECK_DELAY);
}
break;
...........................................
case MSG_OPEN:
removeMessages(MSG_OPEN);
if (!mReady) { //mReady =false
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) {
closeAlertDialog(HEADSET_DIALOG);
}
if (mOver == true) {
Log.d(LOGTAG, "showAlertDialog:STARTUP_DIALOG");
showAlertDialog(STARTUP_DIALOG);
mOpenThread = createOpenThread();
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;
...................................................
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);
}
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