Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4997a4e8 authored by Danny Baumann's avatar Danny Baumann
Browse files

Cleanup code and make call data processing asynchronous.

Change-Id: I99e282e5f32b3f53be5e2421d9a2992e4f1ccb59
parent 81b96649
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -24,10 +24,12 @@
    android:showDividers="end" >

    <LinearLayout
        android:id="@+id/call_stats_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="@dimen/call_log_inner_margin" >
        android:paddingTop="@dimen/call_log_inner_margin"
        android:visibility="gone" >

        <TextView
            android:id="@+id/date_filter"
+2 −3
Original line number Diff line number Diff line
@@ -15,11 +15,10 @@
     limitations under the License.
-->

<view xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    class="com.android.contacts.callstats.CallStatsListItemView"
    android:orientation="vertical" >

    <GridLayout
@@ -116,4 +115,4 @@
        android:layout_marginRight="@dimen/call_log_outer_margin"
        android:background="@color/call_log_divider" />

</view>
</LinearLayout>
+41 −67
Original line number Diff line number Diff line
@@ -22,38 +22,33 @@ import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.telephony.PhoneNumberUtils;
import android.text.format.DateUtils;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.activities.DialtactsActivity;
import com.android.contacts.calllog.ContactInfoHelper;
import com.android.contacts.calllog.ContactInfo;
import com.android.contacts.util.Constants;
import com.android.internal.telephony.CallerInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class CallStatsActivity extends ListActivity implements
        CallStatsQueryHandler.Listener, ActionBar.OnNavigationListener,
@@ -68,6 +63,8 @@ public class CallStatsActivity extends ListActivity implements
    };

    private String[] mNavItems;

    private int mCallTypeFilter = CallStatsQueryHandler.CALL_TYPE_ALL;
    private long mFilterFrom = -1;
    private long mFilterTo = -1;
    private boolean mSortByDuration = true;
@@ -80,27 +77,15 @@ public class CallStatsActivity extends ListActivity implements
    private TextView mSumHeaderView;
    private TextView mDateFilterView;

    private final Handler mHandler = new Handler();

    private final ContentObserver mCallLogObserver = new CustomContentObserver();
    private final ContentObserver mContactsObserver = new CustomContentObserver();
    private boolean mRefreshDataRequired = true;

    private int mCallTypeFilter = CallStatsQueryHandler.CALL_TYPE_ALL;

    private class CustomContentObserver extends ContentObserver {
        public CustomContentObserver() {
            super(mHandler);
        }

    private final ContentObserver mObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            mRefreshDataRequired = true;
        }
    }
    };

    public class CallStatsNavAdapter extends ArrayAdapter<String> {

        public CallStatsNavAdapter(Context context, int textResourceId, Object[] objects) {
            super(context, textResourceId, mNavItems);
        }
@@ -116,16 +101,17 @@ public class CallStatsActivity extends ListActivity implements
        }

        public View getCustomView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = getLayoutInflater();
            View item = inflater.inflate(R.layout.call_stats_nav_item, parent, false);
            if (convertView == null) {
                convertView = getLayoutInflater().inflate(R.layout.call_stats_nav_item, parent, false);
            }

            TextView label = (TextView) item.findViewById(R.id.call_stats_nav_text);
            TextView label = (TextView) convertView.findViewById(R.id.call_stats_nav_text);
            label.setText(mNavItems[position]);

            ImageView icon = (ImageView) item.findViewById(R.id.call_stats_nav_icon);
            ImageView icon = (ImageView) convertView.findViewById(R.id.call_stats_nav_icon);
            icon.setImageResource(CALL_DIRECTION_RESOURCES[position]);

            return item;
            return convertView;
        }
    }

@@ -135,16 +121,13 @@ public class CallStatsActivity extends ListActivity implements

        final ContentResolver cr = getContentResolver();
        mCallStatsQueryHandler = new CallStatsQueryHandler(cr, this);
        cr.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver);
        cr.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, mContactsObserver);
        cr.registerContentObserver(CallLog.CONTENT_URI, true, mObserver);
        cr.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, mObserver);

        Resources res = getResources();
        mNavItems = res.getStringArray(R.array.call_stats_nav_items);
        mNavItems = getResources().getStringArray(R.array.call_stats_nav_items);
        configureActionBar();

        String currentCountryIso = ContactsUtils.getCurrentCountryIso(this);
        mAdapter = new CallStatsAdapter(this,
                new ContactInfoHelper(this, currentCountryIso));
        mAdapter = new CallStatsAdapter(this);
        setListAdapter(mAdapter);

        getListView().setItemsCanFocus(true);
