本篇笔记将从AndroidManifest.xml文件着手来分析Contacts模块。
首 先,AndroidManifest.xml文件授予了Contacts程序某些权限,包括 CALL_PRIVILEGED,WRITE_CONTACTS,INTERNET,以及Google自己定义的Gmail权 限:"com.google.android.googleapps.permission.GOOGLE_AUTH.mail"等等。赋予了这些权 限,Contacts才能正常的工作,因此,<uses-permission>通常都定义在<application>之前, 当然,定义在<application>之后也是允许的。
其次,<application>的定义,其中定义 了一个android:process="android.process.acore"属性,告知用户,Contacts这个应用程序将运行在 android.process.acore这个进程中。我们可以打开模拟器,然后在命令行使用adb shell命令进入模拟器的命令终端,然后使用ps查看当前运行的进程,就可以看到android.process.acore这个进程了:
3

再次,<application>中定义了很多activity和一个service。
这里,对其中几个activity作简要说明。
1. TwelveKeyDialer
这 是下面将要讲到的拨号盘的Activity,拨号盘主要由12个按键组成,分别是0-9十个加上*和#。从LAUNCHER下选择Phone即可进入其 中,它的Intent分类是TAB,说明这是一个Tab Content,是组成Contacts应用程序的四个TAB之一。关于TwelveKeyDialer的详细说明留作以后细究。
2. RecentCallsListActivity
和上面的TAB一样,这也是四个TAB之一,负责通话记录的TAB。从HOME状态下我们按下拨号键即可进入到该TAB,这个TAB是一个ListActivity,关于它的详细介绍这里从略。
3. DialtactsActivity
这 是容纳4个TAB的容器类,它的intent分类是LAUNCHER,说明它可以从LAUNCHER界面启动进入,那么到底是LAUNCHER下的哪个图 标呢?通过它的android:icon="@drawable/ic_launcher_phone"属性我们知道,这正是Phone程序。 DialtactsActivity使用的布局文件是apps/Contacts/res/layout-finger /dialer_activity.xml,关于这点的详细说明,这里也从略。
4. DialtactsContactsEntryActivity
其实这并不是一个Activity,它只是第3个activity DialtactsActivity的别名。它的描述是这样的:

<activity-alias

    android:name="DialtactsContactsEntryActivity"

    android:targetActivity="DialtactsActivity"

    android:label="@string/contactsList"

    android:icon="@drawable/ic_launcher_contacts"

>

这也是一个LAUNCHER分类,它对应于LAUNCHER列表中的Contacts程序。
5. ContactsListActivity
联系人列表的activity,即四个TAB中第三个。其中定义了很多<intent-filter>属性,说明可以在联系人列表项上进行很多操作,例如短按列表,长按列表,短按联系人图像等。
6. ContactsListActivity$ContactsSearchActivity
这是负责联系人搜索功能的activity,这里的$是Java语言对静态内部类的表示法,即ContactsSearchActivity类是ContactsListActivity的一个静态类。
其他的N多activity此处均从略。
下面从TwelveKeyDialer这个activity来讲讲第一个TAB的布局。
首先,使用eclipse插件Hierarchy View(也可以从SDK的tools工具中选择hierarchyviewer.bat)来查看DialPad中的12键布局:
4

一般情况下我们可能认为这些按钮是按照GridView布局器来布局的,因为GridView完全可以胜任这份工作,但是,Android开发人员却没有这么使用,而是自定义了一种layout来布局DialPad。
从 TreeView中我们得知,这里使用的自定义布局文件的名字叫ButtonGridLayout,这个layout类和GridView一样,也是继承 自ViewGroup,定义在apps/Phone/src/com/android/phone/ButtonGridLayout.java中(注 意,这是Phone下面的)。从类的定义上看,该类属于轻量级的布局容器,而GridView则是重量级的,后者非常复杂,这可能是Android开发人 员抛弃GridView改用ButtonGridLayout的一个原因。ButtonGridLayout.java定义了DialPad的几个重要属 性,包括4行3列布局,按钮的数目,按钮的宽度高度,以及按钮之间的间隔等。
这个按钮的布局在文件res/layout-finger/dialpad.xml等中使用到,dialpad.xml中定义了容器的某些属性,例如paddingLeft,layout_gravity等,还分别定义了12个按键的属性,例如数字5的按钮属性:

