Chromium Code Reviews| Index: services/authentication/src/org/chromium/mojo/authentication/AuthenticationServiceImpl.java |
| diff --git a/services/authentication/src/org/chromium/mojo/authentication/AuthenticationServiceImpl.java b/services/authentication/src/org/chromium/mojo/authentication/AuthenticationServiceImpl.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1248d906ac149a8bee8272a6f3d52fc653f6e97c |
| --- /dev/null |
| +++ b/services/authentication/src/org/chromium/mojo/authentication/AuthenticationServiceImpl.java |
| @@ -0,0 +1,192 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
ppi
2015/04/29 13:32:23
2015
qsr
2015/04/29 14:22:20
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.mojo.authentication; |
| + |
| +import android.accounts.AccountManager; |
| +import android.app.Activity; |
| +import android.content.Context; |
| +import android.content.Intent; |
| +import android.os.Parcel; |
| + |
| +import com.google.android.gms.auth.GoogleAuthException; |
| +import com.google.android.gms.auth.GoogleAuthUtil; |
| +import com.google.android.gms.auth.UserRecoverableAuthException; |
| +import com.google.android.gms.common.AccountPicker; |
| + |
| +import org.chromium.mojo.application.ShellHelper; |
| +import org.chromium.mojo.bindings.SideEffectFreeCloseable; |
| +import org.chromium.mojo.intent.IntentReceiver; |
| +import org.chromium.mojo.intent.IntentReceiverManager; |
| +import org.chromium.mojo.intent.IntentReceiverManager.RegisterActivityResultResponse; |
| +import org.chromium.mojo.system.Core; |
| +import org.chromium.mojo.system.MojoException; |
| +import org.chromium.mojom.mojo.Shell; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Implementation of AuthenticationService from services/authentication/authentication.mojom |
| + */ |
| +public class AuthenticationServiceImpl |
| + extends SideEffectFreeCloseable implements AuthenticationService { |
| + /** |
| + * An callback that takes a serialized intent, add the intent the shell needs to send and start |
| + * the container intent. |
| + */ |
| + private final class TrampolineResponse implements RegisterActivityResultResponse { |
|
ppi
2015/04/29 13:32:24
Should this be called RegisterStartActivityForResu
qsr
2015/04/29 14:22:20
Hum, I have no strong opinion, so done.
|
| + /** |
| + * The intent the shell need to send. |
|
ppi
2015/04/29 13:32:24
s/need/needs/
qsr
2015/04/29 14:22:20
Done.
|
| + */ |
| + private final Intent mIntent; |
| + |
| + private TrampolineResponse(Intent intent) { |
| + this.mIntent = intent; |
|
ppi
2015/04/29 13:32:23
nit: "this." is probably not needed.
qsr
2015/04/29 14:22:20
Done.
|
| + } |
| + |
| + /** |
| + * @see RegisterActivityResultResponse#call(byte[]) |
| + */ |
| + @Override |
| + public void call(byte[] serializedIntent) { |
| + Intent trampolineIntent = bytesToIntent(serializedIntent); |
| + trampolineIntent.putExtra("intent", mIntent); |
| + mContext.startService(trampolineIntent); |
| + } |
| + } |
| + |
| + private final Activity mContext; |
| + private final String mConsumerURL; |
| + private final IntentReceiverManager mIntentReceiverManager; |
| + |
| + public AuthenticationServiceImpl(Context context, Core core, String consumerURL, Shell shell) { |
| + mContext = (Activity) context; |
| + mConsumerURL = consumerURL; |
| + mIntentReceiverManager = ShellHelper.connectToService( |
| + core, shell, "mojo:android_handler", IntentReceiverManager.MANAGER); |
| + } |
| + |
| + /** |
| + * @see AuthenticationService#onConnectionError(MojoException) |
| + */ |
| + @Override |
| + public void onConnectionError(MojoException e) {} |
| + |
| + /** |
| + * @see AuthenticationService#getOAuth2Token(String, String[], |
| + * AuthenticationService.GetOAuth2TokenResponse) |
| + */ |
| + @Override |
| + public void getOAuth2Token( |
| + final String username, final String[] scopes, final GetOAuth2TokenResponse callback) { |
| + if (scopes.length == 0) { |
| + callback.call(null); |
| + return; |
| + } |
| + StringBuilder scope = new StringBuilder("oauth2:"); |
| + for (int i = 0; i < scopes.length; ++i) { |
|
ppi
2015/04/29 13:32:23
Can we use http://developer.android.com/reference/
qsr
2015/04/29 14:22:20
We could, and I will if you insist, but this is a
|
| + if (i > 0) { |
| + scope.append(" "); |
| + } |
| + scope.append(scopes[i]); |
| + } |
| + String token = null; |
| + try { |
| + token = GoogleAuthUtil.getToken(mContext, username, scope.toString()); |
| + } catch (final UserRecoverableAuthException e) { |
|
ppi
2015/04/29 13:32:23
Could you add a comment explaining when we would e
qsr
2015/04/29 14:22:20
Done.
|
| + mIntentReceiverManager.registerActivityResult(new IntentReceiver() { |
| + GetOAuth2TokenResponse mCurrentCallback = callback; |
| + |
| + @Override |
| + public void close() { |
| + call(null); |
| + } |
| + |
| + @Override |
| + public void onConnectionError(MojoException e) { |
| + call(null); |
| + } |
| + |
| + @Override |
| + public void onIntent(byte[] bytes) { |
| + if (mCurrentCallback == null) { |
| + return; |
| + } |
| + getOAuth2Token(username, scopes, mCurrentCallback); |
| + mCurrentCallback = null; |
| + } |
| + |
| + private void call(String token) { |
| + if (mCurrentCallback == null) { |
| + return; |
| + } |
| + mCurrentCallback.call(token); |
| + mCurrentCallback = null; |
| + } |
| + }, new TrampolineResponse(e.getIntent())); |
| + return; |
| + } catch (IOException | GoogleAuthException e) { |
| + // Unrecoverable error. A null token will be send to the client. |
|
ppi
2015/04/29 13:32:24
Should we log something informative here?
qsr
2015/04/29 14:22:20
Added an error to the protocol -> we are sending t
|
| + } |
| + callback.call(token); |
| + } |
| + |
| + /** |
| + * @see AuthenticationService#selectAccount(AuthenticationService.SelectAccountResponse) |
| + */ |
| + @Override |
| + public void selectAccount(final SelectAccountResponse callback) { |
| + String[] accountTypes = new String[] {"com.google"}; |
|
tonyg
2015/04/29 13:47:43
The mojom doesn't specify that this only produces
qsr
2015/04/29 14:22:20
This param is android specific, so passing it in s
|
| + String message = "Select an account to use with application: " + mConsumerURL; |
|
tonyg
2015/04/29 13:47:43
I wonder whether we should make this message a lit
qsr
2015/04/29 14:22:20
This part is only sending the identity of an accou
|
| + Intent accountPickerIntent = AccountPicker.newChooseAccountIntent( |
| + null, null, accountTypes, false, message, null, null, null); |
| + |
| + mIntentReceiverManager.registerActivityResult(new IntentReceiver() { |
| + SelectAccountResponse mCurrentCallback = callback; |
| + |
| + @Override |
| + public void close() { |
| + call(null); |
| + } |
| + |
| + @Override |
| + public void onConnectionError(MojoException e) { |
| + call(null); |
| + } |
| + |
| + @Override |
| + public void onIntent(byte[] bytes) { |
| + Intent intent = bytesToIntent(bytes); |
| + call(intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)); |
| + } |
| + |
| + private void call(String username) { |
| + if (mCurrentCallback == null) { |
| + return; |
| + } |
| + mCurrentCallback.call(username); |
| + mCurrentCallback = null; |
| + } |
| + }, new TrampolineResponse(accountPickerIntent)); |
| + } |
| + |
| + /** |
| + * @see AuthenticationService#clearOAuth2Token(String) |
| + */ |
| + @Override |
| + public void clearOAuth2Token(String token) { |
| + try { |
| + GoogleAuthUtil.clearToken(mContext, token); |
| + } catch (GoogleAuthException | IOException e) { |
| + // Nothing to do. |
|
ppi
2015/04/29 13:32:24
Should we log something informative here?
qsr
2015/04/29 14:22:20
Not really. On a failure here, there is absolutely
|
| + } |
| + } |
| + |
| + private static Intent bytesToIntent(byte[] bytes) { |
| + Parcel p = Parcel.obtain(); |
| + p.unmarshall(bytes, 0, bytes.length); |
| + p.setDataPosition(0); |
| + return Intent.CREATOR.createFromParcel(p); |
| + } |
| +} |