{ "id": "63766", "key": "TIMOB-3134", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "11244", "name": "Release 1.7.0", "archived": true, "released": true, "releaseDate": "2011-06-13" }, { "id": "11251", "name": "Sprint 2011-16", "archived": true, "released": true, "releaseDate": "2011-04-25" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2011-05-03T14:09:46.000+0000", "created": "2011-04-15T03:37:45.000+0000", "priority": { "name": "Trivial", "id": "5" }, "labels": [ "android", "enterprise", "regression", "release-1.7.0", "reported-1.6.0", "rplist" ], "versions": [], "issuelinks": [ { "id": "10303", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "64805", "key": "TIMOB-3734", "fields": { "summary": "Confirm TIMOB-3134", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } } } ], "assignee": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2011-05-03T14:09:46.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "{html}

Problem

\n

When an alert dialog and a modal window are launched at the same\ntime, they end up racing each other to see who displays first. This\ncauses an exception to be thrown.

\n

Regression

\n

In 1.5.0, the alert dialog would show over the modal window, and\nno exception would be thrown. This has been introduced since\nthen.

\n

Sample Code

\n
\nvar tabGroup = Titanium.UI.createTabGroup();\n \n// main window\nvar tmpWindow = Titanium.UI.createWindow({  \n    backgroundColor: 'green',\n});\nvar tmpTab = Titanium.UI.createTab({  \n    window:tmpWindow,\n    title:'first'\n});\n \ntabGroup.addTab(tmpTab);\ntabGroup.open();\n \nLogin = {};\n \nLogin.loginDialog = Ti.UI.createWindow({\n   backgroundColor: 'red',\n});\n \nLogin.loginDialog.open({modal:true});\n \nvar alertDialog = Titanium.UI.createAlertDialog({\n    title: 'Welcome',\n    message: 'Stuff in here',\n    buttonNames: ['red pill', 'blue pill']\n});\nalertDialog.show();\n
\n

Trace Log

\n
\n[TRACE] E/WindowManager( 586): Activity org.appcelerator.jss.JssActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43ec9740 that was originally added here\n[TRACE] E/WindowManager( 586): android.view.WindowLeaked: Activity org.appcelerator.jss.JssActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43ec9740 that was originally added here\n[TRACE] E/WindowManager( 586): at android.view.ViewRoot.<init>(ViewRoot.java:247)\n[TRACE] E/WindowManager( 586): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)\n[TRACE] E/WindowManager( 586): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)\n[TRACE] E/WindowManager( 586): at android.view.Window$LocalWindowManager.addView(Window.java:424)\n[TRACE] E/WindowManager( 586): at android.app.Dialog.show(Dialog.java:241)\n[TRACE] E/WindowManager( 586): at ti.modules.titanium.ui.widget.TiUIActivityIndicator.handleShow(TiUIActivityIndicator.java:200)\n[TRACE] E/WindowManager( 586): at ti.modules.titanium.ui.widget.TiUIActivityIndicator.show(TiUIActivityIndicator.java:124)\n[TRACE] E/WindowManager( 586): at ti.modules.titanium.ui.ActivityIndicatorProxy.handleShow(ActivityIndicatorProxy.java:45)\n[TRACE] E/WindowManager( 586): at org.appcelerator.titanium.proxy.TiViewProxy.handleMessage(TiViewProxy.java:212)\n[TRACE] E/WindowManager( 586): at android.os.Handler.dispatchMessage(Handler.java:95)\n[TRACE] E/WindowManager( 586): at android.os.Looper.loop(Looper.java:123)\n[TRACE] E/WindowManager( 586): at android.app.ActivityThread.main(ActivityThread.java:4627)\n[TRACE] E/WindowManager( 586): at java.lang.reflect.Method.invokeNative(Native Method)\n[TRACE] E/WindowManager( 586): at java.lang.reflect.Method.invoke(Method.java:521)\n[TRACE] E/WindowManager( 586): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)\n[TRACE] E/WindowManager( 586): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)\n[TRACE] E/WindowManager( 586): at dalvik.system.NativeStart.main(Native Method)\n
\n

Workaround

\n

The workaround is to remove the race -- only open one, and when\nit is finished, launch the second. Therefore, the workaround for\nthe sample code would be the following (thanks belong to Marshall\nCulpepper for this workaround):

