通话记录分析 --- 初始化

1.1,初始化

1.1 CallLogFragment

在Dialer中,通话记录信息都是通过CallLogActivity 显示,实际上,真正完成的是CallLogFragment 。CallLogActivity的内部类ViewPagerAdapter的getItem方法如下,

public Fragment getItem(int position) {
     switch (getRtlPosition(position)) {
     case TAB_INDEX_ALL:
         return new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL);
    case TAB_INDEX_MISSED:
          return new CallLogFragment(Calls.MISSED_TYPE);
     }
     throw new IllegalStateException("No fragment at position " + position);
}

查询的数据库:contacts2.calls

通话记录没有搜索,在onCreateView函数里根据不同的参数直接查询。

查询的时间顺序是由近到远。

CallLogFragment的构造方法如下,

public CallLogFragment(int filterType, int logLimit, long dateLimit) {
     mCallTypeFilter = filterType;//查询通话记录的类型
     mLogLimit = logLimit;
     mDateLimit = dateLimit;
}

通话记录主要包括以下类型:

所有通话,未接来电,所有外拨电话,所有来电,黑名单来电。

CallLogQueryHandler对应的定义如下,

private static final int INCOMING_IMS_TYPE = 5;
private static final int OUTGOING_IMS_TYPE = 6;
private static final int MISSED_IMS_TYPE = 7;
•••

CallLogFragment的onCreate方法主要逻辑如下,

final Activity activity = getActivity();//获取所在的Activity对象
//获取进程的ContentResolver对象
final ContentResolver resolver = activity.getContentResolver();
String currentCountryIso = GeoUtil.getCurrentCountryIso(activity);
//构造CallLogQueryHandler对象
mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, mLogLimit);
//锁屏管理
mKeyguardManager =
  (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
//注册通话记录数据库监听
resolver.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver);
//注册联系人数据库监听
resolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true,
                mContactsObserver);
resolver.registerContentObserver(Status.CONTENT_URI, true, mVoicemailStatusObserver);
setHasOptionsMenu(true);//设置菜单

CallLogFragment的onCreateView方法主要逻辑如下,

1,获取RecyclerView布局,

mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);

2,构造RecyclerView的Adapter,在此为GroupingListAdapter对象,

mAdapter = ObjectFactory.newCallLogAdapter(getActivity(),this,
   new ContactInfoHelper(getActivity(), currentCountryIso), mVoicemailPlaybackPresenter,
   isShowingRecentsTab);
mRecyclerView.setAdapter(mAdapter);

3,调用fetchCalls方法开始查询通话记录

fetchCalls();

fetchCalls方法如下,

mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit);

调用CallLogQueryHandler的fetchCalls方法进行查询。

1.2 MsimCallLogFragment

MsimCallLogFragment和CallLogFragment几乎完相似,其onCreate方法如下,

final Activity activity = getActivity();  //获取对应的Activity对象
final ContentResolver resolver = activity.getContentResolver();
String currentCountryIso = GeoUtil.getCurrentCountryIso(activity);
// 构造CallLogQueryHandler对象
mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, mLogLimit);
mKeyguardManager =
 (KeyguardManager)activity.getSystemService(Context.KEYGUARD_SERVICE);
//监听数据库的变化
resolver.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver);
resolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true,
                mContactsObserver);
resolver.registerContentObserver(Status.CONTENT_URI, true, mVoicemailStatusObserver);
setHasOptionsMenu(true);//弹出菜单,这样才可以选择其他类型并进行查询

onCreateView主要逻辑如下,

1,调用updateFilterSpinnerViews方法加载弹出菜单,

updateFilterSpinnerViews();

2,调用ObjectFactory的newCallLogAdapter方法构造CallLogAdapter对象,并将CallLogAdapter对象设置为MsimCallLogFragment的Adapter,

String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
boolean isShowingRecentsTab = mLogLimit != NO_LOG_LIMIT || mDateLimit != NO_DATE_LIMIT;
        mAdapter = ObjectFactory.newCallLogAdapter(
                getActivity(),
                this,
                new ContactInfoHelper(getActivity(), currentCountryIso),
                mVoicemailPlaybackPresenter,
                isShowingRecentsTab);
mRecyclerView.setAdapter(mAdapter);

3,调用fetchCalls开始查询通话记录,

fetchCalls();

fetchCalls方法如下,

1, CallLogQueryHandler的fetchCalls方法进行查询,

if (mFilterSubSpinnerView.isEnabled()) {
  int[] subId = SubscriptionManager.getSubId(mCallSubFilter);
  if (subId != null) {
     mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit, subId[0]);
  } else {
      mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit);
   }
} else {
   mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit);
}

并且默认的查询类型就是查询所有通话记录, mCallTypeFilter定义如下,

