From a75397af20d190af7144d650c1187ba8be18d84e Mon Sep 17 00:00:00 2001 From: vakrilov Date: Wed, 4 Dec 2019 14:24:37 +0200 Subject: [PATCH 1/4] fix: check is disposed fragment is in fragmentMngr --- nativescript-core/ui/frame/frame.android.ts | 31 +++++++++++++++++++-- nativescript-core/utils/utils.ios.ts | 4 --- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/nativescript-core/ui/frame/frame.android.ts b/nativescript-core/ui/frame/frame.android.ts index e06248e64d..7e0de46bbf 100644 --- a/nativescript-core/ui/frame/frame.android.ts +++ b/nativescript-core/ui/frame/frame.android.ts @@ -87,6 +87,16 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener { return attachStateChangeListener; } +function nativeArrayIncludes(arr: native.Array, what: T): boolean { + for (let i = 0; i < arr.length; i++) { + if (arr[i] === what) { + return true; + } + } + + return false; +} + export class Frame extends FrameBase { public _originalBackground: any; private _android: AndroidFrame; @@ -264,13 +274,28 @@ export class Frame extends FrameBase { !this._currentEntry.fragment.isAdded()) { return; } + const fragmentManager: androidx.fragment.app.FragmentManager = this._getFragmentManager(); - const manager: androidx.fragment.app.FragmentManager = this._getFragmentManager(); - const transaction = manager.beginTransaction(); + // Check if manager contains the fragment to be removed + // This might happen when a dialog is already closed with android back btn const fragment = this._currentEntry.fragment; + const fragmentFound = nativeArrayIncludes(fragmentManager.getFragments().toArray(), fragment); + + if (traceEnabled()) { + const message = fragmentFound ? + `Frame.disposeCurrentFragment - fragment(${fragment}) found in fragmentManager(${fragmentManager}). Removing ...` : + `Frame.disposeCurrentFragment - fragment(${fragment}) NOT found in fragmentManager(${fragmentManager}). Skipping remove`; + traceWrite(message, traceCategories.NativeLifecycle); + } + + if (!fragmentFound) { + return; + } + + const transaction = fragmentManager.beginTransaction(); const fragmentExitTransition = fragment.getExitTransition(); - // Reset animation to its initial state to prevent mirrorered effect when restore current fragment transitions + // Reset animation to its initial state to prevent mirrored effect when restore current fragment transitions if (fragmentExitTransition && fragmentExitTransition instanceof org.nativescript.widgets.CustomTransition) { fragmentExitTransition.setResetOnTransitionEnd(true); } diff --git a/nativescript-core/utils/utils.ios.ts b/nativescript-core/utils/utils.ios.ts index 17474fd8dc..c01e04f399 100644 --- a/nativescript-core/utils/utils.ios.ts +++ b/nativescript-core/utils/utils.ios.ts @@ -6,8 +6,6 @@ import { export { ios }; export * from "./utils-common"; -let mainScreenScale; - export function openFile(filePath: string): boolean { try { const appPath = ios.getCurrentAppPath(); @@ -47,5 +45,3 @@ export function openUrl(location: string): boolean { return false; } - -mainScreenScale = UIScreen.mainScreen.scale; From 9fd77fb648437e3165fc9e758632cb3a760856dd Mon Sep 17 00:00:00 2001 From: vakrilov Date: Fri, 6 Dec 2019 14:56:19 +0200 Subject: [PATCH 2/4] fix: don't create bitmaps for no-width fragments --- nativescript-core/ui/frame/frame.android.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/nativescript-core/ui/frame/frame.android.ts b/nativescript-core/ui/frame/frame.android.ts index 7e0de46bbf..8070dab47e 100644 --- a/nativescript-core/ui/frame/frame.android.ts +++ b/nativescript-core/ui/frame/frame.android.ts @@ -93,7 +93,7 @@ function nativeArrayIncludes(arr: native.Array, what: T): boolean { return true; } } - + return false; } @@ -291,7 +291,7 @@ export class Frame extends FrameBase { if (!fragmentFound) { return; } - + const transaction = fragmentManager.beginTransaction(); const fragmentExitTransition = fragment.getExitTransition(); @@ -1057,6 +1057,12 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } private loadBitmapFromView(view: android.view.View): android.graphics.Bitmap { + // Don't try to creat bitmaps with no dimensions as this causes a crash + // This might happen when showing and closing dialogs fast. + if (!(view && view.getWidth() > 0 && view.getHeight() > 0)) { + return undefined; + } + // Another way to get view bitmap. Test performance vs setDrawingCacheEnabled // const width = view.getWidth(); // const height = view.getHeight(); @@ -1066,7 +1072,8 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { // view.draw(canvas); view.setDrawingCacheEnabled(true); - const bitmap = android.graphics.Bitmap.createBitmap(view.getDrawingCache()); + const drawCache = view.getDrawingCache(); + const bitmap = android.graphics.Bitmap.createBitmap(drawCache); view.setDrawingCacheEnabled(false); return bitmap; From b20ec8696945cae327c36103ef8f7309518cdadc Mon Sep 17 00:00:00 2001 From: vakrilov Date: Fri, 6 Dec 2019 16:13:52 +0200 Subject: [PATCH 3/4] refactor: use fragment.getFragmentManager --- nativescript-core/ui/frame/frame.android.ts | 31 ++------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/nativescript-core/ui/frame/frame.android.ts b/nativescript-core/ui/frame/frame.android.ts index 8070dab47e..8bc4d5e25c 100644 --- a/nativescript-core/ui/frame/frame.android.ts +++ b/nativescript-core/ui/frame/frame.android.ts @@ -87,16 +87,6 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener { return attachStateChangeListener; } -function nativeArrayIncludes(arr: native.Array, what: T): boolean { - for (let i = 0; i < arr.length; i++) { - if (arr[i] === what) { - return true; - } - } - - return false; -} - export class Frame extends FrameBase { public _originalBackground: any; private _android: AndroidFrame; @@ -274,24 +264,9 @@ export class Frame extends FrameBase { !this._currentEntry.fragment.isAdded()) { return; } - const fragmentManager: androidx.fragment.app.FragmentManager = this._getFragmentManager(); + const fragment: androidx.fragment.app.Fragment = this._currentEntry.fragment; + const fragmentManager: androidx.fragment.app.FragmentManager = fragment.getFragmentManager(); - // Check if manager contains the fragment to be removed - // This might happen when a dialog is already closed with android back btn - const fragment = this._currentEntry.fragment; - const fragmentFound = nativeArrayIncludes(fragmentManager.getFragments().toArray(), fragment); - - if (traceEnabled()) { - const message = fragmentFound ? - `Frame.disposeCurrentFragment - fragment(${fragment}) found in fragmentManager(${fragmentManager}). Removing ...` : - `Frame.disposeCurrentFragment - fragment(${fragment}) NOT found in fragmentManager(${fragmentManager}). Skipping remove`; - traceWrite(message, traceCategories.NativeLifecycle); - } - - if (!fragmentFound) { - return; - } - const transaction = fragmentManager.beginTransaction(); const fragmentExitTransition = fragment.getExitTransition(); @@ -662,7 +637,7 @@ function clearEntry(entry: BackstackEntry): void { entry.recreated = false; entry.fragment = null; const page = entry.resolvedPage; - if (page._context) { + if (page && page._context) { entry.resolvedPage._tearDownUI(true); } } From 6cafd7ae3be9861511002b13f4dde3b966688f42 Mon Sep 17 00:00:00 2001 From: vakrilov Date: Wed, 11 Dec 2019 10:13:11 +0200 Subject: [PATCH 4/4] fix(modal): set update dialogFragment of View after suspend --- nativescript-core/ui/core/view/view.android.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nativescript-core/ui/core/view/view.android.ts b/nativescript-core/ui/core/view/view.android.ts index c6a3132f25..5479b8c62d 100644 --- a/nativescript-core/ui/core/view/view.android.ts +++ b/nativescript-core/ui/core/view/view.android.ts @@ -155,6 +155,8 @@ function initializeDialogFragment() { const ownerId = this.getArguments().getInt(DOMID); const options = getModalOptions(ownerId); this.owner = options.owner; + // Set owner._dialogFragment to this in case the DialogFragment was recreated after app suspend + this.owner._dialogFragment = this; this._fullscreen = options.fullscreen; this._animated = options.animated; this._cancelable = options.cancelable;