`

QuickContactBadge如何实现

阅读更多
从前一篇,我们知道了如何使用了QuikcContactBadge.这一篇我们看QuikcContactBadge是如何实现。开源好处就在于,你可以尽情地了解你想了解。
我们都知道QuickContactBadge是从ImageView继承而来的,我们先来看QuikcContactBadge的源码:
framework\base\core\java\android\widget\QuikcContactBadge.java
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.widget;

import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import com.android.internal.R;

/**
 * Widget used to show an image with the standard QuickContact badge
 * and on-click behavior.
 */
public class QuickContactBadge extends ImageView implements OnClickListener {

    private Uri mContactUri;
    private String mContactEmail;
    private String mContactPhone;
    private int mMode;
    private QueryHandler mQueryHandler;
    private Drawable mBadgeBackground;
    private Drawable mNoBadgeBackground;
    private int mSelectedContactsAppTabIndex = -1;

    protected String[] mExcludeMimes = null;

    static final private int TOKEN_EMAIL_LOOKUP = 0;
    static final private int TOKEN_PHONE_LOOKUP = 1;
    static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
    static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
    static final private int TOKEN_CONTACT_LOOKUP_AND_TRIGGER = 4;

    static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
        RawContacts.CONTACT_ID,
        Contacts.LOOKUP_KEY,
    };
    static final int EMAIL_ID_COLUMN_INDEX = 0;
    static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1;

    static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
        PhoneLookup._ID,
        PhoneLookup.LOOKUP_KEY,
    };
    static final int PHONE_ID_COLUMN_INDEX = 0;
    static final int PHONE_LOOKUP_STRING_COLUMN_INDEX = 1;

    static final String[] CONTACT_LOOKUP_PROJECTION = new String[] {
        Contacts._ID,
        Contacts.LOOKUP_KEY,
    };
    static final int CONTACT_ID_COLUMN_INDEX = 0;
    static final int CONTACT_LOOKUPKEY_COLUMN_INDEX = 1;


    public QuickContactBadge(Context context) {
        this(context, null);
    }

    public QuickContactBadge(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public QuickContactBadge(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a =
            context.obtainStyledAttributes(attrs,
                    com.android.internal.R.styleable.QuickContactBadge, defStyle, 0);

        mMode = a.getInt(com.android.internal.R.styleable.QuickContactBadge_quickContactWindowSize,
                QuickContact.MODE_MEDIUM);

        a.recycle();

        init();

        mBadgeBackground = getBackground();
    }

    private void init() {
        mQueryHandler = new QueryHandler(mContext.getContentResolver());
        setOnClickListener(this);
    }

    /**
     * Set the QuickContact window mode. Options are {@link QuickContact#MODE_SMALL},
     * {@link QuickContact#MODE_MEDIUM}, {@link QuickContact#MODE_LARGE}.
     * @param size
     */
    public void setMode(int size) {
        mMode = size;
    }

    /**
     * Assign the contact uri that this QuickContactBadge should be associated
     * with. Note that this is only used for displaying the QuickContact window and
     * won't bind the contact's photo for you.
     *
     * @param contactUri Either a {@link Contacts#CONTENT_URI} or
     *            {@link Contacts#CONTENT_LOOKUP_URI} style URI.
     */
    public void assignContactUri(Uri contactUri) {
        mContactUri = contactUri;
        mContactEmail = null;
        mContactPhone = null;
        onContactUriChanged();
    }

    /**
     * Sets the currently selected tab of the Contacts application. If not set, this is -1
     * and therefore does not save a tab selection when a phone call is being made
     * @hide
     */
    public void setSelectedContactsAppTabIndex(int value) {
        mSelectedContactsAppTabIndex = value;
    }

    private void onContactUriChanged() {
        if (mContactUri == null && mContactEmail == null && mContactPhone == null) {
            if (mNoBadgeBackground == null) {
                mNoBadgeBackground = getResources().getDrawable(R.drawable.quickcontact_nobadge);
            }
            setBackgroundDrawable(mNoBadgeBackground);
        } else {
            setBackgroundDrawable(mBadgeBackground);
        }
    }

    /**
     * Assign a contact based on an email address. This should only be used when
     * the contact's URI is not available, as an extra query will have to be
     * performed to lookup the URI based on the email.
     *
     * @param emailAddress The email address of the contact.
     * @param lazyLookup If this is true, the lookup query will not be performed
     * until this view is clicked.
     */
    public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
        mContactEmail = emailAddress;
        if (!lazyLookup) {
            mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
                    Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
                    EMAIL_LOOKUP_PROJECTION, null, null, null);
        } else {
            mContactUri = null;
            onContactUriChanged();
        }
    }

    /**
     * Assign a contact based on a phone number. This should only be used when
     * the contact's URI is not available, as an extra query will have to be
     * performed to lookup the URI based on the phone number.
     *
     * @param phoneNumber The phone number of the contact.
     * @param lazyLookup If this is true, the lookup query will not be performed
     * until this view is clicked.
     */
    public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
        mContactPhone = phoneNumber;
        if (!lazyLookup) {
            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
                    PHONE_LOOKUP_PROJECTION, null, null, null);
        } else {
            mContactUri = null;
            onContactUriChanged();
        }
    }

    public void onClick(View v) {
        if (mContactUri != null) {
            mQueryHandler.startQuery(TOKEN_CONTACT_LOOKUP_AND_TRIGGER, null,
                    mContactUri,
                    CONTACT_LOOKUP_PROJECTION, null, null, null);
        } 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);
        } else if (mContactPhone != null) {
            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, mContactPhone,
                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
                    PHONE_LOOKUP_PROJECTION, null, null, null);
        } else {
            // If a contact hasn't been assigned, don't react to click.
            return;
        }
    }

    /**
     * Set a list of specific MIME-types to exclude and not display. For
     * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
     * profile icon.
     */
    public void setExcludeMimes(String[] excludeMimes) {
        mExcludeMimes = excludeMimes;
    }

    private void trigger(Uri lookupUri) {
        final Intent intent = QuickContact.getQuickContactIntent(getContext(), this, lookupUri,
                mMode, mExcludeMimes);
        if (mSelectedContactsAppTabIndex != -1) {
            intent.putExtra(QuickContact.EXTRA_SELECTED_CONTACTS_APP_TAB_INDEX,
                    mSelectedContactsAppTabIndex);
        }
        getContext().startActivity(intent);
    }

    private class QueryHandler extends AsyncQueryHandler {

        public QueryHandler(ContentResolver cr) {
            super(cr);
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            Uri lookupUri = null;
            Uri createUri = null;
            boolean trigger = false;

            try {
                switch(token) {
                    case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
                        trigger = true;
                        createUri = Uri.fromParts("tel", (String)cookie, null);

                        //$FALL-THROUGH$
                    case TOKEN_PHONE_LOOKUP: {
                        if (cursor != null && cursor.moveToFirst()) {
                            long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
                            String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
                            lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                        }

                        break;
                    }
                    case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
                        trigger = true;
                        createUri = Uri.fromParts("mailto", (String)cookie, null);

                        //$FALL-THROUGH$
                    case TOKEN_EMAIL_LOOKUP: {
                        if (cursor != null && cursor.moveToFirst()) {
                            long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
                            String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
                            lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                        }
                        break;
                    }

                    case TOKEN_CONTACT_LOOKUP_AND_TRIGGER: {
                        if (cursor != null && cursor.moveToFirst()) {
                            long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX);
                            String lookupKey = cursor.getString(CONTACT_LOOKUPKEY_COLUMN_INDEX);
                            lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                            trigger = true;
                        }

                        break;
                    }
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }

            mContactUri = lookupUri;
            onContactUriChanged();

            if (trigger && lookupUri != null) {
                // Found contact, so trigger track
                trigger(lookupUri);
            } else if (createUri != null) {
                // Prompt user to add this person to contacts
                final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
                getContext().startActivity(intent);
            }
        }
    }
}

从source code我们可以知道QuickContactBadge已经处理了它的onClick事件。通过AsyncQueryHandler(用这个来查询的好处待会稍后研究^_^)来异步查询Contact的信息,进而做出了不同的处理,// Found contact, so trigger track
                trigger(lookupUri);若查询到了已经有这样的Contact就会发出com.android.contacts.action.QUICK_CONTACT这样的Intent去启动我们看到的Contact tools:call.message,web...而处理这个Intent的Acticity是位于Contact里面的QuickContactActivity.java(大家可以在这里继续研究Contact tools的UI是怎么形成与实现的)。那还有另外一种情况就是这个Contact还没有保存在手机里,那么就会
inal Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
                getContext().startActivity(intent);启动是否要保存这个contact的Activity.发出com.android.contacts.action.SHOW_OR_CREATE_CONTACT这个Intent,而处理这个Activity也是在Contact这个源码里面的ShowOrCreateActivity。




分享到:
评论
1 楼 bingtao115 2011-12-02  
源码引用的太多了,关键的东西说的太少

相关推荐

    通讯录的弹窗效果.

    #### 二、使用QuickContactBadge实现基本通讯录弹窗 1. **布局文件创建**: 在`res/layout`目录下创建布局文件`main.xml`,包含一个`QuickContactBadge`组件。该组件用于显示联系人的图片,并支持点击后弹出一系列...

    QuickContactBadge和AsyncQueryHandler实现联系人列表

    本代码是QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现,对初级程序员会有很大的帮助,可以直接拿来用,还带了首字母拼音的滑动栏,里面有自定义控件可以让你好好学习

    Android2.2 API 中文文档系列(8) —— QuickContactBadge

    - **应用场景**:用于实现用户点击 `QuickContactBadge` 后的具体操作,如打开联系人详情页面等。 5. **`setExcludeMimes(String[] excludeMimes)`** - **功能**:设置要排除的 MIME 类型列表,可以用来隐藏特定...

    Android: 开发短信程序列表界面(QuickContactBadge/ListView混用)

    在这个场景中,`QuickContactBadge` 和 `ListView` 是两个关键组件,它们共同构建了一个高效且用户友好的交互体验。 首先,`QuickContactBadge` 是一个Android SDK提供的视图组件,它主要用于显示联系人头像,并...

    android 自定义ListView实现动画特效

    首先,要实现这个效果,我们需要创建一个自定义的Adapter,它是连接ListView与数据源的关键。Adapter负责将数据转化为ListView中的View,并处理用户的交互事件。在Adapter中,我们可以为每个列表项设置点击监听器,...

    android自定义菜单使用技巧

    本文将深入探讨如何实现Android自定义菜单,并结合QuickContactBadge控件的使用,为用户提供更加丰富的交互体验。 首先,我们来了解自定义菜单的基本概念。在Android中,菜单通常在Action Bar或Overflow Menu中显示...

    android自定义弹出menu

    为了实现类似QuickContactBadge的动画效果,我们可以添加动画资源文件,如`slide_in.xml`和`slide_out.xml`,分别定义菜单弹出和消失的动画。然后在显示和关闭PopupWindow时调用相应的动画: ```java // 弹出动画 ...

    安卓中文API文档

    本文档涵盖了 Android 2.2 版本的 API,包括 TextView、EditText、AccessibilityService、Manifest、View、ImageView、ImageButton、QuickContactBadge、ZoomButton、CheckBox、RadioButton、Button、ToggleButton、...

    Android 通讯录 字母导航 字母悬浮

    在Android中,这一功能通过`SectionIndexer`接口和`QuickContactBadge`组件共同实现。 `SectionIndexer`接口定义了三个方法:`getPositionForSection(int section)`用于获取指定分段(字母)的第一个索引位置;`...

    android 项目代码

    在描述中提到的“根据字母检索”,这意味着该项目可能实现了AlphabetIndexer和QuickContactBadge等功能。AlphabetIndexer用于在搜索结果中添加可滚动的字母索引条,帮助用户快速定位到特定的首字母。...

    安卓Android源码——安卓Android字母排序 类似通讯录字母检索.zip

    4. **QuickContactBadge**:为了增强用户体验,可以在每个联系人项旁边添加QuickContactBadge,当用户点击时可以快速查看或编辑联系人信息。 5. **onSectionChanged()回调**:当用户选择字母栏上的某个字母时,系统...

    QuickContactDemo

    在contact文件中,可能包含了实现以上功能的代码示例,包括布局文件(XML)、Java代码(可能在Activity或Fragment中)以及可能的资源文件(如图片)。通过对这些文件的分析和学习,开发者可以深入理解如何在Android...

    Android 联系人快速索引源码.rar

    5. **QuickContactBadge**:这是一个可以快速查看联系人详细信息的小图标,常用于快速索引栏中,当用户点击特定字母时,显示与该字母相关的联系人。 6. **ListView/RecyclerView**:展示联系人列表的视图组件。...

    android apidemos示例解析

    QuickContactBadge badge = new QuickContactBadge(this, v); badge.assignContactUri(ContactData.getUri()); }); ``` 以上仅为部分示例的简要介绍,更多内容请参考完整的文档或源码。通过这些示例的学习,...

    android4.0 Contacts 联系人jar包

    - 实现联系人搜索功能,通过ContentResolver的`query()`方法查询匹配特定条件的联系人。 - 同步应用内的联系人数据到系统联系人数据库,或者从系统中导入联系人。 - 添加、编辑和删除联系人,包括添加新的数据项...

    android——API中文文档

    ### Android API中文文档知识点概述 本篇文档主要围绕Android中的基本控件展开,对TextView、EditText等常用控件进行了详细...通过对它们的学习和理解,开发者可以更好地设计和实现复杂的应用程序界面,提高用户体验。

    Android 3.0新增UI控件示例说明.rar

    - **使用**:开发者可以通过设置`android:uiOptions="splitActionBarWhenNarrow"`属性或使用`getSupportActionBar()`方法来实现Action Bar。 2. **Fragment** - **定义**:Fragment是Android 3.0引入的一个可重用...

    好的-Android2.2 API中文文档——ImageView.doc

    它有两个已知的直接子类:ImageButton和QuickContactBadge,分别用于显示可点击的图像按钮和快速联系人徽章。除此之外,还有一些间接子类,如ZoomButton,用于处理缩放操作。 ImageView的重要属性包括: 1. `...

    Android2.2—API中文文档

    QuickContactBadge则用于快速显示联系人信息,ZoomButton常用于缩放操作,CheckBox和RadioButton用于复选和单选操作,ToggleButton作为开关按钮,ViewStub是一种延迟加载视图的组件,而GridView则用于创建网格布局。...

    01、基本控件1

    Android系统提供了多种预定义的主题(Theme)和颜色,开发者可以通过修改主题来改变应用的整体风格,系统命名的颜色可以在资源文件中引用,以实现一致性和易维护性。 【总结】 Android开发涉及的内容广泛,包括...

Global site tag (gtag.js) - Google Analytics