protected int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL;

因此,初次进入该界面时,显示的是所有通话记录信息。

2,如果未查到对应的通话类型结果,调用updateEmptyMessage进行更新界面,

updateEmptyMessage(mCallTypeFilter);

弹出菜单界面如下,

通话记录分析 --- 初始化_第1张图片

菜单弹出之后,点击查询类型之后, MsimCallLogFragment对应的界面会显示查询类型的结果,这一过程是如何实现的呢?

updateFilterSpinnerViews方法主要逻辑如下,

1,设置弹出菜单,

ArrayAdapter filterStatusAdapter = new ArrayAdapter(
    getActivity(), R.layout.msim_call_log_spinner_item,
    SpinnerContent.setupStatusFilterContent(getActivity()));
mFilterStatusSpinnerView.setAdapter(filterStatusAdapter);

SpinnerContent的setupStatusFilterContent方法如下,

case INDEX_CALL_TYPE_ALL:
    value = CallLogQueryHandler.CALL_TYPE_ALL;
    label = context.getString(R.string.call_log_all_calls_header);
    break;
case INDEX_CALL_TYPE_INCOMING:
    value = CallLog.Calls.INCOMING_TYPE;
    label = context.getString(R.string.call_log_incoming_header);
    break;
case INDEX_CALL_TYPE_OUTGOING:
    value = CallLog.Calls.OUTGOING_TYPE;
    label = context.getString(R.string.call_log_outgoing_header);
    break;
case INDEX_CALL_TYPE_MISSED:
    value = CallLog.Calls.MISSED_TYPE;
     label = context.getString(R.string.call_log_missed_header);
break;

由此可见,弹出菜单的值和CallLog.Calls中的通话记录类型值是一一对应的。

2,注册监听器,

mFilterStatusSpinnerView.setOnItemSelectedListener(mStatusSelectedListener);
SpinnerContent.setSpinnerContentValue(mFilterStatusSpinnerView, mCallTypeFilter);

mStatusSelectedListener定义如下,

private OnItemSelectedListener mStatusSelectedListener = new OnItemSelectedListener() {
  @Override
  public void onItemSelected(AdapterView parent, View view, int position, long id) {
     Log.i(TAG, "Status selected, position: " + position);
     int type = ((SpinnerContent)parent.getItemAtPosition(position)).value;
     if (type != mCallTypeFilter) {
        mCallTypeFilter = type;
        fetchCalls();
     }
}
•••

这样,一旦弹出菜单的查询的通话类型被选中之后,就会回调onItemSelected方法,如果这次的类型和上次查询的类型不同,则给mCallTypeFilter重新赋值,然后调用fetchCalls方法查询。

MsimCallLogFragment的fetchCalls方法在全面已经论述过,也是调用CallLogQueryHandler的fetchCalls方法完成的。

1.3 CallLogSearchFragment

CallLogSearchFragment对应的activity还是CallLogActivity。

进入通话记录搜索界面之后, CallLogActivity的prepareSearchView方法如下,

mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);//注册监听器
•••

mPhoneSearchQueryTextListener定义如下,

private final OnQueryTextListener mPhoneSearchQueryTextListener = new OnQueryTextListener() {

如果SearchView的text发生变化,则会调用mPhoneSearchQueryTextListener的onQueryTextChange方法,该方法如下,

if (mSearchFragment != null) {
     mSearchFragment.setQueryString(newText);
}

mSearchFragment就是CallLogSearchFragment对象。

CallLogSearchFragment继承CallLogFragment,因此, CallLogSearchFragment还是比较简单,大部分逻辑都在CallLogFragment中完成了。

CallLogSearchFragment中有一个mQueryString变量,主要是保存SearchView中的text值,

private String mQueryString;

CallLogSearchFragment的setQueryString方法如下,

if (!TextUtils.equals(mQueryString, queryString)) { //这次查询和上次查询的字符不同
    //避免每次都查询
    mQueryString = queryString;//记录查询字符
    if (mAdapter != null) {
        mAdapter.setLoading(true);
        mAdapter.setQueryString(mQueryString); //这一句好像没什么作用
        if (TextUtils.isEmpty(queryString)) { //查询字符为空,就查询全部通话记录
            mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
        } else {
            mCallLogQueryHandler.fetchCalls(queryString);
        }
    }
}

最后也是调用CallLogQueryHandler的fetchCalls方法进行查询。

小结:

CallLogFragment, MsimCallLogFragment和CallLogSearchFragment这三个类最后都是调用CallLogQueryHandler的fetchCalls方法查询通话信息。CallLogQueryHandler中一共有7个fetchCalls方法,只是参数不同。

你可能感兴趣的:(---【contact分析】)