| 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..90be06b7989a4f413609dbc1058f76f5d6d648ce
|
| --- /dev/null
|
| +++ b/services/authentication/src/org/chromium/mojo/authentication/AuthenticationServiceImpl.java
|
| @@ -0,0 +1,195 @@
|
| +// Copyright 2015 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.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.RegisterActivityResultReceiverResponse;
|
| +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 RegisterActivityResultReceiverCallback
|
| + implements RegisterActivityResultReceiverResponse {
|
| + /**
|
| + * The intent that the requesting application needs to be run by shell on its
|
| +behalf.
|
| + */
|
| + private final Intent mIntent;
|
| +
|
| + private RegisterActivityResultReceiverCallback(Intent intent) {
|
| + mIntent = intent;
|
| + }
|
| +
|
| + /**
|
| + * @see RegisterActivityResultReceiverResponse#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, "scopes cannot be empty");
|
| + return;
|
| + }
|
| + StringBuilder scope = new StringBuilder("oauth2:");
|
| + for (int i = 0; i < scopes.length; ++i) {
|
| + if (i > 0) {
|
| + scope.append(" ");
|
| + }
|
| + scope.append(scopes[i]);
|
| + }
|
| + try {
|
| + callback.call(GoogleAuthUtil.getToken(mContext, username, scope.toString()), null);
|
| + } catch (final UserRecoverableAuthException e) {
|
| + // If an error occurs that the user can recover from, this exception will contain the
|
| + // intent to run to allow the user to act. This will use the intent manager to start it.
|
| + mIntentReceiverManager.registerActivityResultReceiver(new IntentReceiver() {
|
| + GetOAuth2TokenResponse mPendingCallback = callback;
|
| +
|
| + @Override
|
| + public void close() {
|
| + call(null, "User denied the request.");
|
| + }
|
| +
|
| + @Override
|
| + public void onConnectionError(MojoException e) {
|
| + call(null, e.getMessage());
|
| + }
|
| +
|
| + @Override
|
| + public void onIntent(byte[] bytes) {
|
| + if (mPendingCallback == null) {
|
| + return;
|
| + }
|
| + getOAuth2Token(username, scopes, mPendingCallback);
|
| + mPendingCallback = null;
|
| + }
|
| +
|
| + private void call(String token, String error) {
|
| + if (mPendingCallback == null) {
|
| + return;
|
| + }
|
| + mPendingCallback.call(token, error);
|
| + mPendingCallback = null;
|
| + }
|
| + }, new RegisterActivityResultReceiverCallback(e.getIntent()));
|
| + return;
|
| + } catch (IOException | GoogleAuthException e) {
|
| + // Unrecoverable error.
|
| + callback.call(null, e.getMessage());
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @see AuthenticationService#selectAccount(AuthenticationService.SelectAccountResponse)
|
| + */
|
| + @Override
|
| + public void selectAccount(final SelectAccountResponse callback) {
|
| + String[] accountTypes = new String[] {"com.google"};
|
| + String message = "Select an account to use with application: " + mConsumerURL;
|
| + Intent accountPickerIntent = AccountPicker.newChooseAccountIntent(
|
| + null, null, accountTypes, false, message, null, null, null);
|
| +
|
| + mIntentReceiverManager.registerActivityResultReceiver(new IntentReceiver() {
|
| + SelectAccountResponse mPendingCallback = callback;
|
| +
|
| + @Override
|
| + public void close() {
|
| + call(null, "User denied the request.");
|
| + }
|
| +
|
| + @Override
|
| + public void onConnectionError(MojoException e) {
|
| + call(null, e.getMessage());
|
| + }
|
| +
|
| + @Override
|
| + public void onIntent(byte[] bytes) {
|
| + Intent intent = bytesToIntent(bytes);
|
| + call(intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME), null);
|
| + }
|
| +
|
| + private void call(String username, String error) {
|
| + if (mPendingCallback == null) {
|
| + return;
|
| + }
|
| + mPendingCallback.call(username, error);
|
| + mPendingCallback = null;
|
| + }
|
| + }, new RegisterActivityResultReceiverCallback(accountPickerIntent));
|
| + }
|
| +
|
| + /**
|
| + * @see AuthenticationService#clearOAuth2Token(String)
|
| + */
|
| + @Override
|
| + public void clearOAuth2Token(String token) {
|
| + try {
|
| + GoogleAuthUtil.clearToken(mContext, token);
|
| + } catch (GoogleAuthException | IOException e) {
|
| + // Nothing to do.
|
| + }
|
| + }
|
| +
|
| + private static Intent bytesToIntent(byte[] bytes) {
|
| + Parcel p = Parcel.obtain();
|
| + p.unmarshall(bytes, 0, bytes.length);
|
| + p.setDataPosition(0);
|
| + return Intent.CREATOR.createFromParcel(p);
|
| + }
|
| +}
|
|
|