summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/calllog/ui/NewCallLogFragment.java')
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogFragment.java159
1 files changed, 82 insertions, 77 deletions
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
index 5e676f072..bb1a7303e 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
@@ -22,44 +22,32 @@ import android.support.annotation.VisibleForTesting;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
+import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.dialer.calllog.CallLogComponent;
-import com.android.dialer.calllog.CallLogFramework;
-import com.android.dialer.calllog.CallLogFramework.CallLogUi;
-import com.android.dialer.calllog.RefreshAnnotatedCallLogWorker;
+import com.android.dialer.calllog.RefreshAnnotatedCallLogReceiver;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DefaultFutureCallback;
-import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.common.concurrent.ThreadUtil;
-import com.android.dialer.common.concurrent.UiListener;
+import com.android.dialer.metrics.Metrics;
+import com.android.dialer.metrics.MetricsComponent;
+import com.android.dialer.metrics.jank.RecyclerViewJankLogger;
import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.TimeUnit;
/** The "new" call log fragment implementation, which is built on top of the annotated call log. */
-public final class NewCallLogFragment extends Fragment
- implements CallLogUi, LoaderCallbacks<Cursor> {
-
- /*
- * This is a reasonable time that it might take between related call log writes, that also
- * shouldn't slow down single-writes too much. For example, when populating the database using
- * the simulator, using this value results in ~6 refresh cycles (on a release build) to write 120
- * call log entries.
- */
- private static final long REFRESH_ANNOTATED_CALL_LOG_WAIT_MILLIS = 100L;
+public final class NewCallLogFragment extends Fragment implements LoaderCallbacks<Cursor> {
@VisibleForTesting
static final long MARK_ALL_CALLS_READ_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);
- private RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker;
- private UiListener<Void> refreshAnnotatedCallLogListener;
+ private RefreshAnnotatedCallLogReceiver refreshAnnotatedCallLogReceiver;
private RecyclerView recyclerView;
- @Nullable private Runnable refreshAnnotatedCallLogRunnable;
private boolean shouldMarkCallsRead = false;
private final Runnable setShouldMarkCallsReadTrue = () -> shouldMarkCallsRead = true;
@@ -74,16 +62,7 @@ public final class NewCallLogFragment extends Fragment
LogUtil.enterBlock("NewCallLogFragment.onActivityCreated");
- CallLogComponent component = CallLogComponent.get(getContext());
- CallLogFramework callLogFramework = component.callLogFramework();
- callLogFramework.attachUi(this);
-
- // TODO(zachh): Use support fragment manager and add support for them in executors library.
- refreshAnnotatedCallLogListener =
- DialerExecutorComponent.get(getContext())
- .createUiListener(
- getActivity().getFragmentManager(), "NewCallLogFragment.refreshAnnotatedCallLog");
- refreshAnnotatedCallLogWorker = component.getRefreshAnnotatedCallLogWorker();
+ refreshAnnotatedCallLogReceiver = new RefreshAnnotatedCallLogReceiver(getContext());
}
@Override
@@ -97,13 +76,52 @@ public final class NewCallLogFragment extends Fragment
public void onResume() {
super.onResume();
- LogUtil.enterBlock("NewCallLogFragment.onResume");
+ boolean isHidden = isHidden();
+ LogUtil.i("NewCallLogFragment.onResume", "isHidden = %s", isHidden);
+
+ // As a fragment's onResume() is tied to the containing Activity's onResume(), being resumed is
+ // not equivalent to becoming visible.
+ // For example, when an activity with a hidden fragment is resumed, the fragment's onResume()
+ // will be called but it is not visible.
+ if (!isHidden) {
+ onFragmentShown();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ LogUtil.enterBlock("NewCallLogFragment.onPause");
+
+ onFragmentHidden();
+ }
- CallLogFramework callLogFramework = CallLogComponent.get(getContext()).callLogFramework();
- callLogFramework.attachUi(this);
+ @Override
+ public void onHiddenChanged(boolean hidden) {
+ super.onHiddenChanged(hidden);
+ LogUtil.i("NewCallLogFragment.onHiddenChanged", "hidden = %s", hidden);
- // TODO(zachh): Consider doing this when fragment becomes visible.
- refreshAnnotatedCallLog(true /* checkDirty */);
+ if (hidden) {
+ onFragmentHidden();
+ } else {
+ onFragmentShown();
+ }
+ }
+
+ /**
+ * To be called when the fragment becomes visible.
+ *
+ * <p>Note that for a fragment, being resumed is not equivalent to becoming visible.
+ *
+ * <p>For example, when an activity with a hidden fragment is resumed, the fragment's onResume()
+ * will be called but it is not visible.
+ */
+ private void onFragmentShown() {
+ registerRefreshAnnotatedCallLogReceiver();
+
+ CallLogComponent.get(getContext())
+ .getRefreshAnnotatedCallLogNotifier()
+ .notify(/* checkDirty = */ true);
// There are some types of data that we show in the call log that are not represented in the
// AnnotatedCallLog. For example, CP2 information for invalid numbers can sometimes only be
@@ -123,18 +141,22 @@ public final class NewCallLogFragment extends Fragment
.postDelayed(setShouldMarkCallsReadTrue, MARK_ALL_CALLS_READ_WAIT_MILLIS);
}
- @Override
- public void onPause() {
- super.onPause();
-
- LogUtil.enterBlock("NewCallLogFragment.onPause");
-
+ /**
+ * To be called when the fragment becomes hidden.
+ *
+ * <p>This can happen in the following two cases:
+ *
+ * <ul>
+ * <li>hide the fragment but keep the parent activity visible (e.g., calling {@link
+ * android.support.v4.app.FragmentTransaction#hide(Fragment)} in an activity, or
+ * <li>the parent activity is paused.
+ * </ul>
+ */
+ private void onFragmentHidden() {
// This is pending work that we don't actually need to follow through with.
- ThreadUtil.getUiThreadHandler().removeCallbacks(refreshAnnotatedCallLogRunnable);
ThreadUtil.getUiThreadHandler().removeCallbacks(setShouldMarkCallsReadTrue);
- CallLogFramework callLogFramework = CallLogComponent.get(getContext()).callLogFramework();
- callLogFramework.detachUi();
+ unregisterRefreshAnnotatedCallLogReceiver();
if (shouldMarkCallsRead) {
Futures.addCallback(
@@ -151,48 +173,31 @@ public final class NewCallLogFragment extends Fragment
View view = inflater.inflate(R.layout.new_call_log_fragment, container, false);
recyclerView = view.findViewById(R.id.new_call_log_recycler_view);
+ recyclerView.addOnScrollListener(
+ new RecyclerViewJankLogger(
+ MetricsComponent.get(getContext()).metrics(), Metrics.NEW_CALL_LOG_JANK_EVENT_NAME));
getLoaderManager().restartLoader(0, null, this);
return view;
}
- private void refreshAnnotatedCallLog(boolean checkDirty) {
- LogUtil.enterBlock("NewCallLogFragment.refreshAnnotatedCallLog");
-
- // If we already scheduled a refresh, cancel it and schedule a new one so that repeated requests
- // in quick succession don't result in too much work. For example, if we get 10 requests in
- // 10ms, and a complete refresh takes a constant 200ms, the refresh will take 300ms (100ms wait
- // and 1 iteration @200ms) instead of 2 seconds (10 iterations @ 200ms) since the work requests
- // are serialized in RefreshAnnotatedCallLogWorker.
- //
- // We might get many requests in quick succession, for example, when the simulator inserts
- // hundreds of rows into the system call log, or when the data for a new call is incrementally
- // written to different columns as it becomes available.
- ThreadUtil.getUiThreadHandler().removeCallbacks(refreshAnnotatedCallLogRunnable);
-
- refreshAnnotatedCallLogRunnable =
- () -> {
- ListenableFuture<Void> future =
- checkDirty
- ? refreshAnnotatedCallLogWorker.refreshWithDirtyCheck()
- : refreshAnnotatedCallLogWorker.refreshWithoutDirtyCheck();
- refreshAnnotatedCallLogListener.listen(
- getContext(),
- future,
- unused -> {},
- throwable -> {
- throw new RuntimeException(throwable);
- });
- };
- ThreadUtil.getUiThreadHandler()
- .postDelayed(refreshAnnotatedCallLogRunnable, REFRESH_ANNOTATED_CALL_LOG_WAIT_MILLIS);
+ private void registerRefreshAnnotatedCallLogReceiver() {
+ LogUtil.enterBlock("NewCallLogFragment.registerRefreshAnnotatedCallLogReceiver");
+
+ LocalBroadcastManager.getInstance(getContext())
+ .registerReceiver(
+ refreshAnnotatedCallLogReceiver, RefreshAnnotatedCallLogReceiver.getIntentFilter());
}
- @Override
- public void invalidateUi() {
- LogUtil.enterBlock("NewCallLogFragment.invalidateUi");
- refreshAnnotatedCallLog(false /* checkDirty */);
+ private void unregisterRefreshAnnotatedCallLogReceiver() {
+ LogUtil.enterBlock("NewCallLogFragment.unregisterRefreshAnnotatedCallLogReceiver");
+
+ // Cancel pending work as we don't need it any more.
+ CallLogComponent.get(getContext()).getRefreshAnnotatedCallLogNotifier().cancel();
+
+ LocalBroadcastManager.getInstance(getContext())
+ .unregisterReceiver(refreshAnnotatedCallLogReceiver);
}
@Override