diff options
Diffstat (limited to 'src/com/android/dialer/calllog/NewCallLogFragment.java')
-rw-r--r-- | src/com/android/dialer/calllog/NewCallLogFragment.java | 535 |
1 files changed, 0 insertions, 535 deletions
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; - } - } -} |