OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chromoting; | 5 package org.chromium.chromoting; |
6 | 6 |
7 import android.accounts.Account; | 7 import android.accounts.Account; |
8 import android.accounts.AccountManager; | 8 import android.accounts.AccountManager; |
9 import android.accounts.AccountManagerCallback; | 9 import android.accounts.AccountManagerCallback; |
10 import android.accounts.AccountManagerFuture; | 10 import android.accounts.AccountManagerFuture; |
11 import android.accounts.AuthenticatorException; | 11 import android.accounts.AuthenticatorException; |
12 import android.accounts.OperationCanceledException; | 12 import android.accounts.OperationCanceledException; |
13 import android.app.Activity; | 13 import android.app.Activity; |
14 import android.app.ProgressDialog; | 14 import android.app.ProgressDialog; |
15 import android.content.DialogInterface; | 15 import android.content.DialogInterface; |
16 import android.content.Intent; | 16 import android.content.Intent; |
17 import android.content.SharedPreferences; | 17 import android.content.SharedPreferences; |
18 import android.os.Bundle; | 18 import android.os.Bundle; |
19 import android.os.Handler; | |
20 import android.os.HandlerThread; | |
21 import android.util.Log; | 19 import android.util.Log; |
22 import android.view.Menu; | 20 import android.view.Menu; |
23 import android.view.MenuItem; | 21 import android.view.MenuItem; |
24 import android.widget.ArrayAdapter; | 22 import android.widget.ArrayAdapter; |
25 import android.widget.ListView; | 23 import android.widget.ListView; |
26 import android.widget.TextView; | 24 import android.widget.TextView; |
27 import android.widget.Toast; | 25 import android.widget.Toast; |
28 | 26 |
29 import org.chromium.chromoting.jni.JniInterface; | 27 import org.chromium.chromoting.jni.JniInterface; |
30 import org.json.JSONArray; | |
31 import org.json.JSONException; | |
32 import org.json.JSONObject; | |
33 | 28 |
34 import java.io.IOException; | 29 import java.io.IOException; |
35 import java.net.URL; | |
36 import java.net.URLConnection; | |
37 import java.util.ArrayList; | |
38 import java.util.Collections; | |
39 import java.util.Comparator; | |
40 import java.util.List; | |
41 import java.util.Scanner; | |
42 | 30 |
43 /** | 31 /** |
44 * The user interface for querying and displaying a user's host list from the di rectory server. It | 32 * The user interface for querying and displaying a user's host list from the di rectory server. It |
45 * also requests and renews authentication tokens using the system account manag er. | 33 * also requests and renews authentication tokens using the system account manag er. |
46 */ | 34 */ |
47 public class Chromoting extends Activity implements JniInterface.ConnectionListe ner { | 35 public class Chromoting extends Activity implements JniInterface.ConnectionListe ner, |
36 AccountManagerCallback<Bundle>, HostListLoader.Callback { | |
48 /** Only accounts of this type will be selectable for authentication. */ | 37 /** Only accounts of this type will be selectable for authentication. */ |
49 private static final String ACCOUNT_TYPE = "com.google"; | 38 private static final String ACCOUNT_TYPE = "com.google"; |
50 | 39 |
51 /** Scopes at which the authentication token we request will be valid. */ | 40 /** Scopes at which the authentication token we request will be valid. */ |
52 private static final String TOKEN_SCOPE = "oauth2:https://www.googleapis.com /auth/chromoting " + | 41 private static final String TOKEN_SCOPE = "oauth2:https://www.googleapis.com /auth/chromoting " + |
53 "https://www.googleapis.com/auth/googletalk"; | 42 "https://www.googleapis.com/auth/googletalk"; |
54 | 43 |
55 /** Path from which to download a user's host list JSON object. */ | |
56 private static final String HOST_LIST_PATH = | |
57 "https://www.googleapis.com/chromoting/v1/@me/hosts?key="; | |
58 | |
59 /** Lock to protect |mAccount| and |mToken|. */ | |
60 // TODO(lambroslambrou): |mHosts| needs to be protected as well. | |
61 private Object mLock = new Object(); | |
62 | |
63 /** User's account details. */ | 44 /** User's account details. */ |
64 private Account mAccount; | 45 private Account mAccount; |
65 | 46 |
66 /** Account auth token. */ | 47 /** Account auth token. */ |
67 private String mToken; | 48 private String mToken; |
68 | 49 |
50 /** Helper for fetching the host list. */ | |
51 private HostListLoader mHostListLoader; | |
52 | |
69 /** List of hosts. */ | 53 /** List of hosts. */ |
70 private JSONArray mHosts; | 54 private Host[] mHosts; |
71 | 55 |
72 /** Refresh button. */ | 56 /** Refresh button. */ |
73 private MenuItem mRefreshButton; | 57 private MenuItem mRefreshButton; |
74 | 58 |
75 /** Account switcher. */ | 59 /** Account switcher. */ |
76 private MenuItem mAccountSwitcher; | 60 private MenuItem mAccountSwitcher; |
77 | 61 |
78 /** Greeting at the top of the displayed list. */ | 62 /** Greeting at the top of the displayed list. */ |
79 private TextView mGreeting; | 63 private TextView mGreeting; |
80 | 64 |
81 /** Host list as it appears to the user. */ | 65 /** Host list as it appears to the user. */ |
82 private ListView mList; | 66 private ListView mList; |
83 | 67 |
84 /** Callback handler to be used for network operations. */ | |
85 private Handler mNetwork; | |
86 | |
87 /** Dialog for reporting connection progress. */ | 68 /** Dialog for reporting connection progress. */ |
88 private ProgressDialog mProgressIndicator; | 69 private ProgressDialog mProgressIndicator; |
89 | 70 |
90 /** | 71 /** |
72 * This is set when receiving an authentication error from the HostListLoade r. If that occurs, | |
73 * this flag is set and a fresh authentication token is fetched from the Acc ountsService, and | |
74 * used to request the host list a second time. | |
75 */ | |
76 boolean mAlreadyTried; | |
77 | |
78 /** | |
91 * Called when the activity is first created. Loads the native library and r equests an | 79 * Called when the activity is first created. Loads the native library and r equests an |
92 * authentication token from the system. | 80 * authentication token from the system. |
93 */ | 81 */ |
94 @Override | 82 @Override |
95 public void onCreate(Bundle savedInstanceState) { | 83 public void onCreate(Bundle savedInstanceState) { |
96 super.onCreate(savedInstanceState); | 84 super.onCreate(savedInstanceState); |
97 setContentView(R.layout.main); | 85 setContentView(R.layout.main); |
98 | 86 |
87 mAlreadyTried = false; | |
88 mHostListLoader = new HostListLoader(); | |
89 | |
99 // Get ahold of our view widgets. | 90 // Get ahold of our view widgets. |
100 mGreeting = (TextView)findViewById(R.id.hostList_greeting); | 91 mGreeting = (TextView)findViewById(R.id.hostList_greeting); |
101 mList = (ListView)findViewById(R.id.hostList_chooser); | 92 mList = (ListView)findViewById(R.id.hostList_chooser); |
102 | 93 |
103 // Bring native components online. | 94 // Bring native components online. |
104 JniInterface.loadLibrary(this); | 95 JniInterface.loadLibrary(this); |
105 | 96 |
106 // Thread responsible for downloading/displaying host list. | |
107 HandlerThread thread = new HandlerThread("auth_callback"); | |
108 thread.start(); | |
109 mNetwork = new Handler(thread.getLooper()); | |
110 | |
111 SharedPreferences prefs = getPreferences(MODE_PRIVATE); | 97 SharedPreferences prefs = getPreferences(MODE_PRIVATE); |
112 if (prefs.contains("account_name") && prefs.contains("account_type")) { | 98 if (prefs.contains("account_name") && prefs.contains("account_type")) { |
113 // Perform authentication using saved account selection. | 99 // Perform authentication using saved account selection. |
114 mAccount = new Account(prefs.getString("account_name", null), | 100 mAccount = new Account(prefs.getString("account_name", null), |
115 prefs.getString("account_type", null)); | 101 prefs.getString("account_type", null)); |
116 AccountManager.get(this).getAuthToken(mAccount, TOKEN_SCOPE, null, t his, | 102 AccountManager.get(this).getAuthToken(mAccount, TOKEN_SCOPE, null, t his, this, null); |
117 new HostListDirectoryGrabber(this), mNetwork); | |
118 if (mAccountSwitcher != null) { | 103 if (mAccountSwitcher != null) { |
119 mAccountSwitcher.setTitle(mAccount.name); | 104 mAccountSwitcher.setTitle(mAccount.name); |
120 } | 105 } |
121 } else { | 106 } else { |
122 // Request auth callback once user has chosen an account. | 107 // Request auth callback once user has chosen an account. |
123 Log.i("auth", "Requesting auth token from system"); | 108 Log.i("auth", "Requesting auth token from system"); |
124 AccountManager.get(this).getAuthTokenByFeatures( | 109 AccountManager.get(this).getAuthTokenByFeatures(ACCOUNT_TYPE, TOKEN_ SCOPE, null, this, |
125 ACCOUNT_TYPE, | 110 null, null, this, null); |
126 TOKEN_SCOPE, | |
127 null, | |
128 this, | |
129 null, | |
130 null, | |
131 new HostListDirectoryGrabber(this), | |
132 mNetwork | |
133 ); | |
134 } | 111 } |
135 } | 112 } |
136 | 113 |
137 /** Called when the activity is finally finished. */ | 114 /** Called when the activity is finally finished. */ |
138 @Override | 115 @Override |
139 public void onDestroy() { | 116 public void onDestroy() { |
140 super.onDestroy(); | 117 super.onDestroy(); |
141 JniInterface.disconnectFromHost(); | 118 JniInterface.disconnectFromHost(); |
142 } | 119 } |
143 | 120 |
(...skipping 18 matching lines...) Expand all Loading... | |
162 // If the user has picked an account, show its name directly on the account switcher. | 139 // If the user has picked an account, show its name directly on the account switcher. |
163 mAccountSwitcher.setTitle(mAccount.name); | 140 mAccountSwitcher.setTitle(mAccount.name); |
164 } | 141 } |
165 | 142 |
166 return super.onCreateOptionsMenu(menu); | 143 return super.onCreateOptionsMenu(menu); |
167 } | 144 } |
168 | 145 |
169 /** Called whenever an action bar button is pressed. */ | 146 /** Called whenever an action bar button is pressed. */ |
170 @Override | 147 @Override |
171 public boolean onOptionsItemSelected(MenuItem item) { | 148 public boolean onOptionsItemSelected(MenuItem item) { |
149 mAlreadyTried = false; | |
172 if (item == mAccountSwitcher) { | 150 if (item == mAccountSwitcher) { |
173 // The account switcher triggers a listing of all available accounts . | 151 // The account switcher triggers a listing of all available accounts . |
174 AccountManager.get(this).getAuthTokenByFeatures( | 152 AccountManager.get(this).getAuthTokenByFeatures(ACCOUNT_TYPE, TOKEN_ SCOPE, null, this, |
175 ACCOUNT_TYPE, | 153 null, null, this, null); |
176 TOKEN_SCOPE, | 154 } else { |
177 null, | |
178 this, | |
179 null, | |
180 null, | |
181 new HostListDirectoryGrabber(this), | |
182 mNetwork | |
183 ); | |
184 } | |
185 else { | |
186 // The refresh button simply makes use of the currently-chosen accou nt. | 155 // The refresh button simply makes use of the currently-chosen accou nt. |
187 AccountManager.get(this).getAuthToken(mAccount, TOKEN_SCOPE, null, t his, | 156 AccountManager.get(this).getAuthToken(mAccount, TOKEN_SCOPE, null, t his, this, null); |
188 new HostListDirectoryGrabber(this), mNetwork); | |
189 } | 157 } |
190 | 158 |
191 return true; | 159 return true; |
192 } | 160 } |
193 | 161 |
194 /** Called when the user taps on a host entry. */ | 162 /** Called when the user taps on a host entry. */ |
195 public void connectToHost(JSONObject host) { | 163 public void connectToHost(Host host) { |
164 JniInterface.connectToHost(mAccount.name, mToken, host.jabberId, host.id , host.publicKey, | |
165 this); | |
166 } | |
167 | |
168 @Override | |
169 public void run(AccountManagerFuture<Bundle> future) { | |
170 Log.i("auth", "User finished with auth dialogs"); | |
196 try { | 171 try { |
197 synchronized (mLock) { | 172 // Here comes our auth token from the Android system. |
198 JniInterface.connectToHost(mAccount.name, mToken, host.getString ("jabberId"), | 173 Bundle result = future.getResult(); |
199 host.getString("hostId"), host.getString("publicKey"), t his); | 174 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAM E); |
200 } | 175 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYP E); |
201 } catch (JSONException ex) { | 176 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN); |
202 Log.w("host", ex); | 177 Log.i("auth", "Received an auth token from system"); |
203 Toast.makeText(this, getString(R.string.error_reading_host), | 178 |
204 Toast.LENGTH_LONG).show(); | 179 mAccount = new Account(accountName, accountType); |
205 // Close the application. | 180 mToken = authToken; |
206 finish(); | 181 getPreferences(MODE_PRIVATE).edit().putString("account_name", accoun tName). |
182 putString("account_type", accountType).apply(); | |
183 | |
184 mHostListLoader.retrieveHostList(authToken, this); | |
185 } catch (OperationCanceledException ex) { | |
Sergey Ulanov
2014/02/14 08:55:20
I think you can wrap only the first line (future.g
Lambros
2014/02/15 01:40:21
Done.
| |
186 String explanation = getString(R.string.error_auth_canceled); | |
187 Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); | |
188 } catch (AuthenticatorException ex) { | |
189 String explanation = getString(R.string.error_no_accounts); | |
190 Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); | |
191 } catch (IOException ex) { | |
192 String explanation = getString(R.string.error_bad_connection); | |
193 Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); | |
207 } | 194 } |
208 } | 195 } |
209 | 196 |
210 /** | 197 @Override |
211 * Processes the authentication token once the system provides it. Once in p ossession of such a | 198 public void onHostListReceived(Host[] hosts) { |
212 * token, attempts to request a host list from the directory server. In case of a bad response, | 199 mHosts = hosts; |
213 * this is retried once in case the system's cached auth token had expired. | 200 updateUi(); |
214 */ | 201 } |
215 private class HostListDirectoryGrabber implements AccountManagerCallback<Bun dle> { | |
216 // TODO(lambroslambrou): Refactor this class to provide async interface usable on the UI | |
217 // thread. | |
218 | 202 |
219 /** Whether authentication has already been attempted. */ | 203 @Override |
220 private boolean mAlreadyTried; | 204 public void onError(HostListLoader.Error error) { |
221 | 205 String explanation = null; |
222 /** Communication with the screen. */ | 206 switch (error) { |
223 private Activity mUi; | 207 case AUTH_FAILED: |
224 | 208 break; |
225 /** Constructor. */ | 209 case NETWORK_ERROR: |
226 public HostListDirectoryGrabber(Activity ui) { | 210 explanation = getString(R.string.error_bad_connection); |
227 mAlreadyTried = false; | 211 break; |
228 mUi = ui; | 212 case SERVICE_UNAVAILABLE: |
213 case UNEXPECTED_RESPONSE: | |
214 explanation = getString(R.string.error_unexpected_response); | |
215 break; | |
216 case UNKNOWN: | |
217 explanation = getString(R.string.error_unknown); | |
218 break; | |
219 default: | |
220 // Unreachable. | |
221 return; | |
229 } | 222 } |
230 | 223 |
231 /** | 224 if (explanation != null) { |
232 * Retrieves the host list from the directory server. This method perfor ms | 225 Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); |
233 * network operations and must be run an a non-UI thread. | 226 return; |
234 */ | |
235 @Override | |
236 public void run(AccountManagerFuture<Bundle> future) { | |
237 Log.i("auth", "User finished with auth dialogs"); | |
238 try { | |
239 // Here comes our auth token from the Android system. | |
240 Bundle result = future.getResult(); | |
241 String accountName = result.getString(AccountManager.KEY_ACCOUNT _NAME); | |
242 String accountType = result.getString(AccountManager.KEY_ACCOUNT _TYPE); | |
243 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN ); | |
244 Log.i("auth", "Received an auth token from system"); | |
245 | |
246 synchronized (mLock) { | |
247 mAccount = new Account(accountName, accountType); | |
248 mToken = authToken; | |
249 getPreferences(MODE_PRIVATE).edit().putString("account_name" , accountName). | |
250 putString("account_type", accountType).apply(); | |
251 } | |
252 | |
253 // Send our HTTP request to the directory server. | |
254 URLConnection link = | |
255 new URL(HOST_LIST_PATH + JniInterface.nativeGetApiKey()) .openConnection(); | |
256 link.addRequestProperty("client_id", JniInterface.nativeGetClien tId()); | |
257 link.addRequestProperty("client_secret", JniInterface.nativeGetC lientSecret()); | |
258 link.setRequestProperty("Authorization", "OAuth " + authToken); | |
259 | |
260 // Listen for the server to respond. | |
261 StringBuilder response = new StringBuilder(); | |
262 Scanner incoming = new Scanner(link.getInputStream()); | |
263 Log.i("auth", "Successfully authenticated to directory server"); | |
264 while (incoming.hasNext()) { | |
265 response.append(incoming.nextLine()); | |
266 } | |
267 incoming.close(); | |
268 | |
269 // Interpret what the directory server told us. | |
270 JSONObject data = new JSONObject(String.valueOf(response)).getJS ONObject("data"); | |
271 mHosts = sortHosts(data.getJSONArray("items")); | |
272 Log.i("hostlist", "Received host listing from directory server") ; | |
273 } catch (RuntimeException ex) { | |
274 // Make sure any other failure is reported to the user (as an un known error). | |
275 throw ex; | |
276 } catch (Exception ex) { | |
277 // Assemble error message to display to the user. | |
278 String explanation = getString(R.string.error_unknown); | |
279 if (ex instanceof OperationCanceledException) { | |
280 explanation = getString(R.string.error_auth_canceled); | |
281 } else if (ex instanceof AuthenticatorException) { | |
282 explanation = getString(R.string.error_no_accounts); | |
283 } else if (ex instanceof IOException) { | |
284 if (!mAlreadyTried) { | |
285 // This was our first connection attempt. | |
286 | |
287 synchronized (mLock) { | |
288 if (mAccount != null) { | |
289 // We got an account, but couldn't log into it. We'll retry in case | |
290 // the system's cached authentication token had already expired. | |
291 AccountManager authenticator = AccountManager.ge t(mUi); | |
292 mAlreadyTried = true; | |
293 | |
294 Log.w("auth", "Requesting renewal of rejected au th token"); | |
295 authenticator.invalidateAuthToken(mAccount.type, mToken); | |
296 mToken = null; | |
297 authenticator.getAuthToken( | |
298 mAccount, TOKEN_SCOPE, null, mUi, this, mNetwork); | |
299 | |
300 // We're not in an error state *yet*. | |
301 return; | |
302 } | |
303 } | |
304 | |
305 // We didn't even get an account, so the auth server is likely unreachable. | |
306 explanation = getString(R.string.error_bad_connection); | |
307 } else { | |
308 // Authentication truly failed. | |
309 Log.e("auth", "Fresh auth token was also rejected"); | |
310 explanation = getString(R.string.error_auth_failed); | |
311 } | |
312 } else if (ex instanceof JSONException) { | |
313 explanation = getString(R.string.error_unexpected_response); | |
314 } | |
315 | |
316 mHosts = null; | |
317 Log.w("auth", ex); | |
318 Toast.makeText(mUi, explanation, Toast.LENGTH_LONG).show(); | |
319 } | |
320 | |
321 // Share our findings with the user. | |
322 runOnUiThread(new Runnable() { | |
323 @Override | |
324 public void run() { | |
325 updateUi(); | |
326 } | |
327 }); | |
328 } | 227 } |
329 | 228 |
330 private JSONArray sortHosts(JSONArray hosts) { | 229 // This is the AUTH_FAILED case. |
331 List<JSONObject> hostList = new ArrayList<JSONObject>(); | |
332 for (int i = 0; i < hosts.length(); i++) { | |
333 try { | |
334 hostList.add(hosts.getJSONObject(i)); | |
335 } catch (JSONException ex) { | |
336 // Ignore non-object entries. | |
337 } | |
338 } | |
339 | 230 |
340 Comparator<JSONObject> compareHosts = new Comparator<JSONObject>() { | 231 if (!mAlreadyTried) { |
341 public int compare(JSONObject a, JSONObject b) { | 232 // This was our first connection attempt. |
342 try { | |
343 boolean aOnline = a.getString("status").equals("ONLINE") ; | |
344 boolean bOnline = b.getString("status").equals("ONLINE") ; | |
345 if (aOnline && !bOnline) { | |
346 return -1; | |
347 } | |
348 if (bOnline && !aOnline) { | |
349 return 1; | |
350 } | |
351 String aName = a.getString("hostName").toUpperCase(); | |
352 String bName = b.getString("hostName").toUpperCase(); | |
353 return aName.compareTo(bName); | |
354 } catch (JSONException ex) { | |
355 return 0; | |
356 } | |
357 } | |
358 }; | |
359 Collections.sort(hostList, compareHosts); | |
360 | 233 |
361 JSONArray result = new JSONArray(hostList); | 234 AccountManager authenticator = AccountManager.get(this); |
362 return result; | 235 mAlreadyTried = true; |
236 | |
237 Log.w("auth", "Requesting renewal of rejected auth token"); | |
238 authenticator.invalidateAuthToken(mAccount.type, mToken); | |
239 mToken = null; | |
240 authenticator.getAuthToken(mAccount, TOKEN_SCOPE, null, this, this, null); | |
241 | |
242 // We're not in an error state *yet*. | |
243 return; | |
244 } else { | |
245 // Authentication truly failed. | |
246 Log.e("auth", "Fresh auth token was also rejected"); | |
247 explanation = getString(R.string.error_auth_failed); | |
248 Toast.makeText(this, explanation, Toast.LENGTH_LONG).show(); | |
363 } | 249 } |
364 } | 250 } |
365 | 251 |
366 /** | 252 /** |
367 * Updates the infotext and host list display. | 253 * Updates the infotext and host list display. |
368 * This method affects the UI and must be run on the main thread. | |
369 */ | 254 */ |
370 private void updateUi() { | 255 private void updateUi() { |
371 synchronized (mLock) { | 256 mRefreshButton.setEnabled(mAccount != null); |
372 mRefreshButton.setEnabled(mAccount != null); | 257 if (mAccount != null) { |
373 if (mAccount != null) { | 258 mAccountSwitcher.setTitle(mAccount.name); |
374 mAccountSwitcher.setTitle(mAccount.name); | |
375 } | |
376 } | 259 } |
377 | 260 |
378 if (mHosts == null) { | 261 if (mHosts == null) { |
379 mGreeting.setText(getString(R.string.inst_empty_list)); | 262 mGreeting.setText(getString(R.string.inst_empty_list)); |
380 mList.setAdapter(null); | 263 mList.setAdapter(null); |
381 return; | 264 return; |
382 } | 265 } |
383 | 266 |
384 mGreeting.setText(getString(R.string.inst_host_list)); | 267 mGreeting.setText(getString(R.string.inst_host_list)); |
385 | 268 |
386 ArrayAdapter<JSONObject> displayer = new HostListAdapter(this, R.layout. host); | 269 ArrayAdapter<Host> displayer = new HostListAdapter(this, R.layout.host, mHosts); |
387 Log.i("hostlist", "About to populate host list display"); | 270 Log.i("hostlist", "About to populate host list display"); |
388 try { | 271 mList.setAdapter(displayer); |
389 int index = 0; | |
390 while (!mHosts.isNull(index)) { | |
391 displayer.add(mHosts.getJSONObject(index)); | |
392 ++index; | |
393 } | |
394 mList.setAdapter(displayer); | |
395 } catch (JSONException ex) { | |
396 Log.w("hostlist", ex); | |
397 Toast.makeText(this, getString(R.string.error_cataloging_hosts), | |
398 Toast.LENGTH_LONG).show(); | |
399 | |
400 // Close the application. | |
401 finish(); | |
402 } | |
403 } | 272 } |
404 | 273 |
405 @Override | 274 @Override |
406 public void onConnectionState(JniInterface.ConnectionListener.State state, | 275 public void onConnectionState(JniInterface.ConnectionListener.State state, |
407 JniInterface.ConnectionListener.Error error) { | 276 JniInterface.ConnectionListener.Error error) { |
408 String stateText = getResources().getStringArray(R.array.protoc_states)[ state.value()]; | 277 String stateText = getResources().getStringArray(R.array.protoc_states)[ state.value()]; |
409 boolean dismissProgress = false; | 278 boolean dismissProgress = false; |
410 switch (state) { | 279 switch (state) { |
411 case INITIALIZING: | 280 case INITIALIZING: |
412 case CONNECTING: | 281 case CONNECTING: |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
456 // Unreachable, but required by Google Java style and findbugs. | 325 // Unreachable, but required by Google Java style and findbugs. |
457 assert false : "Unreached"; | 326 assert false : "Unreached"; |
458 } | 327 } |
459 | 328 |
460 if (dismissProgress && mProgressIndicator != null) { | 329 if (dismissProgress && mProgressIndicator != null) { |
461 mProgressIndicator.dismiss(); | 330 mProgressIndicator.dismiss(); |
462 mProgressIndicator = null; | 331 mProgressIndicator = null; |
463 } | 332 } |
464 } | 333 } |
465 } | 334 } |
OLD | NEW |