1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.components.devtools_bridge.ui;
7 import android.accounts.Account;
8 import android.accounts.AccountManager;
9 import android.accounts.AccountManagerCallback;
10 import android.accounts.AccountManagerFuture;
11 import android.app.Activity;
12 import android.app.ListFragment;
13 import android.content.Intent;
14 import android.os.AsyncTask;
15 import android.os.Bundle;
16 import android.util.Log;
17 import android.view.ContextMenu;
18 import android.view.LayoutInflater;
19 import android.view.MenuItem;
20 import android.view.View;
21 import android.view.ViewGroup;
22 import android.widget.ArrayAdapter;
23 import android.widget.ListView;
24 import android.widget.Toast;
26 import org.chromium.components.devtools_bridge.RTCConfiguration;
27 import org.chromium.components.devtools_bridge.SessionBase;
28 import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory;
29 import org.chromium.components.devtools_bridge.apiary.TestApiaryClientFactory;
30 import org.chromium.components.devtools_bridge.commands.Command;
31 import org.chromium.components.devtools_bridge.commands.CommandSender;
32 import org.chromium.components.devtools_bridge.gcd.RemoteInstance;
34 import java.io.IOException;
35 import java.util.List;
38 * Fragment of application for manual testing the DevTools bridge. Shows instances
39 * registered in GCD and lets unregister them.
41 public abstract class RemoteInstanceListFragment extends ListFragment {
42 private static final String TAG = "RemoteInstanceListFragment";
43 private static final String NO_ID = "";
44 private static final int CODE_ACCOUNT_SELECTED = 1;
46 private final TestApiaryClientFactory mClientFactory = new TestApiaryClientFactory();
47 private ArrayAdapter<RemoteInstance> mListAdapter;
48 private String mOAuthToken;
49 private RemoteInstance mSelected;
52 public void onCreate(Bundle savedInstanceState) {
53 super.onCreate(savedInstanceState);
54 mListAdapter = new ArrayAdapter<RemoteInstance>(
55 getActivity(), android.R.layout.simple_list_item_1);
56 new UpdateListAction().execute();
57 setListAdapter(mListAdapter);
61 public void onDestroy() {
62 new AsyncTask<Void, Void, Void>() {
64 protected final Void doInBackground(Void... args) {
65 mClientFactory.close();
73 public View onCreateView(
74 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
75 View root = super.onCreateView(inflater, container, savedInstanceState);
76 registerForContextMenu(root);
81 public void onListItemClick(ListView listView, View view, int position, long id) {
82 mSelected = mListAdapter.getItem(position);
83 if (mOAuthToken == null) {
86 getActivity().openContextMenu(view);
91 public void onCreateContextMenu(
92 ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
93 super.onCreateContextMenu(menu, view, menuInfo);
95 if (mOAuthToken == null) return;
98 .setOnMenuItemClickListener(new ConnectAction())
99 .setEnabled(mSelected != null);
100 menu.add("Send invalid offer")
101 .setOnMenuItemClickListener(new SendInvalidOfferAction())
102 .setEnabled(mSelected != null);
104 .setOnMenuItemClickListener(new DeleteInstanceAction(mSelected))
105 .setEnabled(mSelected != null);
106 menu.add("Update list")
107 .setOnMenuItemClickListener(new UpdateListAction());
108 menu.add("Delete all")
109 .setOnMenuItemClickListener(new DeleteAllAction());
112 public void signIn() {
113 AccountManager manager = AccountManager.get(getActivity());
115 Intent intent = manager.newChooseAccountIntent(
116 null /* selectedAccount */,
117 null /* allowableAccounts */,
118 new String[] { "com.google" } /* allowableAccountTypes */,
119 true /* alwaysPromptForAccount */,
120 "Sign into GCD" /* descriptionOverrideText */,
121 null /* addAccountAuthTokenType */,
122 null /* addAccountRequiredFeatures */,
123 null /* addAccountOptions */);
124 startActivityForResult(intent, CODE_ACCOUNT_SELECTED);
128 public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
129 if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) {
130 queryOAuthToken(new Account(
131 data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME),
132 data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)));
136 protected abstract void connect(String oAuthToken, String remoteInstanceId);
138 public void queryOAuthToken(Account accout) {
139 AccountManager manager = AccountManager.get(getActivity());
141 manager.getAuthToken(
143 "oauth2:" + ApiaryClientFactory.OAUTH_SCOPE, null /* options */, getActivity(),
144 new AccountManagerCallback<Bundle>() {
146 public void run(AccountManagerFuture<Bundle> future) {
148 mOAuthToken = future.getResult().getString(
149 AccountManager.KEY_AUTHTOKEN);
151 } catch (Exception e) {
152 Log.d(TAG, "Failed to get token: ", e);
158 public void updateList() {
159 new UpdateListAction().execute();
162 private final class ConnectAction implements MenuItem.OnMenuItemClickListener {
164 public boolean onMenuItemClick(MenuItem item) {
165 if (mOAuthToken != null && mSelected != null) {
166 connect(mOAuthToken, mSelected.id);
173 private abstract class AsyncAction extends AsyncTask<Void, Void, Boolean>
174 implements MenuItem.OnMenuItemClickListener {
175 private final String mActionName;
177 protected AsyncAction(String actionName) {
178 mActionName = actionName;
182 public boolean onMenuItemClick(MenuItem item) {
188 protected final Boolean doInBackground(Void... args) {
190 doInBackgroundImpl();
192 } catch (IOException e) {
193 Log.e(TAG, mActionName + " failed", e);
194 return Boolean.FALSE;
199 protected void onPostExecute(Boolean success) {
200 if (Boolean.TRUE.equals(success)) {
202 showToast(mActionName + " completed");
205 showToast(mActionName + " failed");
209 protected void showToast(String message) {
210 Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
213 protected abstract void doInBackgroundImpl() throws IOException;
214 protected abstract void onSuccess();
215 protected void onFailure() {}
218 private final class SendInvalidOfferAction extends AsyncAction {
219 private final String mOAuthTokenCopy = mOAuthToken;
220 private final RemoteInstance mSelectedCopy = mSelected;
221 private IOException mException;
223 public SendInvalidOfferAction() {
224 super("Sending invalid offer");
228 protected final void doInBackgroundImpl() throws IOException {
229 if (mOAuthTokenCopy == null || mSelected == null) {
230 throw new IOException("Action cann't be applied.");
233 final String sessionId = "sessionId";
234 final String offer = "INVALID_OFFER";
235 final RTCConfiguration config = new RTCConfiguration();
237 CommandSender sender = new CommandSender() {
239 protected void send(Command command, Runnable completionCallback) {
241 mClientFactory.newTestGCDClient(mOAuthTokenCopy)
242 .send(mSelectedCopy.id, command);
243 } catch (IOException e) {
245 command.setFailure("IO exception");
247 completionCallback.run();
252 sender.startSession(sessionId, config, offer, new SessionBase.NegotiationCallback() {
254 public void onSuccess(String answer) {
255 mException = new IOException("Unexpected success");
259 public void onFailure(String errorMessage) {
260 Log.i(TAG, "Expected failure: " + errorMessage);
264 if (mException != null)
269 protected void onSuccess() {
273 private final class UpdateListAction extends AsyncAction {
274 private final String mOAuthTokenCopy = mOAuthToken;
275 private List<RemoteInstance> mResult;
277 public UpdateListAction() {
278 super("Updating instance list");
282 protected final void doInBackgroundImpl() throws IOException {
283 if (mOAuthTokenCopy == null) return;
285 mResult = mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances();
289 protected void onSuccess() {
290 mListAdapter.clear();
291 if (mOAuthTokenCopy == null) {
292 mListAdapter.add(new RemoteInstance(NO_ID, "Sign in"));
293 } else if (mResult.size() > 0) {
294 mListAdapter.addAll(mResult);
296 mListAdapter.add(new RemoteInstance(NO_ID, "Empty list"));
301 protected void onFailure() {
302 mListAdapter.clear();
303 mListAdapter.add(new RemoteInstance(NO_ID, "Update failed"));
307 protected void showToast(String message) {}
310 private final class DeleteInstanceAction extends AsyncAction {
311 private final String mOAuthTokenCopy = mOAuthToken;
312 private final RemoteInstance mInstance;
314 public DeleteInstanceAction(RemoteInstance instance) {
315 super("Deleting instance");
316 mInstance = instance;
320 protected final void doInBackgroundImpl() throws IOException {
321 mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(mInstance.id);
325 protected void onSuccess() {
330 private final class DeleteAllAction extends AsyncAction {
331 private final String mOAuthTokenCopy = mOAuthToken;
333 public DeleteAllAction() {
334 super("Deleting all");
338 protected final void doInBackgroundImpl() throws IOException {
339 for (RemoteInstance instance :
340 mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances()) {
341 mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(instance.id);
346 protected void onSuccess() {