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..9e8dafa2357848670a2ed50a56f70db8f6fe1acc |
--- /dev/null |
+++ b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java |
@@ -0,0 +1,283 @@ |
+// 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 does not provide UI controls. Descendant is responsible for it. |
+ * It also should have actionable item for registration/unregistration which invokes |
+ * 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("Unregistered"); |
+ } |
+ |
+ @Override |
+ protected void onFailure(Exception e) { |
+ Log.e(TAG, "Unregistration failed", e); |
+ 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:" + ApiaryClientFactory.OAUTH_SCOPE, 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.e(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); |
+ } |
+ |
+ @Override |
+ protected void onSuccess() { |
+ saveRegistration(mDescription, mCredential, ownerEmail); |
+ onRegistrationStatusChange(); |
+ showToast("Registered"); |
+ } |
+ |
+ @Override |
+ protected void onFailure(Exception e) { |
+ Log.e(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); |
+ } |
+} |