Project

General

Profile

Download (27.3 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / external / RubikNetwork.java @ 1a7efafd

1 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 1c327853 Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 acabdd83 Leszek Koltunski
package org.distorted.external;
11 fdec60a3 Leszek Koltunski
12 1d643a0e Leszek Koltunski
import java.io.BufferedReader;
13 b88cdd91 Leszek Koltunski
import java.io.IOException;
14 3f7a4363 Leszek Koltunski
import java.io.InputStream;
15 1d643a0e Leszek Koltunski
import java.io.InputStreamReader;
16 3f7a4363 Leszek Koltunski
import java.net.HttpURLConnection;
17
import java.net.URL;
18
import java.net.UnknownHostException;
19
import java.security.MessageDigest;
20
import java.security.NoSuchAlgorithmException;
21 1c04d054 leszek
import java.util.ArrayList;
22 3f7a4363 Leszek Koltunski
23 e4854e54 Leszek Koltunski
import android.app.Activity;
24 7fe62d1f Leszek Koltunski
import android.content.Context;
25 1780dcb0 Leszek Koltunski
import android.content.pm.PackageInfo;
26
import android.content.pm.PackageManager;
27 b88cdd91 Leszek Koltunski
import android.graphics.Bitmap;
28
import android.graphics.BitmapFactory;
29 1780dcb0 Leszek Koltunski
30 fcf7320f Leszek Koltunski
import org.distorted.objectlib.json.JsonWriter;
31 a7d8c3cd Leszek Koltunski
import org.distorted.objects.RubikObjectList;
32 36e2cbdd Leszek Koltunski
33 7bb30586 leszek
import static org.distorted.objects.RubikObjectList.SHOW_DOWNLOADED_DEBUG;
34
import static org.distorted.external.RubikScores.LEVELS_SHOWN;
35 211b48f2 Leszek Koltunski
36 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
37
38 ffe7e55d Leszek Koltunski
public class RubikNetwork
39 fdec60a3 Leszek Koltunski
  {
40 46be3ddf Leszek Koltunski
  public interface ScoresReceiver
41 b8b38548 Leszek Koltunski
    {
42 65bc1da3 Leszek Koltunski
    void receive(String[][][] country, String[][][] name, int[][][] time);
43 4895fff6 Leszek Koltunski
    void message(String mess);
44 4c0cd600 Leszek Koltunski
    void error(String error);
45 b8b38548 Leszek Koltunski
    }
46
47 46be3ddf Leszek Koltunski
  public interface IconReceiver
48 63dd19c4 Leszek Koltunski
    {
49 7fe62d1f Leszek Koltunski
    void iconDownloaded(int ordinal, Bitmap bitmap, boolean downloaded);
50 46be3ddf Leszek Koltunski
    }
51
52
  public interface Updatee
53
    {
54 1c04d054 leszek
    int getType();
55 63dd19c4 Leszek Koltunski
    void receiveUpdate(RubikUpdates update);
56 1c04d054 leszek
    void objectDownloaded(String shortName);
57 63dd19c4 Leszek Koltunski
    void errorUpdate();
58
    }
59
60 46be3ddf Leszek Koltunski
  public interface Downloadee
61
    {
62
    void jsonDownloaded();
63
    }
64
65 286d73ae Leszek Koltunski
  public static final int MAX_PLACES = 10;
66 d8aa4ba8 Leszek Koltunski
67 1c04d054 leszek
  private static final int UPDATES_RUNNING = 1;
68
  private static final int UPDATES_SUCCESS = 2;
69
  private static final int UPDATES_FAILURE = 3;
70 63dd19c4 Leszek Koltunski
71 36e2cbdd Leszek Koltunski
  private final String[] hex = {
72
    "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
73
    "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",
74
    "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
75
    "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
76
    "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
77
    "%28", "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f",
78
    "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
79
    "%38", "%39", "%3a", "%3b", "%3c", "%3d", "%3e", "%3f",
80
    "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
81
    "%48", "%49", "%4a", "%4b", "%4c", "%4d", "%4e", "%4f",
82
    "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
83
    "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", "%5f",
84
    "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
85
    "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f",
86
    "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
87
    "%78", "%79", "%7a", "%7b", "%7c", "%7d", "%7e", "%7f",
88
    "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
89
    "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f",
90
    "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
91
    "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f",
92
    "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
93
    "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
94
    "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7",
95
    "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf",
96
    "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
97
    "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf",
98
    "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
99
    "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df",
100
    "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7",
101
    "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef",
102
    "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
103
    "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"
104
    };
105
106 a59f38d6 Leszek Koltunski
  private static final String SERVER="https://distorted.org/magic/cgi-bin/";
107
108 a36b9dca Leszek Koltunski
  private static String[][][] mCountry;
109
  private static String[][][] mName;
110 65bc1da3 Leszek Koltunski
  private static int[][][] mTime;
111 a36b9dca Leszek Koltunski
  private static int[][] mPlaces;
112 688f7712 Leszek Koltunski
113 6a083c6a Leszek Koltunski
  private static RubikNetwork mThis;
114 688f7712 Leszek Koltunski
  private static String mScores = "";
115 b8b38548 Leszek Koltunski
  private static boolean mRunning = false;
116 1c04d054 leszek
  private static ArrayList<Updatee> mUpdateeList;
117 4895fff6 Leszek Koltunski
  private static String mVersion;
118 a7d8c3cd Leszek Koltunski
  private static int mNumObjects;
119 fcf7320f Leszek Koltunski
  private static RubikUpdates mUpdates;
120 1c04d054 leszek
  private static int mUpdatesState;
121 b8b38548 Leszek Koltunski
122 a36b9dca Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
123
124
  private static void initializeStatics()
125
    {
126 a7d8c3cd Leszek Koltunski
    int newNum = RubikObjectList.getNumObjects();
127
128 5bda8973 Leszek Koltunski
    if( mCountry==null || newNum!=mNumObjects ) mCountry = new String[newNum][LEVELS_SHOWN+1][MAX_PLACES];
129
    if( mName==null    || newNum!=mNumObjects ) mName    = new String[newNum][LEVELS_SHOWN+1][MAX_PLACES];
130 65bc1da3 Leszek Koltunski
    if( mTime==null    || newNum!=mNumObjects ) mTime    = new    int[newNum][LEVELS_SHOWN+1][MAX_PLACES];
131 5bda8973 Leszek Koltunski
    if( mPlaces==null  || newNum!=mNumObjects ) mPlaces  = new    int[newNum][LEVELS_SHOWN+1];
132 fcf7320f Leszek Koltunski
133
    if( mUpdates==null ) mUpdates = new RubikUpdates();
134 a7d8c3cd Leszek Koltunski
135
    mNumObjects = newNum;
136 a36b9dca Leszek Koltunski
    }
137
138 4895fff6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
139
140 86cbdab1 Leszek Koltunski
  private static String computeHash(String stringToHash, byte[] salt)
141 4895fff6 Leszek Koltunski
    {
142 86cbdab1 Leszek Koltunski
    String generatedPassword;
143
144
    try
145
      {
146
      MessageDigest md = MessageDigest.getInstance("MD5");
147
      md.update(salt);
148
      byte[] bytes = md.digest(stringToHash.getBytes());
149
      StringBuilder sb = new StringBuilder();
150
151
      for (byte aByte : bytes)
152
        {
153
        sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
154
        }
155
156
      generatedPassword = sb.toString();
157
      }
158
    catch (NoSuchAlgorithmException e)
159
      {
160
      return "NoSuchAlgorithm";
161
      }
162
163
    return generatedPassword;
164 4895fff6 Leszek Koltunski
    }
165
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167
168 46be3ddf Leszek Koltunski
  private boolean fillValuesNormal(ScoresReceiver receiver)
169 f3e12931 Leszek Koltunski
    {
170 d8aa4ba8 Leszek Koltunski
    int begin=-1 ,end, len = mScores.length();
171 17f9a695 Leszek Koltunski
    String row;
172 f3e12931 Leszek Koltunski
173 4c0cd600 Leszek Koltunski
    if( len==0 )
174
      {
175 46be3ddf Leszek Koltunski
      receiver.error("1");
176 4c0cd600 Leszek Koltunski
      return false;
177
      }
178 90fd47b0 Leszek Koltunski
    else if( len<=2 )
179 4c0cd600 Leszek Koltunski
      {
180 46be3ddf Leszek Koltunski
      receiver.error(mScores);
181 4c0cd600 Leszek Koltunski
      return false;
182
      }
183
184 a7d8c3cd Leszek Koltunski
    for(int i=0; i<mNumObjects; i++)
185 5bda8973 Leszek Koltunski
      for(int j=0; j<=LEVELS_SHOWN; j++)
186 329c0aeb Leszek Koltunski
        {
187
        mPlaces[i][j] = 0;
188
        }
189
190 d8aa4ba8 Leszek Koltunski
    while( begin<len )
191
      {
192
      end = mScores.indexOf('\n', begin+1);
193
      if( end<0 ) end = len;
194 286d73ae Leszek Koltunski
195
      try
196
        {
197 17f9a695 Leszek Koltunski
        row = mScores.substring(begin+1,end);
198 4c0cd600 Leszek Koltunski
        fillRow(row);
199 286d73ae Leszek Koltunski
        }
200
      catch(Exception ex)
201
        {
202
        // faulty row - ignore
203
        }
204
205 d8aa4ba8 Leszek Koltunski
      begin = end;
206
      }
207 17f9a695 Leszek Koltunski
208
    return true;
209 f3e12931 Leszek Koltunski
    }
210
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212
213 d8aa4ba8 Leszek Koltunski
  private void fillRow(String row)
214 f3e12931 Leszek Koltunski
    {
215 d8aa4ba8 Leszek Koltunski
    int s1 = row.indexOf(' ');
216
    int s2 = row.indexOf(' ',s1+1);
217
    int s3 = row.indexOf(' ',s2+1);
218
    int s4 = row.indexOf(' ',s3+1);
219 286d73ae Leszek Koltunski
    int s5 = row.length();
220 d8aa4ba8 Leszek Koltunski
221
    if( s5>s4 && s4>s3 && s3>s2 && s2>s1 && s1>0 )
222
      {
223 a7d8c3cd Leszek Koltunski
      int object = RubikObjectList.getOrdinal( row.substring(0,s1) );
224 b8b38548 Leszek Koltunski
225 a7d8c3cd Leszek Koltunski
      if( object>=0 && object<mNumObjects )
226 d8aa4ba8 Leszek Koltunski
        {
227 8e3898c8 Leszek Koltunski
        int level      = Integer.parseInt( row.substring(s1+1,s2) );
228 286d73ae Leszek Koltunski
        String name    = row.substring(s2+1, s3);
229
        int time       = Integer.parseInt( row.substring(s3+1,s4) );
230
        String country = row.substring(s4+1, s5);
231 d8aa4ba8 Leszek Koltunski
232 c8249cf6 Leszek Koltunski
        if( country.equals("do") ) country = "dm"; // see RubikScores.setCountry()
233
234 5bda8973 Leszek Koltunski
        if( level>LEVELS_SHOWN ) level = LEVELS_SHOWN;
235
236
        if(level>=0)
237 d8aa4ba8 Leszek Koltunski
          {
238 8e3898c8 Leszek Koltunski
          int p = mPlaces[object][level];
239
          mPlaces[object][level]++;
240 329c0aeb Leszek Koltunski
241 8e3898c8 Leszek Koltunski
          mCountry[object][level][p] = country;
242
          mName   [object][level][p] = name;
243 65bc1da3 Leszek Koltunski
          mTime   [object][level][p] = time;
244 d8aa4ba8 Leszek Koltunski
          }
245
        }
246
      }
247 874c37b1 Leszek Koltunski
    else
248
      {
249 5d50e7a7 Leszek Koltunski
      tryDoCommand(row);
250
      }
251
    }
252
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
255
  private void tryDoCommand(String row)
256
    {
257
    if( row.startsWith("comm") )
258
      {
259
      int colon = row.indexOf(':');
260
261
      if( colon>0 )
262 874c37b1 Leszek Koltunski
        {
263 5d50e7a7 Leszek Koltunski
        String commandNumber = row.substring(4,colon);
264
        int number;
265
266
        try
267
          {
268
          number = Integer.parseInt(commandNumber);
269
          }
270
        catch(NumberFormatException ex)
271
          {
272
          number=0;
273
          }
274 874c37b1 Leszek Koltunski
275 5d50e7a7 Leszek Koltunski
        if(number==1)
276 874c37b1 Leszek Koltunski
          {
277
          String country = row.substring(colon+1);
278
          RubikScores scores = RubikScores.getInstance();
279
          scores.setCountry(country);
280
          }
281
        }
282
      }
283 f3e12931 Leszek Koltunski
    }
284
285 36e2cbdd Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
286
287
  private String URLencode(String s)
288
    {
289
    StringBuilder sbuf = new StringBuilder();
290
    int len = s.length();
291
292
    for (int i = 0; i < len; i++)
293
      {
294
      int ch = s.charAt(i);
295
296
           if ('A' <= ch && ch <= 'Z') sbuf.append((char)ch);
297
      else if ('a' <= ch && ch <= 'z') sbuf.append((char)ch);
298
      else if ('0' <= ch && ch <= '9') sbuf.append((char)ch);
299
      else if (ch == ' '             ) sbuf.append('+');
300
      else if (ch == '-' || ch == '_'
301
            || ch == '.' || ch == '!'
302
            || ch == '~' || ch == '*'
303
            || ch == '\'' || ch == '('
304
            || ch == ')'             ) sbuf.append((char)ch);
305
      else if (ch <= 0x007f)           sbuf.append(hex[ch]);
306
      else if (ch <= 0x07FF)
307
        {
308
        sbuf.append(hex[0xc0 | (ch >> 6)]);
309
        sbuf.append(hex[0x80 | (ch & 0x3F)]);
310
        }
311
      else
312
        {
313
        sbuf.append(hex[0xe0 | (ch >> 12)]);
314
        sbuf.append(hex[0x80 | ((ch >> 6) & 0x3F)]);
315
        sbuf.append(hex[0x80 | (ch & 0x3F)]);
316
        }
317
      }
318
319
    return sbuf.toString();
320
    }
321
322 f3e12931 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
323
324 46be3ddf Leszek Koltunski
  private boolean network(String url, ScoresReceiver receiver)
325 f3e12931 Leszek Koltunski
    {
326 36e2cbdd Leszek Koltunski
    try
327
      {
328 4895fff6 Leszek Koltunski
      java.net.URL connectURL = new URL(url);
329 36e2cbdd Leszek Koltunski
      HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
330
331
      conn.setDoInput(true);
332
      conn.setDoOutput(true);
333
      conn.setUseCaches(false);
334
      conn.setRequestMethod("GET");
335
      conn.connect();
336
      conn.getOutputStream().flush();
337
338 1d643a0e Leszek Koltunski
      InputStream is = conn.getInputStream();
339
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
340
      StringBuilder total = new StringBuilder();
341
342
      for (String line; (line = r.readLine()) != null; )
343 36e2cbdd Leszek Koltunski
        {
344 1d643a0e Leszek Koltunski
        total.append(line).append('\n');
345 36e2cbdd Leszek Koltunski
        }
346 1d643a0e Leszek Koltunski
347
      mScores = total.toString();
348 46be3ddf Leszek Koltunski
      conn.disconnect();
349 36e2cbdd Leszek Koltunski
      }
350 cc5ec229 Leszek Koltunski
    catch( final UnknownHostException e )
351
      {
352 46be3ddf Leszek Koltunski
      receiver.message("No access to Internet");
353 cc5ec229 Leszek Koltunski
      return false;
354
      }
355
    catch( final SecurityException e )
356
      {
357 46be3ddf Leszek Koltunski
      receiver.message("Application not authorized to connect to the Internet");
358 cc5ec229 Leszek Koltunski
      return false;
359
      }
360
    catch( final Exception e )
361 36e2cbdd Leszek Koltunski
      {
362 46be3ddf Leszek Koltunski
      receiver.message(e.getMessage());
363 a675474f Leszek Koltunski
      return false;
364 36e2cbdd Leszek Koltunski
      }
365
366 329c0aeb Leszek Koltunski
    if( mScores.length()==0 )
367
      {
368 46be3ddf Leszek Koltunski
      receiver.message("Failed to download scores");
369 329c0aeb Leszek Koltunski
      return false;
370
      }
371
372 a675474f Leszek Koltunski
    return true;
373 b8b38548 Leszek Koltunski
    }
374 d8aa4ba8 Leszek Koltunski
375 1fa125c2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
376
377 46be3ddf Leszek Koltunski
  private String constructSuspiciousURL(String suspURL)
378 1fa125c2 Leszek Koltunski
    {
379
    RubikScores scores = RubikScores.getInstance();
380 a59f38d6 Leszek Koltunski
    int deviceID       = scores.getDeviceID();
381
    String suspicious  = URLencode(suspURL);
382 1fa125c2 Leszek Koltunski
383 a59f38d6 Leszek Koltunski
    return SERVER+"suspicious.cgi?i="+deviceID+"&d="+suspicious;
384
    }
385 1fa125c2 Leszek Koltunski
386 a59f38d6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
387
388
  private String constructTokenURL(String token)
389
    {
390
    RubikScores scores = RubikScores.getInstance();
391
    String name = URLencode(scores.getName());
392
    int deviceID= scores.getDeviceID();
393
    String country = scores.getCountry();
394
    String version = mVersion==null ? "null" : mVersion;
395
    String tkn = URLencode(token);
396
397
    return SERVER+"token.cgi?n="+name+"&i="+deviceID+"&e="+version+"&c="+country+"&t="+tkn;
398 1fa125c2 Leszek Koltunski
    }
399
400 6a083c6a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
401
402 1c04d054 leszek
  private String constructUpdatesURL()
403 6a083c6a Leszek Koltunski
    {
404 1c04d054 leszek
    RubikScores sco = RubikScores.getInstance();
405
    String name     = URLencode(sco.getName());
406
    int numRuns     = sco.getNumRuns();
407
    int numPlay     = sco.getNumPlays();
408
    String country  = sco.getCountry();
409 0effd5a9 leszek
    int objectAPI   = JsonWriter.VERSION_OBJECT_APP;
410
    int tutorialAPI = JsonWriter.VERSION_EXTRAS_APP;
411 6a083c6a Leszek Koltunski
412 1c04d054 leszek
    String url=SERVER+"updates.cgi";
413
    url += "?n="+name+"&r="+numRuns+"&p="+numPlay+"&c="+country+"&e="+mVersion+"d"+"&a="+objectAPI+"&b="+tutorialAPI;
414 6a083c6a Leszek Koltunski
415
    return url;
416
    }
417
418 17f9a695 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
419
420
  private String constructDownloadURL()
421
    {
422
    RubikScores scores = RubikScores.getInstance();
423
    String name = URLencode(scores.getName());
424
    int numRuns = scores.getNumRuns();
425
    int numPlay = scores.getNumPlays();
426 874c37b1 Leszek Koltunski
    String country = scores.getCountry();
427 17f9a695 Leszek Koltunski
428 a59f38d6 Leszek Koltunski
    return SERVER+"download.cgi?n="+name+"&r="+numRuns+"&p="+numPlay+"&c="+country+"&e="+mVersion;
429 17f9a695 Leszek Koltunski
    }
430
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432
433
  private String constructSubmitURL()
434
    {
435
    RubikScores scores = RubikScores.getInstance();
436
    String name = URLencode(scores.getName());
437 11d68e9c Leszek Koltunski
    String veri = scores.isVerified() ? "1" : "";
438 17f9a695 Leszek Koltunski
    int numRuns = scores.getNumRuns();
439
    int numPlay = scores.getNumPlays();
440
    int deviceID= scores.getDeviceID();
441 6570171b Leszek Koltunski
    String reclist = scores.getRecordList("&o=","&l=","&t=");
442 17f9a695 Leszek Koltunski
    String country = scores.getCountry();
443 86cbdab1 Leszek Koltunski
    long epoch = System.currentTimeMillis();
444 9fe350fe Leszek Koltunski
    String salt = "cuboid";
445 17f9a695 Leszek Koltunski
446 1a7efafd leszek
    String url1 = SERVER+"submit.cgi";
447 11d68e9c Leszek Koltunski
    String url2 = "n="+name+"&v="+veri+"&r="+numRuns+"&p="+numPlay+"&i="+deviceID+"&e="+mVersion;
448 1c04d054 leszek
    url2 += reclist+"&c="+country+"&f="+epoch;
449 9fe350fe Leszek Koltunski
    String hash = computeHash( url2, salt.getBytes() );
450 17f9a695 Leszek Koltunski
451 b3ee0e78 Leszek Koltunski
    return url1 + "?" + url2 + "&h=" + hash;
452 17f9a695 Leszek Koltunski
    }
453
454 d8aa4ba8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
455
456
  private boolean gottaDownload()
457 b8b38548 Leszek Koltunski
    {
458 d8aa4ba8 Leszek Koltunski
    return ((mScores.length()==0) && !mRunning);
459 f3e12931 Leszek Koltunski
    }
460 b8b38548 Leszek Koltunski
461 d8aa4ba8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
462
463 e4854e54 Leszek Koltunski
  private void figureOutVersion(Activity act)
464 d8aa4ba8 Leszek Koltunski
    {
465 e4854e54 Leszek Koltunski
    if( mVersion==null )
466 ffe7e55d Leszek Koltunski
      {
467 e4854e54 Leszek Koltunski
      try
468
        {
469
        PackageInfo pInfo = act.getPackageManager().getPackageInfo( act.getPackageName(), 0);
470
        mVersion = pInfo.versionName;
471
        }
472
      catch (PackageManager.NameNotFoundException e)
473
        {
474
        mVersion = "0.9.2";
475
        }
476 ffe7e55d Leszek Koltunski
      }
477
    }
478 a675474f Leszek Koltunski
479 ffe7e55d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
480 a36b9dca Leszek Koltunski
481 46be3ddf Leszek Koltunski
  private void downloadThread(ScoresReceiver receiver)
482 ffe7e55d Leszek Koltunski
    {
483 aa550481 Leszek Koltunski
    boolean receiveValues=true;
484
485 17f9a695 Leszek Koltunski
    try
486 d8aa4ba8 Leszek Koltunski
      {
487 ffe7e55d Leszek Koltunski
      if( gottaDownload() )
488 4895fff6 Leszek Koltunski
        {
489 17f9a695 Leszek Koltunski
        mRunning = true;
490 aa550481 Leszek Koltunski
        receiveValues = network(constructDownloadURL(),receiver);
491 4895fff6 Leszek Koltunski
492 ffe7e55d Leszek Koltunski
        if( mRunning )
493 17f9a695 Leszek Koltunski
          {
494 46be3ddf Leszek Koltunski
          receiveValues = fillValuesNormal(receiver);
495 ffe7e55d Leszek Koltunski
          mRunning = false;
496 17f9a695 Leszek Koltunski
          }
497 1fa125c2 Leszek Koltunski
        }
498 aa550481 Leszek Koltunski
      if( receiveValues ) receiver.receive(mCountry, mName, mTime);
499 d8aa4ba8 Leszek Koltunski
      }
500 17f9a695 Leszek Koltunski
    catch( Exception e )
501 d8aa4ba8 Leszek Koltunski
      {
502 46be3ddf Leszek Koltunski
      receiver.message("Exception downloading records: "+e.getMessage() );
503 4895fff6 Leszek Koltunski
      }
504 ffe7e55d Leszek Koltunski
    }
505
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507 286d73ae Leszek Koltunski
508 46be3ddf Leszek Koltunski
  private void submitThread(ScoresReceiver receiver)
509 ffe7e55d Leszek Koltunski
    {
510
    try
511
      {
512
      mRunning = true;
513
      RubikScores scores = RubikScores.getInstance();
514
515
      if( scores.thereAreUnsubmittedRecords() )
516
        {
517 46be3ddf Leszek Koltunski
        boolean receiveValues = network(constructSubmitURL(),receiver);
518 ffe7e55d Leszek Koltunski
519
        if( mRunning )
520
          {
521 46be3ddf Leszek Koltunski
          receiveValues = fillValuesNormal(receiver);
522 ffe7e55d Leszek Koltunski
          mRunning = false;
523
          }
524
525
        if( receiveValues )
526
          {
527
          RubikScores.getInstance().successfulSubmit();
528 46be3ddf Leszek Koltunski
          receiver.receive(mCountry, mName, mTime);
529 ffe7e55d Leszek Koltunski
          }
530
        }
531
      }
532
    catch( Exception e )
533 17f9a695 Leszek Koltunski
      {
534 46be3ddf Leszek Koltunski
      receiver.message("Exception submitting records: "+e.getMessage() );
535 17f9a695 Leszek Koltunski
      }
536 ffe7e55d Leszek Koltunski
    }
537 a675474f Leszek Koltunski
538 ffe7e55d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
539
540 1c04d054 leszek
  private void updatesThread()
541 ffe7e55d Leszek Koltunski
    {
542 1c04d054 leszek
    String url = constructUpdatesURL();
543 109a2b68 Leszek Koltunski
544 ffe7e55d Leszek Koltunski
    try
545 a675474f Leszek Koltunski
      {
546 ffe7e55d Leszek Koltunski
      java.net.URL connectURL = new URL(url);
547
      HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
548 17f9a695 Leszek Koltunski
549 ffe7e55d Leszek Koltunski
      conn.setDoInput(true);
550
      conn.setDoOutput(true);
551
      conn.setUseCaches(false);
552
      conn.setRequestMethod("GET");
553
      conn.connect();
554
      conn.getOutputStream().flush();
555
556
      InputStream is = conn.getInputStream();
557
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
558
      StringBuilder answer = new StringBuilder();
559
560 1c04d054 leszek
      for( String line; (line = r.readLine()) != null; )
561 17f9a695 Leszek Koltunski
        {
562 ffe7e55d Leszek Koltunski
        answer.append(line).append('\n');
563 17f9a695 Leszek Koltunski
        }
564 ffe7e55d Leszek Koltunski
565
      String updates = answer.toString();
566 46be3ddf Leszek Koltunski
      conn.disconnect();
567 ffe7e55d Leszek Koltunski
      mUpdates.parse(updates);
568
569 1c04d054 leszek
      if( mUpdateeList!=null )
570
        {
571
        int numUpdatees = mUpdateeList.size();
572
573
        for(int u=0; u<numUpdatees; u++)
574
          {
575
          Updatee upd = mUpdateeList.get(u);
576
          upd.receiveUpdate(mUpdates);
577
          }
578
        }
579
580
      mUpdatesState = UPDATES_SUCCESS;
581 ffe7e55d Leszek Koltunski
      }
582
    catch( final Exception e )
583
      {
584 1c04d054 leszek
      if( mUpdateeList!=null )
585
        {
586
        int numUpdatees = mUpdateeList.size();
587
588
        for(int u=0; u<numUpdatees; u++)
589
          {
590
          Updatee upd = mUpdateeList.get(u);
591
          upd.errorUpdate();
592
          }
593
        }
594
595
      mUpdatesState = UPDATES_FAILURE;
596 ffe7e55d Leszek Koltunski
      }
597
    }
598
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600
601 46be3ddf Leszek Koltunski
  private void suspiciousThread(String suspURL)
602 ffe7e55d Leszek Koltunski
    {
603 46be3ddf Leszek Koltunski
    String url = constructSuspiciousURL(suspURL);
604 ffe7e55d Leszek Koltunski
605
    try
606
      {
607
      java.net.URL connectURL = new URL(url);
608
      HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
609
610
      conn.setDoInput(true);
611
      conn.setDoOutput(true);
612
      conn.setUseCaches(false);
613
      conn.setRequestMethod("GET");
614
      conn.connect();
615
      conn.getOutputStream().flush();
616
      conn.getInputStream();
617 46be3ddf Leszek Koltunski
      conn.disconnect();
618 ffe7e55d Leszek Koltunski
      }
619
    catch( final Exception e )
620
      {
621
      // ignore
622 a675474f Leszek Koltunski
      }
623 d8aa4ba8 Leszek Koltunski
    }
624 4f9f99a2 Leszek Koltunski
625 a59f38d6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
626
627
  private void tokenThread(String token)
628
    {
629
    String url = constructTokenURL(token);
630
631
    try
632
      {
633
      java.net.URL connectURL = new URL(url);
634
      HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
635
636
      conn.setDoInput(true);
637
      conn.setDoOutput(true);
638
      conn.setUseCaches(false);
639
      conn.setRequestMethod("GET");
640
      conn.connect();
641
      conn.getOutputStream().flush();
642
      conn.getInputStream();
643
      conn.disconnect();
644
      }
645
    catch( final Exception e )
646
      {
647
      // ignore
648
      }
649
    }
650
651 b88cdd91 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
652
653
  private Bitmap downloadIcon(String url)
654
    {
655
    try
656
      {
657
      java.net.URL connectURL = new URL(url);
658
      HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
659
      conn.setDoInput(true);
660
      conn.connect();
661
      InputStream input = conn.getInputStream();
662 46be3ddf Leszek Koltunski
      Bitmap icon = BitmapFactory.decodeStream(input);
663
      conn.disconnect();
664
      return icon;
665 b88cdd91 Leszek Koltunski
      }
666
    catch (IOException e)
667
      {
668
      android.util.Log.e("D", "Failed to download "+url);
669
      android.util.Log.e("D", e.getMessage() );
670
      return null;
671
      }
672
    }
673
674
///////////////////////////////////////////////////////////////////////////////////////////////////
675
676 7fe62d1f Leszek Koltunski
  private void iconThread(Context context, IconReceiver receiver)
677 b88cdd91 Leszek Koltunski
    {
678
    int numC = mUpdates.getCompletedNumber();
679
    int numS = mUpdates.getStartedNumber();
680
681
    for(int c=0; c<numC; c++)
682
      {
683 b92ad5cd Leszek Koltunski
      int iconPresent = mUpdates.getCompletedIconPresent(c);
684 b88cdd91 Leszek Koltunski
685 b92ad5cd Leszek Koltunski
      if( iconPresent!=0 )
686 b88cdd91 Leszek Koltunski
        {
687 7fe62d1f Leszek Koltunski
        boolean downloaded = false;
688
        Bitmap icon = mUpdates.getCompletedIcon(context,c);
689 b92ad5cd Leszek Koltunski
690
        if( icon==null )
691
          {
692
          String url = mUpdates.getCompletedURL(c);
693
          icon = downloadIcon(url);
694 7fe62d1f Leszek Koltunski
          downloaded = true;
695 84d746d7 Leszek Koltunski
696 e847c553 Leszek Koltunski
          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Downloading icon "+url);
697 b92ad5cd Leszek Koltunski
          }
698
        if( icon!=null )
699
          {
700
          mUpdates.setCompletedIcon(c,icon);
701 7fe62d1f Leszek Koltunski
          receiver.iconDownloaded(c,icon,downloaded);
702 b92ad5cd Leszek Koltunski
          }
703 b88cdd91 Leszek Koltunski
        }
704
      }
705
706
    for(int s=0; s<numS; s++)
707
      {
708 b92ad5cd Leszek Koltunski
      int iconPresent = mUpdates.getStartedIconPresent(s);
709 b88cdd91 Leszek Koltunski
710 b92ad5cd Leszek Koltunski
      if( iconPresent!=0 )
711 b88cdd91 Leszek Koltunski
        {
712 7fe62d1f Leszek Koltunski
        boolean downloaded = false;
713
        Bitmap icon = mUpdates.getStartedIcon(context,s);
714 b92ad5cd Leszek Koltunski
715
        if( icon==null )
716
          {
717
          String url = mUpdates.getStartedURL(s);
718
          icon = downloadIcon(url);
719 7fe62d1f Leszek Koltunski
          downloaded = true;
720 84d746d7 Leszek Koltunski
721 e847c553 Leszek Koltunski
          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Downloading icon "+url);
722 b92ad5cd Leszek Koltunski
          }
723
        if( icon!=null )
724
          {
725
          mUpdates.setStartedIcon(s,icon);
726 7fe62d1f Leszek Koltunski
          receiver.iconDownloaded(numC+s,icon,downloaded);
727 b92ad5cd Leszek Koltunski
          }
728 b88cdd91 Leszek Koltunski
        }
729
      }
730
    }
731
732 46be3ddf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
733
734
  private InputStream downloadJSON(String name)
735
    {
736
    String url = mUpdates.getURL() + name;
737
738
    try
739
      {
740 e847c553 Leszek Koltunski
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Downloading JSON "+url);
741 84d746d7 Leszek Koltunski
742 46be3ddf Leszek Koltunski
      java.net.URL connectURL = new URL(url);
743
      HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
744
      conn.setDoInput(true);
745
      conn.connect();
746 806329e3 Leszek Koltunski
      return conn.getInputStream();
747 46be3ddf Leszek Koltunski
      }
748
    catch (IOException e)
749
      {
750
      android.util.Log.e("D", "Failed to download "+url);
751
      android.util.Log.e("D", e.getMessage() );
752
      return null;
753
      }
754
    }
755
756
///////////////////////////////////////////////////////////////////////////////////////////////////
757
758
  private void jsonThread(final RubikUpdates.UpdateInfo info, Downloadee downloadee)
759
    {
760
    if(info.mUpdateObject) info.mObjectStream = downloadJSON(info.mObjectShortName+"_object.json");
761
    if(info.mUpdateExtras) info.mExtrasStream = downloadJSON(info.mObjectShortName+"_extras.json");
762
763
    downloadee.jsonDownloaded();
764 806329e3 Leszek Koltunski
765
    try
766
      {
767
      if( info.mObjectStream!=null ) info.mObjectStream.close();
768
      }
769
    catch(IOException ioe)
770
      {
771
      android.util.Log.e("D", "failed to close object input stream");
772
      }
773
774
    try
775
      {
776
      if( info.mExtrasStream!=null ) info.mExtrasStream.close();
777
      }
778
    catch(IOException ioe)
779
      {
780
      android.util.Log.e("D", "failed to close extras input stream");
781
      }
782 46be3ddf Leszek Koltunski
    }
783
784 bc511ea5 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
785
786 6a083c6a Leszek Koltunski
  private RubikNetwork()
787 bc511ea5 Leszek Koltunski
    {
788
789
    }
790
791 4f9f99a2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
792
// PUBLIC API
793
///////////////////////////////////////////////////////////////////////////////////////////////////
794
795
  public static void onPause()
796
    {
797
    mRunning = false;
798 1c04d054 leszek
    mUpdateeList.clear();
799 4f9f99a2 Leszek Koltunski
    }
800
801 bc511ea5 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
802
803 6a083c6a Leszek Koltunski
  public static RubikNetwork getInstance()
804 bc511ea5 Leszek Koltunski
    {
805 35161021 Leszek Koltunski
    if( mThis==null ) mThis = new RubikNetwork();
806 bc511ea5 Leszek Koltunski
    return mThis;
807
    }
808
809 4f9f99a2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
810
811 e4854e54 Leszek Koltunski
  public void download(final ScoresReceiver receiver, final Activity act)
812 4f9f99a2 Leszek Koltunski
    {
813 ffe7e55d Leszek Koltunski
    initializeStatics();
814
    figureOutVersion(act);
815 1780dcb0 Leszek Koltunski
816 ffe7e55d Leszek Koltunski
    Thread thread = new Thread()
817 1780dcb0 Leszek Koltunski
      {
818 ffe7e55d Leszek Koltunski
      public void run()
819
        {
820 46be3ddf Leszek Koltunski
        downloadThread(receiver);
821 ffe7e55d Leszek Koltunski
        }
822
      };
823 6f8e5dfc Leszek Koltunski
824 ffe7e55d Leszek Koltunski
    thread.start();
825 4f9f99a2 Leszek Koltunski
    }
826 bc511ea5 Leszek Koltunski
827
///////////////////////////////////////////////////////////////////////////////////////////////////
828
829 e4854e54 Leszek Koltunski
  public void submit(ScoresReceiver receiver, final Activity act)
830 bc511ea5 Leszek Koltunski
    {
831 ffe7e55d Leszek Koltunski
    initializeStatics();
832
    figureOutVersion(act);
833 bc511ea5 Leszek Koltunski
834 ffe7e55d Leszek Koltunski
    Thread thread = new Thread()
835
      {
836
      public void run()
837
        {
838 46be3ddf Leszek Koltunski
        submitThread(receiver);
839 ffe7e55d Leszek Koltunski
        }
840
      };
841 1780dcb0 Leszek Koltunski
842 ffe7e55d Leszek Koltunski
    thread.start();
843 bc511ea5 Leszek Koltunski
    }
844 6a083c6a Leszek Koltunski
845
///////////////////////////////////////////////////////////////////////////////////////////////////
846
847 1c04d054 leszek
  public void downloadUpdates(final Activity act)
848 6a083c6a Leszek Koltunski
    {
849 ffe7e55d Leszek Koltunski
    initializeStatics();
850 e4854e54 Leszek Koltunski
    figureOutVersion(act);
851 1c04d054 leszek
    mUpdatesState = UPDATES_RUNNING;
852 ffe7e55d Leszek Koltunski
853
    Thread thread = new Thread()
854
      {
855
      public void run()
856
        {
857 1c04d054 leszek
        updatesThread();
858 ffe7e55d Leszek Koltunski
        }
859
      };
860
861
    thread.start();
862 6a083c6a Leszek Koltunski
    }
863 1fa125c2 Leszek Koltunski
864
///////////////////////////////////////////////////////////////////////////////////////////////////
865
866 e4854e54 Leszek Koltunski
  public void suspicious(final String suspicious, final Activity act)
867 1fa125c2 Leszek Koltunski
    {
868 ffe7e55d Leszek Koltunski
    initializeStatics();
869 e4854e54 Leszek Koltunski
    figureOutVersion(act);
870 ffe7e55d Leszek Koltunski
871
    Thread thread = new Thread()
872
      {
873
      public void run()
874
        {
875 46be3ddf Leszek Koltunski
        suspiciousThread(suspicious);
876 ffe7e55d Leszek Koltunski
        }
877
      };
878
879
    thread.start();
880 1fa125c2 Leszek Koltunski
    }
881 63dd19c4 Leszek Koltunski
882 a59f38d6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
883
884
  public void token(final String token)
885
    {
886
    initializeStatics();
887
888
    Thread thread = new Thread()
889
      {
890
      public void run()
891
        {
892
        tokenThread(token);
893
        }
894
      };
895
896
    thread.start();
897
    }
898
899 63dd19c4 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
900
901
  public void signUpForUpdates(Updatee updatee)
902
    {
903 1c04d054 leszek
    if( mUpdateeList==null ) mUpdateeList = new ArrayList<>();
904
905
    int numUpdatees = mUpdateeList.size();
906
    int type = updatee.getType();
907
908
    for(int u=0; u<numUpdatees; u++)
909
      {
910
      Updatee upd = mUpdateeList.get(u);
911
912
      if( upd.getType()==type )
913
        {
914
        mUpdateeList.remove(u);
915
        break;
916
        }
917
      }
918
919
    mUpdateeList.add(updatee);
920
921
    if( mUpdatesState==UPDATES_SUCCESS )
922
      {
923
      updatee.receiveUpdate(mUpdates);
924
      }
925
    else if( mUpdatesState==UPDATES_FAILURE )
926
      {
927
      updatee.errorUpdate();
928
      }
929 63dd19c4 Leszek Koltunski
    }
930 903c7bbc Leszek Koltunski
931 ffe7e55d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
932
933 7fe62d1f Leszek Koltunski
  public void downloadIcons(final Context context, final IconReceiver receiver)
934 46be3ddf Leszek Koltunski
    {
935
    initializeStatics();
936
937
    Thread thread = new Thread()
938
      {
939
      public void run()
940
        {
941 7fe62d1f Leszek Koltunski
        iconThread(context,receiver);
942 46be3ddf Leszek Koltunski
        }
943
      };
944
945
    thread.start();
946
    }
947
948
///////////////////////////////////////////////////////////////////////////////////////////////////
949
950
  public void downloadJSON(final RubikUpdates.UpdateInfo info, final Downloadee downloadee)
951 ffe7e55d Leszek Koltunski
    {
952 b88cdd91 Leszek Koltunski
    initializeStatics();
953
954
    Thread thread = new Thread()
955
      {
956
      public void run()
957
        {
958 46be3ddf Leszek Koltunski
        jsonThread(info,downloadee);
959 b88cdd91 Leszek Koltunski
        }
960
      };
961 ffe7e55d Leszek Koltunski
962 b88cdd91 Leszek Koltunski
    thread.start();
963 ffe7e55d Leszek Koltunski
    }
964
965 903c7bbc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
966
967
  public void updateDone(String shortName)
968
    {
969
    mUpdates.updateDone(shortName);
970 dcc8b2f9 Leszek Koltunski
    mScores = "";
971 1c04d054 leszek
972
    if( mUpdateeList!=null )
973
      {
974
      int numUpdatees = mUpdateeList.size();
975
976
      for(int u=0; u<numUpdatees; u++)
977
        {
978
        Updatee upd = mUpdateeList.get(u);
979
        upd.objectDownloaded(shortName);
980
        }
981
      }
982 903c7bbc Leszek Koltunski
    }
983 b8b38548 Leszek Koltunski
}