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

Revision 977, 18.0 KB checked in by octorian, 2 months ago (diff)

Force use of the stub analytics collector if the real collector is disabled by the user, because simply disabling collection wasn't always causing it to be inactive. (fixes #383)

  • 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                    AnalyticsDataCollector.updateAnalyticsState();
221                    foreground = true;
222                    LogicMail.this.requestForeground();
223                    pushScreen(loadingScreen);
224                    startBackgroundLoadingProcess();
225                }
226            }
227        });
228    }
229
230    private void startBackgroundLoadingProcess() {
231        Thread loadingThread = new Thread() {
232            public void run() {
233                loadConfiguration();
234
235                setDefaultLocale();
236
237                // Initialize the data model explicitly
238                MailManager.initialize();
239
240                // Initialize the notification handler
241                NotificationHandler.getInstance().setEnabled(true);
242
243                // Initialize the navigation controller
244                navigationController = new NavigationController(LogicMail.this);
245
246                addSystemListeners();
247
248                // Explicitly trigger a refresh of the local data location, just in
249                // case the file system appeared before we registered the listeners.
250                MailSettings.getInstance().simulateGlobalDataChange();
251               
252                showMailHomeScreen();
253            };
254        };
255        loadingThread.start();
256    }
257
258    private void loadConfiguration() {
259        // Load the configuration
260        DataStoreFactory.getConnectionCacheStore().load();
261        MailSettings.getInstance().loadSettings();
262    }
263
264    private void setDefaultLocale() {
265        // Locale override is not used in release builds
266        if(!AppInfo.isRelease()) {
267            // Set the language, if configured
268            String languageCode =
269                MailSettings.getInstance().getGlobalConfig().getLanguageCode();
270            if(languageCode != null && languageCode.length() > 0) {
271                try {
272                    Locale.setDefault(Locale.get(languageCode));
273                } catch (Exception e) { }
274            }
275        }
276    }
277
278    private void addSystemListeners() {
279        // Add the filesystem listener
280        try {
281            FileSystemRegistry.addFileSystemListener(MailSettings.getInstance().getFileSystemListener());
282        } catch (ControlledAccessException e) {
283            // Don't fail if file permissions are denied
284        }
285       
286        // Add any sensor listeners
287        try {
288            UtilFactory.getInstance().addSensorListeners();
289        } catch (ControlledAccessException e) {
290            // Don't fail if permissions are denied
291        }
292       
293        // Add the system listener for handling power-related events
294        try {
295            addSystemListener(MailManager.getInstance().getSystemListener());
296        } catch (ControlledAccessException e) {
297            // Don't fail if permissions are denied
298        }
299    }
300
301    private void showMailHomeScreen() {
302        invokeLater(new Runnable() {
303            public void run() {
304                // Push the mail home screen and pop
305                // the loading screen
306                navigationController.displayMailHome();
307                if(loadingScreen != null) {
308                    popScreen(loadingScreen);
309                    loadingScreen = null;
310                }
311                MailManager.getInstance().startupComplete();
312            }
313        });
314    }
315   
316    private void logStartupAppInfo() {
317        // Log application startup information
318        if(EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) {
319            StringBuffer buf = new StringBuffer();
320            buf.append("Application startup\r\n");
321            buf.append("Date: ");
322            buf.append(Calendar.getInstance().getTime().toString());
323            buf.append("\r\n");
324            buf.append("Name: ");
325            buf.append(AppInfo.getName());
326            buf.append("\r\n");
327            buf.append("Version: ");
328            appendAppVersion(buf);
329            buf.append("\r\n");
330            buf.append("Platform: ");
331            buf.append(DeviceInfo.getDeviceName());
332            buf.append(' ');
333            buf.append(AppInfo.getPlatformVersion());
334            if(PlatformInfo.getInstance().hasTouchscreen()) {
335                buf.append(' ');
336                buf.append("(touch)");
337            }
338            buf.append("\r\n");
339            EventLogger.logEvent(AppInfo.GUID, buf.toString().getBytes(), EventLogger.INFORMATION);
340        }
341    }
342
343    private void createLoadingScreen() {
344        loadingScreen = new MainScreen();
345        int displayWidth = Display.getWidth();
346        int displayHeight = Display.getHeight();
347        int fieldSpacerSize = displayHeight / 24;
348        Bitmap splashLogo = Bitmap.getBitmapResource("splash-logo.png");
349        int throbberSize = displayWidth / 4;
350        int fontHeight = Font.getDefault().getHeight();
351        int spacerSize = (displayHeight / 2) - ((splashLogo.getHeight() + throbberSize + fontHeight) / 2) - fieldSpacerSize;
352        if(spacerSize < 0) { spacerSize = 0; }
353
354        loadingScreen.add(new BlankSeparatorField(spacerSize));
355        loadingScreen.add(new BitmapField(splashLogo, Field.FIELD_HCENTER));
356        loadingScreen.add(new BlankSeparatorField(fieldSpacerSize));
357        loadingScreen.add(new ThrobberField(throbberSize, Field.FIELD_HCENTER));
358        loadingScreen.add(new BlankSeparatorField(fieldSpacerSize));
359       
360        StringBuffer buf = new StringBuffer();
361        buf.append("Version ");
362        appendAppVersion(buf);
363        loadingScreen.add(new LabelField(buf.toString(), Field.FIELD_HCENTER));
364    }
365
366    private static void appendAppVersion(StringBuffer buf) {
367        buf.append(AppInfo.getVersion());
368        if(AppInfo.isRelease()) {
369            String moniker = AppInfo.getVersionMoniker();
370            if(moniker != null && moniker.length() > 0) {
371                buf.append(" (");
372                buf.append(moniker);
373                buf.append(')');
374            }
375        }
376        else {
377            buf.append(" (dev)");
378        }
379    }
380   
381    /**
382     * Complete the application shutdown process by unregistering any static
383     * listeners and exiting the application process.
384     */
385    public static void shutdownApplication() {
386        NotificationHandler.getInstance().shutdown();
387
388        try {
389            Application.getApplication().removeSystemListener(MailManager.getInstance().getSystemListener());
390        } catch (ControlledAccessException e) {
391            // Don't fail if permissions are denied
392        }
393       
394        try {
395            UtilFactory.getInstance().removeSensorListeners();
396        } catch (ControlledAccessException e) {
397            // Don't fail if permissions are denied
398        }
399       
400        try {
401            FileSystemRegistry.removeFileSystemListener(MailSettings.getInstance().getFileSystemListener());
402        } catch (ControlledAccessException e) {
403            // Don't fail if file permissions are denied
404        }
405       
406        PermissionsHandler.unregisterReasonProvider();
407        LogicMailRuntimeState.getInstance().setApplicationInstance(null);
408       
409        AnalyticsDataCollector.getInstance().onApplicationTerminate();
410       
411        System.exit(0);
412    }
413
414    private void runAutoStartup() {
415        if(ApplicationManager.getApplicationManager().inStartup()) {
416            systemListener = new StartupSystemListener();
417            this.addSystemListener(systemListener);
418        }
419        else {
420            invokeLater(new Runnable() {
421                public void run() {
422                    startupInitialization();
423                }
424            });
425        }
426    }
427   
428    private class StartupSystemListener implements SystemListener {
429        public void powerUp() {
430            removeSystemListener(systemListener);
431            startupInitialization();
432        }
433       
434        public void powerOff() { }
435        public void batteryGood() { }
436        public void batteryLow() { }
437        public void batteryStatusChange(int status) { }
438    }
439   
440    private void startupInitialization() {
441        // The BlackBerry has finished its startup process
442
443        MailSettings mailSettings = null;
444        boolean initialized = false;
445        try {
446            if(!LogicMailRuntimeState.removeInstance()) {
447                // Configure the rollover icons
448                HomeScreen.updateIcon(AppInfo.getIcon(), 0);
449                HomeScreen.setRolloverIcon(AppInfo.getRolloverIcon(), 0);
450               
451                try {
452                    HomeScreen.updateIcon(AppInfo.getIcon(), 1);
453                    HomeScreen.setRolloverIcon(AppInfo.getRolloverIcon(), 1);
454                } catch (IllegalArgumentException e) { }
455               
456                // Register for synchronization
457                SyncManager.getInstance().enableSynchronization(LogicMailSyncCollection.getInstance());
458            }
459
460            // Load application settings
461            mailSettings = MailSettings.getInstance();
462            mailSettings.loadSettings();
463           
464            LogicMailRuntimeState runtimeState = LogicMailRuntimeState.getInstance();
465           
466            configureNotificationSources(runtimeState, mailSettings);
467   
468            initialized = true;
469        } catch (ControlledAccessException e) {
470            // If permissions have not been granted, we may get here
471        }
472
473        checkForVersionIncrease();
474       
475        if(initialized
476                && AppInfo.isLicenceAccepted()
477                && mailSettings != null
478                && mailSettings.getGlobalConfig().isAutoStartupEnabled()) {
479            LogicMailRuntimeState.getInstance().setApplicationInstance(this);
480            runBackgroundStartup();
481        }
482        else {
483            // Exit the application.
484            PermissionsHandler.unregisterReasonProvider();
485            LogicMailRuntimeState.getInstance().setApplicationInstance(null);
486            System.exit(0);
487        }
488    }
489
490    private static void configureNotificationSources(LogicMailRuntimeState runtimeState, MailSettings mailSettings) {
491        // Configure a notification source for each account
492        int numAccounts = mailSettings.getNumAccounts();
493        for(int i=0; i<numAccounts; i++) {
494            AccountConfig accountConfig = mailSettings.getAccountConfig(i);
495            LogicMailEventSource eventSource =
496                new LogicMailEventSource(accountConfig.getAcctName(), accountConfig.getUniqueId());
497            NotificationsManager.registerSource(
498                    eventSource.getEventSourceId(),
499                    eventSource,
500                    NotificationsConstants.CASUAL);
501            runtimeState.putEventSource(eventSource);
502        }
503    }
504} 
Note: See TracBrowser for help on using the repository browser.