Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-3208] Android: Heavyweight Windows Opened by Menu Items Often Cause Null Pointer Exceptions

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2011-12-28T11:19:53.000+0000
Affected Version/sRelease 1.7.2
Fix Version/sRelease 1.7.0, Sprint 2011-10, Sprint 2011-32, Release 1.8.0, Sprint 2011-52, Release 2.0.0, Release 1.8.1
ComponentsAndroid
Labelsmodule_window, qe-testadded, regression, release-1.7.0, reported-1.6.0
ReporterDawson Toth
AssigneeAllen Yeung
Created2011-04-15T03:39:29.000+0000
Updated2012-02-03T15:50:33.000+0000

Description

Problem

If you open a heavyweight window when the user touches a menu item, you can easily cause a null pointer exception to be thrown and the app to crash.

Theory

Based on the error message, we're hitting the NPE in our call to create a new intent on line 528 of TiUIWindow.java. Because TiActivity.class is not null, activity must be null. This is set on line 185 of the same file, and passed to the createIntent method. My theory is that there is an interim period between when the menu closes and the window regains focus during which proxy.getTiContext().getActivity() will return null, and cause the NPE.

Sample Code

Drop the following in an app.js:

// open a heavyweight window
var win = Titanium.UI.createWindow({ backgroundColor: '#fff', fullscreen: true });
win.add(Ti.UI.createLabel({ text: 'Press your hardware menu button!' }));
win.open();
var modal = Ti.UI.createWindow();

// keep a pointer to the current activity
var currentActivity = win.activity;

// and make an options menu
currentActivity.onCreateOptionsMenu = function(e) {

    // this menu item will effectively work off "proxy.getTiContext().getActivity()",
    // which can be null if the timing is just right when the menu closes and the modal opens
    e.menu.add({ title: 'Crashes Often' }).addEventListener('click', function() {
        // simulate some heavy activity to get the modal ready; having this busy
        // wait present is what makes this bug reproducible
        for (var i = new Date().getTime() + 1000; i > new Date().getTime();) {
        }
        modal.open({ modal: true });
        setTimeout(function() {
            modal.close();
        }, 50);
    });

    // but we explicitly set the activity in this one to our outer activity (the main activity)
    // so it will never be null
    var intent = Ti.Android.createIntent({
        url: 'loginModalWindow.js'
    });
    intent.putExtra('modal', true);
    e.menu.add({ title: 'Never Crashes' }).addEventListener("click", function() {
        // simulate some heavy activity; it won't make a difference
        for (var i = new Date().getTime() + 1000; i > new Date().getTime();) {
        }
        // start the activity; it will fire off without a problem
        currentActivity.startActivity(intent);
    });

};

now drop the following into your tiapp.xml:

    <android xmlns:android="http://schemas.android.com/apk/res/android">
        <activities>
            <activity url="loginModalWindow.js" android:theme="@android:style/Theme.Dialog" />
        </activities>
    </android>

and finally drop the following in loginModalWindow.js:

var win = Ti.UI.currentWindow;
win.modal = true;

setTimeout(function() {
    win.close();
}, 50)

This sample app has two menu items, named "Crashes Often" and "Never Crashes". They both launch modal windows that close themselves right away. The difference is the method they use. "Crashes Often" uses the Titanium way of opening a modal window. "Never Crashes" uses a more native Android way to open the modal, and is not reliant on Titanium automagically determining the current activity that should launch our modal activity. Note that you may need to try "Crashes Often" a couple of times before the app will freeze, crash, and you'll see the NPE in your logs.

Exception

E/TiUncaughtHandler(11317): (main) [1236,5053] Sending event: exception on thread: main msg:java.lang.NullPointerException; Titanium 1.7.0,2011/02/18 18:13,16c2c7
E/TiUncaughtHandler(11317): java.lang.NullPointerException
E/TiUncaughtHandler(11317):     at android.content.ComponentName.<init>(ComponentName.java:75)
E/TiUncaughtHandler(11317):     at android.content.Intent.<init>(Intent.java:2652)
E/TiUncaughtHandler(11317):     at ti.modules.titanium.ui.TiUIWindow.createIntent(TiUIWindow.java:528)
E/TiUncaughtHandler(11317):     at ti.modules.titanium.ui.TiUIWindow.createNewActivity(TiUIWindow.java:186)
E/TiUncaughtHandler(11317):     at ti.modules.titanium.ui.TiUIWindow.<init>(TiUIWindow.java:110)
E/TiUncaughtHandler(11317):     at ti.modules.titanium.ui.WindowProxy.handleOpen(WindowProxy.java:98)
E/TiUncaughtHandler(11317):     at org.appcelerator.titanium.proxy.TiWindowProxy.handleMessage(TiWindowProxy.java:67)
E/TiUncaughtHandler(11317):     at ti.modules.titanium.ui.WindowProxy.handleMessage(WindowProxy.java:85)
E/TiUncaughtHandler(11317):     at android.os.Handler.dispatchMessage(Handler.java:95)
E/TiUncaughtHandler(11317):     at android.os.Looper.loop(Looper.java:123)
E/TiUncaughtHandler(11317):     at android.app.ActivityThread.main(ActivityThread.java:4370)
E/TiUncaughtHandler(11317):     at java.lang.reflect.Method.invokeNative(Native Method)
E/TiUncaughtHandler(11317):     at java.lang.reflect.Method.invoke(Method.java:521)
E/TiUncaughtHandler(11317):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
E/TiUncaughtHandler(11317):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
E/TiUncaughtHandler(11317):     at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(11317): Uncaught handler: thread main exiting due to uncaught exception

