看到网络上的牛人对手机通话的控制,有感而发,希望搞个能在手机接到电话时可以给对方播放一段音频。看了下源码,发现如果仅仅通过
ITelephony.aidl的一些API似乎没有这个功能,难道要把这块的代码给扣出来进行修改吗,就是RIL.java那块。系统似乎没有给出这方
面的功能API啊。
RIL.java
public void
acceptCall (Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_ANSWER, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
处理电话事件:
public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
/**
* mRequestMessagePending++ already happened for every
* EVENT_SEND, thus we must make sure
* mRequestMessagePending-- happens once and only once
*/
boolean alreadySubtracted = false;
try {
LocalSocket s;
s = mSocket;
if (s == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
mRequestMessagesPending--;
alreadySubtracted = true;
return;
}
synchronized (mRequestsList) {
mRequestsList.add(rr);
}
mRequestMessagesPending--;
alreadySubtracted = true;
byte[] data;
data = rr.mp.marshall();
rr.mp.recycle();
rr.mp = null;
if (data.length > RIL_MAX_COMMAND_BYTES) {
throw new RuntimeException(
"Parcel larger than max bytes allowed! "
+ data.length);
}
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
//Log.v(LOG_TAG, "writing packet: " + data.length + " bytes");
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
} catch (IOException ex) {
Log.e(LOG_TAG, "IOException", ex);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
}
} catch (RuntimeException exc) {
Log.e(LOG_TAG, "Uncaught exception ", exc);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(GENERIC_FAILURE, null);
rr.release();
}
}
if (!alreadySubtracted) {
mRequestMessagesPending--;
}
break;
case EVENT_WAKE_LOCK_TIMEOUT:
// Haven't heard back from the last request. Assume we're
// not getting a response and release the wake lock.
// TODO should we clean up mRequestList and mRequestPending
synchronized (mWakeLock) {
if (mWakeLock.isHeld()) {
if (RILJ_LOGD) {
synchronized (mRequestsList) {
int count = mRequestsList.size();
Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
" mReqPending=" + mRequestMessagesPending +
" mRequestList=" + count);
for (int i = 0; i < count; i++) {
rr = mRequestsList.get(i);
Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " +
requestToString(rr.mRequest));
}
}
}
mWakeLock.release();
}
}
break;
}
}
}
图
特附一个简单的demo,根据感应加速度可以接电话的代码,甩下就可以接电话,环境2.0.
有没搞过这块的,交流下。
android 异常分类
http://hi.baidu.com/hkdao/blog/item/521390c8583f198fc817686b.html
一、异常:
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@405d8c20 is not valid; is your activity running?
原因:
这是由于当前activity已经在后台了,后台show dialog 的时候出现的:
解决办法:
if(!isFinishing() && !loadDialog.isShowing()){ loadDialog.show(); }
public class TestPictureLayout extends Activity {
static final int DAY_VIEW_MODE = 0;
static final int WEEK_VIEW_MODE = 1;
private SharedPreferences mPrefs;
private int mCurViewMode;
private int i;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences mPrefs = getSharedPreferences();
mCurViewMode = mPrefs.getInt("view_mode" DAY_VIEW_MODE);
if(savedInstanceState!=null)
{
i=savedInstanceState.getInt("data");
//这个是之前保存的数据
}
else{
//这个是从另外一个界面进入这个时传入的
i=getIntent().getint("data");
}
}
protected void onPause() {
super.onPause();
//界面失去控制权时保存数据
SharedPreferences.Editor ed = mPrefs.edit();
ed.putInt("view_mode", mCurViewMode);
ed.commit();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
//界面销毁之前保存数据
super.onSaveInstanceState(outState);
outState.putInt("data",1);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
//执行于onStart() 之后,回复之前保存过的数据,其实可以不要,因为oncreate中已经获取过了
super.onRestoreInstanceState(savedInstanceState);
i=savedInstanceState.getInt("data");
}
}
在activity被杀掉之前调用保存每个实例的状态,以保证该状态可以在onCreate(Bundle)或者
onRestoreInstanceState(Bundle)
(传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。这个方法在一个activity被杀死前调用,当该
activity在将来某个时刻回来时可以恢复其先前状态。例如,如果activity B启用后位于activity
A的前端,在某个时刻activity
A因为系统回收资源的问题要被杀掉,A通过onSaveInstanceState将有机会保存其用户界面状态,使得将来用户返回到activity
A时能通过onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢复界面的状态。
不要将这个方
法和activity生命周期回调如onPause()或onStop()搞混淆了,onPause()在activtiy被放置到背景或者自行销毁时总
会被调用,onStop()在activity被销毁时被调用。一个会调用onPause()和onStop(),但不触发
onSaveInstanceState的例子是当用户从activity B返回到activity
A时:没有必要调用B的onSaveInstanceState(Bundle),此时的B实例永远不会被恢复,因此系统会避免调用它。一个调用
onPause()但不调用onSaveInstanceState的例子是当activity B启动并处在activity
A的前端:如果在B的整个生命周期里A的用户界面状态都没有被破坏的话,系统是不会调用activity
A的onSaveInstanceState(Bundle)的。
默认的实现负责了大部分UI实例状态(的保存),采用的方式是调用UI层上每
个拥有id的view的onSaveInstanceState()
,并且保存当前获得焦点的view的id(所有保存的状态信息都会在默认的onRestoreInstanceState(Bundle)实现中恢复)。
如果你覆写这个方法来保存额外的没有被各个view保存的信息,你可能想要在默认实现过程中调用或者自己保存每个视图的所有状态。如果被调用,这个方法会
在onStop()前被触发,但系统并不保证是否在onPause()之前或者之后触发。