1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.dialer.app.calllog; 17 18 import android.app.Fragment; 19 import android.app.FragmentManager; 20 import android.content.Intent; 21 import android.os.Bundle; 22 import android.provider.CallLog; 23 import android.provider.CallLog.Calls; 24 import android.support.annotation.VisibleForTesting; 25 import android.support.design.widget.Snackbar; 26 import android.support.v13.app.FragmentPagerAdapter; 27 import android.support.v4.view.ViewPager; 28 import android.support.v7.app.ActionBar; 29 import android.view.Menu; 30 import android.view.MenuInflater; 31 import android.view.MenuItem; 32 import android.view.ViewGroup; 33 import com.android.contacts.common.list.ViewPagerTabs; 34 import com.android.dialer.app.DialtactsActivity; 35 import com.android.dialer.app.R; 36 import com.android.dialer.calldetails.CallDetailsActivity; 37 import com.android.dialer.common.Assert; 38 import com.android.dialer.constants.ActivityRequestCodes; 39 import com.android.dialer.database.CallLogQueryHandler; 40 import com.android.dialer.logging.Logger; 41 import com.android.dialer.logging.ScreenEvent; 42 import com.android.dialer.logging.UiAction; 43 import com.android.dialer.performancereport.PerformanceReport; 44 import com.android.dialer.postcall.PostCall; 45 import com.android.dialer.util.TransactionSafeActivity; 46 import com.android.dialer.util.ViewUtil; 47 48 /** Activity for viewing call history. */ 49 public class CallLogActivity extends TransactionSafeActivity 50 implements ViewPager.OnPageChangeListener { 51 52 @VisibleForTesting static final int TAB_INDEX_ALL = 0; 53 @VisibleForTesting static final int TAB_INDEX_MISSED = 1; 54 private static final int TAB_INDEX_COUNT = 2; 55 private ViewPager viewPager; 56 private ViewPagerTabs viewPagerTabs; 57 private ViewPagerAdapter viewPagerAdapter; 58 private CallLogFragment allCallsFragment; 59 private CallLogFragment missedCallsFragment; 60 private String[] tabTitles; 61 private boolean isResumed; 62 private int selectedPageIndex; 63 64 @Override 65 protected void onCreate(Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 68 setContentView(R.layout.call_log_activity); 69 getWindow().setBackgroundDrawable(null); 70 71 final ActionBar actionBar = getSupportActionBar(); 72 actionBar.setDisplayShowHomeEnabled(true); 73 actionBar.setDisplayHomeAsUpEnabled(true); 74 actionBar.setDisplayShowTitleEnabled(true); 75 actionBar.setElevation(0); 76 77 int startingTab = TAB_INDEX_ALL; 78 final Intent intent = getIntent(); 79 if (intent != null) { 80 final int callType = intent.getIntExtra(CallLog.Calls.EXTRA_CALL_TYPE_FILTER, -1); 81 if (callType == CallLog.Calls.MISSED_TYPE) { 82 startingTab = TAB_INDEX_MISSED; 83 } 84 } 85 selectedPageIndex = startingTab; 86 87 tabTitles = new String[TAB_INDEX_COUNT]; 88 tabTitles[0] = getString(R.string.call_log_all_title); 89 tabTitles[1] = getString(R.string.call_log_missed_title); 90 91 viewPager = (ViewPager) findViewById(R.id.call_log_pager); 92 93 viewPagerAdapter = new ViewPagerAdapter(getFragmentManager()); 94 viewPager.setAdapter(viewPagerAdapter); 95 viewPager.setOffscreenPageLimit(1); 96 viewPager.setOnPageChangeListener(this); 97 98 viewPagerTabs = (ViewPagerTabs) findViewById(R.id.viewpager_header); 99 100 viewPagerTabs.setViewPager(viewPager); 101 viewPager.setCurrentItem(startingTab); 102 } 103 104 @Override 105 protected void onResume() { 106 // Some calls may not be recorded (eg. from quick contact), 107 // so we should restart recording after these calls. (Recorded call is stopped) 108 PostCall.restartPerformanceRecordingIfARecentCallExist(this); 109 if (!PerformanceReport.isRecording()) { 110 PerformanceReport.startRecording(); 111 } 112 113 isResumed = true; 114 super.onResume(); 115 sendScreenViewForChildFragment(); 116 } 117 118 @Override 119 protected void onPause() { 120 isResumed = false; 121 super.onPause(); 122 } 123 124 @Override 125 protected void onStop() { 126 if (!isChangingConfigurations() && viewPager != null) { 127 // Make sure current index != selectedPageIndex 128 selectedPageIndex = -1; 129 updateMissedCalls(viewPager.getCurrentItem()); 130 } 131 super.onStop(); 132 } 133 134 @Override 135 public boolean onCreateOptionsMenu(Menu menu) { 136 final MenuInflater inflater = getMenuInflater(); 137 inflater.inflate(R.menu.call_log_options, menu); 138 return true; 139 } 140 141 @Override 142 public boolean onPrepareOptionsMenu(Menu menu) { 143 final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all); 144 if (allCallsFragment != null && itemDeleteAll != null) { 145 // If onPrepareOptionsMenu is called before fragments are loaded, don't do anything. 146 final CallLogAdapter adapter = allCallsFragment.getAdapter(); 147 itemDeleteAll.setVisible(adapter != null && !adapter.isEmpty()); 148 } 149 return true; 150 } 151 152 @Override 153 public boolean onOptionsItemSelected(MenuItem item) { 154 if (!isSafeToCommitTransactions()) { 155 return true; 156 } 157 158 if (item.getItemId() == android.R.id.home) { 159 PerformanceReport.recordClick(UiAction.Type.CLOSE_CALL_HISTORY_WITH_CANCEL_BUTTON); 160 final Intent intent = new Intent(this, DialtactsActivity.class); 161 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 162 startActivity(intent); 163 return true; 164 } else if (item.getItemId() == R.id.delete_all) { 165 ClearCallLogDialog.show(getFragmentManager()); 166 return true; 167 } 168 return super.onOptionsItemSelected(item); 169 } 170 171 @Override 172 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 173 viewPagerTabs.onPageScrolled(position, positionOffset, positionOffsetPixels); 174 } 175 176 @Override 177 public void onPageSelected(int position) { 178 updateMissedCalls(position); 179 selectedPageIndex = position; 180 if (isResumed) { 181 sendScreenViewForChildFragment(); 182 } 183 viewPagerTabs.onPageSelected(position); 184 } 185 186 @Override 187 public void onPageScrollStateChanged(int state) { 188 viewPagerTabs.onPageScrollStateChanged(state); 189 } 190 191 private void sendScreenViewForChildFragment() { 192 Logger.get(this).logScreenView(ScreenEvent.Type.CALL_LOG_FILTER, this); 193 } 194 195 private int getRtlPosition(int position) { 196 if (ViewUtil.isRtl()) { 197 return viewPagerAdapter.getCount() - 1 - position; 198 } 199 return position; 200 } 201 202 private void updateMissedCalls(int position) { 203 if (position == selectedPageIndex) { 204 return; 205 } 206 switch (getRtlPosition(position)) { 207 case TAB_INDEX_ALL: 208 if (allCallsFragment != null) { 209 allCallsFragment.markMissedCallsAsReadAndRemoveNotifications(); 210 } 211 break; 212 case TAB_INDEX_MISSED: 213 if (missedCallsFragment != null) { 214 missedCallsFragment.markMissedCallsAsReadAndRemoveNotifications(); 215 } 216 break; 217 default: 218 throw Assert.createIllegalStateFailException("Invalid position: " + position); 219 } 220 } 221 222 @Override 223 public void onBackPressed() { 224 PerformanceReport.recordClick(UiAction.Type.PRESS_ANDROID_BACK_BUTTON); 225 super.onBackPressed(); 226 } 227 228 /** Adapter for the view pager. */ 229 public class ViewPagerAdapter extends FragmentPagerAdapter { 230 231 public ViewPagerAdapter(FragmentManager fm) { 232 super(fm); 233 } 234 235 @Override 236 public long getItemId(int position) { 237 return getRtlPosition(position); 238 } 239 240 @Override 241 public Fragment getItem(int position) { 242 switch (getRtlPosition(position)) { 243 case TAB_INDEX_ALL: 244 return new CallLogFragment( 245 CallLogQueryHandler.CALL_TYPE_ALL, true /* isCallLogActivity */); 246 case TAB_INDEX_MISSED: 247 return new CallLogFragment(Calls.MISSED_TYPE, true /* isCallLogActivity */); 248 default: 249 throw new IllegalStateException("No fragment at position " + position); 250 } 251 } 252 253 @Override 254 public Object instantiateItem(ViewGroup container, int position) { 255 final CallLogFragment fragment = (CallLogFragment) super.instantiateItem(container, position); 256 switch (getRtlPosition(position)) { 257 case TAB_INDEX_ALL: 258 allCallsFragment = fragment; 259 break; 260 case TAB_INDEX_MISSED: 261 missedCallsFragment = fragment; 262 break; 263 default: 264 throw Assert.createIllegalStateFailException("Invalid position: " + position); 265 } 266 return fragment; 267 } 268 269 @Override 270 public CharSequence getPageTitle(int position) { 271 return tabTitles[position]; 272 } 273 274 @Override 275 public int getCount() { 276 return TAB_INDEX_COUNT; 277 } 278 } 279 280 @Override 281 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 282 if (requestCode == ActivityRequestCodes.DIALTACTS_CALL_DETAILS) { 283 if (resultCode == RESULT_OK 284 && data != null 285 && data.getBooleanExtra(CallDetailsActivity.EXTRA_HAS_ENRICHED_CALL_DATA, false)) { 286 String number = data.getStringExtra(CallDetailsActivity.EXTRA_PHONE_NUMBER); 287 Snackbar.make(findViewById(R.id.calllog_frame), getString(R.string.ec_data_deleted), 5_000) 288 .setAction( 289 R.string.view_conversation, 290 v -> startActivity(IntentProvider.getSendSmsIntentProvider(number).getIntent(this))) 291 .setActionTextColor(getResources().getColor(R.color.dialer_snackbar_action_text_color)) 292 .show(); 293 } 294 } 295 super.onActivityResult(requestCode, resultCode, data); 296 } 297 } 298