您的位置:首页 > 移动开发 > Android开发

Android Contacts源码分析

2014-10-13 14:01 288 查看

最近出于一些业务上的需要需要对Android Contacts和Phone做出一些改动

首先我们知道

Contacts应用是由Google Android团队编写的Android原生应用。在应用层面上涉及到Contacts.apk,

ContactProvider.apk。其他相关的在Framwork,以及framework与linux内核之间的SQLite.Contacts.apk只是界面

层的逻辑,主要实现UI的流程。对于联系人的查询,存储,增加和删除都在ContactProvider.apk中封装,

是对底层的SQLite进行封装。数据的操作最终都是在底层的SQLite的C代码中进行。

事实上,绝大多数的改动一般只需要改动界面,所以我本次打算做一次完善的Contacts界面分析(MTK为例)
其实,我们都知道对于系统级的应用,它的启动一半在于开机时就已经全部启动运行了,而此次我们重在在于界面
所以,对于启动便不作过多赘述
首先给出Contacts源码位置,Android SourceCode/Packages/apps/Contacts/
进入源码目录
通过AndroidManifest.xml我们也大概可以看出它的启动运行

在AndroidManifest.xml中,我们可以看出大概有NonPhoneActivity、DialtactsActivity、PeopleActivity等activity
其他activity暂时不做考虑,首先NophoneActivity我们也不做考虑(专为非Phone使用)

那么我们先看一下,在MTK平台下的DialtactsActivity、PeopleActivity





这两个界面共同组成手机

联系人

两个应用(此处以MTK为例,个手机厂商各有不同)
下面我们就以代码来做详细分析
源码目录下\packages\apps\ContactsW2014\src\com\android\contacts\activities\DialtactsActivity.java
在DialityActivity文件下
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);}
@Override
public Fragment getItem(int position) {
switch (position) {
case TAB_INDEX_DIALER:
return new DialpadFragment();
case TAB_INDEX_CALL_LOG:
return new CallLogFragment();
case TAB_INDEX_FAVORITES:
return new PhoneFavoriteFragment();
case TAB_INDEX_CONTACTS:
return new PhoneFragment("phone");}
throw new IllegalStateException("No fragment at position " + position);
}
ViewPagerAdapter是构建整个DialtactsActivity界面的核心
在@override protected void onCreate(Bundle icicle){}函数中
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
.......
setContentView(R.layout.dialtacts_activity);
.......
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
mViewPager.setOnPageChangeListener(mPageChangeListener);
mViewPager.setOffscreenPageLimit(2);
.......
}
我们可以发现mViewPager构建了整个DialtactActivity的界面核心
回归到ViewPageAdapter的构建类,我们发现 与上图对应的
键盘
new DialpadFragment();

记录
new CallLogFragment();

我的收藏
new PhoneFavoriteFragment();

联系人
new PhoneFragment("phone");

其中联系人new PhoneFragment("phone"); 比较独特在DialerTabListener中 我们发现
if(tab.getPosition() == TAB_INDEX_CONTACTS)
{if(mCallType.equals("NORMAL"))
{
mLastManuallySelectedFragment = 0;
Intent intent = new Intent();
intent.setClassName("com.android.contacts", "com.android.contacts.activities.PeopleActivity");
startActivity(intent);
mPageChangeListener.setCurrentPosition(mLastManuallySelectedFragment);
finish();
}
.....}


通过它可以直接跳转PeopleActivity(如上图)中去
正如最开始我们所说的Contacts.apk只是界面层的逻辑,此处我们只做界面分析
那么顺藤摸瓜,我们可以去到DialpadFragment()中(同样以键盘为例开始对界面做出分析)
找到DialpadFragment SourceCode/packages\apps\ContactsW2014\src\com\android\contacts\dialpad/DialpadFragment.java
同样的
在onCreateView()函数中我们可以知道DialpadFragment的构造
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
.......
fragmentView = inflater.inflate(R.layout.dialpad_fragment_sx, container, false);
......fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);
.....
}


那么 我们就找到了整个DialpadFragement的布局文件
\packages\apps\ContactsW2014\res\layout/dialpad_fragment.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
........
<span style="white-space:pre">	</span><com.mediatek.contacts.widget.DialpadAdditionalButtons/>//通话信息按钮
<span style="white-space:pre">	</span><View/>
<span style="white-space:pre">	</span><com.mediatek.contacts.widget.ButtonGridLayout/>//数字按键
<span style="white-space:pre">	</span><view/>
<span style="white-space:pre">	</span><listView/>//查询结果列表
<span style="white-space:pre">	</span><FrameLayout>
<span style="white-space:pre">		</span><com.android.contacts.dialpad.DigitsEditText/>//查询编辑框
<span style="white-space:pre">		</span><ImageButton/>//编辑框delete建
<span style="white-space:pre">	</span></FrameLayout>
<span style="white-space:pre">	</span><listView/>
<RelativeLayout/>
整体的布局框架如图,其中值得我们关注的就是DiapadAdditionalButtons和ButtonGirdLayout
其中DialpadAdditionalButtons就是最新面四个按钮
然而ButtonGirdLayout就是数字键盘了
那么到此DialpadFragment整体布局也就分析完了

接下来,如果还想顺藤摸瓜的话
进入DiapadAdditionalButtons(你就会发现dialbutton),其实DialpadAdditonalButtons只是作了布局的样式
真正的进入拨号还是在DialFragment中处理
好,接下来,我们继续前进

同样 ,在onCreateView()函数中
mAdditionalButtonsRow = fragmentView.findViewById(R.id.dialpadAdditionalButtons);

mDialButtonSim1 = mAdditionalButtonsRow.findViewById(R.id.dialButtonSim1);

mDialButtonSim2 = mAdditionalButtonsRow.findViewById(R.id.dialButtonSim2);

这里就不得不吐槽一下,国内的双卡双待真是坑爹啊
好了,不管,我们下一步
mDialButtonSim1.setOnClickListener(this);

mDialButtonSim2.setOnClickListener(this);

那么我们继续跟踪onClick()或者onTouch()
case R.id.dialButton: {

........
keyPressed(KeyEvent.KEYCODE_CALL);

}
那么继续跟踪 keyPressed()
dialButtonPressed();(onTouch())

KeyPressed()
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);

mDigits.onKeyDown(keyCode, event);

dialButtonPressed()
public void dialButtonPressed() {
dialButtonPressedInner(mDigits.getText().toString(), Constants.DIAL_NUMBER_INTENT_NORMAL);
}


protected void dialButtonPressedInner(String number, int type,int id) {
.........
final Intent intent = ContactsUtils.getCallIntent(number,(getActivity() instanceof DialtactsActivity ?((DialtactsActivity) getActivity()).getCallOrigin() : null), type);
.......
mCallOptionHandler.doCallOptionHandle(intent);
......
}


同样,我们继续跟踪mCallOptionHandler = new ContactsCallOptionHandler(getActivity(),
new ContactsCallOptionHandlerFactory());
接下来就会通过JRIL向系统层及硬件传递消息
那么 我们此次分析,到此结束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: