{ "id": "85070", "key": "TIMOB-7360", "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": [], "resolution": { "id": "7", "description": "", "name": "Invalid" }, "resolutiondate": "2012-02-09T21:52:48.000+0000", "created": "2012-01-18T07:05:04.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "regression" ], "versions": [ { "id": "12580", "description": "Dual Runtime 1.8.0", "name": "Release 1.8.0.1", "archived": true, "released": true, "releaseDate": "2011-12-22" } ], "issuelinks": [], "assignee": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2012-02-09T21:52:48.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": "h2. Problem\r\n\r\nThe Android {{pause}} and {{resume}} events are not executed when the application is paused and resumed.\r\n\r\nNote that these events fire as expected using version 1.7.5\r\n\r\nh2. Test case\r\n\r\n# Start the application. The OnAppResume function executes as expected. *The OnAppPause function executes unexpectedly.*\r\n# Pressing the Android Home button pauses the application. However, *the OnAppPause function does not execute.*\r\n# Pressing the applications icon on the Apps screen resumes the application. However, *the OnAppResume function does not execute.*\r\n# Pressing the Android Back button ends the application and the OnAppDestroy function executes as expected. However, *the OnAppPause function does not execute.*\r\n\r\n{code:title=app.js|title=app.js}\r\nTitanium.UI.setBackgroundColor('#000');\r\n\r\nvar win1 = Titanium.UI.createWindow({\r\n title:'Test',\r\n backgroundColor:'#fff',\r\n fullscreen:true,\r\n exitOnClose:true});\r\n\r\nfunction OnAppResume()\r\n{\r\n Ti.API.info('***---> OnAppResume');\r\n}\r\n\r\nfunction OnAppPause()\r\n{\r\n Ti.API.info('***---> OnAppPause');\r\n}\r\n\r\nfunction OnAppDestroy()\r\n{\r\n Ti.API.info('***---> OnAppDestroy');\r\n}\r\n\r\nwin1.open();\r\n\r\nTi.Android.currentActivity.addEventListener('resume', OnAppResume);\r\nTi.Android.currentActivity.addEventListener('pause', OnAppPause);\r\nTi.Android.currentActivity.addEventListener('destroy', OnAppDestroy);\r\n{code} \r\n\r\n", "attachment": [], "flagged": false, "summary": "Android: App - pause and resume events not fired", "creator": { "name": "peteberry@ewrinc.com", "key": "peteberry@ewrinc.com", "displayName": "Pete Berry", "active": true, "timeZone": "America/New_York" }, "subtasks": [], "reporter": { "name": "peteberry@ewrinc.com", "key": "peteberry@ewrinc.com", "displayName": "Pete Berry", "active": true, "timeZone": "America/New_York" }, "environment": "* Titanium Mobile 1.8.0.1\r\n* Android Run Time: V8/Rhino\r\n* Android 2.2 (V8 and Rhino) and Android DroidX 2.3.3 (V8 and Rhino)\r\n* Titanium Studio, build: 1.0.7.201112281340", "comment": { "comments": [ { "id": "180480", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "Still investigating, but I'm generally surprised to see it works in 1.7.5 (and I've run it in 1.7.5 to verify that.) My expectation would have been that this would not have worked in 1.7.5. Window opening (the call to {{win1.open()}} in this case) is asynchronous. It switches from a runtime thread (which is what you're on when you call {{open()}}) to the UI thread (which is required to get view elements like a window up on screen).\r\n\r\nSince it's async, I would actually expect that if the next line after {{open()}} is grabbing {{Ti.Android.currentActivity}}, then it's going to get the Activity that runs app.js, meaning the \"root\" activity, rather than the Activity that will be created to service the new heavyweight window. Indeed, this is what is happening in 1.8.0.1.\r\n\r\nIn other words, the 1.8.0.1 behavior is what I would expect. Interesting that it differs from 1.7.5.\r\n\r\nStill looking...", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2012-01-24T18:32:36.000+0000", "updated": "2012-01-24T18:32:36.000+0000" }, { "id": "180484", "author": { "name": "bitshftr", "key": "bitshftr", "displayName": "Shawn Lipscomb", "active": true, "timeZone": "America/New_York" }, "body": "After reading Bill's comment, I'm wondering if this ({{Ti.Android.currentActivity.addEventListener('pause', OnAppPause)}}) is the correct way to detect the \"pause\" of an app on Android? Note that we're talking about pausing the whole app, like when the Android \"Home\" button is pressed.", "updateAuthor": { "name": "bitshftr", "key": "bitshftr", "displayName": "Shawn Lipscomb", "active": true, "timeZone": "America/New_York" }, "created": "2012-01-24T18:59:56.000+0000", "updated": "2012-01-24T18:59:56.000+0000" }, { "id": "180485", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "BTW, I believe the proper approach for that particular use case is to concentrate more on being sure to get the new window's Activity (i.e., using {{win1.activity}}) rather than the \"current activity\" at the time app.js is being processed.\r\n\r\nFor example, this re-write achieves that:\r\n\r\n{code:title=app.js}\r\nTitanium.UI.setBackgroundColor('#000');\r\n\r\nfunction OnAppResume()\r\n{\r\n Ti.API.info('***---> OnAppResume');\r\n}\r\n\r\nfunction OnAppPause()\r\n{\r\n Ti.API.info('***---> OnAppPause');\r\n}\r\n\r\nfunction OnAppDestroy()\r\n{\r\n Ti.API.info('***---> OnAppDestroy');\r\n}\r\n\r\nvar win1 = Titanium.UI.createWindow({\r\n title:'Test',\r\n backgroundColor:'#fff',\r\n fullscreen:true,\r\n exitOnClose:true});\r\n\r\nwin1.addEventListener(\"open\", function() {\r\n\tvar activity = win1.activity;\r\n\tactivity.addEventListener('resume', OnAppResume);\r\n\tactivity.addEventListener('pause', OnAppPause);\r\n\tactivity.addEventListener('destroy', OnAppDestroy);\r\n});\r\n\r\n\r\nwin1.open();\r\n{code}\r\n\r\nThe only thing you'd miss out on for that is the very first resume event, since that happens just before the window open event is fired. But of course the window open event itself can stand in its place for that purpose. You still get the resume events you would expect when you, for example, pop over to the home screen and pop back again. And of course you get the pause and destroy events when expected.\r\n\r\nThe reason that I find this approach \"more correct\" is that it distinguishes between \"the current activity when all this code in app.js is running\" (so to speak :)) and \"the activity I'm really interested in, which is the one belonging to this heavyweight window i'm creating as the main window of my application.\"\r\n\r\nNevertheless it's still interesting that the original fail case above worked in 1.7.5, and i'll be discussing with my colleagues tomorrow. Meanwhile I think my example in this comment is probably a sufficient work around for most use cases.", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2012-01-24T19:00:13.000+0000", "updated": "2012-01-24T19:00:13.000+0000" }, { "id": "180487", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "There's no concept of an application pause in Android. Only at the activity level. There are definitely pure native (i.e., non-Titanium) Android developers out there who are desperate for such a feature, i.e., knowing when the whole darn app goes in the background. Some resort to trying to keep an integer at the application level (in their Application class) and incrementing/decrementing when activities resume/pause. Then when the number hits 0, they wait a while to see if another activity is opening, then check the number again. If the number is still 0 at that point, they assume the whole app has been backgrounded (i.e., all activities have been paused, not just the ones below the topmost.)\r\n\r\nHorrible hack! :)\r\n\r\nIt's usually suggested that they re-architect their apps to not need to know this information. Needless to say, not everybody is satisfied with that suggestion.\r\n\r\nBut the fact remains, it's simply not supported in Android.\r\n\r\nOf course, if you architect a Titanium app so that it only uses one Activity, you can just rely on the listeners for that activity. When wanting to open other windows above that heavyweight window, you can open these subsequent windows as \"lightweight\" windows. The one big thing you lose by doing that is the back button functionality, since back button by default closes the current activity, and that's going to close your heavyweight window as well, not just your light window that you've put atop it.\r\n\r\nBut in Titanium we've given you a way to hook into the back button (see the {{android:back}} event on [Titanium.UI.Window|http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.UI.Window-object#events]). So if you intercept the back button while you're lightweight window is open, you can then just {{.close()}} the window and fall back to the heavy.\r\n\r\nOf course, there might be other reasons you have for wanting a multiple-activity application in Titanium, besides back button functionality. You may want one window to be fullscreen and navbarhidden, but another to be just navbarhidden, or something like that. In those cases, it's going to be very hard to know when the whole app goes in the background.", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2012-01-24T19:31:53.000+0000", "updated": "2012-01-24T19:34:50.000+0000" }, { "id": "180703", "author": { "name": "opiecyrus", "key": "opiecyrus", "displayName": "Opie Cyrus", "active": true, "timeZone": "America/Chicago" }, "body": "The work around Bill mentions is the correct route for this kind of behavior due to how native Android apps are structured. The current activity is associated with the url for the JS file where Ti.Android.currentActivity is used so the new window opened will not be tied to the current activity within the current url. The Ti.UI.Window.activity property should be used for accessing the activity associated with the window.\r\n\r\nA factory mechanism can be used to make handling this per activity easier. For example, call a method such as the one shown below inside the open event listener for a heavy weight window with the argument Ti.UI.Window.activity:\r\n\r\n{code}\r\nvar registerLifecycleListeners = function(windowActivity) {\r\n windowActivity.addEventListener('resume', );\r\n windowActivity.addEventListener('pause', );\r\n windowActivity.addEventListener('destroy', );\r\n}\r\n{code}", "updateAuthor": { "name": "opiecyrus", "key": "opiecyrus", "displayName": "Opie Cyrus", "active": true, "timeZone": "America/Chicago" }, "created": "2012-01-26T11:03:40.000+0000", "updated": "2012-01-26T11:05:07.000+0000" }, { "id": "181068", "author": { "name": "mpettiford", "key": "mpettiford", "displayName": "Michael Pettiford", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Closing issue\r\n\r\nTested with Ti Studio build 1.0.8.201201262211\r\nTi Mob SDK 1.8.1.v20120127173134\r\nOSX Lion\r\nDroid 3 OS 2.3.4, Android Emulator 2.2.2\r\n\r\nVerified that the expected behavior of pause, resume, and destroy work correctly", "updateAuthor": { "name": "mpettiford", "key": "mpettiford", "displayName": "Michael Pettiford", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-01-30T10:08:56.000+0000", "updated": "2012-01-30T10:08:56.000+0000" } ], "maxResults": 7, "total": 7, "startAt": 0 } } }