@@ -214,7 +197,8 @@ public class CallStatsActivity extends ListActivity implements

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        switch (item.getItemId()) {
        final int itemId = item.getItemId();
        switch (itemId) {
            case android.R.id.home: {
                onHomeSelected();
                break;
@@ -234,15 +218,10 @@ public class CallStatsActivity extends ListActivity implements
                invalidateOptionsMenu();
                break;
            }
            case R.id.sort_by_duration: {
                mSortByDuration = true;
                mAdapter.sort(true);
                invalidateOptionsMenu();
                break;
            }
            case R.id.sort_by_duration:
            case R.id.sort_by_count: {
                mSortByDuration = false;
                mAdapter.sort(false);
                mSortByDuration = itemId == R.id.sort_by_duration;
                mAdapter.updateDisplayedData(mCallTypeFilter, mSortByDuration);
                invalidateOptionsMenu();
                break;
            }
@@ -261,7 +240,7 @@ public class CallStatsActivity extends ListActivity implements
    @Override
    public boolean onNavigationItemSelected(int position, long id) {
        mCallTypeFilter = position;
        mCallStatsQueryHandler.fetchCalls(mFilterFrom, mFilterTo);
        mAdapter.updateDisplayedData(mCallTypeFilter, mSortByDuration);
        return true;
    }

@@ -270,12 +249,13 @@ public class CallStatsActivity extends ListActivity implements
     * fetched or updated.
     */
    @Override
    public void onCallsFetched(Cursor cursor) {
    public void onCallsFetched(Map<ContactInfo, CallStatsDetails> calls) {
        if (isFinishing()) {
            return;
        }
        mAdapter.processCursor(cursor, mCallTypeFilter, mFilterFrom, mFilterTo, mSortByDuration);
        cursor.close();

        mAdapter.updateData(calls, mFilterFrom, mFilterTo);
        mAdapter.updateDisplayedData(mCallTypeFilter, mSortByDuration);
        updateHeader();
    }

@@ -295,19 +275,13 @@ public class CallStatsActivity extends ListActivity implements
    @Override
    public void onDestroy() {
        super.onDestroy();
        mAdapter.stopRequestProcessing();
        getContentResolver().unregisterContentObserver(mCallLogObserver);
        getContentResolver().unregisterContentObserver(mContactsObserver);
        getContentResolver().unregisterContentObserver(mObserver);
    }

    private void fetchCalls() {
        mCallStatsQueryHandler.fetchCalls(mFilterFrom, mFilterTo);
    }

    public void startCallsQuery() {
        mCallStatsQueryHandler.fetchCalls(mFilterFrom, mFilterTo);
    }

    private void updateHeader() {
        final String callCount = mAdapter.getTotalCallCountString();
        final String duration = mAdapter.getFullDurationString(false);
@@ -324,15 +298,16 @@ public class CallStatsActivity extends ListActivity implements
            mDateFilterView.setText(DateUtils.formatDateRange(this, mFilterFrom, mFilterTo, 0));
            mDateFilterView.setVisibility(View.VISIBLE);
        }

        findViewById(R.id.call_stats_header).setVisibility(View.VISIBLE);
    }

    public void callSelectedEntry() {
        int position = getListView().getSelectedItemPosition();
        if (position < 0) {
            // In touch mode you may often not have something selected, so
            // just call the first entry to make sure that [send] [send] calls
            // the
            // most recent entry.
            // just call the first entry to make sure that [send] calls
            // the most recent entry.
            position = 0;
        }
        final CallStatsDetails item = mAdapter.getItem(position);
@@ -344,22 +319,21 @@ public class CallStatsActivity extends ListActivity implements
            // This number can't be called, do nothing
            return;
        }
        Intent intent;

        Uri callUri;
        // If "number" is really a SIP address, construct a sip: URI.
        if (PhoneNumberUtils.isUriNumber(number)) {
            intent = ContactsUtils.getCallIntent(Uri.fromParts(
                    Constants.SCHEME_SIP, number, null));
            callUri = Uri.fromParts(Constants.SCHEME_SIP, number, null);
        } else {
            if (!number.startsWith("+")) {
                // If the caller-id matches a contact with a better qualified
                // number, use it
                String countryIso = item.countryIso;
                number = mAdapter.getBetterNumberFromContacts(number,
                        countryIso);
                number = mAdapter.getBetterNumberFromContacts(number, item.countryIso);
            }
            intent = ContactsUtils.getCallIntent(Uri.fromParts(
                    Constants.SCHEME_TEL, number, null));
            callUri = Uri.fromParts(Constants.SCHEME_TEL, number, null);
        }

        final Intent intent = ContactsUtils.getCallIntent(callUri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        startActivity(intent);
@@ -372,7 +346,7 @@ public class CallStatsActivity extends ListActivity implements
            // Mark all entries in the contact info cache as out of date, so
            // they will be looked up again once being shown.
            mAdapter.invalidateCache();
            startCallsQuery();
            fetchCalls();
            mRefreshDataRequired = false;
        }
    }
+44 −226
Original line number Diff line number Diff line
@@ -19,10 +19,7 @@ package com.android.contacts.callstats;

import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -32,15 +29,14 @@ import com.android.contacts.ContactPhotoManager;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.calllog.CallLogAdapterHelper;
import com.android.contacts.calllog.CallLogAdapterHelper.NumberWithCountryIso;
import com.android.contacts.calllog.ContactInfo;
import com.android.contacts.calllog.ContactInfoHelper;
import com.android.contacts.calllog.PhoneNumberHelper;
import com.android.contacts.util.UriUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
@@ -64,25 +60,10 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>
    private final CallStatsDetailHelper mCallStatsDetailHelper;

    private ArrayList<CallStatsDetails> mAllItems;
    private ConcurrentHashMap<ContactInfo, CallStatsDetails> mInfoLookup;
    private CallStatsDetails mTotalItem;
    private Map<ContactInfo, CallStatsDetails> mInfoLookup;
    private boolean mLoading = true;

    private long mFullDuration = 0;
    private long mFullInDuration = 0;
    private long mFullOutDuration = 0;
    private long mTotalIncomingCount = 0;
    private long mTotalOutgoingCount = 0;
    private long mTotalMissedCount = 0;

    /**
     * Separate list to hold [this]/[sum] percent values for the respective
     * items
     */
    private ArrayList<Float> mPercentageMap = new ArrayList<Float>();
    /**
     * Separate list to hold [this]/[highest] ratio values for the respective
     * items
     */
    private ArrayList<Float> mRatioMap = new ArrayList<Float>();
    private int mType = CallStatsQueryHandler.CALL_TYPE_ALL;
    private long mFilterFrom;
    private long mFilterTo;
@@ -109,7 +90,7 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>
        }
    };

    CallStatsAdapter(Context context, ContactInfoHelper contactInfoHelper) {
    CallStatsAdapter(Context context) {
        super(context, R.layout.call_stats_list_item, R.id.number);

        setNotifyOnChange(false);
@@ -121,176 +102,51 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>
        Resources resources = mContext.getResources();
        PhoneNumberHelper phoneNumberHelper = new PhoneNumberHelper(resources);

        final String currentCountryIso = ContactsUtils.getCurrentCountryIso(mContext);
        final ContactInfoHelper contactInfoHelper = new ContactInfoHelper(mContext, currentCountryIso);

        mAdapterHelper = new CallLogAdapterHelper(mContext, this,
                contactInfoHelper, phoneNumberHelper);
        mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
        mCallStatsDetailHelper = new CallStatsDetailHelper(resources, phoneNumberHelper);
    }

    private void resetData() {
        mFullDuration = 0;
        mFullInDuration = 0;
        mFullOutDuration = 0;
        mTotalIncomingCount = 0;
        mTotalOutgoingCount = 0;
        mTotalMissedCount = 0;
        mAllItems.clear();
    public void updateData(Map<ContactInfo, CallStatsDetails> calls, long from, long to) {
        mInfoLookup.clear();
        mPercentageMap.clear();
        mRatioMap.clear();
    }

    public void processCursor(Cursor c, int qType, long from, long to, boolean sortByDuration) {
        final int count = c.getCount();
        mInfoLookup.putAll(calls);
        mFilterFrom = from;
        mFilterTo = to;
        mType = qType;

        resetData();

        if (count == 0) {
            clear();
            notifyDataSetChanged();
            return;
        }

        c.moveToFirst();

        CallStatsDetails pending = null;

        do {
            final String number = c.getString(CallStatsQuery.NUMBER);
            final long duration = c.getLong(CallStatsQuery.DURATION);
            final int callType = c.getInt(CallStatsQuery.CALL_TYPE);

            if (pending != null && !ContactsUtils.phoneNumbersEqual(pending.number.toString(), number)) {
                mAllItems.add(pending);
                pending = null;
            }

            if (pending == null) {
                final long date = c.getLong(CallStatsQuery.DATE);
                final String countryIso = c.getString(CallStatsQuery.COUNTRY_ISO);
                final String geocode = c.getString(CallStatsQuery.GEOCODED_LOCATION);
                final ContactInfo cachedContactInfo = getContactInfoFromCallStats(c);
                final ContactInfo info = mAdapterHelper.lookupContact(
                        number, countryIso, cachedContactInfo);

                pending = new CallStatsDetails(number, info, countryIso, geocode, date);
                mInfoLookup.put(cachedContactInfo, pending);
            }

            pending.addTimeOrMissed(callType, duration);

            switch (callType) {
                case Calls.INCOMING_TYPE:
                    mTotalIncomingCount++;
                    mFullInDuration += duration;
                    break;
                case Calls.OUTGOING_TYPE:
                    mTotalOutgoingCount++;
                    mFullOutDuration += duration;
                    break;
                case Calls.MISSED_TYPE:
                    mTotalMissedCount++;
                    break;
            }
            mFullDuration += duration;
        } while (c.moveToNext());
        mAllItems.clear();
        mTotalItem = new CallStatsDetails(null, null, null, null, 0);

        if (pending != null) {
            mAllItems.add(pending);
        for (Map.Entry<ContactInfo, CallStatsDetails> entry : calls.entrySet()) {
            final CallStatsDetails call = entry.getValue();
            mAllItems.add(call);
            mTotalItem.mergeWith(call);
            mAdapterHelper.lookupContact(call.number, call.countryIso, entry.getKey());
        }
        mergeItemsByNumber();
        sort(sortByDuration);
    }

    public void sort(boolean sortByDuration) {
        clear();
        mRatioMap.clear();
        mPercentageMap.clear();
    public void updateDisplayedData(int type, boolean sortByDuration) {
        mType = type;
        mSortByDuration = sortByDuration;

        Collections.sort(mAllItems, sortByDuration ? mDurationComparator : mCountComparator);
        float totalValue = sortByDuration ? getTotalDuration() : getTotalCount();
        float firstValue = -1;

        for (CallStatsDetails item : mAllItems) {
            long value = sortByDuration
                    ? item.getRequestedDuration(mType)
                    : item.getRequestedCount(mType);
        clear();

            if (value == 0) {
                continue;
        for (CallStatsDetails call : mAllItems) {
            if (sortByDuration && call.getRequestedDuration(type) > 0) {
                add(call);
            } else if (!sortByDuration && call.getRequestedCount(type) > 0) {
                add(call);
            }

            if (firstValue < 0) firstValue = value;

            mRatioMap.add((float) value / firstValue);
            mPercentageMap.add((float) value * 100F / totalValue);
            add(item);
        }

        mLoading = false;
        notifyDataSetChanged();
    }

    private void mergeItemsByNumber() {
        // temporarily store items marked for removal
        ArrayList<CallStatsDetails> toRemove = new ArrayList<CallStatsDetails>();

        // numbers in non-international format will be the first
        for (int i = 0; i < mAllItems.size(); i++) {
            CallStatsDetails outerItem = mAllItems.get(i);

            final String currentFormattedNumber = outerItem.number.toString();
            if (outerItem.number.toString().startsWith("+")) {
                continue; // we don't check numbers starting with +, only removing from this point
            }

            for (int j = mAllItems.size() - 1; j > i; j--) {
                final CallStatsDetails innerItem = mAllItems.get(j);
                final String innerNumber = innerItem.number.toString();

                if (ContactsUtils.phoneNumbersEqual(currentFormattedNumber, innerNumber)) {
                    outerItem.mergeWith(innerItem);
                    toRemove.add(innerItem);
                    break; // we don't have multiple items with the same number, stop
                }
            }
        }
        for (CallStatsDetails bye : toRemove) {
            mAllItems.remove(bye);
        }
    }

    private long getTotalDuration() {
        switch (mType) {
            case CallStatsQueryHandler.CALL_TYPE_ALL:
                return mFullDuration;
            case Calls.INCOMING_TYPE:
                return mFullInDuration;
            case Calls.OUTGOING_TYPE:
                return mFullOutDuration;
            case Calls.MISSED_TYPE:
                return mTotalMissedCount;
        }
        return 0;
    }

    private long getTotalCount() {
        switch (mType) {
            case CallStatsQueryHandler.CALL_TYPE_ALL:
                return mTotalIncomingCount + mTotalOutgoingCount + mTotalMissedCount;
            case Calls.INCOMING_TYPE:
                return mTotalIncomingCount;
            case Calls.OUTGOING_TYPE:
                return mTotalOutgoingCount;
            case Calls.MISSED_TYPE:
                return mTotalMissedCount;
        }
        return 0;
    }

    public void stopRequestProcessing() {
        mAdapterHelper.stopRequestProcessing();
    }
@@ -304,55 +160,33 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>
    }

    public String getTotalCallCountString() {
        long callCount = 0;

        switch (mType) {
            case CallStatsQueryHandler.CALL_TYPE_ALL:
                callCount = mTotalIncomingCount + mTotalOutgoingCount + mTotalMissedCount;
                break;
            case Calls.INCOMING_TYPE:
                callCount = mTotalIncomingCount;
                break;
            case Calls.OUTGOING_TYPE:
                callCount = mTotalOutgoingCount;
                break;
            case Calls.MISSED_TYPE:
                callCount = mTotalMissedCount;
                break;
        }

        return CallStatsDetailHelper.getCallCountString(mContext.getResources(), callCount);
        return CallStatsDetailHelper.getCallCountString(
                mContext.getResources(), mTotalItem.getRequestedCount(mType));
    }

    public String getFullDurationString(boolean withSeconds) {
        long duration;

        switch (mType) {
            case CallStatsQueryHandler.CALL_TYPE_ALL:
                duration = mFullDuration;
                break;
            case Calls.INCOMING_TYPE:
                duration = mFullInDuration;
                break;
            case Calls.OUTGOING_TYPE:
                duration = mFullOutDuration;
                break;
            default:
                return null;
        }

        final long duration = mTotalItem.getRequestedDuration(mType);
        return CallStatsDetailHelper.getDurationString(
                mContext.getResources(), duration, withSeconds);
    }

    @Override
    public boolean isEmpty() {
        if (mLoading) {
            return false;
        }
        return super.isEmpty();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater)
                mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = convertView;
        if (v == null) {
            LayoutInflater inflater = (LayoutInflater)
                    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.call_stats_list_item, parent, false);
        }

        findAndCacheViews(v);
        bindView(position, v);

@@ -361,16 +195,15 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>

    private void bindView(int position, View v) {
        final CallStatsListItemViews views = (CallStatsListItemViews) v.getTag();
        CallStatsDetails details = getItem(position);
        final float percent = mPercentageMap.get(position);
        final float ratio = mRatioMap.get(position);
        final CallStatsDetails details = getItem(position);
        final CallStatsDetails first = getItem(0);

        views.primaryActionView.setVisibility(View.VISIBLE);
        views.primaryActionView.setTag(IntentProvider.getCallStatsDetailIntentProvider(
                details, mFilterFrom, mFilterTo, mSortByDuration));

        mCallStatsDetailHelper.setCallStatsDetails(views.callStatsDetailViews,
                details, mType, mSortByDuration, percent, ratio);
                details, first, mTotalItem, mType, mSortByDuration);
        setPhoto(views, details.photoId, details.contactUri);

        // Listen for the first draw
@@ -388,21 +221,6 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails>
        mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, true);
    }

    private ContactInfo getContactInfoFromCallStats(Cursor c) {
        ContactInfo info = new ContactInfo();
        info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallStatsQuery.CACHED_LOOKUP_URI));
        info.name = c.getString(CallStatsQuery.CACHED_NAME);
        info.type = c.getInt(CallStatsQuery.CACHED_NUMBER_TYPE);
        info.label = c.getString(CallStatsQuery.CACHED_NUMBER_LABEL);
        String matchedNumber = c.getString(CallStatsQuery.CACHED_MATCHED_NUMBER);
        info.number = matchedNumber == null ? c.getString(CallStatsQuery.NUMBER) : matchedNumber;
        info.normalizedNumber = c.getString(CallStatsQuery.CACHED_NORMALIZED_NUMBER);
        info.photoId = c.getLong(CallStatsQuery.CACHED_PHOTO_ID);
        info.photoUri = null; // We do not cache the photo URI.
        info.formattedNumber = c.getString(CallStatsQuery.CACHED_FORMATTED_NUMBER);
        return info;
    }

    @Override
    public void dataSetChanged() {
        notifyDataSetChanged();
+3 −5

File changed.

Preview size limit exceeded, changes collapsed.

Loading