Commit 0ad3fbda authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

[Android] Make creation of vault key retrieval intent async

Analogous to the recent https://crrev.com/c/1968991, this patch adopts
org.chromium.base.Promise as mechanism to avoid blocking the UI thread
while the Intent is constructed as part of
TrustedVaultClient.createKeyRetrievalIntent().

This patch also adopts PendingIntent as opposed to Intent, which fits
better the need to launch a possibly external flow.

Bug: 1012659
Change-Id: Ib8db263f8b5ce3aa255b90603e4def60456d1459
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1972131
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarBoris Sazonov <bsazonov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732338}
parent 95dbab5c
...@@ -271,6 +271,15 @@ public class Promise<T> { ...@@ -271,6 +271,15 @@ public class Promise<T> {
return promise; return promise;
} }
/**
* Convenience method to return a rejected Promise.
*/
public static <T> Promise<T> rejected() {
Promise<T> promise = new Promise<>();
promise.reject();
return promise;
}
private void checkThread() { private void checkThread() {
assert mThread == Thread.currentThread() : "Promise must only be used on a single Thread."; assert mThread == Thread.currentThread() : "Promise must only be used on a single Thread.";
} }
......
...@@ -9,6 +9,8 @@ import android.content.Intent; ...@@ -9,6 +9,8 @@ import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import androidx.annotation.StringRes;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
...@@ -89,14 +91,21 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC ...@@ -89,14 +91,21 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC
CoreAccountInfo primaryAccountInfo = CoreAccountInfo primaryAccountInfo =
IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo(); IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo();
if (primaryAccountInfo != null) { if (primaryAccountInfo != null) {
Intent intent = int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP;
TrustedVaultClient.get().createKeyRetrievalIntent(primaryAccountInfo); TrustedVaultClient.get()
if (intent != null) { .createKeyRetrievalIntent(primaryAccountInfo)
showSyncNotification(mProfileSyncService.isEncryptEverythingEnabled() .then(
(pendingIntent)
-> {
showSyncNotificationForPendingIntent(
mProfileSyncService.isEncryptEverythingEnabled()
? R.string.sync_error_card_title ? R.string.sync_error_card_title
: R.string.sync_passwords_error_card_title, : R.string.sync_passwords_error_card_title,
intent); new PendingIntentProvider(pendingIntent, flags));
} },
(exception) -> {
Log.w(TAG, "Error creating key retrieval intent: ", exception);
});
} }
} else { } else {
mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_SYNC); mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_SYNC);
...@@ -108,9 +117,10 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC ...@@ -108,9 +117,10 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC
* Builds and shows a notification for the |message|. * Builds and shows a notification for the |message|.
* *
* @param message Resource id of the message to display in the notification. * @param message Resource id of the message to display in the notification.
* @param intent Intent to send when the user activates the notification. * @param contentIntent represents intent to send when the user activates the notification.
*/ */
private void showSyncNotification(int message, Intent intent) { private void showSyncNotificationForPendingIntent(
@StringRes int message, PendingIntentProvider contentIntent) {
Context applicationContext = ContextUtils.getApplicationContext(); Context applicationContext = ContextUtils.getApplicationContext();
String title = null; String title = null;
String text = null; String text = null;
...@@ -125,9 +135,6 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC ...@@ -125,9 +135,6 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC
+ applicationContext.getString(message); + applicationContext.getString(message);
} }
PendingIntentProvider contentIntent =
PendingIntentProvider.getActivity(applicationContext, 0, intent, 0);
// There is no need to provide a group summary notification because the NOTIFICATION_ID_SYNC // There is no need to provide a group summary notification because the NOTIFICATION_ID_SYNC
// notification id ensures there's only one sync notification at a time. // notification id ensures there's only one sync notification at a time.
ChromeNotificationBuilder builder = ChromeNotificationBuilder builder =
...@@ -153,6 +160,19 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC ...@@ -153,6 +160,19 @@ public class SyncNotificationController implements ProfileSyncService.SyncStateC
NotificationUmaTracker.SystemNotificationType.SYNC, notification.getNotification()); NotificationUmaTracker.SystemNotificationType.SYNC, notification.getNotification());
} }
/**
* Builds and shows a notification for the |message|.
*
* @param message Resource id of the message to display in the notification.
* @param intent Intent to send when the user activates the notification.
*/
private void showSyncNotification(@StringRes int message, Intent intent) {
Context applicationContext = ContextUtils.getApplicationContext();
PendingIntentProvider contentIntent =
PendingIntentProvider.getActivity(applicationContext, 0, intent, 0);
showSyncNotificationForPendingIntent(message, contentIntent);
}
private boolean shouldSyncAuthErrorBeShown() { private boolean shouldSyncAuthErrorBeShown() {
switch (mProfileSyncService.getAuthError()) { switch (mProfileSyncService.getAuthError()) {
case State.NONE: case State.NONE:
......
...@@ -4,17 +4,16 @@ ...@@ -4,17 +4,16 @@
package org.chromium.chrome.browser.sync; package org.chromium.chrome.browser.sync;
import android.content.Context; import android.app.Activity;
import android.content.Intent; import android.app.PendingIntent;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.Log;
import org.chromium.base.Promise; import org.chromium.base.Promise;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.AppHooks;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.signin.base.CoreAccountInfo;
import java.util.Collections; import java.util.Collections;
...@@ -39,14 +38,14 @@ public class TrustedVaultClient { ...@@ -39,14 +38,14 @@ public class TrustedVaultClient {
Promise<List<byte[]>> fetchKeys(CoreAccountInfo accountInfo); Promise<List<byte[]>> fetchKeys(CoreAccountInfo accountInfo);
/** /**
* Gets an Intent that can be used to display a UI that allows the user to reauthenticate * Gets a PendingIntent that can be used to display a UI that allows the user to
* and retrieve the sync encryption keys. * reauthenticate and retrieve the sync encryption keys.
* *
* @param accountInfo Account representing the user. * @param accountInfo Account representing the user.
* @return the Intent object or null is something went wrong. * @return a promise for a PendingIntent object. The promise will be rejected if no
* retrieval is actually required.
*/ */
@Nullable Promise<PendingIntent> createKeyRetrievalIntent(CoreAccountInfo accountInfo);
Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo);
/** /**
* Invoked when the result of fetchKeys() represents keys that cannot decrypt Nigori, which * Invoked when the result of fetchKeys() represents keys that cannot decrypt Nigori, which
...@@ -69,8 +68,8 @@ public class TrustedVaultClient { ...@@ -69,8 +68,8 @@ public class TrustedVaultClient {
} }
@Override @Override
public Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo) { public Promise<PendingIntent> createKeyRetrievalIntent(CoreAccountInfo accountInfo) {
return null; return Promise.rejected();
} }
@Override @Override
...@@ -79,6 +78,8 @@ public class TrustedVaultClient { ...@@ -79,6 +78,8 @@ public class TrustedVaultClient {
} }
}; };
private static final String TAG = "TrustedVaultClient";
private static TrustedVaultClient sInstance; private static TrustedVaultClient sInstance;
private final Backend mBackend; private final Backend mBackend;
...@@ -106,28 +107,35 @@ public class TrustedVaultClient { ...@@ -106,28 +107,35 @@ public class TrustedVaultClient {
/** /**
* Displays a UI that allows the user to reauthenticate and retrieve the sync encryption keys. * Displays a UI that allows the user to reauthenticate and retrieve the sync encryption keys.
* *
* @param context Context to use when starting the dialog activity. * @param activity Activity to use when starting the dialog.
* @param accountInfo Account representing the user. * @param accountInfo Account representing the user.
*/ */
public void displayKeyRetrievalDialog(Context context, CoreAccountInfo accountInfo) { public void displayKeyRetrievalDialog(Activity activity, CoreAccountInfo accountInfo) {
Intent intent = createKeyRetrievalIntent(accountInfo); createKeyRetrievalIntent(accountInfo)
if (intent == null) return; .then(
(pendingIntent)
IntentUtils.safeStartActivity(context, intent); -> {
try {
// TODO(crbug.com/1012659): Upon intent completion, the new keys should // TODO(crbug.com/1012659): Upon intent completion, the new keys
// fetched. // should be fetched.
pendingIntent.send(activity, 0, null, null, null, null, null);
} catch (PendingIntent.CanceledException exception) {
Log.w(TAG, "Error sending key retrieval intent: ", exception);
}
},
(exception) -> {
Log.e(TAG, "Error opening key retrieval dialog: ", exception);
});
} }
/** /**
* Creates an intent that launches an activity that triggers the key retrieval UI. * Creates an intent that launches an activity that triggers the key retrieval UI.
* *
* @param accountInfo Account representing the user. * @param accountInfo Account representing the user.
* @return the intent for opening the key retrieval activity or null if none is actually * @return a promise with the intent for opening the key retrieval activity. The promise will be
* required * rejected if no retrieval is actually required.
*/ */
@Nullable public Promise<PendingIntent> createKeyRetrievalIntent(CoreAccountInfo accountInfo) {
public Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo) {
return mBackend.createKeyRetrievalIntent(accountInfo); return mBackend.createKeyRetrievalIntent(accountInfo);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment