diff options
Diffstat (limited to 'src')
12 files changed, 76 insertions, 1598 deletions
diff --git a/src/com/android/dialer/PhoneCallDetailsHelper.java b/src/com/android/dialer/PhoneCallDetailsHelper.java index 0da0d0c39..6f13b2e9d 100644 --- a/src/com/android/dialer/PhoneCallDetailsHelper.java +++ b/src/com/android/dialer/PhoneCallDetailsHelper.java @@ -123,16 +123,9 @@ public class PhoneCallDetailsHelper { numberText = displayNumber; labelText = TextUtils.isEmpty(numberFormattedLabel) ? numberText : numberFormattedLabel; - // We have a real phone number as "numberView" so make it always LTR - if (views.numberView != null) { - views.numberView.setTextDirection(View.TEXT_DIRECTION_LTR); - } } views.nameView.setText(nameText); - if (views.numberView != null) { - views.numberView.setText(numberText); - } views.labelView.setText(labelText); views.labelView.setVisibility(TextUtils.isEmpty(labelText) ? View.GONE : View.VISIBLE); diff --git a/src/com/android/dialer/PhoneCallDetailsViews.java b/src/com/android/dialer/PhoneCallDetailsViews.java index 09f50fbe3..4e482109b 100644 --- a/src/com/android/dialer/PhoneCallDetailsViews.java +++ b/src/com/android/dialer/PhoneCallDetailsViews.java @@ -30,17 +30,14 @@ public final class PhoneCallDetailsViews { public final View callTypeView; public final CallTypeIconsView callTypeIcons; public final TextView callTypeAndDate; - public final TextView numberView; public final TextView labelView; private PhoneCallDetailsViews(TextView nameView, View callTypeView, - CallTypeIconsView callTypeIcons, TextView callTypeAndDate, TextView numberView, - TextView labelView) { + CallTypeIconsView callTypeIcons, TextView callTypeAndDate, TextView labelView) { this.nameView = nameView; this.callTypeView = callTypeView; this.callTypeIcons = callTypeIcons; this.callTypeAndDate = callTypeAndDate; - this.numberView = numberView; this.labelView = labelView; } @@ -56,7 +53,6 @@ public final class PhoneCallDetailsViews { view.findViewById(R.id.call_type), (CallTypeIconsView) view.findViewById(R.id.call_type_icons), (TextView) view.findViewById(R.id.call_count_and_date), - (TextView) view.findViewById(R.id.number), (TextView) view.findViewById(R.id.label)); } @@ -66,7 +62,6 @@ public final class PhoneCallDetailsViews { new View(context), new CallTypeIconsView(context), new TextView(context), - new TextView(context), new TextView(context)); } } diff --git a/src/com/android/dialer/calllog/CallLogActivity.java b/src/com/android/dialer/calllog/CallLogActivity.java index 03ccef7ab..2d976a929 100644 --- a/src/com/android/dialer/calllog/CallLogActivity.java +++ b/src/com/android/dialer/calllog/CallLogActivity.java @@ -38,14 +38,14 @@ import android.view.MenuItem; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; -import com.android.dialer.calllog.NewCallLogFragment; +import com.android.dialer.calllog.CallLogFragment; public class CallLogActivity extends Activity { private ViewPager mViewPager; private ViewPagerAdapter mViewPagerAdapter; - private NewCallLogFragment mAllCallsFragment; - private NewCallLogFragment mMissedCallsFragment; + private CallLogFragment mAllCallsFragment; + private CallLogFragment mMissedCallsFragment; private static final int TAB_INDEX_ALL = 0; private static final int TAB_INDEX_MISSED = 1; @@ -61,10 +61,10 @@ public class CallLogActivity extends Activity { public Fragment getItem(int position) { switch (position) { case TAB_INDEX_ALL: - mAllCallsFragment = new NewCallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL); + mAllCallsFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL); return mAllCallsFragment; case TAB_INDEX_MISSED: - mMissedCallsFragment = new NewCallLogFragment(Calls.MISSED_TYPE); + mMissedCallsFragment = new CallLogFragment(Calls.MISSED_TYPE); return mMissedCallsFragment; } throw new IllegalStateException("No fragment at position " + position); @@ -114,7 +114,7 @@ public class CallLogActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.call_log_activity_new); + setContentView(R.layout.call_log_activity); final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); @@ -159,7 +159,7 @@ public class CallLogActivity extends Activity { public boolean onPrepareOptionsMenu(Menu menu) { final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all); - final NewCallLogAdapter adapter = mAllCallsFragment.getAdapter(); + final CallLogAdapter adapter = mAllCallsFragment.getAdapter(); // Check if all the menu items are inflated correctly. As a shortcut, we assume all // menu items are ready if the first item is non-null. if (itemDeleteAll != null) { diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index 46bb4fd28..2c81f46fe 100644 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -46,7 +46,7 @@ import java.util.LinkedList; /** * Adapter class to fill in data for the Call Log. */ -/*package*/ class CallLogAdapter extends GroupingListAdapter +public class CallLogAdapter extends GroupingListAdapter implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator { /** Interface used to initiate a refresh of the content. */ public interface CallFetcher { @@ -227,7 +227,7 @@ import java.util.LinkedList; } }; - CallLogAdapter(Context context, CallFetcher callFetcher, + public CallLogAdapter(Context context, CallFetcher callFetcher, ContactInfoHelper contactInfoHelper) { super(context); @@ -259,7 +259,7 @@ import java.util.LinkedList; mCallFetcher.fetchCalls(); } - void setLoading(boolean loading) { + public void setLoading(boolean loading) { mLoading = loading; } @@ -518,6 +518,7 @@ import java.util.LinkedList; views.primaryActionView.setTag( IntentProvider.getCallDetailIntentProvider( getCursor(), c.getPosition(), c.getLong(CallLogQuery.ID), count)); + // Store away the voicemail information so we can play it directly. if (callType == Calls.VOICEMAIL_TYPE) { String voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI); @@ -715,7 +716,7 @@ import java.util.LinkedList; private void setPhoto(CallLogListItemViews views, long photoId, Uri contactUri) { views.quickContactView.assignContactUri(contactUri); - mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, true); + mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, false /* darkTheme */); } /** diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java index bc0856f75..5d750044f 100644 --- a/src/com/android/dialer/calllog/CallLogFragment.java +++ b/src/com/android/dialer/calllog/CallLogFragment.java @@ -34,7 +34,6 @@ import android.provider.ContactsContract; import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; -import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -59,7 +58,8 @@ import com.google.common.annotations.VisibleForTesting; import java.util.List; /** - * Displays a list of call log entries. + * Displays a list of call log entries. To filter for a particular kind of call + * (all, missed or voicemails), specify it in the constructor. */ public class CallLogFragment extends ListFragment implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher { @@ -81,7 +81,6 @@ public class CallLogFragment extends ListFragment private View mStatusMessageView; private TextView mStatusMessageText; private TextView mStatusMessageAction; - private TextView mFilterStatusView; private KeyguardManager mKeyguardManager; private boolean mEmptyLoaderRunning; @@ -114,11 +113,30 @@ public class CallLogFragment extends ListFragment // Default to all calls. private int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL; + // Log limit - if no limit is specified, then the default in {@link CallLogQueryHandler} + // will be used. + private int mLogLimit = -1; + + public CallLogFragment() { + this(CallLogQueryHandler.CALL_TYPE_ALL, -1); + } + + public CallLogFragment(int filterType) { + this(filterType, -1); + } + + public CallLogFragment(int filterType, int logLimit) { + super(); + mCallTypeFilter = filterType; + mLogLimit = logLimit; + } + @Override public void onCreate(Bundle state) { super.onCreate(state); - mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(), this); + mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(), + this, mLogLimit); mKeyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE); getActivity().getContentResolver().registerContentObserver( @@ -126,6 +144,7 @@ public class CallLogFragment extends ListFragment getActivity().getContentResolver().registerContentObserver( ContactsContract.Contacts.CONTENT_URI, true, mContactsObserver); setHasOptionsMenu(true); + updateCallList(mCallTypeFilter); } /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */ @@ -210,13 +229,13 @@ public class CallLogFragment extends ListFragment mStatusMessageView = view.findViewById(R.id.voicemail_status); mStatusMessageText = (TextView) view.findViewById(R.id.voicemail_status_message); mStatusMessageAction = (TextView) view.findViewById(R.id.voicemail_status_action); - mFilterStatusView = (TextView) view.findViewById(R.id.filter_status); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + updateEmptyMessage(mCallTypeFilter); String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); mAdapter = new CallLogAdapter(getActivity(), this, new ContactInfoHelper(getActivity(), currentCountryIso)); @@ -320,132 +339,30 @@ public class CallLogFragment extends ListFragment mCallLogQueryHandler.fetchVoicemailStatus(); } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.call_log_options, menu); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all); - // Check if all the menu items are inflated correctly. As a shortcut, we assume all - // menu items are ready if the first item is non-null. - if (itemDeleteAll != null) { - itemDeleteAll.setEnabled(mAdapter != null && !mAdapter.isEmpty()); - - showAllFilterMenuOptions(menu); - hideCurrentFilterMenuOption(menu); - - // Only hide if not available. Let the above calls handle showing. - if (!mVoicemailSourcesAvailable) { - menu.findItem(R.id.show_voicemails_only).setVisible(false); - } - } - } - - private void hideCurrentFilterMenuOption(Menu menu) { - MenuItem item = null; - switch (mCallTypeFilter) { - case CallLogQueryHandler.CALL_TYPE_ALL: - item = menu.findItem(R.id.show_all_calls); - break; - case Calls.INCOMING_TYPE: - item = menu.findItem(R.id.show_incoming_only); - break; - case Calls.OUTGOING_TYPE: - item = menu.findItem(R.id.show_outgoing_only); - break; - case Calls.MISSED_TYPE: - item = menu.findItem(R.id.show_missed_only); - break; - case Calls.VOICEMAIL_TYPE: - menu.findItem(R.id.show_voicemails_only); - break; - } - if (item != null) { - item.setVisible(false); - } - } - - private void showAllFilterMenuOptions(Menu menu) { - menu.findItem(R.id.show_all_calls).setVisible(true); - menu.findItem(R.id.show_incoming_only).setVisible(true); - menu.findItem(R.id.show_outgoing_only).setVisible(true); - menu.findItem(R.id.show_missed_only).setVisible(true); - menu.findItem(R.id.show_voicemails_only).setVisible(true); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.delete_all: - ClearCallLogDialog.show(getFragmentManager()); - return true; - - case R.id.show_outgoing_only: - // We only need the phone call receiver when there is an active call type filter. - // Not many people may use the filters so don't register the receiver until now . - registerPhoneCallReceiver(); - mCallLogQueryHandler.fetchCalls(Calls.OUTGOING_TYPE); - updateFilterTypeAndHeader(Calls.OUTGOING_TYPE); - return true; - - case R.id.show_incoming_only: - registerPhoneCallReceiver(); - mCallLogQueryHandler.fetchCalls(Calls.INCOMING_TYPE); - updateFilterTypeAndHeader(Calls.INCOMING_TYPE); - return true; - - case R.id.show_missed_only: - registerPhoneCallReceiver(); - mCallLogQueryHandler.fetchCalls(Calls.MISSED_TYPE); - updateFilterTypeAndHeader(Calls.MISSED_TYPE); - return true; - - case R.id.show_voicemails_only: - registerPhoneCallReceiver(); - mCallLogQueryHandler.fetchCalls(Calls.VOICEMAIL_TYPE); - updateFilterTypeAndHeader(Calls.VOICEMAIL_TYPE); - return true; - - case R.id.show_all_calls: - // Filter is being turned off, receiver no longer needed. - unregisterPhoneCallReceiver(); - mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL); - updateFilterTypeAndHeader(CallLogQueryHandler.CALL_TYPE_ALL); - return true; - - default: - return false; + private void updateCallList(int filterType) { + if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) { + unregisterPhoneCallReceiver(); + } else { + // TODO krelease: Make this work + //registerPhoneCallReceiver(); } + mCallLogQueryHandler.fetchCalls(filterType); } - private void updateFilterTypeAndHeader(int filterType) { - mCallTypeFilter = filterType; - + private void updateEmptyMessage(int filterType) { + final String message; switch (filterType) { - case CallLogQueryHandler.CALL_TYPE_ALL: - mFilterStatusView.setVisibility(View.GONE); - break; - case Calls.INCOMING_TYPE: - showFilterStatus(R.string.call_log_incoming_header); - break; - case Calls.OUTGOING_TYPE: - showFilterStatus(R.string.call_log_outgoing_header); - break; case Calls.MISSED_TYPE: - showFilterStatus(R.string.call_log_missed_header); + message = getString(R.string.recentMissed_empty); break; - case Calls.VOICEMAIL_TYPE: - showFilterStatus(R.string.call_log_voicemail_header); + case CallLogQueryHandler.CALL_TYPE_ALL: + message = getString(R.string.recentCalls_empty); break; + default: + throw new IllegalArgumentException("Unexpected filter type in CallLogFragment: " + + filterType); } - } - - private void showFilterStatus(int resId) { - mFilterStatusView.setText(resId); - mFilterStatusView.setVisibility(View.VISIBLE); + ((TextView) getListView().getEmptyView()).setText(message); } public void callSelectedEntry() { @@ -489,7 +406,6 @@ public class CallLogFragment extends ListFragment } } - @VisibleForTesting CallLogAdapter getAdapter() { return mAdapter; } @@ -547,6 +463,8 @@ public class CallLogFragment extends ListFragment updateOnTransition(true); } + // TODO krelease: Figure out if we still need this. If so, it should be probably be moved to + // the call log activity instead, or done only in a single call log fragment. private void updateOnTransition(boolean onEntry) { // We don't want to update any call data when keyguard is on because the user has likely not // seen the new calls yet. @@ -570,9 +488,13 @@ public class CallLogFragment extends ListFragment getActivity().startService(serviceIntent); } + // TODO krelease: Make the ViewPager switch to the correct tab (All) when a phone call is + // placed. + // This should probably be moved to the call log activity. /** * Register a phone call filter to reset the call type when a phone call is place. */ + /* private void registerPhoneCallReceiver() { if (mPhoneStateListener != null) { return; // Already registered. @@ -592,13 +514,13 @@ public class CallLogFragment extends ListFragment if (getActivity() == null || getActivity().isFinishing()) { return; } - updateFilterTypeAndHeader(CallLogQueryHandler.CALL_TYPE_ALL); } }); } }; mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); } + */ /** * Un-registers the phone call receiver. diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java index bccd4f45b..fdebeb166 100644 --- a/src/com/android/dialer/calllog/CallLogListItemHelper.java +++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java @@ -27,8 +27,12 @@ import com.android.dialer.R; /** * Helper class to fill in the views of a call log entry. + * TODO krelease: The only difference between this and the original is that we don't touch + * divider views, which are not present in the new dialer. Once the new dialer replaces + * the old one, we can replace it entirely. Otherwise we would have redundant divider=null + * checks all over the place. */ -/*package*/ class CallLogListItemHelper { +/* package */class CallLogListItemHelper { /** Helper for populating the details of a phone call. */ private final PhoneCallDetailsHelper mPhoneCallDetailsHelper; /** Helper for handling phone numbers. */ @@ -67,15 +71,12 @@ import com.android.dialer.R; if (canPlay) { // Playback action takes preference. configurePlaySecondaryAction(views, isHighlighted); - views.dividerView.setVisibility(View.VISIBLE); } else if (canCall) { // Call is the secondary action. configureCallSecondaryAction(views, details); - views.dividerView.setVisibility(View.VISIBLE); } else { // No action available. views.secondaryActionView.setVisibility(View.GONE); - views.dividerView.setVisibility(View.GONE); } } @@ -83,7 +84,7 @@ import com.android.dialer.R; private void configureCallSecondaryAction(CallLogListItemViews views, PhoneCallDetails details) { views.secondaryActionView.setVisibility(View.VISIBLE); - views.secondaryActionView.setImageResource(R.drawable.ic_ab_dialer_holo_dark); + views.secondaryActionView.setImageResource(R.drawable.ic_ab_dialer_holo_light); views.secondaryActionView.setContentDescription(getCallActionDescription(details)); } @@ -103,7 +104,7 @@ import com.android.dialer.R; private void configurePlaySecondaryAction(CallLogListItemViews views, boolean isHighlighted) { views.secondaryActionView.setVisibility(View.VISIBLE); views.secondaryActionView.setImageResource( - isHighlighted ? R.drawable.ic_play_active_holo_dark : R.drawable.ic_play_holo_dark); + isHighlighted ? R.drawable.ic_play_active_holo_dark : R.drawable.ic_play_holo_light); views.secondaryActionView.setContentDescription( mResources.getString(R.string.description_call_log_play_button)); } diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java index 86f531365..0dd4f6344 100644 --- a/src/com/android/dialer/calllog/CallLogListItemViews.java +++ b/src/com/android/dialer/calllog/CallLogListItemViews.java @@ -36,8 +36,6 @@ public final class CallLogListItemViews { public final View primaryActionView; /** The secondary action button on the entry. */ public final ImageView secondaryActionView; - /** The divider between the primary and secondary actions. */ - public final View dividerView; /** The details of the phone call. */ public final PhoneCallDetailsViews phoneCallDetailsViews; /** The text of the header of a section. */ @@ -46,13 +44,11 @@ public final class CallLogListItemViews { public final View bottomDivider; private CallLogListItemViews(QuickContactBadge quickContactView, View primaryActionView, - ImageView secondaryActionView, View dividerView, - PhoneCallDetailsViews phoneCallDetailsViews, + ImageView secondaryActionView, PhoneCallDetailsViews phoneCallDetailsViews, TextView listHeaderTextView, View bottomDivider) { this.quickContactView = quickContactView; this.primaryActionView = primaryActionView; this.secondaryActionView = secondaryActionView; - this.dividerView = dividerView; this.phoneCallDetailsViews = phoneCallDetailsViews; this.listHeaderTextView = listHeaderTextView; this.bottomDivider = bottomDivider; @@ -63,7 +59,6 @@ public final class CallLogListItemViews { (QuickContactBadge) view.findViewById(R.id.quick_contact_photo), view.findViewById(R.id.primary_action_view), (ImageView) view.findViewById(R.id.secondary_action_icon), - view.findViewById(R.id.divider), PhoneCallDetailsViews.fromView(view), (TextView) view.findViewById(R.id.call_log_header), view.findViewById(R.id.call_log_divider)); @@ -75,7 +70,6 @@ public final class CallLogListItemViews { new QuickContactBadge(context), new View(context), new ImageView(context), - new View(context), PhoneCallDetailsViews.createForTest(context), new TextView(context), new View(context)); diff --git a/src/com/android/dialer/calllog/NewCallLogAdapter.java b/src/com/android/dialer/calllog/NewCallLogAdapter.java deleted file mode 100644 index c2f7c71e6..000000000 --- a/src/com/android/dialer/calllog/NewCallLogAdapter.java +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.dialer.calllog; - -import android.content.ContentValues; -import android.content.Context; -import android.content.res.Resources; -import android.database.Cursor; -import android.net.Uri; -import android.os.Handler; -import android.os.Message; -import android.provider.CallLog.Calls; -import android.provider.ContactsContract.PhoneLookup; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; - -import com.android.common.widget.GroupingListAdapter; -import com.android.contacts.common.ContactPhotoManager; -import com.android.contacts.common.util.UriUtils; -import com.android.dialer.PhoneCallDetails; -import com.android.dialer.PhoneCallDetailsHelper; -import com.android.dialer.R; -import com.android.dialer.util.ExpirableCache; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Objects; - -import java.util.LinkedList; - -/** - * Adapter class to fill in data for the Call Log. - */ -public class NewCallLogAdapter extends GroupingListAdapter - implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator { - /** Interface used to initiate a refresh of the content. */ - public interface CallFetcher { - public void fetchCalls(); - } - - /** - * Stores a phone number of a call with the country code where it originally occurred. - * <p> - * Note the country does not necessarily specifies the country of the phone number itself, but - * it is the country in which the user was in when the call was placed or received. - */ - private static final class NumberWithCountryIso { - public final String number; - public final String countryIso; - - public NumberWithCountryIso(String number, String countryIso) { - this.number = number; - this.countryIso = countryIso; - } - - @Override - public boolean equals(Object o) { - if (o == null) return false; - if (!(o instanceof NumberWithCountryIso)) return false; - NumberWithCountryIso other = (NumberWithCountryIso) o; - return TextUtils.equals(number, other.number) - && TextUtils.equals(countryIso, other.countryIso); - } - - @Override - public int hashCode() { - return (number == null ? 0 : number.hashCode()) - ^ (countryIso == null ? 0 : countryIso.hashCode()); - } - } - - /** The time in millis to delay starting the thread processing requests. */ - private static final int START_PROCESSING_REQUESTS_DELAY_MILLIS = 1000; - - /** The size of the cache of contact info. */ - private static final int CONTACT_INFO_CACHE_SIZE = 100; - - private final Context mContext; - private final ContactInfoHelper mContactInfoHelper; - private final CallFetcher mCallFetcher; - private ViewTreeObserver mViewTreeObserver = null; - - /** - * A cache of the contact details for the phone numbers in the call log. - * <p> - * The content of the cache is expired (but not purged) whenever the application comes to - * the foreground. - * <p> - * The key is number with the country in which the call was placed or received. - */ - private ExpirableCache<NumberWithCountryIso, ContactInfo> mContactInfoCache; - - /** - * A request for contact details for the given number. - */ - private static final class ContactInfoRequest { - /** The number to look-up. */ - public final String number; - /** The country in which a call to or from this number was placed or received. */ - public final String countryIso; - /** The cached contact information stored in the call log. */ - public final ContactInfo callLogInfo; - - public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) { - this.number = number; - this.countryIso = countryIso; - this.callLogInfo = callLogInfo; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof ContactInfoRequest)) return false; - - ContactInfoRequest other = (ContactInfoRequest) obj; - - if (!TextUtils.equals(number, other.number)) return false; - if (!TextUtils.equals(countryIso, other.countryIso)) return false; - if (!Objects.equal(callLogInfo, other.callLogInfo)) return false; - - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode()); - result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode()); - result = prime * result + ((number == null) ? 0 : number.hashCode()); - return result; - } - } - - /** - * List of requests to update contact details. - * <p> - * Each request is made of a phone number to look up, and the contact info currently stored in - * the call log for this number. - * <p> - * The requests are added when displaying the contacts and are processed by a background - * thread. - */ - private final LinkedList<ContactInfoRequest> mRequests; - - private boolean mLoading = true; - private static final int REDRAW = 1; - private static final int START_THREAD = 2; - - private QueryThread mCallerIdThread; - - /** Instance of helper class for managing views. */ - private final NewCallLogListItemHelper mCallLogViewsHelper; - - /** Helper to set up contact photos. */ - private final ContactPhotoManager mContactPhotoManager; - /** Helper to parse and process phone numbers. */ - private PhoneNumberHelper mPhoneNumberHelper; - /** Helper to group call log entries. */ - private final CallLogGroupBuilder mCallLogGroupBuilder; - - /** Can be set to true by tests to disable processing of requests. */ - private volatile boolean mRequestProcessingDisabled = false; - - /** Listener for the primary action in the list, opens the call details. */ - private final View.OnClickListener mPrimaryActionListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - IntentProvider intentProvider = (IntentProvider) view.getTag(); - if (intentProvider != null) { - mContext.startActivity(intentProvider.getIntent(mContext)); - } - } - }; - /** Listener for the secondary action in the list, either call or play. */ - private final View.OnClickListener mSecondaryActionListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - IntentProvider intentProvider = (IntentProvider) view.getTag(); - if (intentProvider != null) { - mContext.startActivity(intentProvider.getIntent(mContext)); - } - } - }; - - @Override - public boolean onPreDraw() { - // We only wanted to listen for the first draw (and this is it). - unregisterPreDrawListener(); - - // Only schedule a thread-creation message if the thread hasn't been - // created yet. This is purely an optimization, to queue fewer messages. - if (mCallerIdThread == null) { - mHandler.sendEmptyMessageDelayed(START_THREAD, START_PROCESSING_REQUESTS_DELAY_MILLIS); - } - - return true; - } - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case REDRAW: - notifyDataSetChanged(); - break; - case START_THREAD: - startRequestProcessing(); - break; - } - } - }; - - public NewCallLogAdapter(Context context, CallFetcher callFetcher, - ContactInfoHelper contactInfoHelper) { - super(context); - - mContext = context; - mCallFetcher = callFetcher; - mContactInfoHelper = contactInfoHelper; - - mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE); - mRequests = new LinkedList<ContactInfoRequest>(); - - Resources resources = mContext.getResources(); - CallTypeHelper callTypeHelper = new CallTypeHelper(resources); - - mContactPhotoManager = ContactPhotoManager.getInstance(mContext); - mPhoneNumberHelper = new PhoneNumberHelper(resources); - PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper( - resources, callTypeHelper, mPhoneNumberHelper); - mCallLogViewsHelper = - new NewCallLogListItemHelper( - phoneCallDetailsHelper, mPhoneNumberHelper, resources); - mCallLogGroupBuilder = new CallLogGroupBuilder(this); - } - - /** - * Requery on background thread when {@link Cursor} changes. - */ - @Override - protected void onContentChanged() { - mCallFetcher.fetchCalls(); - } - - public void setLoading(boolean loading) { - mLoading = loading; - } - - @Override - public boolean isEmpty() { - if (mLoading) { - // We don't want the empty state to show when loading. - return false; - } else { - return super.isEmpty(); - } - } - - /** - * Starts a background thread to process contact-lookup requests, unless one - * has already been started. - */ - private synchronized void startRequestProcessing() { - // For unit-testing. - if (mRequestProcessingDisabled) return; - - // Idempotence... if a thread is already started, don't start another. - if (mCallerIdThread != null) return; - - mCallerIdThread = new QueryThread(); - mCallerIdThread.setPriority(Thread.MIN_PRIORITY); - mCallerIdThread.start(); - } - - /** - * Stops the background thread that processes updates and cancels any - * pending requests to start it. - */ - public synchronized void stopRequestProcessing() { - // Remove any pending requests to start the processing thread. - mHandler.removeMessages(START_THREAD); - if (mCallerIdThread != null) { - // Stop the thread; we are finished with it. - mCallerIdThread.stopProcessing(); - mCallerIdThread.interrupt(); - mCallerIdThread = null; - } - } - - /** - * Stop receiving onPreDraw() notifications. - */ - private void unregisterPreDrawListener() { - if (mViewTreeObserver != null && mViewTreeObserver.isAlive()) { - mViewTreeObserver.removeOnPreDrawListener(this); - } - mViewTreeObserver = null; - } - - public void invalidateCache() { - mContactInfoCache.expireAll(); - - // Restart the request-processing thread after the next draw. - stopRequestProcessing(); - unregisterPreDrawListener(); - } - - /** - * Enqueues a request to look up the contact details for the given phone number. - * <p> - * It also provides the current contact info stored in the call log for this number. - * <p> - * If the {@code immediate} parameter is true, it will start immediately the thread that looks - * up the contact information (if it has not been already started). Otherwise, it will be - * started with a delay. See {@link #START_PROCESSING_REQUESTS_DELAY_MILLIS}. - */ - @VisibleForTesting - void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo, - boolean immediate) { - ContactInfoRequest request = new ContactInfoRequest(number, countryIso, callLogInfo); - synchronized (mRequests) { - if (!mRequests.contains(request)) { - mRequests.add(request); - mRequests.notifyAll(); - } - } - if (immediate) startRequestProcessing(); - } - - /** - * Queries the appropriate content provider for the contact associated with the number. - * <p> - * Upon completion it also updates the cache in the call log, if it is different from - * {@code callLogInfo}. - * <p> - * The number might be either a SIP address or a phone number. - * <p> - * It returns true if it updated the content of the cache and we should therefore tell the - * view to update its content. - */ - private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo) { - final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso); - - if (info == null) { - // The lookup failed, just return without requesting to update the view. - return false; - } - - // Check the existing entry in the cache: only if it has changed we should update the - // view. - NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); - ContactInfo existingInfo = mContactInfoCache.getPossiblyExpired(numberCountryIso); - boolean updated = (existingInfo != ContactInfo.EMPTY) && !info.equals(existingInfo); - - // Store the data in the cache so that the UI thread can use to display it. Store it - // even if it has not changed so that it is marked as not expired. - mContactInfoCache.put(numberCountryIso, info); - // Update the call log even if the cache it is up-to-date: it is possible that the cache - // contains the value from a different call log entry. - updateCallLogContactInfoCache(number, countryIso, info, callLogInfo); - return updated; - } - - /* - * Handles requests for contact name and number type. - */ - private class QueryThread extends Thread { - private volatile boolean mDone = false; - - public QueryThread() { - super("CallLogAdapter.QueryThread"); - } - - public void stopProcessing() { - mDone = true; - } - - @Override - public void run() { - boolean needRedraw = false; - while (true) { - // Check if thread is finished, and if so return immediately. - if (mDone) return; - - // Obtain next request, if any is available. - // Keep synchronized section small. - ContactInfoRequest req = null; - synchronized (mRequests) { - if (!mRequests.isEmpty()) { - req = mRequests.removeFirst(); - } - } - - if (req != null) { - // Process the request. If the lookup succeeds, schedule a - // redraw. - needRedraw |= queryContactInfo(req.number, req.countryIso, req.callLogInfo); - } else { - // Throttle redraw rate by only sending them when there are - // more requests. - if (needRedraw) { - needRedraw = false; - mHandler.sendEmptyMessage(REDRAW); - } - - // Wait until another request is available, or until this - // thread is no longer needed (as indicated by being - // interrupted). - try { - synchronized (mRequests) { - mRequests.wait(1000); - } - } catch (InterruptedException ie) { - // Ignore, and attempt to continue processing requests. - } - } - } - } - } - - @Override - protected void addGroups(Cursor cursor) { - mCallLogGroupBuilder.addGroups(cursor); - } - - @Override - protected View newStandAloneView(Context context, ViewGroup parent) { - LayoutInflater inflater = - (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false); - findAndCacheViews(view); - return view; - } - - @Override - protected void bindStandAloneView(View view, Context context, Cursor cursor) { - bindView(view, cursor, 1); - } - - @Override - protected View newChildView(Context context, ViewGroup parent) { - LayoutInflater inflater = - (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false); - findAndCacheViews(view); - return view; - } - - @Override - protected void bindChildView(View view, Context context, Cursor cursor) { - bindView(view, cursor, 1); - } - - @Override - protected View newGroupView(Context context, ViewGroup parent) { - LayoutInflater inflater = - (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false); - findAndCacheViews(view); - return view; - } - - @Override - protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize, - boolean expanded) { - bindView(view, cursor, groupSize); - } - - private void findAndCacheViews(View view) { - // Get the views to bind to. - CallLogListItemViews views = CallLogListItemViews.fromView(view); - views.primaryActionView.setOnClickListener(mPrimaryActionListener); - views.secondaryActionView.setOnClickListener(mSecondaryActionListener); - view.setTag(views); - } - - /** - * Binds the views in the entry to the data in the call log. - * - * @param view the view corresponding to this entry - * @param c the cursor pointing to the entry in the call log - * @param count the number of entries in the current item, greater than 1 if it is a group - */ - private void bindView(View view, Cursor c, int count) { - final CallLogListItemViews views = (CallLogListItemViews) view.getTag(); - - // Default case: an item in the call log. - views.primaryActionView.setVisibility(View.VISIBLE); - views.bottomDivider.setVisibility(View.VISIBLE); - views.listHeaderTextView.setVisibility(View.GONE); - - final String number = c.getString(CallLogQuery.NUMBER); - final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION); - final long date = c.getLong(CallLogQuery.DATE); - final long duration = c.getLong(CallLogQuery.DURATION); - final int callType = c.getInt(CallLogQuery.CALL_TYPE); - final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO); - - final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c); - - views.primaryActionView.setTag( - IntentProvider.getCallDetailIntentProvider( - getCursor(), c.getPosition(), c.getLong(CallLogQuery.ID), count)); - - // Store away the voicemail information so we can play it directly. - if (callType == Calls.VOICEMAIL_TYPE) { - String voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI); - final long rowId = c.getLong(CallLogQuery.ID); - views.secondaryActionView.setTag( - IntentProvider.getPlayVoicemailIntentProvider(rowId, voicemailUri)); - } else if (!TextUtils.isEmpty(number)) { - // Store away the number so we can call it directly if you click on the call icon. - views.secondaryActionView.setTag( - IntentProvider.getReturnCallIntentProvider(number)); - } else { - // No action enabled. - views.secondaryActionView.setTag(null); - } - - // Lookup contacts with this number - NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); - ExpirableCache.CachedValue<ContactInfo> cachedInfo = - mContactInfoCache.getCachedValue(numberCountryIso); - ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue(); - if (!PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation) - || mPhoneNumberHelper.isVoicemailNumber(number)) { - // If this is a number that cannot be dialed, there is no point in looking up a contact - // for it. - info = ContactInfo.EMPTY; - } else if (cachedInfo == null) { - mContactInfoCache.put(numberCountryIso, ContactInfo.EMPTY); - // Use the cached contact info from the call log. - info = cachedContactInfo; - // The db request should happen on a non-UI thread. - // Request the contact details immediately since they are currently missing. - enqueueRequest(number, countryIso, cachedContactInfo, true); - // We will format the phone number when we make the background request. - } else { - if (cachedInfo.isExpired()) { - // The contact info is no longer up to date, we should request it. However, we - // do not need to request them immediately. - enqueueRequest(number, countryIso, cachedContactInfo, false); - } else if (!callLogInfoMatches(cachedContactInfo, info)) { - // The call log information does not match the one we have, look it up again. - // We could simply update the call log directly, but that needs to be done in a - // background thread, so it is easier to simply request a new lookup, which will, as - // a side-effect, update the call log. - enqueueRequest(number, countryIso, cachedContactInfo, false); - } - - if (info == ContactInfo.EMPTY) { - // Use the cached contact info from the call log. - info = cachedContactInfo; - } - } - - final Uri lookupUri = info.lookupUri; - final String name = info.name; - final int ntype = info.type; - final String label = info.label; - final long photoId = info.photoId; - CharSequence formattedNumber = info.formattedNumber; - final int[] callTypes = getCallTypes(c, count); - final String geocode = c.getString(CallLogQuery.GEOCODED_LOCATION); - final PhoneCallDetails details; - if (TextUtils.isEmpty(name)) { - details = new PhoneCallDetails(number, numberPresentation, - formattedNumber, countryIso, geocode, callTypes, date, - duration); - } else { - // We do not pass a photo id since we do not need the high-res picture. - details = new PhoneCallDetails(number, numberPresentation, - formattedNumber, countryIso, geocode, callTypes, date, - duration, name, ntype, label, lookupUri, null); - } - - final boolean isNew = c.getInt(CallLogQuery.IS_READ) == 0; - // New items also use the highlighted version of the text. - final boolean isHighlighted = isNew; - mCallLogViewsHelper.setPhoneCallDetails(views, details, isHighlighted); - setPhoto(views, photoId, lookupUri); - - // Listen for the first draw - if (mViewTreeObserver == null) { - mViewTreeObserver = view.getViewTreeObserver(); - mViewTreeObserver.addOnPreDrawListener(this); - } - } - - /** Checks whether the contact info from the call log matches the one from the contacts db. */ - private boolean callLogInfoMatches(ContactInfo callLogInfo, ContactInfo info) { - // The call log only contains a subset of the fields in the contacts db. - // Only check those. - return TextUtils.equals(callLogInfo.name, info.name) - && callLogInfo.type == info.type - && TextUtils.equals(callLogInfo.label, info.label); - } - - /** Stores the updated contact info in the call log if it is different from the current one. */ - private void updateCallLogContactInfoCache(String number, String countryIso, - ContactInfo updatedInfo, ContactInfo callLogInfo) { - final ContentValues values = new ContentValues(); - boolean needsUpdate = false; - - if (callLogInfo != null) { - if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) { - values.put(Calls.CACHED_NAME, updatedInfo.name); - needsUpdate = true; - } - - if (updatedInfo.type != callLogInfo.type) { - values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type); - needsUpdate = true; - } - - if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) { - values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label); - needsUpdate = true; - } - if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) { - values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri)); - needsUpdate = true; - } - if (!TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) { - values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber); - needsUpdate = true; - } - if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) { - values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number); - needsUpdate = true; - } - if (updatedInfo.photoId != callLogInfo.photoId) { - values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId); - needsUpdate = true; - } - if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) { - values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber); - needsUpdate = true; - } - } else { - // No previous values, store all of them. - values.put(Calls.CACHED_NAME, updatedInfo.name); - values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type); - values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label); - values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri)); - values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number); - values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber); - values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId); - values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber); - needsUpdate = true; - } - - if (!needsUpdate) return; - - if (countryIso == null) { - mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values, - Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL", - new String[]{ number }); - } else { - mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values, - Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?", - new String[]{ number, countryIso }); - } - } - - /** Returns the contact information as stored in the call log. */ - private ContactInfo getContactInfoFromCallLog(Cursor c) { - ContactInfo info = new ContactInfo(); - info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI)); - info.name = c.getString(CallLogQuery.CACHED_NAME); - info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE); - info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL); - String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER); - info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber; - info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER); - info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID); - info.photoUri = null; // We do not cache the photo URI. - info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER); - return info; - } - - /** - * Returns the call types for the given number of items in the cursor. - * <p> - * It uses the next {@code count} rows in the cursor to extract the types. - * <p> - * It position in the cursor is unchanged by this function. - */ - private int[] getCallTypes(Cursor cursor, int count) { - int position = cursor.getPosition(); - int[] callTypes = new int[count]; - for (int index = 0; index < count; ++index) { - callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE); - cursor.moveToNext(); - } - cursor.moveToPosition(position); - return callTypes; - } - - private void setPhoto(CallLogListItemViews views, long photoId, Uri contactUri) { - views.quickContactView.assignContactUri(contactUri); - mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, false /* darkTheme */); - } - - /** - * Sets whether processing of requests for contact details should be enabled. - * <p> - * This method should be called in tests to disable such processing of requests when not - * needed. - */ - @VisibleForTesting - void disableRequestProcessingForTest() { - mRequestProcessingDisabled = true; - } - - @VisibleForTesting - void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) { - NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); - mContactInfoCache.put(numberCountryIso, contactInfo); - } - - @Override - public void addGroup(int cursorPosition, int size, boolean expanded) { - super.addGroup(cursorPosition, size, expanded); - } - - /* - * Get the number from the Contacts, if available, since sometimes - * the number provided by caller id may not be formatted properly - * depending on the carrier (roaming) in use at the time of the - * incoming call. - * Logic : If the caller-id number starts with a "+", use it - * Else if the number in the contacts starts with a "+", use that one - * Else if the number in the contacts is longer, use that one - */ - public String getBetterNumberFromContacts(String number, String countryIso) { - String matchingNumber = null; - // Look in the cache first. If it's not found then query the Phones db - NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); - ContactInfo ci = mContactInfoCache.getPossiblyExpired(numberCountryIso); - if (ci != null && ci != ContactInfo.EMPTY) { - matchingNumber = ci.number; - } else { - try { - Cursor phonesCursor = mContext.getContentResolver().query( - Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number), - PhoneQuery._PROJECTION, null, null, null); - if (phonesCursor != null) { - if (phonesCursor.moveToFirst()) { - matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER); - } - phonesCursor.close(); - } - } catch (Exception e) { - // Use the number from the call log - } - } - if (!TextUtils.isEmpty(matchingNumber) && - (matchingNumber.startsWith("+") - || matchingNumber.length() > number.length())) { - number = matchingNumber; - } - return number; - } -} diff --git a/src/com/android/dialer/calllog/NewCallLogFragment.java b/src/com/android/dialer/calllog/NewCallLogFragment.java deleted file mode 100644 index c470c55d4..000000000 --- a/src/com/android/dialer/calllog/NewCallLogFragment.java +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.dialer.calllog; - -import android.app.Activity; -import android.app.KeyguardManager; -import android.app.ListFragment; -import android.content.Context; -import android.content.Intent; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.CallLog; -import android.provider.CallLog.Calls; -import android.provider.ContactsContract; -import android.telephony.PhoneNumberUtils; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import android.widget.TextView; - -import com.android.common.io.MoreCloseables; -import com.android.contacts.common.CallUtil; -import com.android.contacts.common.GeoUtil; -import com.android.dialer.R; -import com.android.dialer.util.EmptyLoader; -import com.android.dialer.voicemail.VoicemailStatusHelper; -import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage; -import com.android.dialer.voicemail.VoicemailStatusHelperImpl; -import com.android.internal.telephony.ITelephony; -import com.google.common.annotations.VisibleForTesting; - -import java.util.List; - -/** - * Displays a list of call log entries. To filter for a particular kind of call - * (all, missed or voicemails), specify it in the constructor. - */ -public class NewCallLogFragment extends ListFragment - implements CallLogQueryHandler.Listener, NewCallLogAdapter.CallFetcher { - private static final String TAG = "CallLogFragment"; - - /** - * ID of the empty loader to defer other fragments. - */ - private static final int EMPTY_LOADER_ID = 0; - - private NewCallLogAdapter mAdapter; - private CallLogQueryHandler mCallLogQueryHandler; - private boolean mScrollToTop; - - /** Whether there is at least one voicemail source installed. */ - private boolean mVoicemailSourcesAvailable = false; - - private VoicemailStatusHelper mVoicemailStatusHelper; - private View mStatusMessageView; - private TextView mStatusMessageText; - private TextView mStatusMessageAction; - private KeyguardManager mKeyguardManager; - - private boolean mEmptyLoaderRunning; - private boolean mCallLogFetched; - private boolean mVoicemailStatusFetched; - - private final Handler mHandler = new Handler(); - - private TelephonyManager mTelephonyManager; - private PhoneStateListener mPhoneStateListener; - - private class CustomContentObserver extends ContentObserver { - public CustomContentObserver() { - super(mHandler); - } - @Override - public void onChange(boolean selfChange) { - mRefreshDataRequired = true; - } - } - - // See issue 6363009 - private final ContentObserver mCallLogObserver = new CustomContentObserver(); - private final ContentObserver mContactsObserver = new CustomContentObserver(); - private boolean mRefreshDataRequired = true; - - // Exactly same variable is in Fragment as a package private. - private boolean mMenuVisible = true; - - // Default to all calls. - private int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL; - - // Log limit - if no limit is specified, then the default in {@link NewCallLogQueryHandler} - // will be used. - private int mLogLimit = -1; - - public NewCallLogFragment() { - this(CallLogQueryHandler.CALL_TYPE_ALL, -1); - } - - public NewCallLogFragment(int filterType) { - this(filterType, -1); - } - - public NewCallLogFragment(int filterType, int logLimit) { - super(); - mCallTypeFilter = filterType; - mLogLimit = logLimit; - } - - @Override - public void onCreate(Bundle state) { - super.onCreate(state); - - mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(), - this, mLogLimit); - mKeyguardManager = - (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE); - getActivity().getContentResolver().registerContentObserver( - CallLog.CONTENT_URI, true, mCallLogObserver); - getActivity().getContentResolver().registerContentObserver( - ContactsContract.Contacts.CONTENT_URI, true, mContactsObserver); - setHasOptionsMenu(true); - updateCallList(mCallTypeFilter); - } - - /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */ - @Override - public void onCallsFetched(Cursor cursor) { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - mAdapter.setLoading(false); - mAdapter.changeCursor(cursor); - // This will update the state of the "Clear call log" menu item. - getActivity().invalidateOptionsMenu(); - if (mScrollToTop) { - final ListView listView = getListView(); - // The smooth-scroll animation happens over a fixed time period. - // As a result, if it scrolls through a large portion of the list, - // each frame will jump so far from the previous one that the user - // will not experience the illusion of downward motion. Instead, - // if we're not already near the top of the list, we instantly jump - // near the top, and animate from there. - if (listView.getFirstVisiblePosition() > 5) { - listView.setSelection(5); - } - // Workaround for framework issue: the smooth-scroll doesn't - // occur if setSelection() is called immediately before. - mHandler.post(new Runnable() { - @Override - public void run() { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - listView.smoothScrollToPosition(0); - } - }); - - mScrollToTop = false; - } - mCallLogFetched = true; - destroyEmptyLoaderIfAllDataFetched(); - } - - /** - * Called by {@link CallLogQueryHandler} after a successful query to voicemail status provider. - */ - @Override - public void onVoicemailStatusFetched(Cursor statusCursor) { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - updateVoicemailStatusMessage(statusCursor); - - int activeSources = mVoicemailStatusHelper.getNumberActivityVoicemailSources(statusCursor); - setVoicemailSourcesAvailable(activeSources != 0); - MoreCloseables.closeQuietly(statusCursor); - mVoicemailStatusFetched = true; - destroyEmptyLoaderIfAllDataFetched(); - } - - private void destroyEmptyLoaderIfAllDataFetched() { - if (mCallLogFetched && mVoicemailStatusFetched && mEmptyLoaderRunning) { - mEmptyLoaderRunning = false; - getLoaderManager().destroyLoader(EMPTY_LOADER_ID); - } - } - - /** Sets whether there are any voicemail sources available in the platform. */ - private void setVoicemailSourcesAvailable(boolean voicemailSourcesAvailable) { - if (mVoicemailSourcesAvailable == voicemailSourcesAvailable) return; - mVoicemailSourcesAvailable = voicemailSourcesAvailable; - - Activity activity = getActivity(); - if (activity != null) { - // This is so that the options menu content is updated. - activity.invalidateOptionsMenu(); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { - View view = inflater.inflate(R.layout.new_call_log_fragment, container, false); - mVoicemailStatusHelper = new VoicemailStatusHelperImpl(); - mStatusMessageView = view.findViewById(R.id.voicemail_status); - mStatusMessageText = (TextView) view.findViewById(R.id.voicemail_status_message); - mStatusMessageAction = (TextView) view.findViewById(R.id.voicemail_status_action); - return view; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - updateEmptyMessage(mCallTypeFilter); - String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); - mAdapter = new NewCallLogAdapter(getActivity(), this, - new ContactInfoHelper(getActivity(), currentCountryIso)); - setListAdapter(mAdapter); - getListView().setItemsCanFocus(true); - } - - /** - * Based on the new intent, decide whether the list should be configured - * to scroll up to display the first item. - */ - public void configureScreenFromIntent(Intent newIntent) { - // Typically, when switching to the call-log we want to show the user - // the same section of the list that they were most recently looking - // at. However, under some circumstances, we want to automatically - // scroll to the top of the list to present the newest call items. - // For example, immediately after a call is finished, we want to - // display information about that call. - mScrollToTop = Calls.CONTENT_TYPE.equals(newIntent.getType()); - } - - @Override - public void onStart() { - // Start the empty loader now to defer other fragments. We destroy it when both calllog - // and the voicemail status are fetched. - getLoaderManager().initLoader(EMPTY_LOADER_ID, null, - new EmptyLoader.Callback(getActivity())); - mEmptyLoaderRunning = true; - super.onStart(); - } - - @Override - public void onResume() { - Log.d(TAG, "Call Log Fragment resume"); - super.onResume(); - refreshData(); - } - - private void updateVoicemailStatusMessage(Cursor statusCursor) { - List<StatusMessage> messages = mVoicemailStatusHelper.getStatusMessages(statusCursor); - if (messages.size() == 0) { - mStatusMessageView.setVisibility(View.GONE); - } else { - mStatusMessageView.setVisibility(View.VISIBLE); - // TODO: Change the code to show all messages. For now just pick the first message. - final StatusMessage message = messages.get(0); - if (message.showInCallLog()) { - mStatusMessageText.setText(message.callLogMessageId); - } - if (message.actionMessageId != -1) { - mStatusMessageAction.setText(message.actionMessageId); - } - if (message.actionUri != null) { - mStatusMessageAction.setVisibility(View.VISIBLE); - mStatusMessageAction.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().startActivity( - new Intent(Intent.ACTION_VIEW, message.actionUri)); - } - }); - } else { - mStatusMessageAction.setVisibility(View.GONE); - } - } - } - - @Override - public void onPause() { - super.onPause(); - // Kill the requests thread - mAdapter.stopRequestProcessing(); - } - - @Override - public void onStop() { - super.onStop(); - updateOnExit(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mAdapter.stopRequestProcessing(); - mAdapter.changeCursor(null); - getActivity().getContentResolver().unregisterContentObserver(mCallLogObserver); - getActivity().getContentResolver().unregisterContentObserver(mContactsObserver); - unregisterPhoneCallReceiver(); - } - - @Override - public void fetchCalls() { - mCallLogQueryHandler.fetchCalls(mCallTypeFilter); - } - - public void startCallsQuery() { - mAdapter.setLoading(true); - mCallLogQueryHandler.fetchCalls(mCallTypeFilter); - } - - private void startVoicemailStatusQuery() { - mCallLogQueryHandler.fetchVoicemailStatus(); - } - - private void updateCallList(int filterType) { - if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) { - unregisterPhoneCallReceiver(); - } else { - // TODO krelease: Make this work - //registerPhoneCallReceiver(); - } - mCallLogQueryHandler.fetchCalls(filterType); - } - - private void updateEmptyMessage(int filterType) { - final String message; - switch (filterType) { - case Calls.MISSED_TYPE: - message = getString(R.string.recentMissed_empty); - break; - case Calls.VOICEMAIL_TYPE: - message = getString(R.string.recentVoicemails_empty); - break; - default: - message = getString(R.string.recentCalls_empty); - break; - } - ((TextView) getListView().getEmptyView()).setText(message); - } - - 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. - position = 0; - } - final Cursor cursor = (Cursor)mAdapter.getItem(position); - if (cursor != null) { - String number = cursor.getString(CallLogQuery.NUMBER); - int numberPresentation = cursor.getInt(CallLogQuery.NUMBER_PRESENTATION); - if (!PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation)) { - // This number can't be called, do nothing - return; - } - Intent intent; - // If "number" is really a SIP address, construct a sip: URI. - if (PhoneNumberUtils.isUriNumber(number)) { - intent = CallUtil.getCallIntent( - Uri.fromParts(CallUtil.SCHEME_SIP, number, null)); - } else { - // We're calling a regular PSTN phone number. - // Construct a tel: URI, but do some other possible cleanup first. - int callType = cursor.getInt(CallLogQuery.CALL_TYPE); - if (!number.startsWith("+") && - (callType == Calls.INCOMING_TYPE - || callType == Calls.MISSED_TYPE)) { - // If the caller-id matches a contact with a better qualified number, use it - String countryIso = cursor.getString(CallLogQuery.COUNTRY_ISO); - number = mAdapter.getBetterNumberFromContacts(number, countryIso); - } - intent = CallUtil.getCallIntent( - Uri.fromParts(CallUtil.SCHEME_TEL, number, null)); - } - intent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivity(intent); - } - } - - NewCallLogAdapter getAdapter() { - return mAdapter; - } - - @Override - public void setMenuVisibility(boolean menuVisible) { - super.setMenuVisibility(menuVisible); - if (mMenuVisible != menuVisible) { - mMenuVisible = menuVisible; - if (!menuVisible) { - updateOnExit(); - } else if (isResumed()) { - refreshData(); - } - } - } - - /** Requests updates to the data to be shown. */ - private void refreshData() { - // Prevent unnecessary refresh. - if (mRefreshDataRequired) { - // 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(); - startVoicemailStatusQuery(); - updateOnEntry(); - mRefreshDataRequired = false; - } - } - - /** Removes the missed call notifications. */ - private void removeMissedCallNotifications() { - try { - ITelephony telephony = - ITelephony.Stub.asInterface(ServiceManager.getService("phone")); - if (telephony != null) { - telephony.cancelMissedCallsNotification(); - } else { - Log.w(TAG, "Telephony service is null, can't call " + - "cancelMissedCallsNotification"); - } - } catch (RemoteException e) { - Log.e(TAG, "Failed to clear missed calls notification due to remote exception"); - } - } - - /** Updates call data and notification state while leaving the call log tab. */ - private void updateOnExit() { - updateOnTransition(false); - } - - /** Updates call data and notification state while entering the call log tab. */ - private void updateOnEntry() { - updateOnTransition(true); - } - - // TODO krelease: Figure out if we still need this. If so, it should be probably be moved to - // the call log activity instead, or done only in a single call log fragment. - private void updateOnTransition(boolean onEntry) { - // We don't want to update any call data when keyguard is on because the user has likely not - // seen the new calls yet. - // This might be called before onCreate() and thus we need to check null explicitly. - if (mKeyguardManager != null && !mKeyguardManager.inKeyguardRestrictedInputMode()) { - // On either of the transitions we reset the new flag and update the notifications. - // While exiting we additionally consume all missed calls (by marking them as read). - // This will ensure that they no more appear in the "new" section when we return back. - mCallLogQueryHandler.markNewCallsAsOld(); - if (!onEntry) { - mCallLogQueryHandler.markMissedCallsAsRead(); - } - removeMissedCallNotifications(); - updateVoicemailNotifications(); - } - } - - private void updateVoicemailNotifications() { - Intent serviceIntent = new Intent(getActivity(), CallLogNotificationsService.class); - serviceIntent.setAction(CallLogNotificationsService.ACTION_UPDATE_NOTIFICATIONS); - getActivity().startService(serviceIntent); - } - - // TODO krelease: Make the ViewPager switch to the correct tab (All) when a phone call is - // placed. - // This should probably be moved to the call log activity. - /** - * Register a phone call filter to reset the call type when a phone call is place. - */ - /* - private void registerPhoneCallReceiver() { - if (mPhoneStateListener != null) { - return; // Already registered. - } - mTelephonyManager = (TelephonyManager) getActivity().getSystemService( - Context.TELEPHONY_SERVICE); - mPhoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (state != TelephonyManager.CALL_STATE_OFFHOOK && - state != TelephonyManager.CALL_STATE_RINGING) { - return; - } - mHandler.post(new Runnable() { - @Override - public void run() { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - } - }); - } - }; - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - } - */ - - /** - * Un-registers the phone call receiver. - */ - private void unregisterPhoneCallReceiver() { - if (mPhoneStateListener != null) { - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); - mPhoneStateListener = null; - } - } -} diff --git a/src/com/android/dialer/calllog/NewCallLogListItemHelper.java b/src/com/android/dialer/calllog/NewCallLogListItemHelper.java deleted file mode 100644 index 6b4f10151..000000000 --- a/src/com/android/dialer/calllog/NewCallLogListItemHelper.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.dialer.calllog; - -import android.content.res.Resources; -import android.provider.CallLog.Calls; -import android.text.TextUtils; -import android.view.View; - -import com.android.dialer.PhoneCallDetails; -import com.android.dialer.PhoneCallDetailsHelper; -import com.android.dialer.R; - -/** - * Helper class to fill in the views of a call log entry. - * TODO krelease: The only difference between this and the original is that we don't touch - * divider views, which are not present in the new dialer. Once the new dialer replaces - * the old one, we can replace it entirely. Otherwise we would have redundant divider=null - * checks all over the place. - */ -/* package */class NewCallLogListItemHelper { - /** Helper for populating the details of a phone call. */ - private final PhoneCallDetailsHelper mPhoneCallDetailsHelper; - /** Helper for handling phone numbers. */ - private final PhoneNumberHelper mPhoneNumberHelper; - /** Resources to look up strings. */ - private final Resources mResources; - - /** - * Creates a new helper instance. - * - * @param phoneCallDetailsHelper used to set the details of a phone call - * @param phoneNumberHelper used to process phone number - */ - public NewCallLogListItemHelper(PhoneCallDetailsHelper phoneCallDetailsHelper, - PhoneNumberHelper phoneNumberHelper, Resources resources) { - mPhoneCallDetailsHelper = phoneCallDetailsHelper; - mPhoneNumberHelper = phoneNumberHelper; - mResources = resources; - } - - /** - * Sets the name, label, and number for a contact. - * - * @param views the views to populate - * @param details the details of a phone call needed to fill in the data - * @param isHighlighted whether to use the highlight text for the call - */ - public void setPhoneCallDetails(CallLogListItemViews views, PhoneCallDetails details, - boolean isHighlighted) { - mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details, - isHighlighted); - boolean canCall = PhoneNumberHelper.canPlaceCallsTo(details.number, - details.numberPresentation); - boolean canPlay = details.callTypes[0] == Calls.VOICEMAIL_TYPE; - - if (canPlay) { - // Playback action takes preference. - configurePlaySecondaryAction(views, isHighlighted); - } else if (canCall) { - // Call is the secondary action. - configureCallSecondaryAction(views, details); - } else { - // No action available. - views.secondaryActionView.setVisibility(View.GONE); - } - } - - /** Sets the secondary action to correspond to the call button. */ - private void configureCallSecondaryAction(CallLogListItemViews views, - PhoneCallDetails details) { - views.secondaryActionView.setVisibility(View.VISIBLE); - views.secondaryActionView.setImageResource(R.drawable.ic_ab_dialer_holo_light); - views.secondaryActionView.setContentDescription(getCallActionDescription(details)); - } - - /** Returns the description used by the call action for this phone call. */ - private CharSequence getCallActionDescription(PhoneCallDetails details) { - final CharSequence recipient; - if (!TextUtils.isEmpty(details.name)) { - recipient = details.name; - } else { - recipient = mPhoneNumberHelper.getDisplayNumber( - details.number, details.numberPresentation, details.formattedNumber); - } - return mResources.getString(R.string.description_call, recipient); - } - - /** Sets the secondary action to correspond to the play button. */ - private void configurePlaySecondaryAction(CallLogListItemViews views, boolean isHighlighted) { - views.secondaryActionView.setVisibility(View.VISIBLE); - views.secondaryActionView.setImageResource( - isHighlighted ? R.drawable.ic_play_active_holo_dark : R.drawable.ic_play_holo_light); - views.secondaryActionView.setContentDescription( - mResources.getString(R.string.description_call_log_play_button)); - } -} diff --git a/src/com/android/dialer/list/NewPhoneFavoriteFragment.java b/src/com/android/dialer/list/NewPhoneFavoriteFragment.java index 283c7dba0..58dac2fb6 100644 --- a/src/com/android/dialer/list/NewPhoneFavoriteFragment.java +++ b/src/com/android/dialer/list/NewPhoneFavoriteFragment.java @@ -45,7 +45,7 @@ import com.android.contacts.common.list.PhoneNumberListAdapter; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; import com.android.dialer.calllog.ContactInfoHelper; -import com.android.dialer.calllog.NewCallLogAdapter; +import com.android.dialer.calllog.CallLogAdapter; import com.android.dialer.calllog.CallLogQueryHandler; /** @@ -57,7 +57,7 @@ import com.android.dialer.calllog.CallLogQueryHandler; * A contact filter header is also inserted between those adapters' results. */ public class NewPhoneFavoriteFragment extends Fragment implements OnItemClickListener, - CallLogQueryHandler.Listener, NewCallLogAdapter.CallFetcher { + CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher { private static final String TAG = NewPhoneFavoriteFragment.class.getSimpleName(); private static final boolean DEBUG = false; @@ -138,7 +138,7 @@ public class NewPhoneFavoriteFragment extends Fragment implements OnItemClickLis private PhoneFavoritesTileAdapter mContactTileAdapter; private PhoneNumberListAdapter mAllContactsAdapter; - private NewCallLogAdapter mCallLogAdapter; + private CallLogAdapter mCallLogAdapter; private CallLogQueryHandler mCallLogQueryHandler; private TextView mEmptyView; @@ -187,7 +187,7 @@ public class NewPhoneFavoriteFragment extends Fragment implements OnItemClickLis mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(), this, 1); final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); - mCallLogAdapter = new NewCallLogAdapter(getActivity(), this, + mCallLogAdapter = new CallLogAdapter(getActivity(), this, new ContactInfoHelper(getActivity(), currentCountryIso)); setHasOptionsMenu(true); } diff --git a/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java index 28604b963..3c3200407 100644 --- a/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java +++ b/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java @@ -25,11 +25,11 @@ import android.widget.BaseAdapter; import android.widget.FrameLayout; import com.android.dialer.R; -import com.android.dialer.calllog.NewCallLogAdapter; +import com.android.dialer.calllog.CallLogAdapter; /** * An adapter that combines items from {@link com.android.contacts.common.list.ContactTileAdapter} - * and {@link com.android.dialer.calllog.NewCallLogAdapter} into a single list. + * and {@link com.android.dialer.calllog.CallLogAdapter} into a single list. */ public class NewPhoneFavoriteMergedAdapter extends BaseAdapter { @@ -43,7 +43,7 @@ public class NewPhoneFavoriteMergedAdapter extends BaseAdapter { private static final String TAG = NewPhoneFavoriteMergedAdapter.class.getSimpleName(); private final PhoneFavoritesTileAdapter mContactTileAdapter; - private final NewCallLogAdapter mCallLogAdapter; + private final CallLogAdapter mCallLogAdapter; private final View mLoadingView; private final View mShowAllContactsButton; @@ -56,7 +56,7 @@ public class NewPhoneFavoriteMergedAdapter extends BaseAdapter { public NewPhoneFavoriteMergedAdapter(Context context, PhoneFavoritesTileAdapter contactTileAdapter, View accountFilterHeaderContainer, - NewCallLogAdapter callLogAdapter, + CallLogAdapter callLogAdapter, View loadingView, View showAllContactsButton) { final Resources resources = context.getResources(); |