Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: remoting/android/java/src/org/chromium/chromoting/HostListLoader.java

Issue 1948793002: Implement HostListManager by Refactoring HostListLoader (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reviewer's feedback Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 package org.chromium.chromoting;
6
7 import android.os.Handler;
8 import android.os.HandlerThread;
9 import android.os.Looper;
10
11 import org.chromium.base.Log;
12 import org.json.JSONArray;
13 import org.json.JSONException;
14 import org.json.JSONObject;
15
16 import java.io.IOException;
17 import java.net.HttpURLConnection;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.Locale;
24 import java.util.Scanner;
25
26 /** Helper for fetching the host list. */
27 public class HostListLoader {
28 public enum Error {
29 AUTH_FAILED,
30 NETWORK_ERROR,
31 SERVICE_UNAVAILABLE,
32 UNEXPECTED_RESPONSE,
33 UNKNOWN,
34 }
35
36 /** Callback for receiving the host list, or getting notified of an error. * /
37 public interface Callback {
38 void onHostListReceived(HostInfo[] hosts);
39 void onError(Error error);
40 }
41
42 private static final String TAG = "Chromoting";
43
44 /** Path from which to download a user's host list JSON object. */
45 private static final String HOST_LIST_PATH =
46 "https://www.googleapis.com/chromoting/v1/@me/hosts";
47
48 /** Callback handler to be used for network operations. */
49 private Handler mNetworkThread;
50
51 /** Handler for main thread. */
52 private Handler mMainThread;
53
54 public HostListLoader() {
55 // Thread responsible for downloading the host list.
56
57 mMainThread = new Handler(Looper.getMainLooper());
58 }
59
60 private void initNetworkThread() {
61 if (mNetworkThread == null) {
62 HandlerThread thread = new HandlerThread("network");
63 thread.start();
64 mNetworkThread = new Handler(thread.getLooper());
65 }
66 }
67
68 /**
69 * Causes the host list to be fetched on a background thread. This should b e called on the
70 * main thread, and callbacks will also be invoked on the main thread. On s uccess,
71 * callback.onHostListReceived() will be called, otherwise callback.onError () will be called
72 * with an error-code describing the failure.
73 */
74 public void retrieveHostList(String authToken, Callback callback) {
75 initNetworkThread();
76 final String authTokenFinal = authToken;
77 final Callback callbackFinal = callback;
78 mNetworkThread.post(new Runnable() {
79 @Override
80 public void run() {
81 doRetrieveHostList(authTokenFinal, callbackFinal);
82 }
83 });
84 }
85
86 private void doRetrieveHostList(String authToken, Callback callback) {
87 HttpURLConnection link = null;
88 String response = null;
89 try {
90 link = (HttpURLConnection) new URL(HOST_LIST_PATH).openConnection();
91 link.setRequestProperty("Authorization", "OAuth " + authToken);
92
93 // Listen for the server to respond.
94 int status = link.getResponseCode();
95 switch (status) {
96 case HttpURLConnection.HTTP_OK: // 200
97 break;
98 case HttpURLConnection.HTTP_UNAUTHORIZED: // 401
99 postError(callback, Error.AUTH_FAILED);
100 return;
101 case HttpURLConnection.HTTP_BAD_GATEWAY: // 502
102 case HttpURLConnection.HTTP_UNAVAILABLE: // 503
103 postError(callback, Error.SERVICE_UNAVAILABLE);
104 return;
105 default:
106 postError(callback, Error.UNKNOWN);
107 return;
108 }
109
110 StringBuilder responseBuilder = new StringBuilder();
111 Scanner incoming = new Scanner(link.getInputStream());
112 while (incoming.hasNext()) {
113 responseBuilder.append(incoming.nextLine());
114 }
115 response = String.valueOf(responseBuilder);
116 incoming.close();
117 } catch (MalformedURLException ex) {
118 // This should never happen.
119 throw new RuntimeException("Unexpected error while fetching host lis t: ", ex);
120 } catch (IOException ex) {
121 postError(callback, Error.NETWORK_ERROR);
122 return;
123 } finally {
124 if (link != null) {
125 link.disconnect();
126 }
127 }
128
129 // Parse directory response.
130 ArrayList<HostInfo> hostList = new ArrayList<HostInfo>();
131 try {
132 JSONObject data = new JSONObject(response).getJSONObject("data");
133 if (data.has("items")) {
134 JSONArray hostsJson = data.getJSONArray("items");
135
136 int index = 0;
137 while (!hostsJson.isNull(index)) {
138 JSONObject hostJson = hostsJson.getJSONObject(index);
139 // If a host is only recently registered, it may be missing some of the keys
140 // below. It should still be visible in the list, even thoug h a connection
141 // attempt will fail because of the missing keys. The failed attempt will
142 // trigger reloading of the host-list, by which time the key s will hopefully be
143 // present, and the retried connection can succeed.
144 HostInfo host = HostInfo.create(hostJson);
145 hostList.add(host);
146 ++index;
147 }
148 }
149 } catch (JSONException ex) {
150 // Logging the exception stack trace may be too spammy.
151 Log.e(TAG, "Error parsing host list response: %s", ex.getMessage());
152 postError(callback, Error.UNEXPECTED_RESPONSE);
153 return;
154 }
155
156 sortHosts(hostList);
157
158 final Callback callbackFinal = callback;
159 final HostInfo[] hosts = hostList.toArray(new HostInfo[hostList.size()]) ;
160 mMainThread.post(new Runnable() {
161 @Override
162 public void run() {
163 callbackFinal.onHostListReceived(hosts);
164 }
165 });
166 }
167
168 /** Posts error to callback on main thread. */
169 private void postError(Callback callback, Error error) {
170 final Callback callbackFinal = callback;
171 final Error errorFinal = error;
172 mMainThread.post(new Runnable() {
173 @Override
174 public void run() {
175 callbackFinal.onError(errorFinal);
176 }
177 });
178 }
179
180 private static void sortHosts(ArrayList<HostInfo> hosts) {
181 Comparator<HostInfo> hostComparator = new Comparator<HostInfo>() {
182 @Override
183 public int compare(HostInfo a, HostInfo b) {
184 if (a.isOnline != b.isOnline) {
185 return a.isOnline ? -1 : 1;
186 }
187 String aName = a.name.toUpperCase(Locale.getDefault());
188 String bName = b.name.toUpperCase(Locale.getDefault());
189 return aName.compareTo(bName);
190 }
191 };
192 Collections.sort(hosts, hostComparator);
193 }
194 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698