Chromium Code Reviews| Index: components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java |
| diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..162e5f14f29c47d72acc34491dfdb3361265b728 |
| --- /dev/null |
| +++ b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java |
| @@ -0,0 +1,284 @@ |
| +// Copyright 2014 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.devtools_bridge.ui; |
| + |
| +import android.accounts.Account; |
| +import android.accounts.AccountManager; |
| +import android.accounts.AccountManagerCallback; |
| +import android.accounts.AccountManagerFuture; |
| +import android.app.Activity; |
| +import android.app.Fragment; |
| +import android.app.ProgressDialog; |
| +import android.content.Context; |
| +import android.content.DialogInterface; |
| +import android.content.Intent; |
| +import android.os.AsyncTask; |
| +import android.os.Bundle; |
| +import android.util.Log; |
| +import android.widget.Toast; |
| + |
| +import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory; |
| +import org.chromium.components.devtools_bridge.apiary.OAuthResult; |
| +import org.chromium.components.devtools_bridge.gcd.InstanceCredential; |
| +import org.chromium.components.devtools_bridge.gcd.InstanceDescription; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Fragment that responsible for: |
| + * 1. Displaying GCD registration status. |
| + * 2. Instance registration. |
| + * 3. Instance unregistration. |
| + * |
| + * Fragment is abstract and not provide UI controls. Successor is responsible for it. |
|
mnaganov (inactive)
2014/10/30 18:18:22
nit: Successor -> Descendant
mnaganov (inactive)
2014/10/30 18:18:22
nit: does not provide
SeRya
2014/10/31 07:40:17
Done.
SeRya
2014/10/31 07:40:17
Done.
|
| + * It also should have actionable item for registration/unregistration which invoke |
|
mnaganov (inactive)
2014/10/30 18:18:21
nit: invokes
SeRya
2014/10/31 07:40:16
Done.
|
| + * appropriate methods. |
| + */ |
| +public abstract class GCDRegistrationFragment extends Fragment { |
| + private static final String TAG = "GCDRegistrationFragment"; |
| + private static final int CODE_ACCOUNT_SELECTED = 1; |
| + |
| + private ApiaryClientFactory mClientFactory; |
| + private Account mSelectedAccount = null; |
| + |
| + private InstanceCredential mInstanceCredential; |
| + private String mOwnerEmail; |
| + |
| + @Override |
| + public void onCreate(Bundle savedInstanceState) { |
| + mClientFactory = newClientFactory(); |
| + super.onCreate(savedInstanceState); |
| + } |
| + |
| + @Override |
| + public void onDestroy() { |
| + super.onDestroy(); |
| + mClientFactory.close(); |
| + } |
| + |
| + public void register() { |
| + AccountManager manager = AccountManager.get(getActivity()); |
| + |
| + Intent intent = manager.newChooseAccountIntent( |
| + mSelectedAccount, |
| + null /* allowableAccounts */, |
| + new String[] { "com.google" } /* allowableAccountTypes */, |
| + true /* alwaysPromptForAccount */, |
| + "Registration in GCD" /* descriptionOverrideText */, |
| + null /* addAccountAuthTokenType */, |
| + null /* addAccountRequiredFeatures */, |
| + null /* addAccountOptions */); |
| + startActivityForResult(intent, CODE_ACCOUNT_SELECTED); |
| + } |
| + |
| + public void unregister() { |
| + if (mInstanceCredential == null) return; |
| + |
| + new RegistrationTask("Unregistering instance") { |
| + private InstanceCredential mInstranceCredentialCopy = mInstanceCredential; |
| + |
| + @Override |
| + protected void doInBackgroundImpl() throws IOException, InterruptedException { |
| + OAuthResult result = mClientFactory.newOAuthClient() |
| + .authenticate(mInstranceCredentialCopy.secret); |
| + |
| + checkInterrupted(); |
| + |
| + Log.d(TAG, "Access token: " + result.accessToken); |
| + |
| + mClientFactory.newGCDClient(result.accessToken) |
| + .deleteInstance(mInstranceCredentialCopy.id); |
| + } |
| + |
| + @Override |
| + protected void onSuccess() { |
| + saveRegistration(null, null, null); |
| + onRegistrationStatusChange(); |
| + showToast("Unregstered"); |
|
mnaganov (inactive)
2014/10/30 18:18:21
typo: Unregistered
SeRya
2014/10/31 07:40:16
Done.
|
| + } |
| + |
| + @Override |
| + protected void onFailure(Exception e) { |
| + Log.d(TAG, "Unregistration failed", e); |
|
mnaganov (inactive)
2014/10/30 18:18:21
Log.e perhaps? This seems like an error, not a deb
SeRya
2014/10/31 07:40:16
Done.
|
| + showToast("Unregistration failed. See log for details."); |
| + } |
| + }.execute(); |
| + } |
| + |
| + public boolean isRegistered() { |
| + return mInstanceCredential != null; |
| + } |
| + |
| + public String getOwner() { |
| + return mOwnerEmail; |
| + } |
| + |
| + public void queryOAuthToken() { |
| + if (mSelectedAccount == null) return; |
| + |
| + AccountManager manager = AccountManager.get(getActivity()); |
| + |
| + final String ownerEmail = mSelectedAccount.name; |
| + |
| + manager.getAuthToken( |
| + mSelectedAccount, |
| + "oauth2:" + mClientFactory.getOAuthScope(), null /* options */, getActivity(), |
| + new AccountManagerCallback<Bundle>() { |
| + @Override |
| + public void run(AccountManagerFuture<Bundle> future) { |
| + try { |
| + String token = future.getResult().getString( |
| + AccountManager.KEY_AUTHTOKEN); |
| + register(ownerEmail, token); |
| + } catch (Exception e) { |
| + Log.d(TAG, "Failed to get token: ", e); |
| + } |
| + } |
| + }, null); |
| + } |
| + |
| + private void register(final String ownerEmail, final String oAuthToken) { |
| + new RegistrationTask("Registering instance") { |
| + private Context mContext; |
| + |
| + private String mDisplayName; |
| + private InstanceDescription mDescription; |
| + private InstanceCredential mCredential; |
| + |
| + @Override |
| + protected void onPreExecute() { |
| + mContext = getActivity(); |
| + |
| + mDisplayName = generateDisplayName(); |
| + super.onPreExecute(); |
| + } |
| + |
| + @Override |
| + protected void doInBackgroundImpl() throws IOException, InterruptedException { |
| + String ticketId = mClientFactory.newGCDClient(oAuthToken) |
| + .createRegistrationTicket(); |
| + |
| + checkInterrupted(); |
| + |
| + String gcmChannelId = |
| + mClientFactory.newGCMRegistrar().blockingGetRegistrationId(mContext); |
| + |
| + mDescription = new InstanceDescription.Builder() |
| + .setOAuthClientId(mClientFactory.getOAuthClientId()) |
| + .setGCMChannelId(gcmChannelId) |
| + .setDisplayName(mDisplayName) |
| + .build(); |
| + |
| + mClientFactory.newAnonymousGCDClient().patchRegistrationTicket( |
| + ticketId, mDescription); |
| + |
| + checkInterrupted(); |
| + |
| + mCredential = mClientFactory.newAnonymousGCDClient().finalizeRegistration(ticketId); |
| + Log.d(TAG, "Credential: id=" + mCredential.id + ", secret=" + mCredential.secret); |
|
mnaganov (inactive)
2014/10/30 18:18:22
Are you sure it is safe to log this information?
SeRya
2014/10/31 07:40:17
I'd rather remove it.
|
| + } |
| + |
| + @Override |
| + protected void onSuccess() { |
| + saveRegistration(mDescription, mCredential, ownerEmail); |
| + onRegistrationStatusChange(); |
| + showToast("Registered"); |
| + } |
| + |
| + @Override |
| + protected void onFailure(Exception e) { |
| + Log.d(TAG, "Registration failed", e); |
| + showToast("Registration failed. See log for details."); |
| + } |
| + }.execute(); |
| + } |
| + |
| + @Override |
| + public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { |
| + if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) { |
| + mSelectedAccount = new Account( |
| + data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME), |
| + data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)); |
| + Log.d(TAG, "Selected account=" + mSelectedAccount); |
| + queryOAuthToken(); |
| + } |
| + } |
| + |
| + private void saveRegistration( |
| + InstanceDescription description, InstanceCredential credential, String ownerEmail) { |
| + // TODO(serya): Make registration persistant. |
| + mInstanceCredential = credential; |
| + mOwnerEmail = ownerEmail; |
| + onRegistrationStatusChange(); |
| + } |
| + |
| + protected abstract void onRegistrationStatusChange(); |
| + protected abstract ApiaryClientFactory newClientFactory(); |
| + protected abstract String generateDisplayName(); |
| + |
| + private abstract class RegistrationTask extends AsyncTask<Void, Void, Boolean> { |
| + private ProgressDialog mDialog; |
| + private Exception mException; |
| + |
| + private final String mProgressMessage; |
| + |
| + protected RegistrationTask(String progressMessage) { |
| + mProgressMessage = progressMessage; |
| + } |
| + |
| + @Override |
| + protected void onPreExecute() { |
| + mDialog = ProgressDialog.show( |
| + getActivity(), |
| + "GCD registration", |
| + mProgressMessage, |
| + true, |
| + false, |
| + new DialogInterface.OnCancelListener() { |
| + @Override |
| + public void onCancel(DialogInterface dialog) { |
| + cancel(true); |
| + } |
| + }); |
| + } |
| + |
| + @Override |
| + protected final Boolean doInBackground(Void... args) { |
| + try { |
| + doInBackgroundImpl(); |
| + return Boolean.TRUE; |
| + } catch (IOException e) { |
| + mException = e; |
| + } catch (InterruptedException e) { |
| + Thread.currentThread().interrupt(); |
| + } |
| + return Boolean.FALSE; |
| + } |
| + |
| + protected final void checkInterrupted() throws InterruptedException { |
| + if (Thread.currentThread().isInterrupted()) { |
| + throw new InterruptedException(); |
| + } |
| + } |
| + |
| + @Override |
| + protected void onPostExecute(Boolean success) { |
| + mDialog.dismiss(); |
| + if (Boolean.TRUE.equals(success)) { |
| + onSuccess(); |
| + } else if (mException != null) { |
| + onFailure(mException); |
| + } |
| + } |
| + |
| + protected void showToast(String message) { |
| + Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); |
| + } |
| + |
| + protected abstract void doInBackgroundImpl() throws IOException, InterruptedException; |
| + protected abstract void onSuccess(); |
| + protected abstract void onFailure(Exception e); |
| + } |
| +} |