summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-03-28 02:54:13 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-03-28 02:54:13 +0000
commitf17830ac721ab233e3bbb331ea91741614641009 (patch)
treec14d8aea364c511d69db8e8ab3b097ec1547b494
parentdc5935b31560e90eb402de7319ae27f068d963d5 (diff)
parent68ea8cf4e1d5a19bf8ef44e9686305ded95852de (diff)
Merge "Support new call log fragment in old peer."
-rw-r--r--java/com/android/dialer/calllog/CallLogFramework.java34
-rw-r--r--java/com/android/dialer/calllog/CallLogState.java9
-rw-r--r--java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java4
-rw-r--r--java/com/android/dialer/main/impl/OldMainActivityPeer.java152
4 files changed, 182 insertions, 17 deletions
diff --git a/java/com/android/dialer/calllog/CallLogFramework.java b/java/com/android/dialer/calllog/CallLogFramework.java
index 53ff43057..b86bfbc10 100644
--- a/java/com/android/dialer/calllog/CallLogFramework.java
+++ b/java/com/android/dialer/calllog/CallLogFramework.java
@@ -16,11 +16,17 @@
package com.android.dialer.calllog;
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
import com.android.dialer.calllog.datasources.CallLogDataSource;
import com.android.dialer.calllog.datasources.DataSources;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.Ui;
+import com.android.dialer.inject.ApplicationContext;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayList;
import java.util.List;
@@ -35,13 +41,24 @@ import javax.inject.Singleton;
@Singleton
public final class CallLogFramework {
+ private final Context appContext;
private final DataSources dataSources;
private final AnnotatedCallLogMigrator annotatedCallLogMigrator;
+ private final ListeningExecutorService uiExecutor;
+ private final CallLogState callLogState;
@Inject
- CallLogFramework(DataSources dataSources, AnnotatedCallLogMigrator annotatedCallLogMigrator) {
+ CallLogFramework(
+ @ApplicationContext Context appContext,
+ DataSources dataSources,
+ AnnotatedCallLogMigrator annotatedCallLogMigrator,
+ @Ui ListeningExecutorService uiExecutor,
+ CallLogState callLogState) {
+ this.appContext = appContext;
this.dataSources = dataSources;
this.annotatedCallLogMigrator = annotatedCallLogMigrator;
+ this.uiExecutor = uiExecutor;
+ this.callLogState = callLogState;
}
/** Registers the content observers for all data sources. */
@@ -73,12 +90,25 @@ public final class CallLogFramework {
dataSource.unregisterContentObservers();
}
+ callLogState.clearData();
+
// Clear data only after all content observers have been disabled.
List<ListenableFuture<Void>> allFutures = new ArrayList<>();
for (CallLogDataSource dataSource : dataSources.getDataSourcesIncludingSystemCallLog()) {
allFutures.add(dataSource.clearData());
}
+
return Futures.transform(
- Futures.allAsList(allFutures), unused -> null, MoreExecutors.directExecutor());
+ Futures.allAsList(allFutures),
+ unused -> {
+ // Send a broadcast to the OldMainActivityPeer to remove the NewCallLogFragment if it is
+ // currently attached. If this is not done, user interaction with the fragment could cause
+ // call log framework state to be unexpectedly written. For example scrolling could cause
+ // the AnnotatedCallLog to be read (which would trigger database creation).
+ LocalBroadcastManager.getInstance(appContext)
+ .sendBroadcastSync(new Intent("disableNewCallLogFragment"));
+ return null;
+ },
+ uiExecutor);
}
}
diff --git a/java/com/android/dialer/calllog/CallLogState.java b/java/com/android/dialer/calllog/CallLogState.java
index bdb30a769..6d2ec1e5e 100644
--- a/java/com/android/dialer/calllog/CallLogState.java
+++ b/java/com/android/dialer/calllog/CallLogState.java
@@ -54,6 +54,15 @@ public final class CallLogState {
}
/**
+ * Clear the call log state. This is useful for example if the annotated call log needs to be
+ * disabled because there was a problem.
+ */
+ @AnyThread
+ public void clearData() {
+ sharedPreferences.edit().remove(ANNOTATED_CALL_LOG_BUILT_PREF).apply();
+ }
+
+ /**
* Returns true if the annotated call log has been built at least once.
*
* <p>It may not yet have been built if the user was just upgraded to the new call log, or they
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 9332acdb1..8362a81ac 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -30,7 +30,6 @@ import android.provider.CallLog.Calls;
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Voicemails;
import android.support.annotation.ColorInt;
-import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.VisibleForTesting;
@@ -102,11 +101,8 @@ public class SystemCallLogDataSource implements CallLogDataSource {
this.annotatedCallLogDatabaseHelper = annotatedCallLogDatabaseHelper;
}
- @MainThread
@Override
public void registerContentObservers() {
- Assert.isMainThread();
-
LogUtil.enterBlock("SystemCallLogDataSource.registerContentObservers");
if (!PermissionsUtil.hasCallLogReadPermissions(appContext)) {
diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
index 9e8bd1ad6..6d78a5171 100644
--- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
@@ -21,9 +21,11 @@ import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
@@ -37,6 +39,7 @@ import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
+import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.telecom.PhoneAccount;
@@ -65,6 +68,8 @@ import com.android.dialer.callcomposer.CallComposerActivity;
import com.android.dialer.calldetails.OldCallDetailsActivity;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.CallSpecificAppData;
+import com.android.dialer.calllog.config.CallLogConfigComponent;
+import com.android.dialer.calllog.ui.NewCallLogFragment;
import com.android.dialer.common.FragmentUtils.FragmentUtilListener;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
@@ -110,7 +115,6 @@ import com.android.dialer.voicemailstatus.VoicemailStatusHelper;
import com.android.voicemail.VoicemailComponent;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Locale;
-import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
@@ -132,6 +136,23 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
// TODO(calderwoodra): change to AppCompatActivity once new speed dial ships
private final TransactionSafeActivity activity;
+ private final BroadcastReceiver disableNewCallLogReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (bottomNavTabListener == null) {
+ return;
+ }
+ /*
+ * Remove the NewCallLogFragment if it is currently attached. If this is not done, user
+ * interaction with the fragment could cause call log framework state to be unexpectedly
+ * written. For example scrolling could cause the AnnotatedCallLog to be read (which would
+ * trigger database creation).
+ */
+ bottomNavTabListener.disableNewCallLogFragment();
+ }
+ };
+
// Contacts
private MainOnContactSelectedListener onContactSelectedListener;
@@ -161,6 +182,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
private LastTabController lastTabController;
private BottomNavBar bottomNav;
+ private MainBottomNavBarBottomNavTabListener bottomNavTabListener;
private View snackbarContainer;
private UiListener<String> getLastOutgoingCallListener;
@@ -217,8 +239,9 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
activity.setSupportActionBar(activity.findViewById(R.id.toolbar));
bottomNav = activity.findViewById(R.id.bottom_nav_bar);
- MainBottomNavBarBottomNavTabListener bottomNavTabListener =
- new MainBottomNavBarBottomNavTabListener(activity, activity.getFragmentManager(), fab);
+ bottomNavTabListener =
+ new MainBottomNavBarBottomNavTabListener(
+ activity, activity.getFragmentManager(), activity.getSupportFragmentManager(), fab);
bottomNav.addOnTabSelectedListener(bottomNavTabListener);
// TODO(uabdullah): Handle case of when a sim is inserted/removed while the activity is open.
boolean showVoicemailTab = canVoicemailTabBeShown(activity);
@@ -432,6 +455,22 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
bottomNav.setVisibility(View.VISIBLE);
}
+ /*
+ * While the activity is running, listen for the call log framework being disabled. If this is
+ * not done, user interaction with the fragment could cause call log framework state to be
+ * unexpectedly written. For example scrolling could cause the AnnotatedCallLog to be read
+ * (which would trigger database creation).
+ */
+ LocalBroadcastManager.getInstance(activity)
+ .registerReceiver(disableNewCallLogReceiver, new IntentFilter("disableNewCallLogFragment"));
+
+ /*
+ * Similar to above, if the new call log is being shown and then the activity is paused, when
+ * the user returns we need to remove the NewCallLogFragment if the framework has been disabled
+ * in the meantime.
+ */
+ bottomNavTabListener.ensureCorrectCallLogShown();
+
// add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
ThreadUtil.postDelayedOnUiThread(
() ->
@@ -449,6 +488,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
@Override
public void onActivityPause() {
searchController.onActivityPause();
+ LocalBroadcastManager.getInstance(activity).unregisterReceiver(disableNewCallLogReceiver);
}
@Override
@@ -1122,14 +1162,19 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
private final AppCompatActivity activity;
private final FragmentManager fragmentManager;
+ private final android.support.v4.app.FragmentManager supportFragmentManager;
private final FloatingActionButton fab;
@TabIndex private int selectedTab = -1;
private MainBottomNavBarBottomNavTabListener(
- AppCompatActivity activity, FragmentManager fragmentManager, FloatingActionButton fab) {
+ AppCompatActivity activity,
+ FragmentManager fragmentManager,
+ android.support.v4.app.FragmentManager supportFragmentManager,
+ FloatingActionButton fab) {
this.activity = activity;
this.fragmentManager = fragmentManager;
+ this.supportFragmentManager = supportFragmentManager;
this.fab = fab;
}
@@ -1154,11 +1199,46 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
}
Logger.get(activity).logScreenView(ScreenEvent.Type.MAIN_CALL_LOG, activity);
selectedTab = TabIndex.CALL_LOG;
- Fragment fragment = fragmentManager.findFragmentByTag(CALL_LOG_TAG);
- showFragment(fragment == null ? new CallLogFragment() : fragment, CALL_LOG_TAG);
+
+ if (CallLogConfigComponent.get(activity).callLogConfig().isNewCallLogFragmentEnabled()) {
+ android.support.v4.app.Fragment supportFragment =
+ supportFragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ showSupportFragment(
+ supportFragment == null ? new NewCallLogFragment() : supportFragment, CALL_LOG_TAG);
+ } else {
+ Fragment fragment = fragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ showFragment(fragment == null ? new CallLogFragment() : fragment, CALL_LOG_TAG);
+ }
fab.show();
}
+ void disableNewCallLogFragment() {
+ LogUtil.i("MainBottomNavBarBottomNavTabListener.disableNewCallLogFragment", "disabled");
+ android.support.v4.app.Fragment supportFragment =
+ supportFragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ if (supportFragment != null) {
+ supportFragmentManager.beginTransaction().remove(supportFragment).commit();
+ // If the NewCallLogFragment was showing, immediately show the old call log fragment
+ // instead.
+ if (selectedTab == TabIndex.CALL_LOG) {
+ LogUtil.i(
+ "MainBottomNavBarBottomNavTabListener.disableNewCallLogFragment", "showing old");
+ Fragment fragment = fragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ showFragment(fragment == null ? new CallLogFragment() : fragment, CALL_LOG_TAG);
+ }
+ }
+ }
+
+ void ensureCorrectCallLogShown() {
+ android.support.v4.app.Fragment supportFragment =
+ supportFragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ if (supportFragment != null
+ && !CallLogConfigComponent.get(activity).callLogConfig().isNewCallLogFragmentEnabled()) {
+ LogUtil.i("MainBottomNavBarBottomNavTabListener.ensureCorrectCallLogShown", "disabling");
+ disableNewCallLogFragment();
+ }
+ }
+
@Override
public void onContactsSelected() {
LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onContactsSelected");
@@ -1193,34 +1273,65 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
fragment.onVisible();
}
+ private void showFragment(@NonNull Fragment fragment, String tag) {
+ showFragment(fragment, null, tag);
+ }
+
/**
* Shows the passed in fragment and hides all of the others in one transaction.
*
+ * <p>Exactly one of fragment or supportFragment should be provided.
+ *
* <p>Executes all fragment shows/hides in one transaction with no conflicting transactions
* (like showing and hiding the same fragment in the same transaction). See a bug.
*
* <p>Special care should be taken to avoid calling this method several times in a short window
* as it can lead to fragments overlapping.
*/
- private void showFragment(@NonNull Fragment fragment, String tag) {
+ private void showFragment(
+ @Nullable Fragment fragment,
+ @Nullable android.support.v4.app.Fragment supportFragment,
+ String tag) {
LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.showFragment");
Fragment speedDial = fragmentManager.findFragmentByTag(SPEED_DIAL_TAG);
- Fragment callLog = fragmentManager.findFragmentByTag(CALL_LOG_TAG);
+ Fragment oldCallLog = fragmentManager.findFragmentByTag(CALL_LOG_TAG);
Fragment contacts = fragmentManager.findFragmentByTag(CONTACTS_TAG);
Fragment voicemail = fragmentManager.findFragmentByTag(VOICEMAIL_TAG);
FragmentTransaction transaction = fragmentManager.beginTransaction();
boolean fragmentShown = showIfEqualElseHide(transaction, fragment, speedDial);
- fragmentShown |= showIfEqualElseHide(transaction, fragment, callLog);
+ fragmentShown |= showIfEqualElseHide(transaction, fragment, oldCallLog);
fragmentShown |= showIfEqualElseHide(transaction, fragment, contacts);
fragmentShown |= showIfEqualElseHide(transaction, fragment, voicemail);
- if (!fragmentShown) {
+ if (!fragmentShown && fragment != null) {
LogUtil.i(
"MainBottomNavBarBottomNavTabListener.showFragment", "Not added yet: " + fragment);
transaction.add(R.id.fragment_container, fragment, tag);
}
transaction.commit();
+
+ // Handle support fragments.
+ // TODO(calderwoodra): Handle other new fragments.
+ android.support.v4.app.Fragment newCallLog =
+ supportFragmentManager.findFragmentByTag(CALL_LOG_TAG);
+
+ android.support.v4.app.FragmentTransaction supportTransaction =
+ supportFragmentManager.beginTransaction();
+ boolean supportFragmentShown =
+ showIfEqualElseHideSupport(supportTransaction, supportFragment, newCallLog);
+ if (!supportFragmentShown && supportFragment != null) {
+ LogUtil.i(
+ "MainBottomNavBarBottomNavTabListener.showFragment",
+ "Not added yet: " + supportFragment);
+ supportTransaction.add(R.id.fragment_container, supportFragment, tag);
+ }
+ supportTransaction.commit();
+ }
+
+ private void showSupportFragment(
+ @NonNull android.support.v4.app.Fragment supportFragment, String tag) {
+ showFragment(null, supportFragment, tag);
}
/**
@@ -1231,7 +1342,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
private boolean showIfEqualElseHide(
FragmentTransaction transaction, Fragment fragment1, Fragment fragment2) {
boolean shown = false;
- if (Objects.equals(fragment1, fragment2)) {
+ if (fragment1 != null && fragment1.equals(fragment2)) {
transaction.show(fragment1);
shown = true;
} else if (fragment2 != null) {
@@ -1243,6 +1354,25 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
}
return shown;
}
+
+ /**
+ * @param supportFragment1 will be shown if equal to {@code fragment2}
+ * @param supportFragment2 will be hidden if unequal to {@code fragment1}
+ * @return {@code true} if {@code fragment1} was shown
+ */
+ private boolean showIfEqualElseHideSupport(
+ android.support.v4.app.FragmentTransaction supportTransaction,
+ android.support.v4.app.Fragment supportFragment1,
+ android.support.v4.app.Fragment supportFragment2) {
+ boolean shown = false;
+ if (supportFragment1 != null && supportFragment1.equals(supportFragment2)) {
+ supportTransaction.show(supportFragment1);
+ shown = true;
+ } else if (supportFragment2 != null) {
+ supportTransaction.hide(supportFragment2);
+ }
+ return shown;
+ }
}
private static final class LastTabController {