Uploaded image for project: 'Titanium SDK/CLI'
  1. Titanium SDK/CLI
  2. TIMOB-26978

Android: Showing/hiding dialog while window is being destroyed by "Don't keep activities" sometimes crashes

    Details

    • Story Points:
      13
    • Sprint:
      2019 Sprint 8, 2019 Sprint 9, 2019 Sprint 10

      Description

      Summary:
      Showing or hiding a dialog (alert or progress indicator) from an activity window that is in the middle of being destroy, but not "finished", will sometimes cause the following crashes.

      Note that an Android activity can be flagged as "destroyed", but not "finished", if the Android OS destroys it due to low memory or if system developer option "Don't keep activities" is enabled. When this happens, the Android OS intends to restore the activity when the end-user navigates back to it.


      Steps to reproduce dialog "dismiss" crash:
      Unknown.

      Theoretically, this should be possible by calling a dialog's hide() method via the Ti.UI.Window object's window.activity.onDestroy callback, but it doesn't crash for me.

      Below is the stack trace reported by some app developers when this issue happens

      java.lang.IllegalArgumentException: View=DecorView@1a43283[TiActivity] not attached to window manager
      at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:485)
      at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:394)
      at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:124)
      at android.app.Dialog.dismissDialog(Dialog.java:375)
      at android.app.Dialog.dismiss(Dialog.java:358)
      at ti.modules.titanium.ui.widget.TiUIProgressIndicator.handleHide(TiUIProgressIndicator.java:252)
      at ti.modules.titanium.ui.widget.TiUIProgressIndicator.handleMessage(TiUIProgressIndicator.java:78)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:193)
      at android.app.ActivityThread.main(ActivityThread.java:6718)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
      


      Steps to reproduce dialog "show" crash:

      1. Go to the Android device's main "Settings" screen.
      2. Tap on "System" under "Settings.
      3. Tap on "Developer options" under "System" settings.
      4. Enable "Don't keep activities", which should be near the bottom of the list.
      5. Build and run the below code on the above Android device.
      6. Press the Android "Home" button.
      7. Resume the app.
      8. Press the Android "Back" button.
      9. Observe the Android log. You'll see one of the below exception stack traces.

      app.js

      var progressIndicator = Ti.UI.Android.createProgressIndicator({
      	message: "Progressing...",
      	location: Ti.UI.Android.PROGRESS_INDICATOR_DIALOG,
      	type: Ti.UI.Android.PROGRESS_INDICATOR_INDETERMINANT,
      	cancelable: false,
      });
      var window = Ti.UI.createWindow();
      window.add(Ti.UI.createLabel({ text: "Press Back" }));
      window.activity.onDestroy = function() {
      	var isShowingAlert = true;
      	if (isShowingAlert) {
      		alert("Hello World!");
      	} else {
      		var progressIndicator = Ti.UI.Android.createProgressIndicator({
      			message: "Progressing...",
      			location: Ti.UI.Android.PROGRESS_INDICATOR_DIALOG,
      			type: Ti.UI.Android.PROGRESS_INDICATOR_INDETERMINANT,
      			cancelable: false,
      		});
      		progressIndicator.show();
      	}
      }
      window.open();
      

      Stack trace in 7.5.x...

      [ERROR] TiExceptionHandler: (main) [611,6711] Attempt to invoke virtual method 'java.lang.Object org.appcelerator.kroll.KrollObject.callProperty(java.lang.String, java.lang.Object[])' on a null object reference
      [ERROR] TiExceptionHandler:
      [ERROR] TiExceptionHandler:     org.appcelerator.kroll.KrollProxy.handleMessage(KrollProxy.java:1210)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.proxy.ActivityProxy.handleMessage(ActivityProxy.java:394)
      [ERROR] TiExceptionHandler:     android.os.Handler.dispatchMessage(Handler.java:102)
      [ERROR] TiExceptionHandler:     android.os.Looper.loop(Looper.java:193)
      [ERROR] TiExceptionHandler:     android.app.ActivityThread.main(ActivityThread.java:6669)
      [ERROR] TiExceptionHandler:     java.lang.reflect.Method.invoke(Native Method)
      [ERROR] TiExceptionHandler:     com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
      [ERROR] TiExceptionHandler:     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
      [ERROR] TiExceptionHandler: (main) [34,6745] Unable to add window -- token android.os.BinderProxy@b66e705 is not valid; is your activity running?
      [ERROR] TiExceptionHandler:
      [ERROR] TiExceptionHandler:     android.view.ViewRootImpl.setView(ViewRootImpl.java:798)
      [ERROR] TiExceptionHandler:     android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
      [ERROR] TiExceptionHandler:     android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
      [ERROR] TiExceptionHandler:     android.app.Dialog.show(Dialog.java:329)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiExceptionHandler.createDialog(TiExceptionHandler.java:233)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiExceptionHandler$1.onCurrentActivityReady(TiExceptionHandler.java:171)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.util.TiUIHelper.waitForCurrentActivity(TiUIHelper.java:193)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiApplication.waitForCurrentActivity(TiApplication.java:817)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiExceptionHandler.handleOpenErrorDialog(TiExceptionHandler.java:167)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiExceptionHandler.openErrorDialog(TiExceptionHandler.java:139)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiExceptionHandler.handleException(TiExceptionHandler.java:264)
      [ERROR] TiExceptionHandler:     org.appcelerator.kroll.KrollRuntime.dispatchException(KrollRuntime.java:540)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.TiApplication$1.uncaughtException(TiApplication.java:362)
      [ERROR] TiExceptionHandler:     org.appcelerator.kroll.KrollProxy.handleMessage(KrollProxy.java:1225)
      [ERROR] TiExceptionHandler:     org.appcelerator.titanium.proxy.ActivityProxy.handleMessage(ActivityProxy.java:394)
      [ERROR] TiExceptionHandler:     android.os.Handler.dispatchMessage(Handler.java:102)
      [ERROR] TiExceptionHandler:     android.os.Looper.loop(Looper.java:193)
      [ERROR] TiExceptionHandler:     android.app.ActivityThread.main(ActivityThread.java:6669)
      [ERROR] TiExceptionHandler:     java.lang.reflect.Method.invoke(Native Method)
      [ERROR] TiExceptionHandler:     com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
      [ERROR] TiExceptionHandler:     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
      

      Stack trace in 8.0.0...

      [ERROR] WindowManager: android.view.WindowLeaked: Activity org.appcelerator.titanium.TiActivity has leaked window DecorView@89a3790[TiActivity] that was originally added here
      [ERROR] WindowManager: 	at android.view.ViewRootImpl.<init>(ViewRootImpl.java:511)
      [ERROR] WindowManager: 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
      [ERROR] WindowManager: 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
      [ERROR] WindowManager: 	at android.app.Dialog.show(Dialog.java:329)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.widget.TiUIProgressIndicator.handleShow(TiUIProgressIndicator.java:231)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.widget.TiUIProgressIndicator.show(TiUIProgressIndicator.java:146)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.android.ProgressIndicatorProxy.handleShow(ProgressIndicatorProxy.java:59)
      [ERROR] WindowManager: 	at org.appcelerator.titanium.proxy.TiViewProxy.show(TiViewProxy.java:763)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.TiDialogProxy.access$001(TiDialogProxy.java:29)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.TiDialogProxy$1.onCurrentActivityReady(TiDialogProxy.java:47)
      [ERROR] WindowManager: 	at org.appcelerator.titanium.util.TiUIHelper.waitForCurrentActivity(TiUIHelper.java:194)
      [ERROR] WindowManager: 	at ti.modules.titanium.ui.TiDialogProxy.show(TiDialogProxy.java:42)
      [ERROR] WindowManager: 	at org.appcelerator.kroll.runtime.v8.V8Object.nativeCallProperty(Native Method)
      [ERROR] WindowManager: 	at org.appcelerator.kroll.runtime.v8.V8Object.callProperty(V8Object.java:75)
      [ERROR] WindowManager: 	at org.appcelerator.kroll.KrollProxy.callPropertySync(KrollProxy.java:753)
      [ERROR] WindowManager: 	at org.appcelerator.titanium.TiBaseActivity.dispatchCallback(TiBaseActivity.java:1304)
      [ERROR] WindowManager: 	at org.appcelerator.titanium.TiBaseActivity.onDestroy(TiBaseActivity.java:1589)
      [ERROR] WindowManager: 	at org.appcelerator.titanium.TiActivity.onDestroy(TiActivity.java:58)
      [ERROR] WindowManager: 	at android.app.Activity.performDestroy(Activity.java:7395)
      [ERROR] WindowManager: 	at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1306)
      [ERROR] WindowManager: 	at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4443)
      [ERROR] WindowManager: 	at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4476)
      [ERROR] WindowManager: 	at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:39)
      [ERROR] WindowManager: 	at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
      [ERROR] WindowManager: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
      [ERROR] WindowManager: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
      [ERROR] WindowManager: 	at android.os.Handler.dispatchMessage(Handler.java:106)
      [ERROR] WindowManager: 	at android.os.Looper.loop(Looper.java:193)
      [ERROR] WindowManager: 	at android.app.ActivityThread.main(ActivityThread.java:6669)
      [ERROR] WindowManager: 	at java.lang.reflect.Method.invoke(Native Method)
      [ERROR] WindowManager: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
      [ERROR] WindowManager: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
      


      Solution:
      The dialog handling code will attempt to show a dialog use the top-most activity that is being shown. This activity is fetched via TiApplication.getCurrentActivity(). This method will checks the top-most activity's isFinishing() method and ignores skips them knowing that they are in the middle of being destroyed... but this code is also missing an isDestroyed() check since an activity can be destroyed but not finished for the "Don't keep activities" edge-case.
      TiApplication.getCurrentActivity()

      Our dialog dismissing code needs to check if the hosting activity has been destroyed as well, not just finished. We should also wrap a dismiss() call with a try/catch block just in case since we don't know how to reproduce this issue (might be a bug on Google's end that we need to work-around?).
      TiUIDialog.java
      TiUIProgressIndicator.java

        Attachments

          Activity

            People

            • Assignee:
              jquick Joshua Quick
              Reporter:
              jquick Joshua Quick
              Reviewer:
              Gary Mathews
              Tester:
              Lokesh Choudhary
            • Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Backbone Issue Sync

                • Backbone Issue Sync is enabled for your project, but we do not have any synchronization info for this issue.

                  Git Integration