在ContactsLIstActiviry中的newView()和bindView()函数中都使用了ContactListItemCache类型的Cache:
final staticclass ContactListItemCache {
public View header;
public TextView headerText;
public View divider;
public TextView nameView;
public View callView;
public ImageView callButton;
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
public TextView labelView;
public CharArrayBuffer labelBuffer = new CharArrayBuffer(128);
public TextView dataView;
public CharArrayBuffer dataBuffer = new CharArrayBuffer(128);
public ImageView presenceView;
public QuickContactBadge photoView;
public ImageView nonQuickContactPhotoView;
}
其中QuickContactBadge类型的photoView,就是指的图片,点击图片之后会弹出QuickContacts框。
看一下QuickContactBadge的代码:
public void onClick(View v){
…………..……
} else if (mContactEmail != null) {
mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER,mContactEmail,
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI,Uri.encode(mContactEmail)),
EMAIL_LOOKUP_PROJECTION, null, null,null);
…………..……
//在相应点击时触发一个startQuery()方法,这个方法执行完毕之后自动调用mQueryHandler的//onQueryComplete()方法
}
protected voidonQueryComplete(int token, Object cookie, Cursor cursor){
…………………………………….
if (trigger&& lookupUri != null) {
trigger(lookupUri);//在调用trigger()方法。
…………………………………..
}
}
private voidtrigger(Uri lookupUri) {
QuickContact.showQuickContact(getContext(), this, lookupUri, mMode,mExcludeMimes);
}
对于showQuickContact方法来说,它是ContactsContract类中的一个函数。下面是代码:
public static voidshowQuickContact(Context context, Rect target, Uri lookupUri, intmode,
String[] excludeMimes) {
// Launch pivot dialog through intent for now
final Intent intent = newIntent(ACTION_QUICK_CONTACT);//这个就是.UI.QuickContactsActivity的IntentFilter的Action
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setData(lookupUri);
intent.putExtra(EXTRA_TARGET_RECT, target);
intent.putExtra(EXTRA_MODE, mode);
intent.putExtra(EXTRA_EXCLUDE_MIMES, excludeMimes);
context.startActivity(intent);//此时就会启动.UI.QuickContactsActivity
}
QuickContactsActivity类中的代码比较少。它继承了QuickContactWindow.OnDismissListener,使用onDismiss()函数来把QuickContact框dismiss掉。
QuickContactsActivity类在onNewIntent()函数中先将Intent解析出来,再调用show()方法将QuickContactWindow显示出来。
public voidonNewIntent(Intent intent) {
super.onNewIntent(intent);
……………
mQuickContact.show(lookupUri, target, mode,excludeMimes);//show()方法是QuickContactWindow类中的函数
}
.UI.QuickContactsActivity界面的绘制就是在QuickContactWindow类中完成的。
首先,在Show()方法中调用mHandler.startQuery()方法
public synchronized void show(UrilookupUri, Rect anchor, int mode, String[] excludeMimes) {
………………………………….
if (mMode == QuickContact.MODE_LARGE) {
// Select photos, but only super-primary
mHandler.startQuery(TOKEN_DATA, lookupUri, dataUri,DataQuery.PROJECTION, Data.MIMETYPE
+ "!=? OR (" + Data.MIMETYPE + "=? AND " + Data._ID +"=" + Contacts.PHOTO_ID
+ ")", new String[] { Photo.CONTENT_ITEM_TYPE,Photo.CONTENT_ITEM_TYPE }, null);
} else {
// Exclude all photos from cursor
mHandler.startQuery(TOKEN_DATA, lookupUri, dataUri,DataQuery.PROJECTION, Data.MIMETYPE
+ "!=?", new String[] { Photo.CONTENT_ITEM_TYPE }, null);
}
}
然后在onQueryComplete()方法中调用handleData()
publicsynchronized void onQueryComplete(int token, Object cookie,Cursor cursor) {
if (cookie != mLookupUri) return;
if (cursor == null) {
// Problem while running query, so bail without showing
Log.w(TAG, "Missing cursor for token=" + token);
this.dismiss();
return;
}
//绘制QuickContact框的过程基本都在此函数中完成。
handleData(cursor);
mHasData = true;
if (!cursor.isClosed()) {
cursor.close();
}
considerShowing();
}
再来看handleData()的代码:
private voidhandleData(Cursor cursor) {
if (cursor == null) return;
…………………………………………………………
// 使用一个while循环,将从onQueryComplete()方法中得到的cursor遍历。
while (cursor.moveToNext()) {
// 将cursor中的数据解出来。
final long dataId = cursor.getLong(DataQuery._ID);
final String accountType =cursor.getString(DataQuery.ACCOUNT_TYPE);
final String resPackage =cursor.getString(DataQuery.RES_PACKAGE);
final String mimeType = cursor.getString(DataQuery.MIMETYPE);
…………………………………………………………
//中间通过判断mimeType的类型,生成DataAction类的实例,然后使用函数considerAdd()将
//DataAction类型的action以mimeType为键存储在mActions中。
…………………………………………………………
}//end while
// 将mActions的键取出。
final Set<String> containedTypes =mActions.keySet();
String[] temp = containedTypes.toArray(newString[containedTypes.size()]);
int length = temp.length;
//在此循环中调用inflateAction()函数,将QuickContact框中的图标生成。
for (String mimeType :ORDERED_MIMETYPES) {
if (containedTypes.contains(mimeType)) {
final int index = mTrack.getChildCount() - 1;
mTrack.addView(inflateAction(mimeType), index); //将快速联系人的小图标add到mTrack中,在showInternal()函数中会调用startAnimation()将其动画效果显示出来
containedTypes.remove(mimeType);
}
}
…………………………………………………………
}
private voidconsiderAdd(Action action, String mimeType) {
if (mResolveCache.hasResolve(action)) {
mActions.collect(mimeType, action);
}
}
private ViewinflateAction(String mimeType) {
……………………………….
ActionList children = mActions.get(mimeType);
Action firstInfo = children.get(0);
if (children.size() == 1) {
view.setTag(firstInfo);
} else {
for (Action action : children) {
if (action.isPrimary()) {
view.setTag(action);
isActionSet = true;
break;
}
}
if (!isActionSet) {
view.setTag(children);
}
}
// Set icon and listen for clicks
final CharSequence descrip =mResolveCache.getDescription(firstInfo);
final Drawable icon = mResolveCache.getIcon(firstInfo);
view.setChecked(false);
view.setContentDescription(descrip);
view.setImageDrawable(icon);
view.setOnClickListener(this);
return view;
}
此时,handleData()函数已经完成,接着调用considerShowing(),由considerShowing()调用showInternal()函数来完成绘制工作。
private voidconsiderShowing() {
if (mHasData && !mShowing&& !mDismissed) {
if (mMode == QuickContact.MODE_MEDIUM&& !mHasValidSocial) {
// Missing valid social, swap medium for small header
mHeader.setVisibility(View.GONE);
mHeader = getHeaderView(QuickContact.MODE_SMALL);
}
// All queries have returned, pull curtain
showInternal();
}
}
private voidshowInternal() {
mDecor = mWindow.getDecorView();
mDecor.getViewTreeObserver().addOnGlobalLayoutListener(this);
WindowManager.LayoutParams l = mWindow.getAttributes();
l.width = mScreenWidth + mShadowHoriz + mShadowHoriz;
l.height = WindowManager.LayoutParams.WRAP_CONTENT;
// Force layout measuring pass so we have baseline numbers
mDecor.measure(l.width, l.height);
final int blockHeight = mDecor.getMeasuredHeight();
l.gravity = Gravity.TOP | Gravity.LEFT;
l.x = -mShadowHoriz;
if (mAnchor.top > blockHeight) {
// Show downwards callout when enough room, aligning bottomblock
// edge with top of anchor area, and adjusting to inset arrow.
showArrow(R.id.arrow_down, mAnchor.centerX());
l.y = mAnchor.top - blockHeight + mShadowVert;
l.windowAnimations = R.style.QuickContactAboveAnimation;
} else {
// Otherwise show upwards callout, aligning block top with bottomof
// anchor area, and adjusting to inset arrow.
showArrow(R.id.arrow_up, mAnchor.centerX());
l.y = mAnchor.bottom - mShadowVert;
l.windowAnimations = R.style.QuickContactBelowAnimation;
}
l.flags =WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
mRequestedY = l.y;
mWindowManager.addView(mDecor, l);
mShowing = true;
mQuerying = false;
mDismissed = false;
mTrack.startAnimation(mTrackAnim);// 调用动画效果
if (TRACE_LAUNCH) {
android.os.Debug.stopMethodTracing();
Log.d(TAG, "Window recycled " + mWindowRecycled + "times, chiclets "
+ mActionRecycled + " times");
}
}
到此,完了。
若有错,欢迎指正。