[Signin][Android] Add SigninActivityMonitor
SigninActivityMonitor tracks sign-in activities started from SigninUtils
and exposes this as an observable value. This CL also wires up
ConsistencyCookieManager so it tracks this value and exposes it for the
native side.
Bug: 949562
Change-Id: If2e5f9b596bd3d03a8d73d3606785e1aff020300
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1578548
Commit-Queue: David Roger <droger@chromium.org>
Reviewed-by: David Roger <droger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#653509}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
index 2732c24..3e5a5ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
@@ -12,7 +12,6 @@
import android.provider.Settings;
import android.support.annotation.Nullable;
-import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.chrome.browser.ChromeFeatureList;
@@ -20,6 +19,7 @@
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.GAIAServiceType;
+import org.chromium.components.signin.SigninActivityMonitor;
import org.chromium.ui.base.WindowAndroid;
/**
@@ -49,6 +49,7 @@
return IntentUtils.safeStartActivity(context, intent);
}
+ // TODO(https://crbug.com/955501): Migrate all clients to WindowAndroid and remove this.
/**
* Opens a Settings page with all accounts on the device.
* @param context Context to use when starting the Activity.
@@ -60,6 +61,16 @@
return IntentUtils.safeStartActivity(context, intent);
}
+ /**
+ * Opens a Settings page with all accounts on the device.
+ * @param windowAndroid WindowAndroid to use when starting the Activity.
+ * @return Whether or not Android accepted the Intent.
+ */
+ public static boolean openSettingsForAllAccounts(WindowAndroid windowAndroid) {
+ Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+ return startActivity(windowAndroid, intent);
+ }
+
@CalledByNative
private static void openAccountManagementScreen(WindowAndroid windowAndroid,
@GAIAServiceType int gaiaServiceType, @Nullable String email) {
@@ -86,7 +97,7 @@
break;
default:
// Open generic accounts settings.
- SigninUtils.openSettingsForAllAccounts(ContextUtils.getApplicationContext());
+ openSettingsForAllAccounts(windowAndroid);
break;
}
return;
@@ -105,16 +116,35 @@
logEvent(ProfileAccountManagementMetrics.DIRECT_ADD_ACCOUNT, gaiaServiceTypeSignup);
AccountManagerFacade.get().createAddAccountIntent((@Nullable Intent intent) -> {
- Activity activity = windowAndroid.getActivity().get();
- if (intent == null || activity == null
- || !IntentUtils.safeStartActivity(activity, intent)) {
- // Failed to create or show an intent, open settings for all accounts so
- // the user has a chance to create an account manually.
- SigninUtils.openSettingsForAllAccounts(ContextUtils.getApplicationContext());
+ if (intent != null && startActivity(windowAndroid, intent)) {
+ return;
}
+ // Failed to create or show an intent, open settings for all accounts so
+ // the user has a chance to create an account manually.
+ SigninUtils.openSettingsForAllAccounts(windowAndroid);
});
}
+ // TODO(https://crbug.com/953765): Move this to SigninActivityMonitor.
+ /**
+ * Starts an activity using the provided intent. The started activity will be tracked by
+ * {@link SigninActivityMonitor#hasOngoingActivity()}.
+ *
+ * @param windowAndroid The window to use when launching the intent.
+ * @param intent The intent to launch.
+ * @return Whether {@link WindowAndroid#showIntent} succeeded.
+ */
+ private static boolean startActivity(WindowAndroid windowAndroid, Intent intent) {
+ SigninActivityMonitor signinActivityMonitor = SigninActivityMonitor.get();
+ WindowAndroid.IntentCallback intentCallback =
+ (window, resultCode, data) -> signinActivityMonitor.activityFinished();
+ if (windowAndroid.showIntent(intent, intentCallback, null)) {
+ signinActivityMonitor.activityStarted();
+ return true;
+ }
+ return false;
+ }
+
/**
* Log a UMA event for a given metric and a signin type.
* @param metric One of ProfileAccountManagementMetrics constants.
diff --git a/components/signin/core/browser/android/BUILD.gn b/components/signin/core/browser/android/BUILD.gn
index 497cd55..52d54b2 100644
--- a/components/signin/core/browser/android/BUILD.gn
+++ b/components/signin/core/browser/android/BUILD.gn
@@ -24,6 +24,7 @@
"//net/android:net_java",
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:com_android_support_support_annotations_java",
+ "//ui/android:ui_java",
]
java_files = [
@@ -46,6 +47,7 @@
"java/src/org/chromium/components/signin/OAuth2TokenService.java",
"java/src/org/chromium/components/signin/ObservableValue.java",
"java/src/org/chromium/components/signin/ProfileDataSource.java",
+ "java/src/org/chromium/components/signin/SigninActivityMonitor.java",
"java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
]
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/ConsistencyCookieManager.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/ConsistencyCookieManager.java
index 3fdb3acc..56185c9 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/ConsistencyCookieManager.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/ConsistencyCookieManager.java
@@ -18,15 +18,17 @@
public class ConsistencyCookieManager implements ObservableValue.Observer {
private final long mNativeConsistencyCookieManager;
private final AccountManagerFacade mAccountManagerFacade;
+ private final SigninActivityMonitor mSigninActivityMonitor;
private boolean mIsUpdatePending;
private ConsistencyCookieManager(long nativeConsistencyCookieManager) {
ThreadUtils.assertOnUiThread();
mNativeConsistencyCookieManager = nativeConsistencyCookieManager;
mAccountManagerFacade = AccountManagerFacade.get();
+ mSigninActivityMonitor = SigninActivityMonitor.get();
mAccountManagerFacade.isUpdatePending().addObserver(this);
- // TODO(https://crbug.com/949562): Observe ongoing sign-in activities.
+ mSigninActivityMonitor.hasOngoingActivity().addObserver(this);
mIsUpdatePending = calculateIsUpdatePending();
}
@@ -41,8 +43,8 @@
}
private boolean calculateIsUpdatePending() {
- // TODO(https://crbug.com/949562): Check for ongoing sign-in activities.
- return mAccountManagerFacade.isUpdatePending().get();
+ return mAccountManagerFacade.isUpdatePending().get()
+ || mSigninActivityMonitor.hasOngoingActivity().get();
}
@CalledByNative
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SigninActivityMonitor.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SigninActivityMonitor.java
new file mode 100644
index 0000000..761b3f2
--- /dev/null
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SigninActivityMonitor.java
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.signin;
+
+import android.annotation.SuppressLint;
+import android.support.annotation.MainThread;
+
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Monitors external activities started from sign-in flows (for example, activity to add an account
+ * to the device). Activities have to be launched using {@link #startSigninActivity}.
+ */
+public class SigninActivityMonitor {
+ @SuppressLint("StaticFieldLeak")
+ private static SigninActivityMonitor sInstance;
+
+ private int mActivityCounter;
+ private MutableObservableValue<Boolean> mHasOngoingActivity =
+ new MutableObservableValue<>(false);
+
+ private SigninActivityMonitor() {}
+
+ /**
+ * Returns a singleton instance of the SigninActivityMonitor.
+ */
+ @MainThread
+ public static SigninActivityMonitor get() {
+ ThreadUtils.assertOnUiThread();
+ if (sInstance == null) {
+ sInstance = new SigninActivityMonitor();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Returns whether there are any ongoing sign-in activities.
+ */
+ public ObservableValue<Boolean> hasOngoingActivity() {
+ return mHasOngoingActivity;
+ }
+
+ // TODO(https://crbug.com/953765): Make this private.
+ /**
+ * Should be invoked when a signin activity is started.
+ */
+ public void activityStarted() {
+ assert mActivityCounter >= 0;
+
+ ++mActivityCounter;
+ if (mActivityCounter == 1) mHasOngoingActivity.set(true);
+ }
+
+ // TODO(https://crbug.com/953765): Make this private.
+ /**
+ * Should be invoked when a signin activity is finished. There should be a strict parity between
+ * {@link #activityStarted()} and {@link #activityFinished()} calls.
+ */
+ public void activityFinished() {
+ assert mActivityCounter > 0;
+
+ --mActivityCounter;
+ if (mActivityCounter == 0) mHasOngoingActivity.set(false);
+ }
+}