From 184935c605a3ab4e6efd352f61bab9836b093571 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Wed, 14 Sep 2016 15:16:57 +0200 Subject: Don't use a different call log for MSIM. Change-Id: Ic5a0a4f8521e66d5d78416302a76a4314e3cb0b4 --- res/layout/call_log_fragment.xml | 32 +- res/layout/msim_call_log_activity.xml | 39 -- res/layout/msim_call_log_fragment.xml | 54 -- res/layout/msim_call_log_spinner.xml | 53 -- res/layout/msim_call_log_spinner_item.xml | 38 -- res/values/cm_strings.xml | 1 + .../android/dialer/calllog/CallLogActivity.java | 85 +-- .../android/dialer/calllog/CallLogFragment.java | 130 +++- .../dialer/calllog/CallLogQueryHandler.java | 75 +-- .../dialer/calllog/MSimCallLogFragment.java | 658 --------------------- .../android/dialer/widget/EmptyContentView.java | 5 - 11 files changed, 168 insertions(+), 1002 deletions(-) delete mode 100644 res/layout/msim_call_log_activity.xml delete mode 100644 res/layout/msim_call_log_fragment.xml delete mode 100644 res/layout/msim_call_log_spinner.xml delete mode 100644 res/layout/msim_call_log_spinner_item.xml delete mode 100644 src/com/android/dialer/calllog/MSimCallLogFragment.java diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml index aad7d8e77..6b6726491 100644 --- a/res/layout/call_log_fragment.xml +++ b/res/layout/call_log_fragment.xml @@ -15,19 +15,41 @@ --> - + android:background="@color/background_dialer_call_log" + design:statusBarBackground="@null"> - + + + + + + + + + + + android:paddingBottom="@dimen/floating_action_button_list_bottom_padding" + design:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + diff --git a/res/layout/msim_call_log_activity.xml b/res/layout/msim_call_log_activity.xml deleted file mode 100644 index bca6bf4fa..000000000 --- a/res/layout/msim_call_log_activity.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - diff --git a/res/layout/msim_call_log_fragment.xml b/res/layout/msim_call_log_fragment.xml deleted file mode 100644 index 6ee584b78..000000000 --- a/res/layout/msim_call_log_fragment.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - diff --git a/res/layout/msim_call_log_spinner.xml b/res/layout/msim_call_log_spinner.xml deleted file mode 100644 index 5310acee1..000000000 --- a/res/layout/msim_call_log_spinner.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - diff --git a/res/layout/msim_call_log_spinner_item.xml b/res/layout/msim_call_log_spinner_item.xml deleted file mode 100644 index 0b1bcf308..000000000 --- a/res/layout/msim_call_log_spinner_item.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 6dae69cfd..0fa559024 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -50,6 +50,7 @@ All SIMs All calls Blocked calls only + You have no blocked calls. Statistics diff --git a/src/com/android/dialer/calllog/CallLogActivity.java b/src/com/android/dialer/calllog/CallLogActivity.java index 9686e41b9..35f258876 100644 --- a/src/com/android/dialer/calllog/CallLogActivity.java +++ b/src/com/android/dialer/calllog/CallLogActivity.java @@ -73,7 +73,6 @@ public class CallLogActivity extends TransactionSafeActivity implements private CallLogFragment mMissedCallsFragment; private CallStatsFragment mStatsFragment; - private MSimCallLogFragment mMSimCallsFragment; private CallLogSearchFragment mSearchFragment; private EditText mSearchView; private ImageView mClearButtonView; @@ -88,9 +87,6 @@ public class CallLogActivity extends TransactionSafeActivity implements private boolean mIsResumed; - private static final int TAB_INDEX_MSIM = 0; - private static final int TAB_INDEX_COUNT_MSIM = 1; - public class ViewPagerAdapter extends FragmentPagerAdapter { public ViewPagerAdapter(FragmentManager fm) { super(fm); @@ -143,39 +139,6 @@ public class CallLogActivity extends TransactionSafeActivity implements } } - public class MSimViewPagerAdapter extends FragmentPagerAdapter { - public MSimViewPagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public Fragment getItem(int position) { - switch (position) { - case TAB_INDEX_MSIM: - mMSimCallsFragment = new MSimCallLogFragment(); - return mMSimCallsFragment; - } - throw new IllegalStateException("No fragment at position " + position); - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - final MSimCallLogFragment fragment = - (MSimCallLogFragment) super.instantiateItem(container, position); - switch (position) { - case TAB_INDEX_MSIM: - mMSimCallsFragment = fragment; - break; - } - return fragment; - } - - @Override - public int getCount() { - return TAB_INDEX_COUNT_MSIM; - } - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { @@ -194,11 +157,6 @@ public class CallLogActivity extends TransactionSafeActivity implements actionBar.setDisplayShowTitleEnabled(true); actionBar.setElevation(0); - if ( TelephonyManager.getDefault().isMultiSimEnabled()) { - initMSimCallLog(); - return; - } - setContentView(R.layout.call_log_activity); getWindow().setBackgroundDrawable(null); @@ -255,22 +213,6 @@ public class CallLogActivity extends TransactionSafeActivity implements } } - private void initMSimCallLog() { - setContentView(R.layout.msim_call_log_activity); - getWindow().setBackgroundDrawable(null); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowHomeEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - - mViewPager = (ViewPager) findViewById(R.id.call_log_pager); - - mViewPagerAdapter = new MSimViewPagerAdapter(getFragmentManager()); - mViewPager.setAdapter(mViewPagerAdapter); - mViewPager.setOffscreenPageLimit(1); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { final MenuInflater inflater = getMenuInflater(); @@ -283,10 +225,6 @@ public class CallLogActivity extends TransactionSafeActivity implements final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all); final MenuItem itemSearchCallLog = menu.findItem(R.id.search_calllog); - if (mMSimCallsFragment != null && itemDeleteAll != null) { - final CallLogAdapter adapter = mMSimCallsFragment.getAdapter(); - itemDeleteAll.setVisible(adapter != null && !adapter.isEmpty()); - } if (mInSearchUi) { if (itemDeleteAll != null) { itemDeleteAll.setVisible(false); @@ -394,12 +332,8 @@ public class CallLogActivity extends TransactionSafeActivity implements } final ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowCustomEnabled(true); - if (mMSimCallsFragment != null) { - updateMSimFragmentVisibility(false); - } else { - for (int i = 0; i < mViewPagerAdapter.getCount(); i++) { - updateFragmentVisibility(i, false /* not visible */); - } + for (int i = 0; i < mViewPagerAdapter.getCount(); i++) { + updateFragmentVisibility(i, false /* not visible */); } mViewPager.setVisibility(View.GONE); if (mViewPagerTabs != null) { @@ -417,13 +351,6 @@ public class CallLogActivity extends TransactionSafeActivity implements } } - private void updateMSimFragmentVisibility(boolean visibility) { - if (mMSimCallsFragment != null) { - mMSimCallsFragment.setMenuVisibility(visibility); - mMSimCallsFragment.setUserVisibleHint(visibility); - } - } - private Fragment getFragmentAt(int position) { switch (position) { case TAB_INDEX_ALL: @@ -556,12 +483,8 @@ public class CallLogActivity extends TransactionSafeActivity implements // We want to hide SearchView and show Tabs. Also focus on previously // selected one. actionBar.setDisplayShowCustomEnabled(false); - if (mMSimCallsFragment != null) { - updateMSimFragmentVisibility(true); - } else { - for (int i = 0; i < mViewPagerAdapter.getCount(); i++) { - updateFragmentVisibility(i, i == mViewPager.getCurrentItem()); - } + for (int i = 0; i < mViewPagerAdapter.getCount(); i++) { + updateFragmentVisibility(i, i == mViewPager.getCurrentItem()); } mViewPager.setVisibility(View.VISIBLE); if (mViewPagerTabs != null) { diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java index 96551a4b4..0cd7a4eb8 100644 --- a/src/com/android/dialer/calllog/CallLogFragment.java +++ b/src/com/android/dialer/calllog/CallLogFragment.java @@ -27,6 +27,7 @@ import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.preference.PreferenceManager; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract; @@ -34,9 +35,14 @@ import android.support.annotation.Nullable; import android.support.v13.app.FragmentCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.telephony.SubscriptionManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.Spinner; import com.android.contacts.common.GeoUtil; import com.android.contacts.common.util.PermissionsUtil; @@ -86,6 +92,15 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis protected CallLogQueryHandler mCallLogQueryHandler; private boolean mScrollToTop; + // 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 EmptyContentView mEmptyListView; private KeyguardManager mKeyguardManager; @@ -106,6 +121,40 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis } }; + private final OnItemSelectedListener mSubSelectedListener = new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + int sub = position - 1; + if (sub != mCallSubFilter) { + mCallSubFilter = sub; + setSelectedSub(sub); + fetchCalls(); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + // Do nothing. + } + }; + + private final OnItemSelectedListener mStatusSelectedListener = new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + int type = ((SpinnerContent)parent.getItemAtPosition(position)).value; + if (type != mCallTypeFilter) { + mCallTypeFilter = type; + updateEmptyMessage(mCallTypeFilter); + fetchCalls(); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + // Do nothing. + } + }; + private final Handler mHandler = new Handler(); protected class CustomContentObserver extends ContentObserver { @@ -143,6 +192,7 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis * True if this instance of the CallLogFragment shown in the CallLogActivity. */ private boolean mIsCallLogActivity = false; + private boolean mShowingAllCallsByDefault = true; public interface HostInterface { public void showDialpad(); @@ -186,6 +236,7 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis mCallTypeFilter = filterType; mLogLimit = logLimit; mDateLimit = dateLimit; + mShowingAllCallsByDefault = filterType == CallLogQueryHandler.CALL_TYPE_ALL; } @Override @@ -301,6 +352,11 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis 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(); + int activityType = mIsCallLogActivity ? CallLogAdapter.ACTIVITY_TYPE_CALL_LOG : CallLogAdapter.ACTIVITY_TYPE_DIALTACTS; String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); @@ -386,7 +442,13 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis @Override public void fetchCalls() { - mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit); + int[] subIds = mCallSubFilter == CallLogQueryHandler.CALL_SUB_ALL + ? null : SubscriptionManager.getSubId(mCallSubFilter); + if (subIds != null) { + mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit, subIds[0]); + } else { + mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit); + } if (!mIsCallLogActivity) { ((ListsFragment) getParentFragment()).updateTabUnreadCounts(); } @@ -406,9 +468,18 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis 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.BLOCKED_TYPE: + messageId = R.string.call_log_blocked_empty; + break; case Calls.VOICEMAIL_TYPE: messageId = R.string.call_log_voicemail_empty; break; @@ -531,4 +602,61 @@ public class CallLogFragment extends Fragment implements CallLogQueryHandler.Lis private void cancelDisplayUpdate() { mDisplayUpdateHandler.removeMessages(EVENT_UPDATE_DISPLAY); } + + /** + * Initialize the filter views content. + */ + private void updateFilterSpinnerViews() { + if (mFilterSubSpinnerView == null || mFilterStatusSpinnerView == null) { + return; + } + + // Update the sub filter's content. + final SubscriptionManager subscriptionManager = SubscriptionManager.from(getActivity()); + if (!mIsCallLogActivity || subscriptionManager.getActiveSubscriptionInfoCount() < 2) { + mFilterSubSpinnerView.setVisibility(View.GONE); + } else { + ArrayAdapter filterSubAdapter = new ArrayAdapter( + getActivity(), R.layout.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); + } + } + if (!mIsCallLogActivity || !mShowingAllCallsByDefault) { + mFilterStatusSpinnerView.setVisibility(View.GONE); + } else { + // Update the status filter's content. + ArrayAdapter filterStatusAdapter = new ArrayAdapter( + getActivity(), R.layout.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(); + } } diff --git a/src/com/android/dialer/calllog/CallLogQueryHandler.java b/src/com/android/dialer/calllog/CallLogQueryHandler.java index 116d9ef17..7c29cd184 100644 --- a/src/com/android/dialer/calllog/CallLogQueryHandler.java +++ b/src/com/android/dialer/calllog/CallLogQueryHandler.java @@ -156,7 +156,8 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler { public void fetchCalls(int callType, long newerThan) { cancelFetch(); if (PermissionsUtil.hasPhonePermissions(mContext)) { - fetchCalls(QUERY_CALLLOG_TOKEN, callType, false /* newOnly */, newerThan); + fetchCalls(QUERY_CALLLOG_TOKEN, callType, false /* newOnly */, + newerThan, CALL_SUB_ALL); } else { updateAdapterData(null); } @@ -206,7 +207,7 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler { } /** Fetches the list of calls in the call log. */ - private void fetchCalls(int token, int callType, boolean newOnly, long newerThan) { + private void fetchCalls(int token, int callType, boolean newOnly, long newerThan, int sub) { StringBuilder where = new StringBuilder(); List selectionArgs = Lists.newArrayList(); @@ -253,75 +254,15 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler { where.append("(" + Calls.TYPE + " = " + AppCompatConstants.CALLS_VOICEMAIL_TYPE + ")"); } - // Add a clause to fetch only items newer than the requested date - if (newerThan > 0) { - where.append(" AND (").append(Calls.DATE).append(" > ?)"); - selectionArgs.add(Long.toString(newerThan)); - } - - final int limit = (mLogLimit == -1) ? NUM_LOGS_TO_DISPLAY : mLogLimit; - final String selection = where.length() > 0 ? where.toString() : null; - Uri uri = TelecomUtil.getCallLogUri(mContext).buildUpon() - .appendQueryParameter(Calls.LIMIT_PARAM_KEY, Integer.toString(limit)) - .build(); - startQuery(token, null, uri, CallLogQuery._PROJECTION, selection, selectionArgs.toArray( - new String[selectionArgs.size()]), Calls.DEFAULT_SORT_ORDER); - } - - private void fetchCalls(int token, int callType, boolean newOnly, - long newerThan, int sub) { - // We need to check for NULL explicitly otherwise entries with where READ is NULL - // may not match either the query or its negation. - // We consider the calls that are not yet consumed (i.e. IS_READ = 0) as "new". - StringBuilder where = new StringBuilder(); - List selectionArgs = Lists.newArrayList(); - - // Ignore voicemails marked as deleted - where.append(Voicemails.DELETED); - where.append(" = 0"); - - if (newOnly) { - where.append(" AND "); - where.append(Calls.NEW); - where.append(" = 1"); - } - - if (callType > CALL_TYPE_ALL) { - where.append(" AND "); - if ((callType == Calls.INCOMING_TYPE) || (callType == Calls.OUTGOING_TYPE) - || (callType == Calls.MISSED_TYPE)) { - where.append(String.format("(%s = ? OR %s = ? OR %s = ?)", - Calls.TYPE, Calls.TYPE, Calls.TYPE)); - } else { - // Add a clause to fetch only items of type voicemail. - where.append(String.format("(%s = ?)", Calls.TYPE)); - } - // Add a clause to fetch only items newer than the requested date - selectionArgs.add(Integer.toString(callType)); - if (callType == Calls.INCOMING_TYPE) { - selectionArgs.add(Integer.toString(AppCompatConstants.INCOMING_IMS_TYPE)); - selectionArgs.add(Integer.toString(AppCompatConstants.INCOMING_WIFI_TYPE)); - } else if (callType == Calls.OUTGOING_TYPE) { - selectionArgs.add(Integer.toString(AppCompatConstants.OUTGOING_IMS_TYPE)); - selectionArgs.add(Integer.toString(AppCompatConstants.OUTGOING_WIFI_TYPE)); - } else if (callType == Calls.MISSED_TYPE) { - selectionArgs.add(Integer.toString(AppCompatConstants.MISSED_IMS_TYPE)); - selectionArgs.add(Integer.toString(AppCompatConstants.MISSED_WIFI_TYPE)); - } - } else { - where.append(" AND NOT "); - where.append("(" + Calls.TYPE + " = " + Calls.VOICEMAIL_TYPE + ")"); - } - if (sub > CALL_SUB_ALL) { where.append(" AND "); where.append(String.format("(%s = ?)", Calls.PHONE_ACCOUNT_ID)); selectionArgs.add(Integer.toString(sub)); } + // Add a clause to fetch only items newer than the requested date if (newerThan > 0) { - where.append(" AND "); - where.append(String.format("(%s > ?)", Calls.DATE)); + where.append(" AND (").append(Calls.DATE).append(" > ?)"); selectionArgs.add(Long.toString(newerThan)); } @@ -330,12 +271,10 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler { Uri uri = TelecomUtil.getCallLogUri(mContext).buildUpon() .appendQueryParameter(Calls.LIMIT_PARAM_KEY, Integer.toString(limit)) .build(); - startQuery(token, null, uri, - CallLogQuery._PROJECTION, selection, selectionArgs.toArray(EMPTY_STRING_ARRAY), - Calls.DEFAULT_SORT_ORDER); + startQuery(token, null, uri, CallLogQuery._PROJECTION, selection, selectionArgs.toArray( + new String[selectionArgs.size()]), Calls.DEFAULT_SORT_ORDER); } - /** Cancel any pending fetch request. */ private void cancelFetch() { cancelOperation(QUERY_CALLLOG_TOKEN); 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 filterSubAdapter = new ArrayAdapter( - 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 filterStatusAdapter = new ArrayAdapter( - 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(); - } - -} diff --git a/src/com/android/dialer/widget/EmptyContentView.java b/src/com/android/dialer/widget/EmptyContentView.java index 70f0e5a64..719fd3ff8 100644 --- a/src/com/android/dialer/widget/EmptyContentView.java +++ b/src/com/android/dialer/widget/EmptyContentView.java @@ -74,11 +74,6 @@ public class EmptyContentView extends LinearLayout implements View.OnClickListen mDescriptionView.setText(null); mDescriptionView.setVisibility(View.GONE); } else { - if (resourceId == R.string.no_call_log) { - mDescriptionView.setText(resourceId); - mDescriptionView.setVisibility(View.VISIBLE); - mDescriptionView.setPadding(0, 0, 0, 700); - } mDescriptionView.setText(resourceId); mDescriptionView.setVisibility(View.VISIBLE); } -- cgit v1.2.3