source: trunk/LogicMail/src/org/logicprobe/LogicMail/LogicMail.java @ 939

Revision 939, 17.9 KB checked in by octorian, 6 months ago (diff)

Added basic support for detecting device poweroff/poweron to connection handling (refs #329)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*-
2 * Copyright (c) 2009, Derek Konigsberg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its
15 *    contributors may be used to endorse or promote products derived
16 *    from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.logicprobe.LogicMail;
33
34import java.util.Calendar;
35
36import javax.microedition.io.file.FileSystemRegistry;
37
38import net.rim.blackberry.api.homescreen.HomeScreen;
39import net.rim.device.api.i18n.Locale;
40import net.rim.device.api.notification.NotificationsConstants;
41import net.rim.device.api.notification.NotificationsManager;
42import net.rim.device.api.synchronization.SyncManager;
43import net.rim.device.api.system.Application;
44import net.rim.device.api.system.ApplicationManager;
45import net.rim.device.api.system.Bitmap;
46import net.rim.device.api.system.ControlledAccessException;
47import net.rim.device.api.system.DeviceInfo;
48import net.rim.device.api.system.Display;
49import net.rim.device.api.system.EventLogger;
50import net.rim.device.api.system.SystemListener;
51import net.rim.device.api.ui.Field;
52import net.rim.device.api.ui.Font;
53import net.rim.device.api.ui.Screen;
54import net.rim.device.api.ui.UiApplication;
55import net.rim.device.api.ui.UiEngine;
56import net.rim.device.api.ui.component.BitmapField;
57import net.rim.device.api.ui.component.LabelField;
58import net.rim.device.api.ui.container.MainScreen;
59
60import org.logicprobe.LogicMail.model.MailManager;
61import org.logicprobe.LogicMail.ui.BlankSeparatorField;
62import org.logicprobe.LogicMail.ui.HomeScreenPopup;
63import org.logicprobe.LogicMail.ui.NavigationController;
64import org.logicprobe.LogicMail.ui.NotificationHandler;
65import org.logicprobe.LogicMail.ui.ThrobberField;
66import org.logicprobe.LogicMail.util.DataStoreFactory;
67import org.logicprobe.LogicMail.util.UtilFactory;
68import org.logicprobe.LogicMail.conf.AccountConfig;
69import org.logicprobe.LogicMail.conf.MailSettings;
70
71/*
72 * Logging levels:
73 *  EventLogger.ALWAYS_LOG   = 0
74 *  EventLogger.SEVERE_ERROR = 1
75 *  EventLogger.ERROR        = 2
76 *  EventLogger.WARNING      = 3
77 *  EventLogger.INFORMATION  = 4
78 *  EventLogger.DEBUG_INFO   = 5
79 */
80
81/**
82 * Main class for the application.
83 */
84public final class LogicMail extends UiApplication {
85    private boolean analyticsAppStartHappened = false;
86    private boolean autoStart;
87    private StartupSystemListener systemListener;
88    private NavigationController navigationController;
89    private Screen loadingScreen;
90    private volatile boolean foreground;
91
92    /**
93     * Instantiates a new instance of the application.
94     *
95     * @param args arguments passed to the application's <code>main()</code> method
96     */
97    public LogicMail(String[] args) {
98        for(int i=0; i<args.length; i++) {
99            if(args[i].indexOf("autostartup") != -1) {
100                autoStart = true;                       
101            }
102        }
103        AppInfo.initialize(args);
104    }
105
106    /**
107     * Run the application.
108     */
109    public void run() {
110        PermissionsHandler.registerReasonProvider();
111        if(autoStart) {
112            runAutoStartup();
113        }
114        else {
115            runNormalStartup();
116        }
117        enterEventDispatcher();
118    }
119   
120    public void activate() {
121        activateAnalytics();
122        super.activate();
123    }
124   
125    public void deactivate() {
126        deactivateAnalytics();
127        super.deactivate();
128    }
129   
130    protected boolean acceptsForeground() {
131        return foreground;
132    }
133
134    private void activateAnalytics() {
135        if(AppInfo.isAnalyticsEnabled()) {
136            if(analyticsAppStartHappened) {
137                AnalyticsDataCollector.getInstance().onApplicationForeground();
138            }
139            else {
140                AnalyticsDataCollector.getInstance().onApplicationStart();
141                analyticsAppStartHappened = true;
142            }
143        }
144    }
145
146    private void deactivateAnalytics() {
147        if(AppInfo.isAnalyticsEnabled() && analyticsAppStartHappened) {
148            AnalyticsDataCollector.getInstance().onApplicationBackground();
149        }
150    }
151   
152    private void runNormalStartup() {
153        logStartupAppInfo();
154        createLoadingScreen();
155        checkForVersionIncrease();
156       
157        if(AppInfo.isLicenceAccepted()) {
158            beginNormalStartup(true);
159        }
160        else {
161            showLicenseDialog();
162        }
163    }
164
165    private void runBackgroundStartup() {
166        logStartupAppInfo();
167        beginNormalStartup(false);
168    }
169   
170    private void checkForVersionIncrease() {
171        if(!AppInfo.getVersion().equals(AppInfo.getLastVersion())) {
172            AppInfo.setLicenseAccepted(false);
173        }
174    }
175
176    private void beginNormalStartup(boolean runInForeground) {
177        // First check to see if we have an already-running instance
178        if(runInForeground) {
179            tryRequestForground();
180        }
181       
182        foreground = true;
183        PermissionsHandler.checkStartupPermissions(false);
184        AnalyticsDataCollector.getInstance().setConfigured(AppInfo.isAnalyticsEnabled());
185        if(runInForeground) {
186            requestForeground();
187            pushScreen(loadingScreen);
188        }
189        startBackgroundLoadingProcess();
190    }
191
192    private void tryRequestForground() {
193        try {
194            UiApplication applicationInstance =
195                LogicMailRuntimeState.getInstance().getApplicationInstance();
196            if(applicationInstance != null) {
197                applicationInstance.requestForeground();
198                System.exit(0);
199            }
200        } catch (ControlledAccessException e) { }
201    }
202
203    private void showLicenseDialog() {
204        foreground = false;
205        invokeLater(new Runnable() {
206            public void run() {
207                HomeScreenPopup popupDialog = new HomeScreenPopup();
208                pushGlobalScreen(popupDialog, 1, UiEngine.GLOBAL_MODAL);
209
210                if(!popupDialog.isLicenseAccepted()) {
211                    PermissionsHandler.unregisterReasonProvider();
212                    LogicMailRuntimeState.getInstance().setApplicationInstance(null);
213                    System.exit(0);
214                }
215                else {
216                    AppInfo.updateLastVersion();
217                    AppInfo.setLicenseAccepted(true);
218                    AppInfo.setAnalyticsEnabled(popupDialog.isAnalyticsEnabled());
219                    PermissionsHandler.checkStartupPermissions(true);
220                    foreground = true;
221                    LogicMail.this.requestForeground();
222                    pushScreen(loadingScreen);
223                    startBackgroundLoadingProcess();
224                }
225            }
226        });
227    }
228
229    private void startBackgroundLoadingProcess() {
230        Thread loadingThread = new Thread() {
231            public void run() {
232                loadConfiguration();
233
234                setDefaultLocale();
235
236                // Initialize the data model explicitly
237                MailManager.initialize();
238
239                // Initialize the notification handler
240                NotificationHandler.getInstance().setEnabled(true);
241
242                // Initialize the navigation controller
243                navigationController = new NavigationController(LogicMail.this);
244
245                addSystemListeners();
246
247                // Explicitly trigger a refresh of the local data location, just in
248                // case the file system appeared before we registered the listeners.
249                MailSettings.getInstance().simulateGlobalDataChange();
250               
251                showMailHomeScreen();
252            };
253        };
254        loadingThread.start();
255    }
256
257    private void loadConfiguration() {
258        // Load the configuration
259        DataStoreFactory.getConnectionCacheStore().load();
260        MailSettings.getInstance().loadSettings();
261    }
262
263    private void setDefaultLocale() {
264        // Locale override is not used in release builds
265        if(!AppInfo.isRelease()) {
266            // Set the language, if configured
267            String languageCode =
268                MailSettings.getInstance().getGlobalConfig().getLanguageCode();
269            if(languageCode != null && languageCode.length() > 0) {
270                try {
271                    Locale.setDefault(Locale.get(languageCode));
272                } catch (Exception e) { }
273            }
274        }
275    }
276
277    private void addSystemListeners() {
278        // Add the filesystem listener
279        try {
280            FileSystemRegistry.addFileSystemListener(MailSettings.getInstance().getFileSystemListener());
281        } catch (ControlledAccessException e) {
282            // Don't fail if file permissions are denied
283        }
284       
285        // Add any sensor listeners
286        try {
287            UtilFactory.getInstance().addSensorListeners();
288        } catch (ControlledAccessException e) {
289            // Don't fail if permissions are denied
290        }
291       
292        // Add the system listener for handling power-related events
293        try {
294            addSystemListener(MailManager.getInstance().getSystemListener());
295        } catch (ControlledAccessException e) {
296            // Don't fail if permissions are denied
297        }
298    }
299
300    private void showMailHomeScreen() {
301        invokeLater(new Runnable() {
302            public void run() {
303                // Push the mail home screen and pop
304                // the loading screen
305                navigationController.displayMailHome();
306                if(loadingScreen != null) {
307                    popScreen(loadingScreen);
308                    loadingScreen = null;
309                }
310                MailManager.getInstance().startupComplete();
311            }
312        });
313    }
314   
315    private void logStartupAppInfo() {
316        // Log application startup information
317        if(EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) {
318            StringBuffer buf = new StringBuffer();
319            buf.append("Application startup\r\n");
320            buf.append("Date: ");
321            buf.append(Calendar.getInstance().getTime().toString());
322            buf.append("\r\n");
323            buf.append("Name: ");
324            buf.append(AppInfo.getName());
325            buf.append("\r\n");
326            buf.append("Version: ");
327            appendAppVersion(buf);
328            buf.append("\r\n");
329            buf.append("Platform: ");
330            buf.append(DeviceInfo.getDeviceName());
331            buf.append(' ');
332            buf.append(AppInfo.getPlatformVersion());
333            if(PlatformInfo.getInstance().hasTouchscreen()) {
334                buf.append(' ');
335                buf.append("(touch)");
336            }
337            buf.append("\r\n");
338            EventLogger.logEvent(AppInfo.GUID, buf.toString().getBytes(), EventLogger.INFORMATION);
339        }
340    }
341
342    private void createLoadingScreen() {
343        loadingScreen = new MainScreen();
344        int displayWidth = Display.getWidth();
345        int displayHeight = Display.getHeight();
346        int fieldSpacerSize = displayHeight / 24;
347        Bitmap splashLogo = Bitmap.getBitmapResource("splash-logo.png");
348        int throbberSize = displayWidth / 4;
349        int fontHeight = Font.getDefault().getHeight();
350        int spacerSize = (displayHeight / 2) - ((splashLogo.getHeight() + throbberSize + fontHeight) / 2) - fieldSpacerSize;
351        if(spacerSize < 0) { spacerSize = 0; }
352
353        loadingScreen.add(new BlankSeparatorField(spacerSize));
354        loadingScreen.add(new BitmapField(splashLogo, Field.FIELD_HCENTER));
355        loadingScreen.add(new BlankSeparatorField(fieldSpacerSize));
356        loadingScreen.add(new ThrobberField(throbberSize, Field.FIELD_HCENTER));
357        loadingScreen.add(new BlankSeparatorField(fieldSpacerSize));
358       
359        StringBuffer buf = new StringBuffer();
360        buf.append("Version ");
361        appendAppVersion(buf);
362        loadingScreen.add(new LabelField(buf.toString(), Field.FIELD_HCENTER));
363    }
364
365    private static void appendAppVersion(StringBuffer buf) {
366        buf.append(AppInfo.getVersion());
367        if(AppInfo.isRelease()) {
368            String moniker = AppInfo.getVersionMoniker();
369            if(moniker != null && moniker.length() > 0) {
370                buf.append(" (");
371                buf.append(moniker);
372                buf.append(')');
373            }
374        }
375        else {
376            buf.append(" (dev)");
377        }
378    }
379   
380    /**
381     * Complete the application shutdown process by unregistering any static
382     * listeners and exiting the application process.
383     */
384    public static void shutdownApplication() {
385        NotificationHandler.getInstance().shutdown();
386
387        try {
388            Application.getApplication().removeSystemListener(MailManager.getInstance().getSystemListener());
389        } catch (ControlledAccessException e) {
390            // Don't fail if permissions are denied
391        }
392       
393        try {
394            UtilFactory.getInstance().removeSensorListeners();
395        } catch (ControlledAccessException e) {
396            // Don't fail if permissions are denied
397        }
398       
399        try {
400            FileSystemRegistry.removeFileSystemListener(MailSettings.getInstance().getFileSystemListener());
401        } catch (ControlledAccessException e) {
402            // Don't fail if file permissions are denied
403        }
404       
405        PermissionsHandler.unregisterReasonProvider();
406        LogicMailRuntimeState.getInstance().setApplicationInstance(null);
407       
408        AnalyticsDataCollector.getInstance().onApplicationTerminate();
409       
410        System.exit(0);
411    }
412
413    private void runAutoStartup() {
414        if(ApplicationManager.getApplicationManager().inStartup()) {
415            systemListener = new StartupSystemListener();
416            this.addSystemListener(systemListener);
417        }
418        else {
419            invokeLater(new Runnable() {
420                public void run() {
421                    startupInitialization();
422                }
423            });
424        }
425    }
426   
427    private class StartupSystemListener implements SystemListener {
428        public void powerUp() {
429            removeSystemListener(systemListener);
430            startupInitialization();
431        }
432       
433        public void powerOff() { }
434        public void batteryGood() { }
435        public void batteryLow() { }
436        public void batteryStatusChange(int status) { }
437    }
438   
439    private void startupInitialization() {
440        // The BlackBerry has finished its startup process
441
442        MailSettings mailSettings = null;
443        boolean initialized = false;
444        try {
445            if(!LogicMailRuntimeState.removeInstance()) {
446                // Configure the rollover icons
447                HomeScreen.updateIcon(AppInfo.getIcon(), 0);
448                HomeScreen.setRolloverIcon(AppInfo.getRolloverIcon(), 0);
449               
450                try {
451                    HomeScreen.updateIcon(AppInfo.getIcon(), 1);
452                    HomeScreen.setRolloverIcon(AppInfo.getRolloverIcon(), 1);
453                } catch (IllegalArgumentException e) { }
454               
455                // Register for synchronization
456                SyncManager.getInstance().enableSynchronization(LogicMailSyncCollection.getInstance());
457            }
458
459            // Load application settings
460            mailSettings = MailSettings.getInstance();
461            mailSettings.loadSettings();
462           
463            LogicMailRuntimeState runtimeState = LogicMailRuntimeState.getInstance();
464           
465            configureNotificationSources(runtimeState, mailSettings);
466   
467            initialized = true;
468        } catch (ControlledAccessException e) {
469            // If permissions have not been granted, we may get here
470        }
471
472        checkForVersionIncrease();
473       
474        if(initialized
475                && AppInfo.isLicenceAccepted()
476                && mailSettings != null
477                && mailSettings.getGlobalConfig().isAutoStartupEnabled()) {
478            LogicMailRuntimeState.getInstance().setApplicationInstance(this);
479            runBackgroundStartup();
480        }
481        else {
482            // Exit the application.
483            PermissionsHandler.unregisterReasonProvider();
484            LogicMailRuntimeState.getInstance().setApplicationInstance(null);
485            System.exit(0);
486        }
487    }
488
489    private static void configureNotificationSources(LogicMailRuntimeState runtimeState, MailSettings mailSettings) {
490        // Configure a notification source for each account
491        int numAccounts = mailSettings.getNumAccounts();
492        for(int i=0; i<numAccounts; i++) {
493            AccountConfig accountConfig = mailSettings.getAccountConfig(i);
494            LogicMailEventSource eventSource =
495                new LogicMailEventSource(accountConfig.getAcctName(), accountConfig.getUniqueId());
496            NotificationsManager.registerSource(
497                    eventSource.getEventSourceId(),
498                    eventSource,
499                    NotificationsConstants.CASUAL);
500            runtimeState.putEventSource(eventSource);
501        }
502    }
503} 
Note: See TracBrowser for help on using the repository browser.