1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/* 2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2011 The Android Open Source Project 3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License"); 5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License. 6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at 7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * http://www.apache.org/licenses/LICENSE-2.0 9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software 11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS, 12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and 14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License. 15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.dialer.app.calllog; 18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static android.Manifest.permission.READ_CALL_LOG; 20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.Activity; 22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.Fragment; 23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.KeyguardManager; 24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.ContentResolver; 25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context; 26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.pm.PackageManager; 27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.ContentObserver; 28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.Cursor; 29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Bundle; 30ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Handler; 31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Message; 32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.CallLog; 33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.CallLog.Calls; 34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract; 35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.CallSuper; 36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.Nullable; 37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.v13.app.FragmentCompat; 38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.v7.app.AppCompatActivity; 39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.v7.widget.LinearLayoutManager; 40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.v7.widget.RecyclerView; 41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.LayoutInflater; 42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.View; 43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.ViewGroup; 44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.Bindings; 45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.R; 46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.calllog.calllogcache.CallLogCache; 47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.contactinfo.ContactInfoCache; 48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.contactinfo.ContactInfoCache.OnContactInfoChangedListener; 49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.contactinfo.ExpirableCacheHeadlessFragment; 50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.list.ListsFragment; 51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.voicemail.VoicemailPlaybackPresenter; 52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.widget.EmptyContentView; 53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.app.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; 54d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; 55d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.common.Assert; 56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.LogUtil; 57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.database.CallLogQueryHandler; 5810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.location.GeoUtil; 59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.phonenumbercache.ContactInfoHelper; 60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.util.PermissionsUtil; 61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/** 63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Displays a list of call log entries. To filter for a particular kind of call (all, missed or 64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * voicemails), specify it in the constructor. 65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class CallLogFragment extends Fragment 67d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian implements CallLogQueryHandler.Listener, 68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallLogAdapter.CallFetcher, 69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian OnEmptyViewActionButtonClickedListener, 70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian FragmentCompat.OnRequestPermissionsResultCallback, 71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallLogModalAlertManager.Listener { 72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final String KEY_FILTER_TYPE = "filter_type"; 73d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private static final String KEY_LOG_LIMIT = "log_limit"; 74d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private static final String KEY_DATE_LIMIT = "date_limit"; 75d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private static final String KEY_IS_CALL_LOG_ACTIVITY = "is_call_log_activity"; 76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final String KEY_HAS_READ_CALL_LOG_PERMISSION = "has_read_call_log_permission"; 77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final String KEY_REFRESH_DATA_REQUIRED = "refresh_data_required"; 78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 79d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // No limit specified for the number of logs to show; use the CallLogQueryHandler's default. 80d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private static final int NO_LOG_LIMIT = -1; 81d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // No date-based filtering. 82d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private static final int NO_DATE_LIMIT = 0; 83d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int READ_CALL_LOG_PERMISSION_REQUEST_CODE = 1; 85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int EVENT_UPDATE_DISPLAY = 1; 87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final long MILLIS_IN_MINUTE = 60 * 1000; 89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final Handler mHandler = new Handler(); 90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // See issue 6363009 91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final ContentObserver mCallLogObserver = new CustomContentObserver(); 92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final ContentObserver mContactsObserver = new CustomContentObserver(); 93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private RecyclerView mRecyclerView; 94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private LinearLayoutManager mLayoutManager; 95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private CallLogAdapter mAdapter; 96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private CallLogQueryHandler mCallLogQueryHandler; 97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean mScrollToTop; 98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private EmptyContentView mEmptyListView; 99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private KeyguardManager mKeyguardManager; 100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private ContactInfoCache mContactInfoCache; 101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final OnContactInfoChangedListener mOnContactInfoChangedListener = 102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new OnContactInfoChangedListener() { 103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onContactInfoChanged() { 105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mAdapter != null) { 106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.notifyDataSetChanged(); 107ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }; 110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean mRefreshDataRequired; 111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean mHasReadCallLogPermission; 112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Exactly same variable is in Fragment as a package private. 113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean mMenuVisible = true; 114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Default to all calls. 115d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL; 116d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // Log limit - if no limit is specified, then the default in {@link CallLogQueryHandler} 117d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // will be used. 118d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private int mLogLimit = NO_LOG_LIMIT; 119d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // Date limit (in millis since epoch) - when non-zero, only calls which occurred on or after 120d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // the date filter are included. If zero, no date-based filtering occurs. 121d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private long mDateLimit = NO_DATE_LIMIT; 122d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /* 123d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * True if this instance of the CallLogFragment shown in the CallLogActivity. 124d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 125d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private boolean mIsCallLogActivity = false; 126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final Handler mDisplayUpdateHandler = 127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new Handler() { 128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void handleMessage(Message msg) { 130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian switch (msg.what) { 131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case EVENT_UPDATE_DISPLAY: 132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian refreshData(); 133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian rescheduleDisplayUpdate(); 134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 135d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian default: 136d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian throw Assert.createAssertionFailException("Invalid message: " + msg); 137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }; 140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected CallLogModalAlertManager mModalAlertManager; 141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private ViewGroup mModalAlertView; 142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 143d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment() { 144d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian this(CallLogQueryHandler.CALL_TYPE_ALL, NO_LOG_LIMIT); 145d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 146d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 147d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment(int filterType) { 148d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian this(filterType, NO_LOG_LIMIT); 149d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 150d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 151d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment(int filterType, boolean isCallLogActivity) { 152d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian this(filterType, NO_LOG_LIMIT); 153d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mIsCallLogActivity = isCallLogActivity; 154d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 155d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 156d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment(int filterType, int logLimit) { 157d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian this(filterType, logLimit, NO_DATE_LIMIT); 158d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 159d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 160d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 161d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Creates a call log fragment, filtering to include only calls of the desired type, occurring 162d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * after the specified date. 163d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 164d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param filterType type of calls to include. 165d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param dateLimit limits results to calls occurring on or after the specified date. 166d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 167d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment(int filterType, long dateLimit) { 168d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian this(filterType, NO_LOG_LIMIT, dateLimit); 169d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 170d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 171d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 172d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Creates a call log fragment, filtering to include only calls of the desired type, occurring 173d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * after the specified date. Also provides a means to limit the number of results returned. 174d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 175d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param filterType type of calls to include. 176d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param logLimit limits the number of results to return. 177d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param dateLimit limits results to calls occurring on or after the specified date. 178d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 179d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public CallLogFragment(int filterType, int logLimit, long dateLimit) { 180d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mCallTypeFilter = filterType; 181d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mLogLimit = logLimit; 182d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mDateLimit = dateLimit; 183d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 184d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onCreate(Bundle state) { 187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d("CallLogFragment.onCreate", toString()); 188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onCreate(state); 189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = true; 190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state != null) { 191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCallTypeFilter = state.getInt(KEY_FILTER_TYPE, mCallTypeFilter); 192d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mLogLimit = state.getInt(KEY_LOG_LIMIT, mLogLimit); 193d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mDateLimit = state.getLong(KEY_DATE_LIMIT, mDateLimit); 194d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mIsCallLogActivity = state.getBoolean(KEY_IS_CALL_LOG_ACTIVITY, mIsCallLogActivity); 195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mHasReadCallLogPermission = state.getBoolean(KEY_HAS_READ_CALL_LOG_PERMISSION, false); 196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = state.getBoolean(KEY_REFRESH_DATA_REQUIRED, mRefreshDataRequired); 197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Activity activity = getActivity(); 200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final ContentResolver resolver = activity.getContentResolver(); 201d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, mLogLimit); 202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mKeyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); 203c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian 204c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian if (PermissionsUtil.hasCallLogReadPermissions(getContext())) { 205c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian resolver.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver); 206c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } else { 207c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian LogUtil.w("CallLogFragment.onCreate", "call log permission not available"); 208c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } 209c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian if (PermissionsUtil.hasContactsReadPermissions(getContext())) { 210c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian resolver.registerContentObserver( 211c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian ContactsContract.Contacts.CONTENT_URI, true, mContactsObserver); 212c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } else { 213c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian LogUtil.w("CallLogFragment.onCreate", "contacts permission not available."); 214c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } 215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setHasOptionsMenu(true); 216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */ 219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public boolean onCallsFetched(Cursor cursor) { 221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (getActivity() == null || getActivity().isFinishing()) { 222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Return false; we did not take ownership of the cursor 223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return false; 224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.invalidatePositions(); 226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.setLoading(false); 227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.changeCursor(cursor); 228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This will update the state of the "Clear call log" menu item. 229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActivity().invalidateOptionsMenu(); 230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (cursor != null && cursor.getCount() > 0) { 232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setPaddingRelative( 233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.getPaddingStart(), 234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 0, 235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.getPaddingEnd(), 236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getResources().getDimensionPixelSize(R.dimen.floating_action_button_list_bottom_padding)); 237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setVisibility(View.GONE); 238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setPaddingRelative( 240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.getPaddingStart(), 0, mRecyclerView.getPaddingEnd(), 0); 241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setVisibility(View.VISIBLE); 242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mScrollToTop) { 244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // The smooth-scroll animation happens over a fixed time period. 245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // As a result, if it scrolls through a large portion of the list, 246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // each frame will jump so far from the previous one that the user 247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // will not experience the illusion of downward motion. Instead, 248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // if we're not already near the top of the list, we instantly jump 249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // near the top, and animate from there. 250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mLayoutManager.findFirstVisibleItemPosition() > 5) { 251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // TODO: Jump to near the top, then begin smooth scroll. 252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.smoothScrollToPosition(0); 253ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 254ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Workaround for framework issue: the smooth-scroll doesn't 255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // occur if setSelection() is called immediately before. 256ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mHandler.post( 257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new Runnable() { 258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void run() { 260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (getActivity() == null || getActivity().isFinishing()) { 261ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.smoothScrollToPosition(0); 264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 265ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }); 266ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mScrollToTop = false; 268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return true; 270ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 271ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 272ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 273ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onVoicemailStatusFetched(Cursor statusCursor) {} 274ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 275ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 276ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onVoicemailUnreadCountFetched(Cursor cursor) {} 277ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 278ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 279ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onMissedCallsUnreadCountFetched(Cursor cursor) {} 280ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 281ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 282ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 283ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian View view = inflater.inflate(R.layout.call_log_fragment, container, false); 284ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setupView(view); 285ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return view; 286ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 287ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 288ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected void setupView(View view) { 289ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); 290ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setHasFixedSize(true); 291ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mLayoutManager = new LinearLayoutManager(getActivity()); 292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setLayoutManager(mLayoutManager); 293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view); 294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setImage(R.drawable.empty_call_log); 295ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setActionClickedListener(this); 296ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mModalAlertView = (ViewGroup) view.findViewById(R.id.modal_message_container); 297ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mModalAlertManager = 298ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new CallLogModalAlertManager(LayoutInflater.from(getContext()), mModalAlertView, this); 299ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 300ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 301ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected void setupData() { 302d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian int activityType = 303d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mIsCallLogActivity 304d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ? CallLogAdapter.ACTIVITY_TYPE_CALL_LOG 305d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian : CallLogAdapter.ACTIVITY_TYPE_DIALTACTS; 306ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); 307ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 308ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache = 309ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ContactInfoCache( 310ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ExpirableCacheHeadlessFragment.attach((AppCompatActivity) getActivity()) 311ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .getRetainedCache(), 312ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ContactInfoHelper(getActivity(), currentCountryIso), 313ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mOnContactInfoChangedListener); 314ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter = 315ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bindings.getLegacy(getActivity()) 316ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .newCallLogAdapter( 317ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActivity(), 318ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView, 319ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian this, 320ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallLogCache.getCallLogCache(getActivity()), 321ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache, 322ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getVoicemailPlaybackPresenter(), 323d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new FilteredNumberAsyncQueryHandler(getActivity()), 324ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian activityType); 325ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setAdapter(mAdapter); 326ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian fetchCalls(); 327ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 328ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 329ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Nullable 330ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected VoicemailPlaybackPresenter getVoicemailPlaybackPresenter() { 331ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return null; 332ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 333ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 334ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 335ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onActivityCreated(Bundle savedInstanceState) { 336ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onActivityCreated(savedInstanceState); 337ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setupData(); 338ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.onRestoreInstanceState(savedInstanceState); 339ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 340ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 341ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 342ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onViewCreated(View view, Bundle savedInstanceState) { 343ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onViewCreated(view, savedInstanceState); 344ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateEmptyMessage(mCallTypeFilter); 345ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 346ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 347ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 348ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onResume() { 349ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d("CallLogFragment.onResume", toString()); 350ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onResume(); 351ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean hasReadCallLogPermission = 352ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PermissionsUtil.hasPermission(getActivity(), READ_CALL_LOG); 353ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!mHasReadCallLogPermission && hasReadCallLogPermission) { 354ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // We didn't have the permission before, and now we do. Force a refresh of the call log. 355ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Note that this code path always happens on a fresh start, but mRefreshDataRequired 356ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // is already true in that case anyway. 357ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = true; 358ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateEmptyMessage(mCallTypeFilter); 359ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 360ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 361ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mHasReadCallLogPermission = hasReadCallLogPermission; 362ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 363ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /* 364ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Always clear the filtered numbers cache since users could have blocked/unblocked numbers 365ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * from the settings page 366ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 367ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.clearFilteredNumbersCache(); 368ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian refreshData(); 369ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.onResume(); 370ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 371ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian rescheduleDisplayUpdate(); 372ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 373ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 374ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 375ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onPause() { 376ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d("CallLogFragment.onPause", toString()); 377ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cancelDisplayUpdate(); 378ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.onPause(); 379ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onPause(); 380ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 381ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 382ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 383ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onStop() { 384ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateOnTransition(); 385ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 386ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onStop(); 387ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.onStop(); 38810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian mContactInfoCache.stop(); 389ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 390ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 391ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 392ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDestroy() { 393ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d("CallLogFragment.onDestroy", toString()); 394ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.changeCursor(null); 395ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 396ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActivity().getContentResolver().unregisterContentObserver(mCallLogObserver); 397ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActivity().getContentResolver().unregisterContentObserver(mContactsObserver); 398ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onDestroy(); 399ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 400ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 401ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 402ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onSaveInstanceState(Bundle outState) { 403ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.onSaveInstanceState(outState); 404ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian outState.putInt(KEY_FILTER_TYPE, mCallTypeFilter); 405d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian outState.putInt(KEY_LOG_LIMIT, mLogLimit); 406d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian outState.putLong(KEY_DATE_LIMIT, mDateLimit); 407d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian outState.putBoolean(KEY_IS_CALL_LOG_ACTIVITY, mIsCallLogActivity); 408ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian outState.putBoolean(KEY_HAS_READ_CALL_LOG_PERMISSION, mHasReadCallLogPermission); 409ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian outState.putBoolean(KEY_REFRESH_DATA_REQUIRED, mRefreshDataRequired); 410ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 411ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.onSaveInstanceState(outState); 412ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 413ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 414ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 415ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void fetchCalls() { 416d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit); 417d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (!mIsCallLogActivity) { 418d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ((ListsFragment) getParentFragment()).updateTabUnreadCounts(); 419d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 420ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 421ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 422ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void updateEmptyMessage(int filterType) { 423ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Context context = getActivity(); 424ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (context == null) { 425ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 426ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 427ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 428ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!PermissionsUtil.hasPermission(context, READ_CALL_LOG)) { 429ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setDescription(R.string.permission_no_calllog); 430ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setActionLabel(R.string.permission_single_turn_on); 431ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 432ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 433ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 434ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int messageId; 435ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian switch (filterType) { 436ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case Calls.MISSED_TYPE: 437ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian messageId = R.string.call_log_missed_empty; 438ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 439ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case Calls.VOICEMAIL_TYPE: 440ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian messageId = R.string.call_log_voicemail_empty; 441ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 442ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case CallLogQueryHandler.CALL_TYPE_ALL: 443ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian messageId = R.string.call_log_all_empty; 444ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 445ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian default: 446ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian throw new IllegalArgumentException( 447ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "Unexpected filter type in CallLogFragment: " + filterType); 448ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 449ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setDescription(messageId); 450d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (mIsCallLogActivity) { 451d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mEmptyListView.setActionLabel(EmptyContentView.NO_LABEL); 452d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } else if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) { 453ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mEmptyListView.setActionLabel(R.string.call_log_all_empty_action); 454ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 455ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 456ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 457ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public CallLogAdapter getAdapter() { 458ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mAdapter; 459ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 460ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 461ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 462ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void setMenuVisibility(boolean menuVisible) { 463ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super.setMenuVisibility(menuVisible); 464ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mMenuVisible != menuVisible) { 465ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mMenuVisible = menuVisible; 466ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!menuVisible) { 467ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateOnTransition(); 468ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (isResumed()) { 469ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian refreshData(); 470ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 471ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 472ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 473ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 474ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Requests updates to the data to be shown. */ 475ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void refreshData() { 476ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Prevent unnecessary refresh. 477ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mRefreshDataRequired) { 478ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Mark all entries in the contact info cache as out of date, so they will be looked up 479ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // again once being shown. 480ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache.invalidate(); 481ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.setLoading(true); 482ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 483ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian fetchCalls(); 484ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCallLogQueryHandler.fetchVoicemailStatus(); 485ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCallLogQueryHandler.fetchMissedCallsUnreadCount(); 486ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateOnTransition(); 487ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = false; 488ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 489ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Refresh the display of the existing data to update the timestamp text descriptions. 490ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mAdapter.notifyDataSetChanged(); 491ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 492ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 493ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 494ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 495ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Updates the voicemail notification state. 496ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 497ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>TODO: Move to CallLogActivity 498ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 499ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void updateOnTransition() { 500ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // We don't want to update any call data when keyguard is on because the user has likely not 501ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // seen the new calls yet. 502ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This might be called before onCreate() and thus we need to check null explicitly. 503ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mKeyguardManager != null 504ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian && !mKeyguardManager.inKeyguardRestrictedInputMode() 505ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian && mCallTypeFilter == Calls.VOICEMAIL_TYPE) { 506c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian CallLogNotificationsService.markNewVoicemailsAsOld(getActivity(), null); 507ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 508ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 509ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 510ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 511ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onEmptyViewActionButtonClicked() { 512ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Activity activity = getActivity(); 513ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (activity == null) { 514ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 515ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 516ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 517ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) { 518ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian FragmentCompat.requestPermissions( 519ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian this, new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE); 520d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } else if (!mIsCallLogActivity) { 521d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian // Show dialpad if we are not in the call log activity. 522ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ((HostInterface) activity).showDialpad(); 523ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 524ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 525ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 526ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 527ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onRequestPermissionsResult( 528ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int requestCode, String[] permissions, int[] grantResults) { 529ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (requestCode == READ_CALL_LOG_PERMISSION_REQUEST_CODE) { 530ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) { 531ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Force a refresh of the data since we were missing the permission before this. 532ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = true; 533ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 534ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 535ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 536ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 537ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Schedules an update to the relative call times (X mins ago). */ 538ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void rescheduleDisplayUpdate() { 539ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!mDisplayUpdateHandler.hasMessages(EVENT_UPDATE_DISPLAY)) { 540ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian long time = System.currentTimeMillis(); 541ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This value allows us to change the display relatively close to when the time changes 542ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // from one minute to the next. 543ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian long millisUtilNextMinute = MILLIS_IN_MINUTE - (time % MILLIS_IN_MINUTE); 544ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDisplayUpdateHandler.sendEmptyMessageDelayed(EVENT_UPDATE_DISPLAY, millisUtilNextMinute); 545ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 546ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 547ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 548ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Cancels any pending update requests to update the relative call times (X mins ago). */ 549ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void cancelDisplayUpdate() { 550ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDisplayUpdateHandler.removeMessages(EVENT_UPDATE_DISPLAY); 551ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 552ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 553ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @CallSuper 554d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian public void onVisible() { 555d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian LogUtil.enterBlock("CallLogFragment.onPageSelected"); 556d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (getActivity() != null) { 557d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian ((HostInterface) getActivity()) 558ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .enableFloatingButton(mModalAlertManager == null || mModalAlertManager.isEmpty()); 559ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 560ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 561ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 562ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @CallSuper 563d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian public void onNotVisible() { 564d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian LogUtil.enterBlock("CallLogFragment.onPageUnselected"); 565ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 566ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 567ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 568ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onShowModalAlert(boolean show) { 569ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d( 570ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "CallLogFragment.onShowModalAlert", 571ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "show: %b, fragment: %s, isVisible: %b", 572ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian show, 573ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian this, 574ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getUserVisibleHint()); 575ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getAdapter().notifyDataSetChanged(); 576ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian HostInterface hostInterface = (HostInterface) getActivity(); 577ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (show) { 578ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setVisibility(View.GONE); 579ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mModalAlertView.setVisibility(View.VISIBLE); 580ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (hostInterface != null && getUserVisibleHint()) { 581ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian hostInterface.enableFloatingButton(false); 582ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 583ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 584ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRecyclerView.setVisibility(View.VISIBLE); 585ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mModalAlertView.setVisibility(View.GONE); 586ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (hostInterface != null && getUserVisibleHint()) { 587ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian hostInterface.enableFloatingButton(true); 588ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 589ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 590ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 591ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 592ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public interface HostInterface { 593ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 594ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian void showDialpad(); 595ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 596ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian void enableFloatingButton(boolean enabled); 597ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 598ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 599ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected class CustomContentObserver extends ContentObserver { 600ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 601ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public CustomContentObserver() { 602ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super(mHandler); 603ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 604ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 605ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 606ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onChange(boolean selfChange) { 607ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRefreshDataRequired = true; 608ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 609ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 610ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian} 611