<ImageButton

    android:id="@+id/five" 

    android:layout_width="88dp" 

    android:layout_height="50dp" 

    android:src="@drawable/dial_num_5" 

    android:background="@drawable/btn_dial" 

    android:soundEffectsEnabled="false" 

    android:contentDescription="@string/description_image_button_five" 

/>

这里的dial_num_5并不是dial_num_5.png图片,而是dial_num_5.xml文件。笔记一中说到这个xml文件定义了一 个<selector>用于根据按钮不同状态来选择不同的图片。其里面的dial_num_5_blk和dial_num_5_wht才是 png格式的图片,分别表示按钮按下去(黑色5)和正常情况下(白色5)的图片。
下面我们再来讨论DialPad界面中其他元素的布局,首先是顶部的TabWidget:
5

TabWidget是包含在TabHost容器中的,容纳上述TabWidget的TabHost定义在res/layout-finger /dialer_activity.xml中,而src/com/android/contacts/DialtactsActivity.java这个 TabActivity使用了这个布局,因此,DialtactsActivity.java是管理上面四个Tab的容器类。其中的四个方法就是用来定义 四个tab的:

// Setup the tabs

setupDialerTab();

setupCallLogTab();

setupContactsTab();

setupFavoritesTab();

这四个方法均设置了一个intent,用于按下Tab按钮时跳转到指定的Activity,例如:
Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
intent.setClass(this, RecentCallsListActivity.class);
这是第二个Tab定义的Intent,其对应的目标Activity是RecentCallsListActivity,即通话记录TAB。
再来看看号码显示区域的布局属性:
6

首先,这是一个EditText组件,定义在res/layout-finger/twelve_key_dialer.xml中,其定义如下:

<EditText android:id="@+id/digits"

    android:layout_width="match_parent"

    android:layout_height="67dip"

    android:gravity="center"

    android:maxLines="1"

    android:scrollHorizontally="true"

    android:textSize="33sp"

    android:freezesText="true"

    android:background="@drawable/btn_dial_textfield"

    android:textColor="@color/dialer_button_text"

    android:focusableInTouchMode="true"

    android:editable="true"

    android:cursorVisible="false"

    android:layout_weight="0"

    android:contentDescription="@string/description_digits_edittext"

/>

从属性中我们知道,它的背景图片是在btn_dial_textfield.xml中定义的几个9-patch图片,分别表示无号码时,有号码时, 按下时EditText的背景色变化。属性中还定义了文本的颜色dialer_button_text.xml文件,正常情况下是白色的,按下时变成了黑 色。其他的一些属性很容易从字面上理解,这里不作说明。
最底下的三个按钮分别叫做语音邮件按钮,拨号按钮和删除按钮。
上面的twelve_key_dialer.xml布局中,我们摘取中间几行:

<!– Keypad section –>

<include layout="@layout/dialpad" />

<!– Horizontal row of buttons (Voicemail + DialButton + Delete.) –>

<include layout="@layout/voicemail_dial_delete" />

这里的include关键字就是要引用外部已存在的xml文件作为子布局,这里的两个布局文件分别是dialpad.xml(前面已经讲过)和 voicemail_dial_delete.xml。最底下的三个按钮就是由voicemail_dial_delete.xml文件来控制显示的,我 们进去看看:

<!– Onscreen "Voicemail" button.

     The width is 75 (from the mocks) + 12 of padding from the

     9patch, total is 87.

–>

<ImageButton android:id="@+id/voicemailButton"

    android:layout_width="87dip"

    android:layout_height="50dip"

    android:layout_gravity="center_vertical"

    android:state_enabled="false"

    android:background="@drawable/btn_dial_voicemail"

    android:contentDescription="@string/description_voicemail_button"

    android:src="@drawable/ic_dial_action_voice_mail"

/>

这只是语音邮件那个按钮的属性,其他两个按钮和这类似,从略。
这个ImageButton的背景用的是btn_dial_voicemail.xml文件,这里面定义了两个9-patch图片,那个耳机标志则是定义在drawable下的ic_dial_action_voice_mail.png透明图片。
—————————————————————————————-
最 终,上述的<EditText>,dialpad.xml,voicemail_dial_delete.xml,还有这里没有提到的一个 ListView,共同组成了Contacts四个TAB之一的拨号盘TAB的布局文件twelve_key_dialer.xml,该文件服务的 activity是TwelveKeyDialer.java,因为是Tab content,并不包含顶部的TabWidget,而TabWidget定义在dialer_activity.xml中。