1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file. 4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochpackage org.chromium.chromoting; 6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.Account; 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.AccountManager; 9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.AccountManagerCallback; 10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.AccountManagerFuture; 11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.AuthenticatorException; 12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.accounts.OperationCanceledException; 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.annotation.SuppressLint; 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.app.ActionBar; 15ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.app.Activity; 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.app.AlertDialog; 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.app.ProgressDialog; 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.content.DialogInterface; 19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.content.Intent; 20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import android.content.SharedPreferences; 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.content.res.Configuration; 22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.os.Bundle; 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.provider.Settings; 24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.util.Log; 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import android.view.Menu; 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import android.view.MenuItem; 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.view.View; 28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.widget.ArrayAdapter; 29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.widget.ListView; 30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport android.widget.Toast; 31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport org.chromium.chromoting.jni.JniInterface; 33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochimport java.io.IOException; 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.Arrays; 36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/** 38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * The user interface for querying and displaying a user's host list from the directory server. It 39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * also requests and renews authentication tokens using the system account manager. 40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */ 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)public class Chromoting extends Activity implements JniInterface.ConnectionListener, 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch AccountManagerCallback<Bundle>, ActionBar.OnNavigationListener, HostListLoader.Callback, 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch View.OnClickListener { 44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** Only accounts of this type will be selectable for authentication. */ 45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch private static final String ACCOUNT_TYPE = "com.google"; 46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** Scopes at which the authentication token we request will be valid. */ 48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch private static final String TOKEN_SCOPE = "oauth2:https://www.googleapis.com/auth/chromoting " + 49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "https://www.googleapis.com/auth/googletalk"; 50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** Web page to be displayed in the Help screen when launched from this activity. */ 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private static final String HELP_URL = 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "http://support.google.com/chrome/?p=mobile_crd_hostslist"; 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** Web page to be displayed when user triggers the hyperlink for setting up hosts. */ 56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private static final String HOST_SETUP_URL = 57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch "https://support.google.com/chrome/answer/1649523"; 58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** User's account details. */ 60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private Account mAccount; 61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** List of accounts on the system. */ 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private Account[] mAccounts; 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** SpinnerAdapter used in the action bar for selecting accounts. */ 66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private AccountsAdapter mAccountsAdapter; 67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** Account auth token. */ 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private String mToken; 70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** Helper for fetching the host list. */ 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private HostListLoader mHostListLoader; 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** List of hosts. */ 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private HostInfo[] mHosts = new HostInfo[0]; 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch /** Refresh button. */ 78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch private MenuItem mRefreshButton; 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** Host list as it appears to the user. */ 81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private ListView mHostListView; 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** Progress view shown instead of the host list when the host list is loading. */ 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private View mProgressView; 85ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** Dialog for reporting connection progress. */ 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private ProgressDialog mProgressIndicator; 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) /** Object for fetching OAuth2 access tokens from third party authorization servers. */ 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private ThirdPartyTokenFetcher mTokenFetcher; 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * This is set when receiving an authentication error from the HostListLoader. If that occurs, 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * this flag is set and a fresh authentication token is fetched from the AccountsService, and 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * used to request the host list a second time. 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) boolean mTriedNewAuthToken; 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 9934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) /** 10034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) * Flag to track whether a call to AccountManager.getAuthToken() is currently pending. 10134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) * This avoids infinitely-nested calls in case onStart() gets triggered a second time 10234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) * while a token is being fetched. 10334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) */ 10434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) private boolean mWaitingForAuthToken = false; 10534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** Shows a warning explaining that a Google account is required, then closes the activity. */ 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private void showNoAccountsDialog() { 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AlertDialog.Builder builder = new AlertDialog.Builder(this); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) builder.setMessage(R.string.noaccounts_message); 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) builder.setPositiveButton(R.string.noaccounts_add_account, 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new DialogInterface.OnClickListener() { 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) @SuppressLint("InlinedApi") 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public void onClick(DialogInterface dialog, int id) { 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Intent intent = new Intent(Settings.ACTION_ADD_ACCOUNT); 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new String[] { ACCOUNT_TYPE }); 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (intent.resolveActivity(getPackageManager()) != null) { 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) startActivity(intent); 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) finish(); 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) builder.setNegativeButton(R.string.close, new DialogInterface.OnClickListener() { 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public void onClick(DialogInterface dialog, int id) { 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) finish(); 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) builder.setOnCancelListener(new DialogInterface.OnCancelListener() { 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public void onCancel(DialogInterface dialog) { 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) finish(); 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AlertDialog dialog = builder.create(); 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dialog.show(); 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** Shows or hides the progress indicator for loading the host list. */ 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private void setHostListProgressVisible(boolean visible) { 143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mHostListView.setVisibility(visible ? View.GONE : View.VISIBLE); 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mProgressView.setVisibility(visible ? View.VISIBLE : View.GONE); 145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Hiding the host-list does not automatically hide the empty view, so do that here. 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (visible) { 148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mHostListView.getEmptyView().setVisibility(View.GONE); 149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch /** 153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Called when the activity is first created. Loads the native library and requests an 154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * authentication token from the system. 155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */ 156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch @Override 157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch public void onCreate(Bundle savedInstanceState) { 158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch super.onCreate(savedInstanceState); 159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch setContentView(R.layout.main); 160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mTriedNewAuthToken = false; 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mHostListLoader = new HostListLoader(); 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Get ahold of our view widgets. 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mHostListView = (ListView) findViewById(R.id.hostList_chooser); 166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mHostListView.setEmptyView(findViewById(R.id.hostList_empty)); 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mProgressView = findViewById(R.id.hostList_progress); 168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch findViewById(R.id.host_setup_link_android).setOnClickListener(this); 170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Bring native components online. 172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch JniInterface.loadLibrary(this); 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) @Override 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) protected void onNewIntent(Intent intent) { 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) super.onNewIntent(intent); 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (mTokenFetcher != null) { 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (mTokenFetcher.handleTokenFetched(intent)) { 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) mTokenFetcher = null; 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** 186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Called when the activity becomes visible. This happens on initial launch and whenever the 187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * user switches to the activity, for example, by using the window-switcher or when coming from 188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * the device's lock screen. 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch @Override 191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch public void onStart() { 192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch super.onStart(); 193ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mAccounts = AccountManager.get(this).getAccountsByType(ACCOUNT_TYPE); 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (mAccounts.length == 0) { 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) showNoAccountsDialog(); 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) SharedPreferences prefs = getPreferences(MODE_PRIVATE); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int index = -1; 202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (prefs.contains("account_name") && prefs.contains("account_type")) { 203a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) mAccount = new Account(prefs.getString("account_name", null), 204a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) prefs.getString("account_type", null)); 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) index = Arrays.asList(mAccounts).indexOf(mAccount); 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (index == -1) { 208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Preference not loaded, or does not correspond to a valid account, so just pick the 209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // first account arbitrarily. 210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) index = 0; 211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mAccount = mAccounts[0]; 212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (mAccounts.length == 1) { 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) getActionBar().setDisplayShowTitleEnabled(true); 216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch getActionBar().setTitle(R.string.mode_me2me); 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) getActionBar().setSubtitle(mAccount.name); 219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mAccountsAdapter = new AccountsAdapter(this, mAccounts); 221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch getActionBar().setDisplayShowTitleEnabled(false); 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch getActionBar().setListNavigationCallbacks(mAccountsAdapter, this); 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) getActionBar().setSelectedNavigationItem(index); 225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refreshHostList(); 228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) /** Called when the activity is finally finished. */ 231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) @Override 232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public void onDestroy() { 233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) super.onDestroy(); 234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) JniInterface.disconnectFromHost(); 235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** Called when the display is rotated (as registered in the manifest). */ 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public void onConfigurationChanged(Configuration newConfig) { 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) super.onConfigurationChanged(newConfig); 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Reload the spinner resources, since the font sizes are dependent on the screen 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // orientation. 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (mAccounts.length != 1) { 245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mAccountsAdapter.notifyDataSetChanged(); 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) /** Called to initialize the action bar. */ 250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) @Override 251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public boolean onCreateOptionsMenu(Menu menu) { 252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) getMenuInflater().inflate(R.menu.chromoting_actionbar, menu); 253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch mRefreshButton = menu.findItem(R.id.actionbar_directoryrefresh); 254ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 255ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (mAccount == null) { 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If there is no account, don't allow the user to refresh the listing. 257ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch mRefreshButton.setEnabled(false); 258a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 260a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return super.onCreateOptionsMenu(menu); 261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 263a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) /** Called whenever an action bar button is pressed. */ 264a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) @Override 265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public boolean onOptionsItemSelected(MenuItem item) { 2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch int id = item.getItemId(); 2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (id == R.id.actionbar_directoryrefresh) { 2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch refreshHostList(); 2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return true; 2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (id == R.id.actionbar_help) { 2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch HelpActivity.launch(this, HELP_URL); 2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return true; 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return super.onOptionsItemSelected(item); 276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** Called when the user touches hyperlinked text. */ 279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch @Override 280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch public void onClick(View view) { 281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch HelpActivity.launch(this, HOST_SETUP_URL); 282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** Called when the user taps on a host entry. */ 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void connectToHost(HostInfo host) { 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mProgressIndicator = ProgressDialog.show(this, 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) host.name, getString(R.string.footer_connecting), true, true, 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new DialogInterface.OnCancelListener() { 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public void onCancel(DialogInterface dialog) { 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) JniInterface.disconnectFromHost(); 2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) mTokenFetcher = null; 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SessionConnector connector = new SessionConnector(this, this, mHostListLoader); 2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) assert mTokenFetcher == null; 2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) mTokenFetcher = createTokenFetcher(host); 298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) connector.connectToHost(mAccount.name, mToken, host); 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private void refreshHostList() { 30234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) if (mWaitingForAuthToken) { 30334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) return; 30434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) } 30534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) 306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mTriedNewAuthToken = false; 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) setHostListProgressVisible(true); 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The refresh button simply makes use of the currently-chosen account. 31034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) requestAuthToken(); 31134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) } 31234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) 31334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) private void requestAuthToken() { 314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AccountManager.get(this).getAuthToken(mAccount, TOKEN_SCOPE, null, this, this, null); 31534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) mWaitingForAuthToken = true; 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void run(AccountManagerFuture<Bundle> future) { 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.i("auth", "User finished with auth dialogs"); 32134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) mWaitingForAuthToken = false; 32234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Bundle result = null; 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) String explanation = null; 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try { 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Here comes our auth token from the Android system. 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result = future.getResult(); 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (OperationCanceledException ex) { 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // User canceled authentication. No need to report an error. 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (AuthenticatorException ex) { 331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explanation = getString(R.string.error_unexpected); 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (IOException ex) { 333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explanation = getString(R.string.error_network_error); 334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result == null) { 33734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) setHostListProgressVisible(false); 338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (explanation != null) { 339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); 340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mToken = result.getString(AccountManager.KEY_AUTHTOKEN); 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.i("auth", "Received an auth token from system"); 346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mHostListLoader.retrieveHostList(mToken, this); 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public boolean onNavigationItemSelected(int itemPosition, long itemId) { 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mAccount = mAccounts[itemPosition]; 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) getPreferences(MODE_PRIVATE).edit().putString("account_name", mAccount.name). 355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) putString("account_type", mAccount.type).apply(); 356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The current host list is no longer valid for the new account, so clear the list. 358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mHosts = new HostInfo[0]; 359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) updateUi(); 360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refreshHostList(); 361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @Override 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void onHostListReceived(HostInfo[] hosts) { 3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Store a copy of the array, so that it can't be mutated by the HostListLoader. HostInfo 3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // is an immutable type, so a shallow copy of the array is sufficient here. 3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mHosts = Arrays.copyOf(hosts, hosts.length); 369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) setHostListProgressVisible(false); 3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) updateUi(); 371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void onError(HostListLoader.Error error) { 3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) String explanation = null; 3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (error) { 3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case AUTH_FAILED: 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case NETWORK_ERROR: 380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explanation = getString(R.string.error_network_error); 3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case UNEXPECTED_RESPONSE: 383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case SERVICE_UNAVAILABLE: 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case UNKNOWN: 385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explanation = getString(R.string.error_unexpected); 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Unreachable. 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 391ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (explanation != null) { 3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); 394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) setHostListProgressVisible(false); 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 396ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 397ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This is the AUTH_FAILED case. 399a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!mTriedNewAuthToken) { 4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This was our first connection attempt. 402a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AccountManager authenticator = AccountManager.get(this); 404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mTriedNewAuthToken = true; 405ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.w("auth", "Requesting renewal of rejected auth token"); 4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) authenticator.invalidateAuthToken(mAccount.type, mToken); 4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mToken = null; 40934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles) requestAuthToken(); 410ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We're not in an error state *yet*. 4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Authentication truly failed. 4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.e("auth", "Fresh auth token was also rejected"); 416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explanation = getString(R.string.error_authentication_failed); 4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); 418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) setHostListProgressVisible(false); 419ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 420ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 421ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Updates the infotext and host list display. 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void updateUi() { 42646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (mRefreshButton != null) { 42746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) mRefreshButton.setEnabled(mAccount != null); 42846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ArrayAdapter<HostInfo> displayer = new HostListAdapter(this, R.layout.host, mHosts); 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.i("hostlist", "About to populate host list display"); 431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch mHostListView.setAdapter(displayer); 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void onConnectionState(JniInterface.ConnectionListener.State state, 4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) JniInterface.ConnectionListener.Error error) { 4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) boolean dismissProgress = false; 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (state) { 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case INITIALIZING: 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case CONNECTING: 4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case AUTHENTICATED: 442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The connection is still being established. 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case CONNECTED: 4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dismissProgress = true; 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Display the remote desktop. 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) startActivityForResult(new Intent(this, Desktop.class), 0); 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case FAILED: 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dismissProgress = true; 453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Toast.makeText(this, getString(error.message()), Toast.LENGTH_LONG).show(); 4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Close the Desktop view, if it is currently running. 4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finishActivity(0); 4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case CLOSED: 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // No need to show toast in this case. Either the connection will have failed 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // because of an error, which will trigger toast already. Or the disconnection will 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // have been initiated by the user. 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dismissProgress = true; 4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finishActivity(0); 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Unreachable, but required by Google Java style and findbugs. 4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert false : "Unreached"; 4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (dismissProgress && mProgressIndicator != null) { 4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mProgressIndicator.dismiss(); 4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mProgressIndicator = null; 474ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 475ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 476f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 4776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) private ThirdPartyTokenFetcher createTokenFetcher(HostInfo host) { 478f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ThirdPartyTokenFetcher.Callback callback = new ThirdPartyTokenFetcher.Callback() { 4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 480f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public void onTokenFetched(String code, String accessToken) { 481f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The native client sends the OAuth authorization code to the host as the token so 482f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // that the host can obtain the shared secret from the third party authorization 483f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // server. 484f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) String token = code; 485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The native client uses the OAuth access token as the shared secret to 487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // authenticate itself with the host using spake. 488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) String sharedSecret = accessToken; 489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 4906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) JniInterface.onThirdPartyTokenFetched(token, sharedSecret); 491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) }; 4936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return new ThirdPartyTokenFetcher(this, host.getTokenUrlPatterns(), callback); 494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 4966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) public void fetchThirdPartyToken(String tokenUrl, String clientId, String scope) { 4976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) assert mTokenFetcher != null; 4986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) mTokenFetcher.fetchToken(tokenUrl, clientId, scope); 4996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 500ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 501