1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.location;
18
19import android.content.Context;
20import android.net.Proxy;
21import android.net.http.AndroidHttpClient;
22import android.util.Log;
23
24import org.apache.http.HttpEntity;
25import org.apache.http.HttpHost;
26import org.apache.http.HttpResponse;
27import org.apache.http.StatusLine;
28import org.apache.http.client.HttpClient;
29import org.apache.http.client.methods.HttpGet;
30import org.apache.http.client.methods.HttpUriRequest;
31import org.apache.http.conn.params.ConnRouteParams;
32
33import java.io.DataInputStream;
34import java.io.IOException;
35import java.util.Properties;
36import java.util.Random;
37
38/**
39 * A class for downloading GPS XTRA data.
40 *
41 * {@hide}
42 */
43public class GpsXtraDownloader {
44
45    private static final String TAG = "GpsXtraDownloader";
46    static final boolean DEBUG = false;
47
48    private Context mContext;
49    private String[] mXtraServers;
50    // to load balance our server requests
51    private int mNextServerIndex;
52
53    GpsXtraDownloader(Context context, Properties properties) {
54        mContext = context;
55
56        // read XTRA servers from the Properties object
57        int count = 0;
58        String server1 = properties.getProperty("XTRA_SERVER_1");
59        String server2 = properties.getProperty("XTRA_SERVER_2");
60        String server3 = properties.getProperty("XTRA_SERVER_3");
61        if (server1 != null) count++;
62        if (server2 != null) count++;
63        if (server3 != null) count++;
64
65        if (count == 0) {
66            Log.e(TAG, "No XTRA servers were specified in the GPS configuration");
67            return;
68        } else {
69            mXtraServers = new String[count];
70            count = 0;
71            if (server1 != null) mXtraServers[count++] = server1;
72            if (server2 != null) mXtraServers[count++] = server2;
73            if (server3 != null) mXtraServers[count++] = server3;
74
75            // randomize first server
76            Random random = new Random();
77            mNextServerIndex = random.nextInt(count);
78        }
79    }
80
81    byte[] downloadXtraData() {
82        String proxyHost = Proxy.getHost(mContext);
83        int proxyPort = Proxy.getPort(mContext);
84        boolean useProxy = (proxyHost != null && proxyPort != -1);
85        byte[] result = null;
86        int startIndex = mNextServerIndex;
87
88        if (mXtraServers == null) {
89            return null;
90        }
91
92        // load balance our requests among the available servers
93        while (result == null) {
94            result = doDownload(mXtraServers[mNextServerIndex], useProxy, proxyHost, proxyPort);
95
96            // increment mNextServerIndex and wrap around if necessary
97            mNextServerIndex++;
98            if (mNextServerIndex == mXtraServers.length) {
99                mNextServerIndex = 0;
100            }
101            // break if we have tried all the servers
102            if (mNextServerIndex == startIndex) break;
103        }
104
105        return result;
106    }
107
108    protected static byte[] doDownload(String url, boolean isProxySet,
109            String proxyHost, int proxyPort) {
110        if (DEBUG) Log.d(TAG, "Downloading XTRA data from " + url);
111
112        AndroidHttpClient client = null;
113        try {
114            client = AndroidHttpClient.newInstance("Android");
115            HttpUriRequest req = new HttpGet(url);
116
117            if (isProxySet) {
118                HttpHost proxy = new HttpHost(proxyHost, proxyPort);
119                ConnRouteParams.setDefaultProxy(req.getParams(), proxy);
120            }
121
122            req.addHeader(
123                    "Accept",
124                    "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
125
126            req.addHeader(
127                    "x-wap-profile",
128                    "http://www.openmobilealliance.org/tech/profiles/UAPROF/ccppschema-20021212#");
129
130            HttpResponse response = client.execute(req);
131            StatusLine status = response.getStatusLine();
132            if (status.getStatusCode() != 200) { // HTTP 200 is success.
133                if (DEBUG) Log.d(TAG, "HTTP error: " + status.getReasonPhrase());
134                return null;
135            }
136
137            HttpEntity entity = response.getEntity();
138            byte[] body = null;
139            if (entity != null) {
140                try {
141                    if (entity.getContentLength() > 0) {
142                        body = new byte[(int) entity.getContentLength()];
143                        DataInputStream dis = new DataInputStream(entity.getContent());
144                        try {
145                            dis.readFully(body);
146                        } finally {
147                            try {
148                                dis.close();
149                            } catch (IOException e) {
150                                Log.e(TAG, "Unexpected IOException.", e);
151                            }
152                        }
153                    }
154                } finally {
155                    if (entity != null) {
156                        entity.consumeContent();
157                    }
158                }
159            }
160            return body;
161        } catch (Exception e) {
162            if (DEBUG) Log.d(TAG, "error " + e);
163        } finally {
164            if (client != null) {
165                client.close();
166            }
167        }
168        return null;
169    }
170
171}
172