OLD | NEW |
---|---|
(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 import android.util.Log; | |
11 | |
12 import org.chromium.chromoting.jni.JniInterface; | |
13 import org.json.JSONArray; | |
14 import org.json.JSONException; | |
15 import org.json.JSONObject; | |
16 | |
17 import java.io.IOException; | |
18 import java.net.HttpURLConnection; | |
19 import java.net.MalformedURLException; | |
20 import java.net.URL; | |
21 import java.util.ArrayList; | |
22 import java.util.Collections; | |
23 import java.util.Comparator; | |
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(Host[] hosts); | |
39 void onError(Error error); | |
40 } | |
41 | |
42 /** Path from which to download a user's host list JSON object. */ | |
43 private static final String HOST_LIST_PATH = | |
44 "https://www.googleapis.com/chromoting/v1/@me/hosts?key="; | |
45 | |
46 /** Callback handler to be used for network operations. */ | |
47 private Handler mNetworkThread; | |
48 | |
49 /** Handler for main thread. */ | |
50 private Handler mMainThread; | |
51 | |
52 public HostListLoader() { | |
53 // Thread responsible for downloading the host list. | |
54 HandlerThread thread = new HandlerThread("network"); | |
55 thread.start(); | |
56 mNetworkThread = new Handler(thread.getLooper()); | |
57 | |
58 mMainThread = new Handler(Looper.getMainLooper()); | |
59 } | |
60 | |
61 /** | |
62 * Causes the host list to be fetched on a background thread. This should b e called on the | |
63 * main thread, and callbacks will also be invoked on the main thread. On s uccess, | |
64 * callback.onHostListReceived() will be called, otherwise callback.onError () will be called | |
65 * with an error-code describing the failure. | |
66 */ | |
67 public void retrieveHostList(String authToken, Callback callback) { | |
68 final String authTokenFinal = authToken; | |
69 final Callback callbackFinal = callback; | |
70 mNetworkThread.post(new Runnable() { | |
71 @Override | |
72 public void run() { | |
73 doRetrieveHostList(authTokenFinal, callbackFinal); | |
74 } | |
75 }); | |
76 } | |
77 | |
78 private void doRetrieveHostList(String authToken, Callback callback) { | |
79 HttpURLConnection link = null; | |
80 try { | |
81 link = (HttpURLConnection) | |
82 new URL(HOST_LIST_PATH + JniInterface.nativeGetApiKey()).ope nConnection(); | |
83 link.addRequestProperty("client_id", JniInterface.nativeGetClientId( )); | |
84 link.addRequestProperty("client_secret", JniInterface.nativeGetClien tSecret()); | |
85 link.setRequestProperty("Authorization", "OAuth " + authToken); | |
86 | |
87 // Listen for the server to respond. | |
88 int status = link.getResponseCode(); | |
89 switch (status) { | |
90 case HttpURLConnection.HTTP_OK: // 200 | |
91 break; | |
92 case HttpURLConnection.HTTP_UNAUTHORIZED: // 401 | |
93 postError(callback, Error.AUTH_FAILED); | |
94 return; | |
95 case HttpURLConnection.HTTP_BAD_GATEWAY: // 502 | |
96 case HttpURLConnection.HTTP_UNAVAILABLE: // 503 | |
97 postError(callback, Error.SERVICE_UNAVAILABLE); | |
98 return; | |
99 default: | |
100 postError(callback, Error.UNKNOWN); | |
101 return; | |
102 } | |
103 | |
104 StringBuilder response = new StringBuilder(); | |
105 Scanner incoming = new Scanner(link.getInputStream()); | |
106 Log.i("auth", "Successfully authenticated to directory server"); | |
107 while (incoming.hasNext()) { | |
108 response.append(incoming.nextLine()); | |
109 } | |
110 incoming.close(); | |
111 | |
112 // Interpret what the directory server told us. | |
Sergey Ulanov
2014/02/14 08:55:20
suggest rewording: "Parse directory response"
Lambros
2014/02/15 01:40:21
Done.
| |
113 JSONObject data = new JSONObject(String.valueOf(response)).getJSONOb ject("data"); | |
114 JSONArray hostsJson = data.getJSONArray("items"); | |
115 Log.i("hostlist", "Received host listing from directory server"); | |
116 | |
117 int index = 0; | |
118 ArrayList<Host> hostList = new ArrayList<Host>(); | |
119 while (!hostsJson.isNull(index)) { | |
120 JSONObject hostJson = hostsJson.getJSONObject(index); | |
121 Host host = new Host(); | |
122 host.name = hostJson.getString("hostName"); | |
123 host.id = hostJson.getString("hostId"); | |
124 host.jabberId = hostJson.getString("jabberId"); | |
Sergey Ulanov
2014/02/14 08:55:20
jabberId may not be set when the host was just reg
Lambros
2014/02/15 01:40:21
Done.
| |
125 host.publicKey = hostJson.getString("publicKey"); | |
126 host.isOnline = hostJson.getString("status").equals("ONLINE"); | |
127 hostList.add(host); | |
128 ++index; | |
129 } | |
130 | |
131 sortHosts(hostList); | |
Sergey Ulanov
2014/02/14 08:55:20
Sorting should be UI feature. Move this to HostLis
Sergey Ulanov
2014/02/14 08:55:20
This and code below it doesn't need to be in try-c
Lambros
2014/02/15 01:40:21
This was already decided in the CL here: https://c
Lambros
2014/02/15 01:40:21
Done.
| |
132 | |
133 final Callback callbackFinal = callback; | |
134 final Host[] hosts = hostList.toArray(new Host[hostList.size()]); | |
135 mMainThread.post(new Runnable() { | |
136 @Override | |
137 public void run() { | |
138 callbackFinal.onHostListReceived(hosts); | |
139 } | |
140 }); | |
141 } catch (MalformedURLException ex) { | |
142 // This should never happen. | |
143 Log.e("hostlist", "Unexpected error while fetching host list: " + ex ); | |
Sergey Ulanov
2014/02/14 08:55:20
Throw RuntimeException?
Lambros
2014/02/15 01:40:21
Done.
| |
144 } catch (JSONException ex) { | |
Sergey Ulanov
2014/02/14 08:55:20
I suggest having two separate try-catch block. One
Lambros
2014/02/15 01:40:21
Done.
| |
145 postError(callback, Error.UNEXPECTED_RESPONSE); | |
146 } catch (IOException ex) { | |
147 postError(callback, Error.NETWORK_ERROR); | |
148 } finally { | |
149 if (link != null) { | |
150 link.disconnect(); | |
151 } | |
152 } | |
153 } | |
154 | |
155 /** Posts error to callback on main thread. */ | |
156 private void postError(Callback callback, Error error) { | |
157 final Callback callbackFinal = callback; | |
158 final Error errorFinal = error; | |
159 mMainThread.post(new Runnable() { | |
160 @Override | |
161 public void run() { | |
162 callbackFinal.onError(errorFinal); | |
163 } | |
164 }); | |
165 } | |
166 | |
167 private static void sortHosts(ArrayList<Host> hosts) { | |
168 Comparator<Host> compareHosts = new Comparator<Host>() { | |
Sergey Ulanov
2014/02/14 08:55:20
nit: hostComparator
Lambros
2014/02/15 01:40:21
Done.
| |
169 public int compare(Host a, Host b) { | |
170 if (a.isOnline != b.isOnline) { | |
171 return a.isOnline ? -1 : 1; | |
172 } | |
173 String aName = a.name.toUpperCase(); | |
174 String bName = b.name.toUpperCase(); | |
175 return aName.compareTo(bName); | |
176 } | |
177 }; | |
178 Collections.sort(hosts, compareHosts); | |
179 } | |
180 } | |
OLD | NEW |