root / mobile / src / main / java / org / wannatrak / mobile / controller / Controller.java @ 37

View | Annotate | Download

1
/*
2
 * Copyright 2009 Andrey Khalzov, and individual contributors as indicated by the @author tag.
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,
11
 * software 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 limitations under the License.
14
 */
15
16
/**
17
 * Created by Andrey Khalzov
18
 * 16.08.2008 17:54:38
19
 */
20
package org.wannatrak.mobile.controller;
21
22
import org.wannatrak.mobile.*;
23
import org.wannatrak.mobile.controller.exception.LoginException;
24
import org.wannatrak.mobile.controller.exception.ServerException;
25
import org.wannatrak.mobile.controller.exception.BluetoothException;
26
import org.wannatrak.mobile.model.Position;
27
import org.wannatrak.mobile.model.Cell;
28
import org.wannatrak.mobile.view.*;
29
30
import javax.microedition.io.Connector;
31
import javax.microedition.io.HttpConnection;
32
import javax.microedition.io.ConnectionNotFoundException;
33
import javax.microedition.lcdui.*;
34
import javax.microedition.midlet.MIDlet;
35
import javax.microedition.rms.RecordStore;
36
import javax.microedition.rms.RecordStoreException;
37
import java.io.*;
38
import java.util.Vector;
39
40
public class Controller {
41
    public static final String INTERNAL_DEVICE_ADDRESS = "internal";
42
43
    public static final int MAX_SEND_PAUSE = 1439;
44
    public static final int MAX_SAVE_PAUSE = 86399;
45
    public static final int MAX_POINTS_IN_PATH = 100;
46
47
    private static final MessagesBundle messagesBundle
48
            = MessagesBundle.getMessageBundle("org.wannatrak.mobile.controller.Controller");
49
50
    private static final int LOGS_LENGTH = 200;
51
52
    final MIDlet midlet;
53
54
    private final RecordStore recordStore;
55
56
    private final Vector logs = new Vector(LOGS_LENGTH);
57
    private final Vector btLogs = new Vector(LOGS_LENGTH);
58
59
    private final Vector executors = new Vector();
60
    private final Thread daemonThread;
61
62
    boolean started = false;
63
    private long startedTs;
64
65
    boolean positionsUpdated = false;
66
    Parser parser;
67
    Position position;
68
    long devicePositionTimestamp;
69
70
    int savePause = 5;
71
    int sendPause = 1;
72
    int numOfPointsInPath = 50;
73
74
    String deviceId;
75
    String subjectName;
76
    String deviceKey;
77
78
    String login;
79
    String password;
80
81
    private Cell cell;
82
83
    private Vector path;
84
85
    private String deviceName;
86
    private String deviceAddress;
87
88
    private LoginForm loginForm;
89
    private CreateSubjectForm createSubjectForm;
90
    private UnlinkedSubjectsList unlinkedSubjectsList;
91
    private TrakForm trakForm;
92
    private PositionInfoForm positionInfoForm;
93
    private SettingsForm settingsForm;
94
    private Map map;
95
    private CellIDFacade cellIDFacade;
96
97
    public Controller(MIDlet midlet) {
98
        this.midlet = midlet;
99
100
        this.parser = new Parser(this);
101
        try {
102
            recordStore = RecordStore.openRecordStore("Gdebox", true);
103
            final int n = PropertyKey.getNumOfPropeties() - recordStore.getNumRecords();
104
            for (int i = 0; i < n; i++) {
105
                recordStore.addRecord(new byte[0], 0, 0);
106
            }
107
        } catch (RecordStoreException e) {
108
            throw new RuntimeException(e.getMessage());
109
        }
110
        deviceId = getProperty(PropertyKey.ID);
111
        deviceKey = getProperty(PropertyKey.KEY);
112
        subjectName = getProperty(PropertyKey.NAME);
113
        deviceName = getProperty(PropertyKey.DEVICE_NAME);
114
        deviceAddress = getProperty(PropertyKey.DEVICE_ADDRESS);
115
116
        login = getProperty(PropertyKey.LOGIN).trim();
117
        password = getProperty(PropertyKey.PASSWORD).trim();
118
119
        Integer sendPause = getIntProperty(PropertyKey.SEND_PAUSE);
120
        if (sendPause != null) {
121
            setSendPause(sendPause.intValue());
122
        }
123
124
        Integer savePause = getIntProperty(PropertyKey.SAVE_PAUSE);
125
        if (savePause != null) {
126
            setSavePause(savePause.intValue());
127
        }
128
129
        Integer numOfPointsInPathI = getIntProperty(PropertyKey.POINTS_IN_PATH);
130
        numOfPointsInPath = numOfPointsInPathI == null ? 100 : numOfPointsInPathI.intValue();
131
        path = new Vector(numOfPointsInPath);
132
133
        daemonThread = new Thread(new Runnable() {
134
            public void run() {
135
                while (true) {
136
137
                    if (!executors.isEmpty()) {
138
                        final Executor executor = (Executor) executors.firstElement();
139
                        executor.execute();
140
                        executors.removeElement(executor);
141
                    }
142
143
                    if (executors.isEmpty()) {
144
                        synchronized (Controller.this) {
145
                            try {
146
                                Controller.this.wait();
147
                            } catch (InterruptedException e) {
148
                            }
149
                        }
150
                    }
151
                }
152
            }
153
        });
154
    }
155
156
    public Position getPosition() {
157
        return position;
158
    }
159
160
    public String getDeviceName() {
161
        return deviceName;
162
    }
163
164
    public boolean hasDeviceId() {
165
        return deviceId != null && deviceId.length() != 0;
166
    }
167
168
    public boolean hasDeviceAddress() {
169
        return deviceAddress != null && deviceAddress.length() != 0;
170
    }
171
172
    public boolean isCellIDAvailable() {
173
        return getCellIDFacade().isCellIDAvailable();
174
    }
175
176
    public boolean isStarted() {
177
        return started;
178
    }
179
180
    public void stop() {
181
        started = false;
182
    }
183
184
    public void start() {
185
        started = true;
186
        startedTs = System.currentTimeMillis();
187
    }
188
189
    public void setLoginForm(LoginForm loginForm) {
190
        this.loginForm = loginForm;
191
    }
192
193
    public void setCreateSubjectForm(CreateSubjectForm createSubjectForm) {
194
        this.createSubjectForm = createSubjectForm;
195
    }
196
197
    public void setUnlinkedSubjectsList(UnlinkedSubjectsList unlinkedSubjectsList) {
198
        this.unlinkedSubjectsList = unlinkedSubjectsList;
199
    }
200
201
    public void setTrakForm(TrakForm trakForm) {
202
        this.trakForm = trakForm;
203
    }
204
205
    public void setPositionInfoForm(PositionInfoForm positionInfoForm) {
206
        this.positionInfoForm = positionInfoForm;
207
    }
208
209
    public void setMap(Map map) {
210
        this.map = map;
211
    }
212
213
    public void setSettingsForm(SettingsForm settingsForm) {
214
        this.settingsForm = settingsForm;
215
    }
216
217
    public boolean setCellIfNew(Cell cell) {
218
        if (cell == null) {
219
            return false;
220
        }
221
222
        if (this.cell == null) {
223
            this.cell = cell;
224
            return true;
225
        }
226
227
        if (!this.cell.equals(cell)) {
228
            this.cell = cell;
229
            return true;
230
        }
231
232
        return false;
233
    }
234
235
    public void logoutAndExit() {
236
        stop();
237
        showLoading(MessagesBundle.getGlobal("exit"));
238
239
        executeAsynch(new Executor() {
240
            public void execute() {
241
                logout();
242
                midlet.notifyDestroyed();
243
            }
244
245
            public void stop() {
246
            }
247
        });
248
    }
249
250
    public void exit() {
251
        stop();
252
        midlet.notifyDestroyed();
253
    }
254
255
    public int getSizeAvailable() {
256
        try {
257
            return recordStore.getNumRecords();
258
        } catch (RecordStoreException e) {
259
            throw new RuntimeException(e.getClass().getName());
260
        }
261
    }
262
263
    public Integer getIntProperty(PropertyKey propertyKey) {
264
        DataInputStream dataInputStream = null;
265
        try {
266
            final byte[] record = recordStore.getRecord(propertyKey.getNumber());
267
            if (record == null) {
268
                return null;
269
            }
270
            dataInputStream = new DataInputStream(new ByteArrayInputStream(record));
271
            return new Integer(dataInputStream.readInt());
272
        } catch (RecordStoreException e) {
273
            throw new RuntimeException(e.getClass().getName());
274
        } catch (IOException e) {
275
            throw new RuntimeException(e.getClass().getName());
276
        } finally {
277
            if (dataInputStream != null) {
278
                try {
279
                    dataInputStream.close();
280
                } catch (IOException e) {
281
                }
282
            }
283
        }
284
    }
285
286
    public void setIntProperty(PropertyKey propertyKey, int value) {
287
        DataOutputStream dataOutputStream = null;
288
        try {
289
            final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
290
            dataOutputStream = new DataOutputStream(byteArrayOutputStream);
291
            dataOutputStream.writeInt(value);
292
            recordStore.setRecord(
293
                    propertyKey.getNumber(),
294
                    byteArrayOutputStream.toByteArray(),
295
                    0,
296
                    byteArrayOutputStream.size()
297
            );
298
        } catch (RecordStoreException e) {
299
            throw new RuntimeException(e.getClass().getName());
300
        } catch (UnsupportedEncodingException e) {
301
            throw new RuntimeException(e.getClass().getName());
302
        } catch (IOException e) {
303
            throw new RuntimeException(e.getClass().getName());
304
        } finally {
305
            if (dataOutputStream != null) {
306
                try {
307
                    dataOutputStream.close();
308
                } catch (IOException e) {
309
                }
310
            }
311
        }
312
    }
313
314
    public String getProperty(PropertyKey propertyKey) {
315
        try {
316
            final byte[] record = recordStore.getRecord(propertyKey.getNumber());
317
            if (record == null) {
318
                return "";
319
            }
320
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(record);
321
            char[] buf = new char[recordStore.getRecordSize(propertyKey.getNumber())];
322
            new InputStreamReader(byteArrayInputStream, "utf-8").read(buf);
323
            return String.valueOf(buf);
324
        } catch (RecordStoreException e) {
325
            throw new RuntimeException(e.getClass().getName());
326
        } catch (UnsupportedEncodingException e) {
327
            throw new RuntimeException(e.getClass().getName());
328
        } catch (IOException e) {
329
            throw new RuntimeException(e.getClass().getName());
330
        }
331
    }
332
333
    public void setProperty(PropertyKey propertyKey, String value) {
334
        try {
335
            recordStore.setRecord(propertyKey.getNumber(), value.getBytes("utf-8"), 0, value.getBytes("utf-8").length);
336
        } catch (RecordStoreException e) {
337
            throw new RuntimeException(e.getClass().getName());
338
        } catch (UnsupportedEncodingException e) {
339
            throw new RuntimeException(e.getClass().getName());
340
        }
341
    }
342
343
344
    public Vector getGpsDevices() throws BluetoothException {
345
        try {
346
            return BluetoothHelper.getBluetoothDevices();
347
        } catch (Exception e) {
348
            btLog("getGpsDevices: " + e.getClass().getName());
349
            throw new BluetoothException(e.getMessage());
350
        }
351
    }
352
353
    public long getStartedTs() {
354
        return startedTs;
355
    }
356
357
    public boolean hasInternalGPS() {
358
        return System.getProperty("microedition.location.version") != null;
359
    }
360
361
    public void showConnectExternalDeviceForm() {
362
        Display.getDisplay(midlet).setCurrent(new ConnectExternalDeviceForm(this));
363
    }
364
365
    public void showExternalDevicesList() {
366
        Display.getDisplay(midlet).setCurrent(new GpsDevicesList(this));
367
    }
368
369
    public void selectDevice(String deviceName, String deviceAddress) {
370
        setDeviceName(deviceName);
371
        setDeviceAddress(deviceAddress);
372
373
        if (!hasDeviceId()) {
374
            showCreateSubjectForm();
375
        } else {
376
            showTrakForm();
377
        }
378
    }
379
380
    public void showErrorAlert(IOException e, CommandListener commandListener) {
381
        showErrorAlert(messagesBundle.get("serverError") + " " + e.getMessage(), commandListener);
382
    }
383
384
    public void showErrorAlert(IOException e) {
385
        showErrorAlert(messagesBundle.get("serverError") + " " + e.getMessage());
386
    }
387
388
    public void showErrorAlert(String msg) {
389
        showErrorAlert(msg, null);
390
    }
391
392
    public void showErrorAlert(String msg, CommandListener commandListener) {
393
        final Alert alert = new Alert(messagesBundle.get("error"), msg, null, AlertType.ERROR);
394
        if (commandListener != null) {
395
            alert.setCommandListener(commandListener);
396
        }
397
        showAlert(alert);
398
    }
399
400
    public void showCreateSubjectForm() {
401
        if (createSubjectForm != null) {
402
            createSubjectForm.reinit();
403
        }
404
        Display.getDisplay(midlet).setCurrent(createSubjectForm == null ? new CreateSubjectForm(this) : createSubjectForm);
405
    }
406
407
    public void showUnlinkedSubjectsList() {
408
        if (unlinkedSubjectsList != null) {
409
            unlinkedSubjectsList.reinit();
410
        }
411
        Display.getDisplay(midlet).setCurrent(
412
                unlinkedSubjectsList == null ? new UnlinkedSubjectsList(this) : unlinkedSubjectsList
413
        );
414
    }
415
416
    public void showTrakForm() {
417
        Display.getDisplay(midlet).setCurrent(trakForm == null ? new TrakForm(this) : trakForm);
418
        trakForm.show();
419
        if (hasDeviceId()) {
420
            setGPSReceiverFound(true);
421
        }
422
    }
423
424
    public void showLoginForm() {
425
        if (loginForm != null) {
426
            loginForm.reinit();
427
        }
428
        Display.getDisplay(midlet).setCurrent(loginForm == null ? new LoginForm(this) : loginForm);
429
    }
430
431
    public void showSettingsForm() {
432
        if (settingsForm != null) {
433
            settingsForm.init();
434
        }
435
        Display.getDisplay(midlet).setCurrent(settingsForm == null ? new SettingsForm(this) : settingsForm);
436
    }
437
438
    public void showAlert(Alert alert) {
439
        Display.getDisplay(midlet).setCurrent(alert);
440
    }
441
442
    public void showPositionInfoForm() {
443
        Display.getDisplay(midlet).setCurrent(positionInfoForm == null ? new PositionInfoForm(this) : positionInfoForm);
444
    }
445
446
    public void showLoading(String name, String stopName, Executor executor) {
447
        Display.getDisplay(midlet).setCurrent(new LoadingForm(name, stopName, executor));
448
    }
449
450
    public void showLoading(String name) {
451
        Display.getDisplay(midlet).setCurrent(new LoadingForm(name));
452
    }
453
454
    public void hide() {
455
        Display.getDisplay(midlet).setCurrent(null);
456
    }
457
458
    public void loadAndShowMap() {
459
        if (map != null) {
460
            map.updateMap();
461
        } else {
462
            new Map(this);
463
            map.updateMap();
464
        }
465
    }
466
467
    public void showMap() {
468
        Display.getDisplay(midlet).setCurrent(map);
469
    }
470
471
    public Display getDisplay() {
472
        return Display.getDisplay(midlet);
473
    }
474
475
    public void startTrak() {
476
        start();
477
478
        if (trakForm != null) {
479
            trakForm.updateStatus();
480
        }
481
482
        final Runnable locationReceiver = createLocationReceiver();
483
        if (locationReceiver != null) {
484
            new Thread(createLocationReceiver()).start();
485
            log("GPS Receiving started");
486
        }
487
488
        new Thread(new Runnable() {
489
            public void run() {
490
                try {
491
                    boolean positionNotUpdatedLogged = false;
492
                    while (started) {
493
                        try {
494
                            final Position[] positions;
495
                            if (positionsUpdated) {
496
                                log("positions updated");
497
                                positionNotUpdatedLogged = false;
498
                                synchronized (Controller.this) {
499
                                    log("positions mutex");
500
                                    positions = getPositions(false);
501
                                    log("got " + positions.length + " positions");
502
                                    sendPositions(positions);
503
                                    setPositions(new Position[0]);
504
                                    log("positions cleaned");
505
                                    positionsUpdated = false;
506
                                    log("positions mutex end");
507
                                }
508
                            } else {
509
                                if (isTimeToUpdate() && System.currentTimeMillis() - startedTs > 5000) {
510
                                    setGPSReceiverFound(false);
511
                                }
512
                                if (!positionNotUpdatedLogged) {
513
                                    log("positions not updated");
514
                                    positionNotUpdatedLogged = true;
515
                                }
516
                                sendPositions(new Position[0]);
517
                            }
518
                            saveLogs();
519
                            sendLogs();
520
                            initLog();
521
522
                            pauseSend();
523
                        }  catch (IOException e) {
524
                            log("trak: " + e.getClass().getName() + ": " + e.getMessage());
525
                            pause(1);
526
                        } catch (Exception e) {
527
                            log("trak: " + e.getClass().getName() + ": " + e.getMessage());
528
                            pause(1);
529
                        }
530
                    }
531
                    if (trakForm != null) {
532
                        trakForm.updateStatus();
533
                    }
534
                } catch (Exception e) {
535
                    log("trak stopped: " + e.getClass().getName());
536
                }
537
            }
538
        }).start();
539
        log("GPS Sending started");
540
    }
541
542
    public boolean isTimeToUpdate() {
543
        return System.currentTimeMillis() - devicePositionTimestamp >= (this.savePause * 1000);
544
    }
545
546
    public CellIDFacade getCellIDFacade() {
547
        if (cellIDFacade == null) {
548
            cellIDFacade = new CellIDFacade(this);
549
        }
550
        return cellIDFacade;
551
    }
552
553
    public Position getPositionByCellID() {
554
        return getCellIDFacade().getPosition();
555
    }
556
557
    public void attractAttention() {
558
        AlertType.ALARM.playSound(getDisplay());
559
        AlertType.ERROR.playSound(getDisplay());
560
        AlertType.CONFIRMATION.playSound(getDisplay());
561
        AlertType.INFO.playSound(getDisplay());
562
        AlertType.WARNING.playSound(getDisplay());
563
564
        vibrate(500);
565
        flashBackLight(5000);
566
    }
567
568
    public void vibrate(int millis) {
569
        Display.getDisplay(midlet).vibrate(millis);
570
    }
571
572
    public void flashBackLight(int millis) {
573
        Display.getDisplay(midlet).flashBacklight(millis);
574
    }
575
576
    public void setDeviceId(String deviceId) {
577
        this.deviceId = deviceId;
578
        setProperty(PropertyKey.ID, deviceId);
579
    }
580
581
    public String getDeviceId() {
582
        return deviceId;
583
    }
584
585
    public void setDeviceKey(String deviceKey) {
586
        this.deviceKey = deviceKey;
587
        setProperty(PropertyKey.KEY, deviceKey);
588
    }
589
590
    public String getDeviceKey() {
591
        return deviceKey;
592
    }
593
594
    public String getSubjectName() {
595
        return subjectName;
596
    }
597
598
    public void setSubjectName(String subjectName) {
599
        this.subjectName = subjectName;
600
        setProperty(PropertyKey.NAME, subjectName);
601
    }
602
603
    public void setDeviceName(String deviceName) {
604
        this.deviceName = deviceName;
605
        setProperty(PropertyKey.DEVICE_NAME, deviceName);
606
    }
607
608
    public void setDeviceAddress(String deviceAddress) {
609
        this.deviceAddress = deviceAddress;
610
        setProperty(PropertyKey.DEVICE_ADDRESS, deviceAddress);
611
    }
612
613
    public String getLogin() {
614
        return login;
615
    }
616
617
    public void setLogin(String login) {
618
        this.login = login;
619
        setProperty(PropertyKey.LOGIN, login);
620
    }
621
622
    public String getPassword() {
623
        return password;
624
    }
625
626
    public void setPassword(String password) {
627
        this.password = password;
628
        setProperty(PropertyKey.PASSWORD, password);
629
    }
630
631
    public void log(String message) {
632
        /*try {
633
            message = (position != null ? new Date(position.getTimestamp()).toString() : "null") + ": " + message + "\n";
634
            synchronized (logs) {
635
                if (logs.size() >= LOGS_LENGTH) {
636
                    logs.removeElementAt(0);
637
                }
638
                logs.addElement(message);
639
            }
640
        } catch (IllegalArgumentException e) {
641
        }*/
642
    }
643
644
    public void btLog(String message) {
645
        /*try {
646
            message = (position != null ? new Date(position.getTimestamp()).toString() : "null") + ": " + message + "\n";
647
            synchronized (btLogs) {
648
                if (btLogs.size() >= Controller.LOGS_LENGTH) {
649
                    btLogs.removeElementAt(0);
650
                }
651
                btLogs.addElement(message);
652
            }
653
        } catch (IllegalArgumentException e) {
654
        }*/
655
    }
656
657
    public void saveLogs() {
658
        /*final StringBuffer logs = new StringBuffer();
659
        synchronized (this.logs) {
660
            for (int i = 0; i < this.logs.size(); i++) {
661
                logs.append(this.logs.elementAt(i));
662
            }
663
        }
664
665
        final StringBuffer btLogs = new StringBuffer();
666
        synchronized (this.btLogs) {
667
            for (int i = 0; i < this.btLogs.size(); i++) {
668
                btLogs.append(this.btLogs.elementAt(i));
669
            }
670
        }
671
        setProperty(PropertyKey.LOG, logs.toString());
672
        setProperty(PropertyKey.BT_LOG, btLogs.toString());*/
673
    }
674
675
    public void sendLogs() {
676
        final String logs = getProperty(PropertyKey.LOG);
677
        final String btLogs = getProperty(PropertyKey.BT_LOG);
678
679
        if (logs != null && btLogs != null) {
680
            try {
681
                sendLog(logs + "\nBT:\n" + btLogs);
682
            } catch (IOException e) {
683
                throw new RuntimeException(e.getClass().getName());
684
            }
685
        } else {
686
            initLog();
687
        }
688
    }
689
690
    public void initLog() {
691
        setProperty(PropertyKey.LOG, "");
692
        setProperty(PropertyKey.BT_LOG, "");
693
    }
694
695
    public void sendLog(String msg) throws IOException {
696
        HttpConnection conn = null;
697
        InputStream dis = null;
698
        DataOutputStream dos = null;
699
        try {
700
            conn = (HttpConnection) Connector.open(WannatrakMidlet.URL + "debug/" + deviceId);
701
            conn.setRequestMethod("POST");
702
            conn.setRequestProperty("Content-Type", "text/plain");
703
            dos = conn.openDataOutputStream();
704
            dos.writeUTF(msg);
705
            conn.getResponseCode();
706
        } catch (IOException e) {
707
            e.printStackTrace();
708
        } finally {
709
            if (dos!=null) {
710
                try {
711
                    dos.close();
712
                } catch (IOException e) {
713
                }
714
            }
715
            if(dis!=null) {
716
                try {
717
                    dis.close();
718
                } catch (IOException e) {
719
                }
720
            }
721
            if (conn!=null) {
722
                try {
723
                    conn.close();
724
                } catch (IOException e) {
725
                }
726
            }
727
        }
728
    }
729
730
    public void putGPSPosition(Position position) {
731
        if (isSavingPosition(position)) {
732
            btLog("saving position");
733
734
            putPosition(position);
735
736
            final Cell cell = getCellIDFacade().getCell();
737
            if (setCellIfNew(cell)) {
738
                getCellIDFacade().postCellPosition(cell, position);
739
            }
740
        } else {
741
            btLog("position is not saving: " + (position.getTimestamp() - this.position.getTimestamp()));
742
            putCellPositionIfTimeToUpdate();
743
        }
744
    }
745
746
    public void putCellPositionIfTimeToUpdate() {
747
        if (isTimeToUpdate()) {
748
            final Position cellPosition = getPositionByCellID();
749
            if (cellPosition != null) {
750
                putPosition(cellPosition);
751
            }
752
        }
753
    }
754
755
    public void putPosition(Position position) {
756
        _putPosition(position);
757
        addToPath(position);
758
        devicePositionTimestamp = System.currentTimeMillis();
759
    }
760
761
    public void logout() {
762
        if (deviceKey == null) {
763
            return;
764
        }
765
        HttpConnection conn = null;
766
        try {
767
            conn = (HttpConnection) Connector.open(WannatrakMidlet.URL + "logout?deviceId=" + deviceKey);
768
            conn.setRequestMethod("GET");
769
            conn.setRequestProperty("Content-Type", "text/plain");
770
771
            conn.openInputStream().close();
772
            setDeviceKey("");
773
            setDeviceId("");
774
        } catch (IOException e) {
775
            e.printStackTrace();
776
        } finally {
777
            try {
778
                if (conn!=null) {
779
                    conn.close();
780
                }
781
            } catch (IOException e) {
782
                e.printStackTrace();
783
            }
784
        }
785
    }
786
787
    public String login(String login, String password) throws LoginException, IOException, ServerException {
788
        HttpConnection conn = null;
789
        DataOutputStream dos = null;
790
        InputStream dis = null;
791
        try {
792
            conn = (HttpConnection) Connector.open(WannatrakMidlet.URL + "login");
793
            conn.setRequestMethod("POST");
794
            conn.setRequestProperty("Content-Type", "text/plain");
795
796
            dos = conn.openDataOutputStream();
797
            dos.writeUTF(login);
798
            dos.writeUTF(password);
799
800
            final int responseCode = conn.getResponseCode();
801
            if (responseCode == HttpConnection.HTTP_FORBIDDEN) {
802
                throw new LoginException();
803
            } else if (responseCode != HttpConnection.HTTP_OK) {
804
                throw new ServerException(responseCode);
805
            }
806
807
            dis = conn.openInputStream();
808
            StringBuffer b = new StringBuffer();
809
            int ch;
810
            while ( ( ch = dis.read() ) != -1 ) {
811
                b = b.append( ( char ) ch );
812
            }
813
            return b.toString();
814
        } finally {
815
            try {
816
                if(dos != null) {
817
                    dos.close();
818
                }
819
                if(dis != null) {
820
                    dis.close();
821
                }
822
                if (conn != null) {
823
                    conn.close();
824
                }
825
            } catch (IOException e) {
826
                e.printStackTrace();
827
            }
828
        }
829
    }
830
831
    public String unlink() throws IOException, LoginException, ServerException {
832
        HttpConnection conn = null;
833
        InputStream dis = null;
834
        DataOutputStream dos = null;
835
        try {
836
            conn = (HttpConnection) Connector.open(
837
                    WannatrakMidlet.URL
838
                            + "subjects/unlink?deviceId="
839
                            + deviceKey
840
            );
841
            conn.setRequestMethod("POST");
842
            conn.setRequestProperty("Content-Type", "text/plain");
843
844
            dos = conn.openDataOutputStream();
845
            dos.writeUTF(login);
846
            dos.writeUTF(password);
847
848
            final int responseCode = conn.getResponseCode();
849
            if (responseCode == HttpConnection.HTTP_FORBIDDEN) {
850
                throw new LoginException();
851
            } else if (responseCode != HttpConnection.HTTP_OK) {
852
                throw new ServerException(responseCode);
853
            }
854
855
            dis = conn.openInputStream();
856
            StringBuffer b = new StringBuffer();
857
            int ch;
858
            while ( ( ch = dis.read() ) != -1 ) {
859
                b = b.append( ( char ) ch );
860
            }
861
            return b.toString();
862
        } finally {
863
            try {
864
                if(dos != null) {
865
                    dos.close();
866
                }
867
                if(dis != null) {
868
                    dis.close();
869
                }
870
                if (conn != null) {
871
                    conn.close();
872
                }
873
            } catch (IOException e) {
874
                e.printStackTrace();
875
            }
876
        }
877
    }
878
879
    public int getSendPause() {
880
        return sendPause;
881
    }
882
883
    public void setSendPause(int sendPause) {
884
        if (sendPause > 0 && sendPause <= MAX_SEND_PAUSE) {
885
            this.sendPause = sendPause;
886
        }
887
    }
888
889
    public int getSavePause() {
890
        return savePause;
891
    }
892
893
    public void setSavePause(int savePause) {
894
        if (savePause > 0 && savePause <= MAX_SAVE_PAUSE) {
895
            this.savePause = savePause;
896
        }
897
    }
898
899
    public void setGPSReceiverFound(boolean gpsReceiverFound) {
900
        if (trakForm != null) {
901
            trakForm.setLocationProviderDefined(gpsReceiverFound);
902
        }
903
    }
904
905
    public void setNumOfPointsInPath(int numOfPointsInPath) {
906
        final Vector newPath = new Vector(numOfPointsInPath);
907
        int i = path.size() - numOfPointsInPath;
908
        if (i < 0) {
909
            i = 0;
910
        }
911
        for (; i < path.size(); i++) {
912
            newPath.addElement(path.elementAt(i));
913
        }
914
        path = newPath;
915
916
        this.numOfPointsInPath = numOfPointsInPath;
917
        setIntProperty(PropertyKey.POINTS_IN_PATH, numOfPointsInPath);
918
    }
919
920
    public int getNumOfPointsInPath() {
921
        return numOfPointsInPath;
922
    }
923
924
    public void checkNewVersion() {
925
        String currentVersion = getCurrentVersion();
926
927
        if (currentVersion != null && currentVersion.trim().length() > 0
928
                && !currentVersion.equals(midlet.getAppProperty("MIDlet-Version"))
929
        ) {
930
            final Alert alert = new Alert(
931
                    messagesBundle.get("update"),
932
                    messagesBundle.get("newVersion") + " " + currentVersion + " " + messagesBundle.get("sureToUpdate"),
933
                    null,
934
                    AlertType.CONFIRMATION
935
            );
936
            alert.addCommand(new Command(messagesBundle.get("ok"), Command.OK, 1));
937
            alert.addCommand(new Command(messagesBundle.get("no"), Command.CANCEL, 2));
938
            alert.setCommandListener(new CommandListener() {
939
                public void commandAction(Command command, Displayable displayable) {
940
                    if (command.getCommandType() == Command.OK) {
941
                        downloadNewVersion();
942
                        exit();
943
                    } else {
944
                        showLoading(
945
                                MessagesBundle.getGlobal("loading"),
946
                                MessagesBundle.getGlobal("exit"),
947
                                new Executor() {
948
                                    public void execute() {
949
                                    }
950
951
                                    public void stop() {
952
                                        exit();
953
                                    }
954
                                }
955
                        );
956
                        synchronized (midlet) {
957
                            midlet.notify();
958
                        }
959
                    }
960
                }
961
            });
962
            showAlert(alert);
963
            try {
964
                synchronized (midlet) {
965
                    midlet.wait();
966
                }
967
            } catch (InterruptedException e) {
968
                throw new RuntimeException(e.getMessage());
969
            }
970
        }
971
    }
972
973
    public Position[] getPositions() {
974
        return getPositions(false);
975
    }
976
977
    public Vector getPath() {
978
        return path;
979
    }
980
981
    public synchronized void executeAsynch(Executor executor) {
982
        executors.addElement(executor);
983
984
        if (!daemonThread.isAlive()) {
985
            daemonThread.start();
986
        } else {
987
            notify();
988
        }
989
    }
990
991
    public void executeAsynchInSingleThread(final Executor executor) {
992
        new Thread(new Runnable() {
993
            public void run() {
994
                executor.execute();
995
            }
996
        }).start();
997
    }
998
999
    public void showLog(String log) {
1000
            if (trakForm != null) {
1001
                    trakForm.showLog(log);
1002
            }
1003
    }
1004
1005
    Position[] getPositions(boolean withEmpty) {
1006
        final Integer number = getIntProperty(PropertyKey.POSITIONS_NUM);
1007
        if (number == null) {
1008
            return new Position[withEmpty ? 1 : 0];
1009
        }
1010
        return getPositions(getIntProperty(PropertyKey.POSITIONS_NUM).intValue(), withEmpty);
1011
    }
1012
1013
    void setPositions(Position[]  positions) {
1014
        DataOutputStream dataOutputStream = null;
1015
        try {
1016
            int number = positions.length;
1017
            int sizeShortage = Position.SIZE * positions.length - recordStore.getSizeAvailable();
1018
            if (sizeShortage > 0) {
1019
                number -= sizeShortage / Position.SIZE + 1;
1020
            }
1021
            final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
1022
            dataOutputStream = new DataOutputStream(byteArrayOutputStream);
1023
            for (int i = positions.length - number; i < positions.length; i++) {
1024
                positions[i].serialize(dataOutputStream);
1025
            }
1026
            recordStore.setRecord(
1027
                    PropertyKey.POSITIONS.getNumber(),
1028
                    byteArrayOutputStream.toByteArray(),
1029
                    0,
1030
                    byteArrayOutputStream.size()
1031
            );
1032
            setIntProperty(PropertyKey.POSITIONS_NUM, number);
1033
        } catch (RecordStoreException e) {
1034
            throw new RuntimeException(e.getClass().getName());
1035
        } catch (UnsupportedEncodingException e) {
1036
            throw new RuntimeException(e.getClass().getName());
1037
        } catch (IOException e) {
1038
            throw new RuntimeException(e.getClass().getName());
1039
        } finally {
1040
            if (dataOutputStream != null) {
1041
                try {
1042
                    dataOutputStream.close();
1043
                } catch (IOException e) {
1044
                }
1045
            }
1046
        }
1047
    }
1048
1049
    private synchronized void addToPath(Position position) {
1050
        try {
1051
            if (path.size() >= numOfPointsInPath) {
1052
                path.removeElementAt(0);
1053
            }
1054
            path.addElement(position);
1055
        } catch (IllegalArgumentException e) {
1056
        }
1057
    }
1058
1059
    private String getCurrentVersion() {
1060
        String currentVersion = "";
1061
1062
        HttpConnection conn = null;
1063
        InputStream inputStream = null;
1064
1065
        try {
1066
            conn = (HttpConnection) Connector.open(MessagesBundle.getGlobal("versionUrl"));
1067
            conn.setRequestMethod("GET");
1068
            conn.setRequestProperty("Content-Type", "text/plain");
1069
1070
            final int responseCode = conn.getResponseCode();
1071
            if (responseCode == HttpConnection.HTTP_OK) {
1072
                inputStream = conn.openInputStream();
1073
1074
                StringBuffer version = new StringBuffer();
1075
                int ch;
1076
                while ( ( ch = inputStream.read() ) != -1 ) {
1077
                    version = version.append( ( char ) ch );
1078
                }
1079
                currentVersion = version.toString();
1080
            }
1081
        } catch (IOException e) {
1082
            showErrorAlert(e);
1083
        } finally {
1084
            if(inputStream != null) {
1085
                try {
1086
                    inputStream.close();
1087
                } catch (IOException e) {
1088
                }
1089
            }
1090
            try {
1091
                if (conn!=null) {
1092
                    conn.close();
1093
                }
1094
            } catch (IOException e) {
1095
                e.printStackTrace();
1096
            }
1097
        }
1098
        return currentVersion;
1099
    }
1100
1101
    private void downloadNewVersion() {
1102
        try {
1103
            midlet.platformRequest(MessagesBundle.getGlobal("updateUrl"));
1104
        } catch (ConnectionNotFoundException e) {
1105
            showErrorAlert(e);
1106
        }
1107
    }
1108
1109
    private synchronized void _putPosition(Position position) {
1110
        final Position[] positions = getPositions(true);
1111
        positions[positions.length - 1] = position;
1112
        setPositions(positions);
1113
        positionsUpdated = true;
1114
        this.position = position;
1115
        if (positionInfoForm != null) {
1116
            positionInfoForm.setNewPosition(position);
1117
        }
1118
        btLog("position " + positions.length + " added");
1119
    }
1120
1121
    private boolean isSavingPosition(Position position) {
1122
        return this.position == null
1123
                || position.getTimestamp() == 0
1124
                || (position.getTimestamp() - this.position.getTimestamp()) >= (this.savePause * 1000);
1125
    }
1126
1127
    private boolean isDeviceInternal() {
1128
            return INTERNAL_DEVICE_ADDRESS.equals(deviceAddress);
1129
    }
1130
1131
    private Runnable createLocationReceiver() {
1132
        if (deviceAddress == null) {
1133
            return  getCellIDFacade().isCellIDAvailable() ? new CellIDLocationReceiver(this) : null;
1134
        } else if (isDeviceInternal()) {
1135
            return new InternalLocationReceiver(this);
1136
        } else {
1137
            return new BluetoothGPSReceiver(this, deviceAddress);
1138
        }
1139
    }
1140
1141
    private void sendPositions(final Position[] positions) throws IOException {
1142
        HttpConnection conn = null;
1143
        DataInputStream dis = null;
1144
        DataOutputStream dos = null;
1145
        try {
1146
            conn = (HttpConnection) Connector.open(WannatrakMidlet.URL + "post/" + deviceId);
1147
            log("http con opened");
1148
            conn.setRequestMethod("POST");
1149
            conn.setRequestProperty("Content-Type", "text/plain");
1150
            dos = conn.openDataOutputStream();
1151
            log("http dos opened");
1152
            dos.writeInt(positions.length);
1153
            for (int i = 0; i < positions.length; i++) {
1154
                positions[i].serialize(dos);
1155
            }
1156
1157
            if (conn.getResponseCode() == HttpConnection.HTTP_BAD_REQUEST) {
1158
                relogin();
1159
                return;
1160
            }
1161
1162
            dis = conn.openDataInputStream();
1163
1164
            log("http dis opened");
1165
            final int sendPause = dis.readInt();
1166
            setSendPause(sendPause);
1167
1168
            final int savePause = dis.readInt();
1169
            setSavePause(savePause);
1170
            log("http dis read");
1171
1172
            final String subjectName = dis.readUTF();
1173
            setSubjectName(subjectName);
1174
            if (trakForm != null) {
1175
                trakForm.setName(subjectName);
1176
                trakForm.setServerFound(true);
1177
            }
1178
1179
            log(sendPause + " :sendPause: " + this.sendPause);
1180
            log(savePause + " :savePause: " + this.savePause);
1181
        } catch (IOException e) {
1182
            log(e.getClass().getName());
1183
            if (trakForm != null) {
1184
                trakForm.setServerFound(false);
1185
            }
1186
        } finally {
1187
            if (dos != null) {
1188
                try {
1189
                    dos.close();
1190
                    log("http dos closed");
1191
                } catch (IOException e) {
1192
                }
1193
            }
1194
            if(dis != null) {
1195
                try {
1196
                    dis.close();
1197
                    log("http dis closed");
1198
                } catch (IOException e) {
1199
                }
1200
            }
1201
            if (conn != null) {
1202
                try {
1203
                    conn.close();
1204
                    log("conn closed");
1205
                } catch (IOException e) {
1206
                }
1207
            }
1208
        }
1209
    }
1210
1211
    private void relogin() {
1212
        stop();
1213
        try {
1214
            final String deviceKey = login(login, password);
1215
            setDeviceKey(deviceKey);
1216
            setDeviceId(deviceId);
1217
            showCreateSubjectForm();
1218
        } catch (Exception e) {
1219
            showLoginForm();
1220
        }
1221
    }
1222
1223
    private Position[] getPositions(int number, boolean withEmpty) {
1224
        DataInputStream dataInputStream = null;
1225
        try {
1226
            final byte[] record;
1227
1228
            record = recordStore.getRecord(PropertyKey.POSITIONS.getNumber());
1229
            if (record == null) {
1230
                return new Position[withEmpty ? 1 : 0];
1231
            }
1232
            final Position[] positions = new Position[number + (withEmpty ? 1 : 0)];
1233
            dataInputStream = new DataInputStream(new ByteArrayInputStream(record));
1234
            for (int i = 0; i < number; i++) {
1235
                final Position position = new Position(dataInputStream);
1236
                positions[i] = position;
1237
            }
1238
            return positions;
1239
        } catch (RecordStoreException e) {
1240
            throw new RuntimeException(e.getClass().getName());
1241
        } catch (IOException e) {
1242
            throw new RuntimeException(e.getClass().getName());
1243
        } finally {
1244
            if (dataInputStream != null) {
1245
                try {
1246
                    dataInputStream.close();
1247
                } catch (IOException e) {
1248
                }
1249
            }
1250
        }
1251
    }
1252
1253
    private void pauseSend() {
1254
        pause(sendPause * 60);
1255
    }
1256
1257
    private void pause(int secs) {
1258
        try {
1259
            Thread.sleep(secs * 1000);
1260
        } catch (InterruptedException e) {
1261
            throw new RuntimeException(e.getClass().getName());
1262
        }
1263
    }
1264
}