Tested On

Titanium SDK version: 1.7.0 (02/18/11 18:13 316c2c7)
BROKEN on Android EPIC 4G 2.1

Associated Helpdesk Ticket

http://developer.appcelerator.com/helpdesk/view/75121">http://developer.appcelerator.com/helpdesk/view/75121

Attachments

FileDateSize
app.zip2011-08-10T12:22:33.000+00001205
resources.zip2011-04-15T03:39:29.000+0000825520

Comments

  1. Dawson Toth 2011-04-15

    Workaround

    Incidentally... there is a workaround that I did not explicitly mention. If you take a more manual approach to launching modal windows, the NPE can be avoided entirely. Take a look at the "Never Crashes" menu item and at what it is doing.

  2. Opie Cyrus 2011-04-15

    Spawned #3337 in order to address issue with HW windows not setting the opened state correctly when closing. This applies to non modal windows.

  3. Opie Cyrus 2011-04-15

    Upon further investigation, #3337 has been set to invalid and fix will be attached to this ticket.

  4. Opie Cyrus 2011-04-15

    (from [56ff1de427f78c3e5e69b719a005e1deb102d611]) [#3208 state:fixed-in-qa] Make sure opened flag is set correctly when closing HW window

    opened window was not being set correctly upon HW window close. This was resulting in the incorrect conext being associated with the window proxy and would sometimes resul in an exception when opening the window a second time.
    https://github.com/appcelerator/titanium_mobile/commit/56ff1de427f78c3e5e69b719a005e1deb102d611"> https://github.com/appcelerator/titanium_mobile/commit/56ff1de427f7...

  5. Opie Cyrus 2011-04-15

    Please use attached resources directory (modified version of original test) to verify fix. While this fix resolves the reported exception, it should be noted that there is a delay when closing a modal window that is opened from the options menu. The onDestroy logic does not actually fire for the window until the menu is opened again or there are activity changes such as orientation change.

    During testing this behavior was seen to not have any negative side effects but still documenting here in case this info needs to be referenced in the future.

  6. Natalie Huynh 2011-04-15

    Tested with Titanium SDK version: 1.7.0 (03/23/11 09:50 87caf1e...) on
    Emulator 2.1
    Nexus S 2.3.2

    No longer catching exception

  7. Alan Vaghti 2011-07-25

    Works as expected as on 1.7.1 version=1.7.1 timestamp=06/21/11 14:28 githash=1293a6d However pressing 'Never Crashes' causes a force close on 1.7.2 and the latest 1.8.0 build: "The application BugTest (process com.appcelerator.bugtest) has stopped unexpectedly. Please try again." version=1.7.2 timestamp=07/21/11 09:36 githash=97c3689 version=1.8.0 timestamp=07/25/11 14:29 githash=65a5393... Tested on a Droid running Android 2.2.2
  8. Don Thorp 2011-07-25

    Please look into this.
  9. Opie Cyrus 2011-08-10

    Issue reported is a duplicated of #4643. Please refer to #4643 for the work around. In short, the theme specified does not support the features that the custom activity is trying to utilize. In order to address this situation, navBarHidden should be set to true when launching the new activity. I have provided an example of the work around.
  10. Opie Cyrus 2011-08-10

    work around attached for the the problem introduced by setting theme on custom activity
  11. Natalie Huynh 2011-12-19

    Tested with 1.8.0.1.RC3 with rhino/v8, not able to invoke the menu, spoke to Allen, he said he will try to reproduce first before kicking it back. May be an issue with the test case
  12. Allen Yeung 2011-12-27

  13. Wilson Luu 2012-01-13

    Closing bug. Verified fix on: SDK build: 1.9.0.v20120112153134 Runtime: V8, Rhino Titanium Studio, build: 1.0.8.201201122152 Device: Droid 3 (2.3.4)

JSON Source