summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/com/android/dialer/app/calllog/CallLogAdapter.java16
-rw-r--r--java/com/android/dialer/main/impl/BottomNavBar.java49
-rw-r--r--java/com/android/dialer/main/impl/MainActivity.java159
3 files changed, 205 insertions, 19 deletions
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index 9e1d4a7b9..b8ec168f6 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -54,8 +54,8 @@ import android.view.ViewGroup;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
+import com.android.dialer.app.calllog.CallLogFragment.CallLogFragmentListener;
import com.android.dialer.app.calllog.CallLogGroupBuilder.GroupCreator;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
import com.android.dialer.app.contactinfo.ContactInfoCache;
@@ -68,6 +68,7 @@ import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction;
import com.android.dialer.calllogutils.PhoneCallDetails;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.FragmentUtils.FragmentUtilListener;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.AsyncTaskExecutor;
import com.android.dialer.common.concurrent.AsyncTaskExecutors;
@@ -379,7 +380,18 @@ public class CallLogAdapter extends GroupingListAdapter
if (viewHolder.callType == CallLog.Calls.MISSED_TYPE) {
CallLogAsyncTaskUtil.markCallAsRead(activity, viewHolder.callIds);
if (activityType == ACTIVITY_TYPE_DIALTACTS) {
- ((DialtactsActivity) v.getContext()).updateTabUnreadCounts();
+ if (v.getContext() instanceof CallLogFragmentListener) {
+ ((CallLogFragmentListener) v.getContext()).updateTabUnreadCounts();
+ } else if (v.getContext() instanceof FragmentUtilListener) {
+ // This is really bad, but we must do this to prevent a dependency cycle, enforce
+ // best practices in new code, and avoid refactoring DialtactsActivity.
+ ((FragmentUtilListener) v.getContext())
+ .getImpl(CallLogFragmentListener.class)
+ .updateTabUnreadCounts();
+ } else {
+ throw Assert.createIllegalStateFailException(
+ "View parent does not implement CallLogFragmentListener");
+ }
}
}
expandViewHolderActions(viewHolder);
diff --git a/java/com/android/dialer/main/impl/BottomNavBar.java b/java/com/android/dialer/main/impl/BottomNavBar.java
index a4ddc0652..6d43ee29d 100644
--- a/java/com/android/dialer/main/impl/BottomNavBar.java
+++ b/java/com/android/dialer/main/impl/BottomNavBar.java
@@ -22,8 +22,11 @@ import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
+import com.android.dialer.common.Assert;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/** Dialer Bottom Nav Bar for {@link MainActivity}. */
final class BottomNavBar extends LinearLayout {
@@ -32,22 +35,23 @@ final class BottomNavBar extends LinearLayout {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
TabIndex.SPEED_DIAL,
- TabIndex.HISTORY,
+ TabIndex.CALL_LOG,
TabIndex.CONTACTS,
TabIndex.VOICEMAIL,
})
public @interface TabIndex {
int SPEED_DIAL = 0;
- int HISTORY = 1;
+ int CALL_LOG = 1;
int CONTACTS = 2;
int VOICEMAIL = 3;
}
+ private final List<OnBottomNavTabSelectedListener> listeners = new ArrayList<>();
+
private BottomNavItem speedDial;
private BottomNavItem callLog;
private BottomNavItem contacts;
private BottomNavItem voicemail;
- private OnBottomNavTabSelectedListener listener;
private @TabIndex int selectedTab;
public BottomNavBar(Context context, @Nullable AttributeSet attrs) {
@@ -71,25 +75,25 @@ final class BottomNavBar extends LinearLayout {
v -> {
selectedTab = TabIndex.SPEED_DIAL;
setSelected(speedDial);
- listener.onSpeedDialSelected();
+ updateListeners(selectedTab);
});
callLog.setOnClickListener(
v -> {
- selectedTab = TabIndex.HISTORY;
+ selectedTab = TabIndex.CALL_LOG;
setSelected(callLog);
- listener.onCallLogSelected();
+ updateListeners(selectedTab);
});
contacts.setOnClickListener(
v -> {
selectedTab = TabIndex.CONTACTS;
setSelected(contacts);
- listener.onContactsSelected();
+ updateListeners(selectedTab);
});
voicemail.setOnClickListener(
v -> {
selectedTab = TabIndex.VOICEMAIL;
setSelected(voicemail);
- listener.onVoicemailSelected();
+ updateListeners(selectedTab);
});
}
@@ -108,7 +112,7 @@ final class BottomNavBar extends LinearLayout {
void selectTab(@TabIndex int tab) {
if (tab == TabIndex.SPEED_DIAL) {
speedDial.performClick();
- } else if (tab == TabIndex.HISTORY) {
+ } else if (tab == TabIndex.CALL_LOG) {
callLog.performClick();
} else if (tab == TabIndex.CONTACTS) {
contacts.performClick();
@@ -122,7 +126,7 @@ final class BottomNavBar extends LinearLayout {
void setNotificationCount(@TabIndex int tab, int count) {
if (tab == TabIndex.SPEED_DIAL) {
speedDial.setNotificationCount(count);
- } else if (tab == TabIndex.HISTORY) {
+ } else if (tab == TabIndex.CALL_LOG) {
callLog.setNotificationCount(count);
} else if (tab == TabIndex.CONTACTS) {
contacts.setNotificationCount(count);
@@ -133,8 +137,29 @@ final class BottomNavBar extends LinearLayout {
}
}
- void setOnTabSelectedListener(OnBottomNavTabSelectedListener listener) {
- this.listener = listener;
+ void addOnTabSelectedListener(OnBottomNavTabSelectedListener listener) {
+ listeners.add(listener);
+ }
+
+ private void updateListeners(@TabIndex int tabIndex) {
+ for (OnBottomNavTabSelectedListener listener : listeners) {
+ switch (tabIndex) {
+ case TabIndex.SPEED_DIAL:
+ listener.onSpeedDialSelected();
+ break;
+ case TabIndex.CALL_LOG:
+ listener.onCallLogSelected();
+ break;
+ case TabIndex.CONTACTS:
+ listener.onContactsSelected();
+ break;
+ case TabIndex.VOICEMAIL:
+ listener.onVoicemailSelected();
+ break;
+ default:
+ throw Assert.createIllegalStateFailException("Invalid tab: " + tabIndex);
+ }
+ }
}
public int getSelectedTab() {
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 57cc684e3..b94f07588 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -16,10 +16,14 @@
package com.android.dialer.main.impl;
+import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.app.KeyguardManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.CallLog.Calls;
@@ -33,6 +37,7 @@ import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.app.calllog.CallLogFragment;
import com.android.dialer.app.calllog.CallLogFragment.CallLogFragmentListener;
+import com.android.dialer.app.calllog.CallLogNotificationsService;
import com.android.dialer.app.list.DragDropController;
import com.android.dialer.app.list.OldSpeedDialFragment;
import com.android.dialer.app.list.OnDragDropListener;
@@ -52,6 +57,7 @@ import com.android.dialer.constants.ActivityRequestCodes;
import com.android.dialer.contactsfragment.ContactsFragment;
import com.android.dialer.contactsfragment.ContactsFragment.Header;
import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener;
+import com.android.dialer.database.CallLogQueryHandler;
import com.android.dialer.database.Database;
import com.android.dialer.dialpadview.DialpadFragment;
import com.android.dialer.dialpadview.DialpadFragment.DialpadListener;
@@ -62,6 +68,7 @@ import com.android.dialer.interactions.PhoneNumberInteraction.DisambigDialogDism
import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode;
import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorListener;
import com.android.dialer.main.impl.BottomNavBar.OnBottomNavTabSelectedListener;
+import com.android.dialer.main.impl.BottomNavBar.TabIndex;
import com.android.dialer.main.impl.toolbar.MainToolbar;
import com.android.dialer.postcall.PostCall;
import com.android.dialer.precall.PreCall;
@@ -73,6 +80,7 @@ import com.android.dialer.util.DialerUtils;
import com.android.dialer.util.TransactionSafeActivity;
import com.android.dialer.voicemail.listui.NewVoicemailFragment;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.TimeUnit;
/** This is the main activity for dialer. It hosts favorites, call log, search, dialpad, etc... */
// TODO(calderwoodra): Do not extend TransactionSafeActivity after new SpeedDial is launched
@@ -147,7 +155,11 @@ public final class MainActivity extends TransactionSafeActivity
MainBottomNavBarBottomNavTabListener bottomNavTabListener =
new MainBottomNavBarBottomNavTabListener(
this, getFragmentManager(), getSupportFragmentManager());
- bottomNav.setOnTabSelectedListener(bottomNavTabListener);
+ bottomNav.addOnTabSelectedListener(bottomNavTabListener);
+
+ callLogFragmentListener =
+ new MainCallLogFragmentListener(this, getContentResolver(), bottomNav);
+ bottomNav.addOnTabSelectedListener(callLogFragmentListener);
searchController = new MainSearchController(this, bottomNav, fab, toolbar);
toolbar.setSearchBarListener(searchController);
@@ -158,7 +170,7 @@ public final class MainActivity extends TransactionSafeActivity
callLogAdapterOnActionModeStateChangedListener =
new MainCallLogAdapterOnActionModeStateChangedListener();
callLogHostInterface = new MainCallLogHost(searchController, fab);
- callLogFragmentListener = new MainCallLogFragmentListener();
+
onListFragmentScrolledListener = new MainOnListFragmentScrolledListener(snackbarContainer);
onPhoneNumberPickerActionListener = new MainOnPhoneNumberPickerActionListener(this);
oldSpeedDialFragmentHostInterface =
@@ -179,6 +191,7 @@ public final class MainActivity extends TransactionSafeActivity
@Override
protected void onResume() {
super.onResume();
+ callLogFragmentListener.onActivityResume();
// Start the thread that updates the smart dial database if the activity is recreated with a
// language change.
boolean forceUpdate = !CompatUtils.getLocale(this).getISO3Language().equals(savedLanguageCode);
@@ -186,6 +199,13 @@ public final class MainActivity extends TransactionSafeActivity
showPostCallPrompt();
}
+ @Override
+ protected void onStop() {
+ super.onStop();
+ callLogFragmentListener.onActivityStop(
+ isChangingConfigurations(), getSystemService(KeyguardManager.class).isKeyguardLocked());
+ }
+
private void showPostCallPrompt() {
if (TelecomUtil.isInManagedCall(this)) {
// No prompt to show if the user is in a call
@@ -417,18 +437,147 @@ public final class MainActivity extends TransactionSafeActivity
}
}
- /** @see CallLogFragmentListener */
- private static final class MainCallLogFragmentListener implements CallLogFragmentListener {
+ /**
+ * Handles the logic for callbacks from:
+ *
+ * <ul>
+ * <li>{@link CallLogFragment}
+ * <li>{@link CallLogQueryHandler}
+ * <li>{@link BottomNavBar}
+ * </ul>
+ *
+ * This mainly entails:
+ *
+ * <ul>
+ * <li>Handling querying for missed calls/unread voicemails.
+ * <li>Displaying a badge to the user in the bottom nav when there are missed calls/unread
+ * voicemails present.
+ * <li>Marking missed calls as read when appropriate. See {@link
+ * #markMissedCallsAsReadAndRemoveNotification()}
+ * <li>TODO(calderwoodra): multiselect
+ * <li>TODO(calderwoodra): voicemail status
+ * </ul>
+ *
+ * @see CallLogFragmentListener
+ * @see CallLogQueryHandler.Listener
+ * @see OnBottomNavTabSelectedListener
+ */
+ private static final class MainCallLogFragmentListener
+ implements CallLogFragmentListener,
+ CallLogQueryHandler.Listener,
+ OnBottomNavTabSelectedListener {
+
+ private final CallLogQueryHandler callLogQueryHandler;
+ private final BottomNavBar bottomNavBar;
+ private final Context context;
+
+ private @TabIndex int currentTab = TabIndex.SPEED_DIAL;
+ private long timeSelected = -1;
+ private boolean activityIsAlive;
+
+ MainCallLogFragmentListener(
+ Context context, ContentResolver contentResolver, BottomNavBar bottomNavBar) {
+ callLogQueryHandler = new CallLogQueryHandler(context, contentResolver, this);
+ this.bottomNavBar = bottomNavBar;
+ this.context = context;
+ }
@Override
public void updateTabUnreadCounts() {
- // TODO(a bug): implement unread counts
+ callLogQueryHandler.fetchMissedCallsUnreadCount();
+ callLogQueryHandler.fetchVoicemailUnreadCount();
}
@Override
public void showMultiSelectRemoveView(boolean show) {
// TODO(a bug): handle multiselect mode
}
+
+ @Override
+ public void onVoicemailStatusFetched(Cursor statusCursor) {
+ // TODO(calderwoodra): handle this when voicemail is implemented
+ }
+
+ @Override
+ public void onVoicemailUnreadCountFetched(Cursor cursor) {
+ if (activityIsAlive) {
+ bottomNavBar.setNotificationCount(TabIndex.VOICEMAIL, cursor.getCount());
+ }
+ cursor.close();
+ }
+
+ @Override
+ public void onMissedCallsUnreadCountFetched(Cursor cursor) {
+ if (activityIsAlive) {
+ bottomNavBar.setNotificationCount(TabIndex.CALL_LOG, cursor.getCount());
+ }
+ cursor.close();
+ }
+
+ @Override
+ public boolean onCallsFetched(Cursor combinedCursor) {
+ // Return false; did not take ownership of cursor
+ return false;
+ }
+
+ @Override
+ public void onSpeedDialSelected() {
+ setCurrentTab(TabIndex.SPEED_DIAL);
+ }
+
+ @Override
+ public void onCallLogSelected() {
+ setCurrentTab(TabIndex.CALL_LOG);
+ }
+
+ @Override
+ public void onContactsSelected() {
+ setCurrentTab(TabIndex.CONTACTS);
+ }
+
+ @Override
+ public void onVoicemailSelected() {
+ setCurrentTab(TabIndex.VOICEMAIL);
+ }
+
+ private void markMissedCallsAsReadAndRemoveNotification() {
+ callLogQueryHandler.markMissedCallsAsRead();
+ CallLogNotificationsService.cancelAllMissedCalls(context);
+ }
+
+ private void setCurrentTab(@TabIndex int tabIndex) {
+ if (currentTab == TabIndex.CALL_LOG && tabIndex != TabIndex.CALL_LOG) {
+ markMissedCallsAsReadAndRemoveNotification();
+ }
+ currentTab = tabIndex;
+ timeSelected = System.currentTimeMillis();
+ }
+
+ public void onActivityResume() {
+ activityIsAlive = true;
+ callLogQueryHandler.fetchVoicemailStatus();
+ callLogQueryHandler.fetchMissedCallsUnreadCount();
+ // Reset the tab on resume to restart the timer
+ setCurrentTab(bottomNavBar.getSelectedTab());
+ }
+
+ /** Should be called when {@link Activity#onStop()} is called. */
+ public void onActivityStop(boolean changingConfigurations, boolean keyguardLocked) {
+ activityIsAlive = false;
+ if (viewedCallLogTabPastTimeThreshold() && !changingConfigurations && !keyguardLocked) {
+ markMissedCallsAsReadAndRemoveNotification();
+ }
+ }
+
+ /**
+ * Returns true if the user has been (and still is) on the history tab for long than the
+ * threshold.
+ */
+ private boolean viewedCallLogTabPastTimeThreshold() {
+ return currentTab == TabIndex.CALL_LOG
+ && timeSelected != -1
+ && System.currentTimeMillis() - timeSelected > TimeUnit.SECONDS.toMillis(3);
+ }
}
/** @see OnListFragmentScrolledListener */