\n
\nLogin.loginDialog.addEventListener(\"open\", function(e) {\n    var alertDialog = Titanium.UI.createAlertDialog({\n        title: 'Welcome',\n        message: 'Stuff in here',\n        buttonNames: ['red pill', 'blue pill']\n    });\n    alertDialog.show();\n});\nLogin.loginDialog.open({ modal: true });\n
\n

Tested On

\n

Titanium SDK version: 1.6.0 (02/10/11 14:34 9db0685...)
\nBROKEN on Android Simulator 2.2

\n

Associated Helpdesk Ticket

\n

http://developer.appcelerator.com/helpdesk/view/72761

{html}", "attachment": [], "flagged": false, "summary": "Android: Alert Dialog appears behind activities and is invisible to user", "creator": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "subtasks": [], "reporter": { "name": "dtoth", "key": "dtoth", "displayName": "Dawson Toth", "active": true, "timeZone": "America/New_York" }, "environment": null, "comment": { "comments": [ { "id": "130136", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "{html}

Technically it's not a race condition, and it's not really\nrelated to modality. That's not an exception either, it's a stack\ntrace Android is giving us, basically saying \"Hey you leaked a\nwindow, if you want to know which window is leaked, here's the code\npath that created that window.\" I.e., no exception is thrown.

\n

It's not a race condition because, in fact, the alert dialog is\nbeing shown -- it's the window being leaked. You just can't see it\nbecause it's behind everything. When you back out of the tabgroup,\nthe application closes while that window (the alert) is still\nshowing, thus that complaint by Android.

\n

So I'm gonna go ahead and change the title here, just to be\nanal. :)

\n

Here's a much simpler test case to show this behavior:

\n
\nTi.UI.createWindow({exitOnClose:true,fullscreen:false, backgroundColor:'blue'}).open();\nTi.UI.createAlertDialog({message:'.'}).show();\n
{html}", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-04-15T03:37:47.000+0000", "updated": "2011-04-15T03:37:47.000+0000" }, { "id": "130137", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "{html}

Trace with some notes. It's from running the two-liner app.js I\nshow above. I'm putting this here so I don't \"lose it\". :)

\n

https://img.skitch.com/20110406-mtb9dq7txs42f835dx88xe5231.png

{html}", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-04-15T03:37:47.000+0000", "updated": "2011-04-15T03:37:47.000+0000" }, { "id": "132681", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "I got the failcase to work by adding code that notices if the activity stack is in flux and, if so, delays the call to the alert dialog.\n\nHowever, I *strongly* recommend against using code like that in the fail case. In a sense, there was some luck involved that this ever worked in 1.5.x. The reason is because of the way Android activities work. For an alert dialog to be visible, it is important that it appear \"above\" the topmost Activity in the Android activity stack. \n\nWhat is the topmost Activity when {{alertDialog.show()}} is called in the fail case app.js? Is it the \"root\" Activity, which is the Activity that runs when the application launches and executes app.js? Or is it the Activity that is created when the {{TabGroup}} opens? ( {{TabGroup}} s have their own Activity). Or is it the Activity created by the modal window being opened (a modal window causes its own Activity)?\n\nIn other words, there are three Activities involved in that app.js code sequence. The launching of the {{TabGroup}} and the modal {{Window}} create two of those Activities, and their launches are _asynchronous_. When {{alertDialog.show()}} comes around, which of those three Activities is going to be \"current\"? It's dangerous to assume that the modal window's activity will be current.\n\nIt's better to be sure that the modal window (atop of which you want the dialog to show, else it won't be visible) has opened by putting the call to {{alertDialog.show()}} in an {{open}} event listener for that modal window:\n\n{code:title=sample.js}\nvar alertDialog = Titanium.UI.createAlertDialog({\n title: 'Welcome',\n message: 'Stuff in here',\n buttonNames: ['red pill', 'blue pill']\n});\nLogin = {};\n \nLogin.loginDialog = Ti.UI.createWindow({\n backgroundColor: 'red',\n});\n\nLogin.loginDialog.addEventListener('open', function(){\n alertDialog.show();\n});\nLogin.loginDialog.open({modal:true});\n\n{code}", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-04-25T06:50:25.000+0000", "updated": "2011-04-25T06:51:12.000+0000" } ], "maxResults": 3, "total": 3, "startAt": 0 } } }