diff options
Diffstat (limited to 'src/com/android/dialer/calllog/MSimCallLogFragment.java')
-rw-r--r-- | src/com/android/dialer/calllog/MSimCallLogFragment.java | 658 |
1 files changed, 0 insertions, 658 deletions
diff --git a/src/com/android/dialer/calllog/MSimCallLogFragment.java b/src/com/android/dialer/calllog/MSimCallLogFragment.java deleted file mode 100644 index d94f5c247..000000000 --- a/src/com/android/dialer/calllog/MSimCallLogFragment.java +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved - * Not a Contribution. - * 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 static android.Manifest.permission.READ_CALL_LOG; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.app.Activity; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.KeyguardManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.database.Cursor; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Handler; -import android.provider.CallLog; -import android.provider.CallLog.Calls; -import android.provider.ContactsContract; -import android.provider.VoicemailContract.Status; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.LinearLayoutManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.view.ViewGroup.LayoutParams; -import android.widget.ListView; -import android.widget.TextView; - -import com.android.contacts.common.GeoUtil; -import com.android.contacts.common.util.PermissionsUtil; -import com.android.contacts.common.util.ViewUtil; -import com.android.dialer.R; -import com.android.dialer.list.ListsFragment.HostInterface; -import com.android.dialer.util.DialerUtils; -import com.android.dialer.util.EmptyLoader; -import com.android.dialer.voicemail.VoicemailPlaybackPresenter; -import com.android.dialer.voicemail.VoicemailStatusHelper; -import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage; -import com.android.dialer.voicemail.VoicemailStatusHelperImpl; -import com.android.dialer.widget.EmptyContentView; -import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; -import com.android.dialerbind.ObjectFactory; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.util.Log; -import android.preference.PreferenceManager; -import android.telephony.SubscriptionManager; - -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 MSimCallLogFragment extends Fragment implements CallLogQueryHandler.Listener, - CallLogAdapter.CallFetcher, OnEmptyViewActionButtonClickedListener { - private static final String TAG = "CallLogFragment"; - - /** - * ID of the empty loader to defer other fragments. - */ - private static final int EMPTY_LOADER_ID = 0; - - private static final String KEY_FILTER_TYPE = "filter_type"; - private static final String KEY_LOG_LIMIT = "log_limit"; - private static final String KEY_DATE_LIMIT = "date_limit"; - - // No limit specified for the number of logs to show; use the CallLogQueryHandler's default. - private static final int NO_LOG_LIMIT = -1; - // No date-based filtering. - private static final int NO_DATE_LIMIT = 0; - - private static final int READ_CALL_LOG_PERMISSION_REQUEST_CODE = 1; - - private RecyclerView mRecyclerView; - private LinearLayoutManager mLayoutManager; - private CallLogAdapter mAdapter; - protected CallLogQueryHandler mCallLogQueryHandler; - private VoicemailPlaybackPresenter mVoicemailPlaybackPresenter; - private boolean mScrollToTop; - - /** Whether there is at least one voicemail source installed. */ - private boolean mVoicemailSourcesAvailable = false; - - private EmptyContentView mEmptyListView; - private KeyguardManager mKeyguardManager; - - private boolean mEmptyLoaderRunning; - private boolean mCallLogFetched; - private boolean mVoicemailStatusFetched; - - private final Handler mHandler = new Handler(); - - // The Spinners to filter call log. - private Spinner mFilterSubSpinnerView; - private Spinner mFilterStatusSpinnerView; - // Default to all slots. - private int mCallSubFilter = CallLogQueryHandler.CALL_SUB_ALL; - /** - * Key for the call log sub saved in the default preference. - */ - private static final String PREFERENCE_KEY_CALLLOG_SUB = "call_log_sub"; - - 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 final ContentObserver mVoicemailStatusObserver = new CustomContentObserver(); - private boolean mRefreshDataRequired = true; - - private boolean mHasReadCallLogPermission = false; - - // Exactly same variable is in Fragment as a package private. - private boolean mMenuVisible = true; - - // Default to all calls. - protected 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 = NO_LOG_LIMIT; - - // Date limit (in millis since epoch) - when non-zero, only calls which occurred on or after - // the date filter are included. If zero, no date-based filtering occurs. - private long mDateLimit = NO_DATE_LIMIT; - - /* - * True if this instance of the CallLogFragment is the Recents screen shown in - * DialtactsActivity. - */ - private boolean mIsRecentsFragment; - - public interface HostInterface { - public void showDialpad(); - } - - public MSimCallLogFragment() { - this(CallLogQueryHandler.CALL_TYPE_ALL, NO_LOG_LIMIT); - } - - public MSimCallLogFragment(int filterType) { - this(filterType, NO_LOG_LIMIT); - } - - public MSimCallLogFragment(int filterType, int logLimit) { - this(filterType, logLimit, NO_DATE_LIMIT); - } - - /** - * Creates a call log fragment, filtering to include only calls of the desired type, occurring - * after the specified date. - * @param filterType type of calls to include. - * @param dateLimit limits results to calls occurring on or after the specified date. - */ - public MSimCallLogFragment(int filterType, long dateLimit) { - this(filterType, NO_LOG_LIMIT, dateLimit); - } - - /** - * Creates a call log fragment, filtering to include only calls of the desired type, occurring - * after the specified date. Also provides a means to limit the number of results returned. - * @param filterType type of calls to include. - * @param logLimit limits the number of results to return. - * @param dateLimit limits results to calls occurring on or after the specified date. - */ - public MSimCallLogFragment(int filterType, int logLimit, long dateLimit) { - mCallTypeFilter = filterType; - mLogLimit = logLimit; - mDateLimit = dateLimit; - } - - @Override - public void onCreate(Bundle state) { - super.onCreate(state); - if (state != null) { - mCallTypeFilter = state.getInt(KEY_FILTER_TYPE, mCallTypeFilter); - mLogLimit = state.getInt(KEY_LOG_LIMIT, mLogLimit); - mDateLimit = state.getLong(KEY_DATE_LIMIT, mDateLimit); - } - - mIsRecentsFragment = mLogLimit != NO_LOG_LIMIT; - - final Activity activity = getActivity(); - final ContentResolver resolver = activity.getContentResolver(); - String currentCountryIso = GeoUtil.getCurrentCountryIso(activity); - mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, mLogLimit); - mKeyguardManager = - (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); - resolver.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver); - resolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, - mContactsObserver); - resolver.registerContentObserver(Status.CONTENT_URI, true, mVoicemailStatusObserver); - setHasOptionsMenu(true); - - if (mCallTypeFilter == Calls.VOICEMAIL_TYPE) { - mVoicemailPlaybackPresenter = VoicemailPlaybackPresenter - .getInstance(activity, state); - } - } - - /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */ - @Override - public boolean onCallsFetched(Cursor cursor) { - if (getActivity() == null || getActivity().isFinishing()) { - // Return false; we did not take ownership of the cursor - return false; - } - - mAdapter.setLoading(false); - mAdapter.changeCursor(cursor); - // This will update the state of the "Clear call log" menu item. - getActivity().invalidateOptionsMenu(); - - boolean showListView = cursor != null && cursor.getCount() > 0; - mRecyclerView.setVisibility(showListView ? View.VISIBLE : View.GONE); - mEmptyListView.setVisibility(!showListView ? View.VISIBLE : View.GONE); - - if (mScrollToTop) { - // 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 (mLayoutManager.findFirstVisibleItemPosition() > 5) { - // TODO: Jump to near the top, then begin smooth scroll. - mRecyclerView.smoothScrollToPosition(0); - } - // 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; - } - mRecyclerView.smoothScrollToPosition(0); - } - }); - - mScrollToTop = false; - } - mCallLogFetched = true; - destroyEmptyLoaderIfAllDataFetched(); - return true; - } - - /** - * Called by {@link CallLogQueryHandler} after a successful query to voicemail status provider. - */ - @Override - public void onVoicemailStatusFetched(Cursor statusCursor) { - Activity activity = getActivity(); - if (activity == null || activity.isFinishing()) { - return; - } - - mVoicemailStatusFetched = true; - destroyEmptyLoaderIfAllDataFetched(); - } - - @Override - public void onVoicemailUnreadCountFetched(Cursor cursor){ - //to do somthing - } - - @Override - public void onMissedCallsUnreadCountFetched(Cursor cursor){ - //to do somthing - } - - private void destroyEmptyLoaderIfAllDataFetched() { - if (mCallLogFetched && mVoicemailStatusFetched && mEmptyLoaderRunning) { - mEmptyLoaderRunning = false; - getLoaderManager().destroyLoader(EMPTY_LOADER_ID); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { - View view = inflater.inflate(R.layout.msim_call_log_fragment, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - mRecyclerView.setHasFixedSize(true); - mLayoutManager = new LinearLayoutManager(getActivity()); - mRecyclerView.setLayoutManager(mLayoutManager); - mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view); - mEmptyListView.setImage(R.drawable.empty_call_log); - mEmptyListView.setActionClickedListener(this); - mFilterSubSpinnerView = (Spinner) view.findViewById(R.id.filter_sub_spinner); - mFilterStatusSpinnerView = (Spinner) view.findViewById(R.id.filter_status_spinner); - // Update the filter views. - updateFilterSpinnerViews(); - - String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); - mAdapter = ObjectFactory.newCallLogAdapter( - getActivity(), - this, - new ContactInfoHelper(getActivity(), currentCountryIso), - mVoicemailPlaybackPresenter, - CallLogAdapter.ACTIVITY_TYPE_CALL_LOG); - mRecyclerView.setAdapter(mAdapter); - - fetchCalls(); - return view; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - updateEmptyMessage(mCallTypeFilter); - mAdapter.onRestoreInstanceState(savedInstanceState); - } - - @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() { - super.onResume(); - - final boolean hasReadCallLogPermission = - PermissionsUtil.hasPermission(getActivity(), READ_CALL_LOG); - if (!mHasReadCallLogPermission && hasReadCallLogPermission) { - // We didn't have the permission before, and now we do. Force a refresh of the call log. - // Note that this code path always happens on a fresh start, but mRefreshDataRequired - // is already true in that case anyway. - mRefreshDataRequired = true; - updateEmptyMessage(mCallTypeFilter); - } - mHasReadCallLogPermission = hasReadCallLogPermission; - refreshData(); - mAdapter.startCache(); - } - - @Override - public void onPause() { - if (mVoicemailPlaybackPresenter != null) { - mVoicemailPlaybackPresenter.onPause(); - } - mAdapter.pauseCache(); - super.onPause(); - } - - @Override - public void onStop() { - updateOnTransition(false /* onEntry */); - - super.onStop(); - } - - @Override - public void onDestroy() { - mAdapter.pauseCache(); - mAdapter.changeCursor(null); - - if (mVoicemailPlaybackPresenter != null) { - mVoicemailPlaybackPresenter.onDestroy(); - } - - getActivity().getContentResolver().unregisterContentObserver(mCallLogObserver); - getActivity().getContentResolver().unregisterContentObserver(mContactsObserver); - getActivity().getContentResolver().unregisterContentObserver(mVoicemailStatusObserver); - super.onDestroy(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(KEY_FILTER_TYPE, mCallTypeFilter); - outState.putInt(KEY_LOG_LIMIT, mLogLimit); - outState.putLong(KEY_DATE_LIMIT, mDateLimit); - - mAdapter.onSaveInstanceState(outState); - - if (mVoicemailPlaybackPresenter != null) { - mVoicemailPlaybackPresenter.onSaveInstanceState(outState); - } - } - - @Override - public void fetchCalls() { - if (mFilterSubSpinnerView.isEnabled()) { - int[] subId = SubscriptionManager.getSubId(mCallSubFilter); - if (subId != null) { - Log.d(TAG, "fetchCalls subId = " + subId[0]); - mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit, subId[0]); - } else { - mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit); - } - } else { - mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit); - } - updateEmptyMessage(mCallTypeFilter); - } - - private void updateEmptyMessage(int filterType) { - final Context context = getActivity(); - if (context == null) { - return; - } - - if (!PermissionsUtil.hasPermission(context, READ_CALL_LOG)) { - mEmptyListView.setDescription(R.string.permission_no_calllog); - mEmptyListView.setActionLabel(R.string.permission_single_turn_on); - return; - } - - final int messageId; - switch (filterType) { - case Calls.INCOMING_TYPE: - messageId = R.string.recentIncoming_empty; - break; - case Calls.OUTGOING_TYPE: - messageId = R.string.recentOutgoing_empty; - break; - case Calls.MISSED_TYPE: - messageId = R.string.call_log_missed_empty; - break; - case Calls.VOICEMAIL_TYPE: - messageId = R.string.call_log_voicemail_empty; - break; - case CallLogQueryHandler.CALL_TYPE_ALL: - messageId = R.string.recentCalls_empty; - break; - default: - throw new IllegalArgumentException("Unexpected filter type in CallLogFragment: " - + filterType); - } - mEmptyListView.setDescription(messageId); - if (mIsRecentsFragment) { - mEmptyListView.setActionLabel(R.string.call_log_all_empty_action); - } else { - mEmptyListView.setActionLabel(EmptyContentView.NO_LABEL); - } - } - - CallLogAdapter getAdapter() { - return mAdapter; - } - - @Override - public void setMenuVisibility(boolean menuVisible) { - super.setMenuVisibility(menuVisible); - if (mMenuVisible != menuVisible) { - mMenuVisible = menuVisible; - if (!menuVisible) { - updateOnTransition(false /* onEntry */); - } else if (isResumed()) { - refreshData(); - } - } - } - - /** Requests updates to the data to be shown. */ - protected 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(); - mAdapter.setLoading(true); - - fetchCalls(); - mCallLogQueryHandler.fetchVoicemailStatus(); - - updateOnTransition(true /* onEntry */); - mRefreshDataRequired = false; - } else { - // Refresh the display of the existing data to update the timestamp text descriptions. - mAdapter.notifyDataSetChanged(); - } - } - - /** - * Updates the call data and notification state on entering or leaving the call log tab. - * - * If we are leaving the call log tab, mark all the missed calls as read. - * - * TODO: Move to CallLogActivity - */ - 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 update the missed call and voicemail notifications. - // While exiting we additionally consume all missed calls (by marking them as read). - mCallLogQueryHandler.markNewCallsAsOld(); - if (!onEntry) { - mCallLogQueryHandler.markMissedCallsAsRead(); - } - CallLogNotificationsHelper.removeMissedCallNotifications(getActivity()); - CallLogNotificationsHelper.updateVoicemailNotifications(getActivity()); - } - } - - @Override - public void onEmptyViewActionButtonClicked() { - final Activity activity = getActivity(); - if (activity == null) { - return; - } - - if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) { - requestPermissions(new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE); - } else if (mIsRecentsFragment) { - // Show dialpad if we are the recents fragment. - ((HostInterface) activity).showDialpad(); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, - int[] grantResults) { - if (requestCode == READ_CALL_LOG_PERMISSION_REQUEST_CODE) { - if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) { - // Force a refresh of the data since we were missing the permission before this. - mRefreshDataRequired = true; - } - } - } - - private OnItemSelectedListener mSubSelectedListener = new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - Log.i(TAG, "Sub selected, position: " + position); - int sub = position - 1; - if (sub != mCallSubFilter) { - mCallSubFilter = sub; - setSelectedSub(sub); - fetchCalls(); - } - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Do nothing. - } - - }; - - private OnItemSelectedListener mStatusSelectedListener = new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - Log.i(TAG, "Status selected, position: " + position); - int type = ((SpinnerContent)parent.getItemAtPosition(position)).value; - if (type != mCallTypeFilter) { - mCallTypeFilter = type; - fetchCalls(); - } - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Do nothing. - } - - }; - - /** - * Initialize the filter views content. - */ - private void updateFilterSpinnerViews() { - if (mFilterSubSpinnerView == null - || mFilterStatusSpinnerView == null) { - Log.w(TAG, "The filter spinner view is null!"); - return; - } - - // Update the sub filter's content. - final SubscriptionManager subscriptionManager = SubscriptionManager.from(getActivity()); - if (subscriptionManager.getActiveSubscriptionInfoCount() < 2) { - mFilterSubSpinnerView.setVisibility(View.GONE); - }else{ - ArrayAdapter<SpinnerContent> filterSubAdapter = new ArrayAdapter<SpinnerContent>( - getActivity(), R.layout.msim_call_log_spinner_item, - SpinnerContent.setupSubFilterContent(getActivity())); - if (filterSubAdapter.getCount() <= 1) { - mFilterSubSpinnerView.setVisibility(View.GONE); - }else{ - mCallSubFilter = getSelectedSub(); - mFilterSubSpinnerView.setAdapter(filterSubAdapter); - mFilterSubSpinnerView.setOnItemSelectedListener(mSubSelectedListener); - SpinnerContent.setSpinnerContentValue(mFilterSubSpinnerView, mCallSubFilter); - } - } - // Update the status filter's content. - ArrayAdapter<SpinnerContent> filterStatusAdapter = new ArrayAdapter<SpinnerContent>( - getActivity(), R.layout.msim_call_log_spinner_item, - SpinnerContent.setupStatusFilterContent(getActivity(), false)); - mFilterStatusSpinnerView.setAdapter(filterStatusAdapter); - mFilterStatusSpinnerView.setOnItemSelectedListener(mStatusSelectedListener); - SpinnerContent.setSpinnerContentValue(mFilterStatusSpinnerView, mCallTypeFilter); - } - - /** - * @return the saved selected subscription. - */ - private int getSelectedSub() { - // Get the saved selected sub, and the default value is display all. - int sub = PreferenceManager.getDefaultSharedPreferences(this.getActivity()).getInt( - PREFERENCE_KEY_CALLLOG_SUB, CallLogQueryHandler.CALL_SUB_ALL); - return sub; - } - - /** - * Save the selected subscription to preference. - */ - private void setSelectedSub(int sub) { - // Save the selected sub to the default preference. - PreferenceManager.getDefaultSharedPreferences(this.getActivity()).edit() - .putInt(PREFERENCE_KEY_CALLLOG_SUB, sub).commit(); - } - -} |