diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index f3bbc4871..7703aa599 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -145,6 +145,10 @@
+
+
+
+
Designer
@@ -2116,6 +2120,7 @@
PreserveNewest
+
@@ -2213,7 +2218,7 @@
False
-
+
\ No newline at end of file
diff --git a/apps/App_Resources/Android/drawable-hdpi/icon.png b/apps/App_Resources/Android/drawable-hdpi/icon.png
new file mode 100644
index 000000000..1034356e2
Binary files /dev/null and b/apps/App_Resources/Android/drawable-hdpi/icon.png differ
diff --git a/apps/App_Resources/Android/drawable-ldpi/icon.png b/apps/App_Resources/Android/drawable-ldpi/icon.png
new file mode 100644
index 000000000..ddfc17a71
Binary files /dev/null and b/apps/App_Resources/Android/drawable-ldpi/icon.png differ
diff --git a/apps/App_Resources/Android/drawable-mdpi/icon.png b/apps/App_Resources/Android/drawable-mdpi/icon.png
new file mode 100644
index 000000000..486e41091
Binary files /dev/null and b/apps/App_Resources/Android/drawable-mdpi/icon.png differ
diff --git a/apps/App_Resources/Android/drawable-nodpi/splashscreen.9.png b/apps/App_Resources/Android/drawable-nodpi/splashscreen.9.png
new file mode 100644
index 000000000..bd53be2ec
Binary files /dev/null and b/apps/App_Resources/Android/drawable-nodpi/splashscreen.9.png differ
diff --git a/apps/App_Resources/package.json b/apps/App_Resources/package.json
new file mode 100644
index 000000000..08e44e117
--- /dev/null
+++ b/apps/App_Resources/package.json
@@ -0,0 +1,2 @@
+{ "name" : "app-resources",
+ "main" : "dummy.js" }
diff --git a/apps/perf-tests/NavigationTest/app.ts b/apps/perf-tests/NavigationTest/app.ts
index 80b471c3e..dff5826b6 100644
--- a/apps/perf-tests/NavigationTest/app.ts
+++ b/apps/perf-tests/NavigationTest/app.ts
@@ -1,11 +1,14 @@
import * as application from "application";
import {NavPage} from "../nav-page";
import * as trace from "trace";
+import { Frame } from "ui/frame";
+
+Frame.defaultTransition = { name: "fade" };
+
trace.enable();
trace.setCategories(trace.categories.concat(
trace.categories.NativeLifecycle,
trace.categories.Navigation,
- //trace.categories.Animation,
trace.categories.Transition
));
diff --git a/apps/perf-tests/nav-page.ts b/apps/perf-tests/nav-page.ts
index fa421434a..ccaf0fe25 100644
--- a/apps/perf-tests/nav-page.ts
+++ b/apps/perf-tests/nav-page.ts
@@ -1,7 +1,7 @@
import definition = require("controls-page");
import {View} from "ui/core/view";
import {Page} from "ui/page";
-import {topmost as topmostFrame, NavigationTransition} from "ui/frame";
+import {topmost as topmostFrame, NavigationTransition, Frame} from "ui/frame";
import {Orientation, AnimationCurve} from "ui/enums";
import {StackLayout} from "ui/layouts/stack-layout";
import {Button} from "ui/button";
@@ -10,6 +10,7 @@ import {TextField} from "ui/text-field";
import {Switch} from "ui/switch";
import {Slider} from "ui/slider";
import {Color} from "color";
+import {ScrollView} from "ui/scroll-view";
import * as platform from "platform";
var availableTransitions = ["default", "custom", "flip", "flipRight", "flipLeft", "slide", "slideLeft", "slideRight", "slideTop", "slideBottom", "fade"];
@@ -57,6 +58,10 @@ export class NavPage extends Page implements definition.ControlsPage {
});
that.on(Page.navigatedToEvent, (args) => {
console.log(`${args.object}.navigatedToEvent`);
+ (topmostFrame())._printFrameBackStack();
+ if (topmostFrame().android) {
+ (topmostFrame())._printNativeBackStack();
+ }
});
this.id = "" + context.index;
@@ -122,6 +127,14 @@ export class NavPage extends Page implements definition.ControlsPage {
animatedSwitch.checked = context.animated;
optionsLayout.addChild(animatedSwitch);
+ var globalTransitionButton = new Button();
+ globalTransitionButton.text = "global: " + (Frame.defaultTransition ? Frame.defaultTransition.name : "none");
+ globalTransitionButton.on("tap", (args) => {
+ Frame.defaultTransition = Frame.defaultTransition ? null : { name: "fade" };
+ (args.object).text = "global: " + (Frame.defaultTransition ? Frame.defaultTransition.name : "none");
+ });
+ optionsLayout.addChild(globalTransitionButton);
+
var transitionButton = new Button();
transitionButton.text = availableTransitions[context.transition];
transitionButton.on("tap", () => {
@@ -202,6 +215,8 @@ export class NavPage extends Page implements definition.ControlsPage {
});
stackLayout.addChild(forwardButton);
- this.content = stackLayout;
+ var scrollView = new ScrollView();
+ scrollView.content = stackLayout;
+ this.content = scrollView;
}
}
diff --git a/apps/tests/navigation/navigation-tests.ts b/apps/tests/navigation/navigation-tests.ts
index 659a3bce2..ee1a7bff1 100644
--- a/apps/tests/navigation/navigation-tests.ts
+++ b/apps/tests/navigation/navigation-tests.ts
@@ -1,6 +1,6 @@
import * as TKUnit from "../TKUnit";
import {Page} from "ui/page";
-import {topmost as topmostFrame} from "ui/frame";
+import {topmost as topmostFrame, NavigationTransition} from "ui/frame";
import {Color} from "color";
// Creates a random colorful page full of meaningless stuff.
@@ -10,32 +10,41 @@ var pageFactory = function(): Page {
return page;
};
-export var test_backstackVisible = function () {
- var mainTestPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== mainTestPage; });
+function _test_backstackVisible(transition?: NavigationTransition) {
+ let topmost = topmostFrame();
+ let mainTestPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== mainTestPage; });
// page1 should not be added to the backstack
- var page0 = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory, backstackVisible: false });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== page0; });
+ let page0 = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, backstackVisible: false, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== page0; });
- var page1 = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== page1; });
+ let page1 = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== page1; });
- var page2 = topmostFrame().currentPage;
- topmostFrame().goBack();
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== page2; });
+ let page2 = topmost.currentPage;
+ topmost.goBack();
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== page2; });
// From page2 we have to go directly to page0, skipping page1.
- TKUnit.assert(topmostFrame().currentPage === page0, "Page 1 should be skipped when going back.");
+ TKUnit.assert(topmost.currentPage === page0, "Page 1 should be skipped when going back.");
- topmostFrame().goBack();
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage === mainTestPage; });
+ topmost.goBack();
+ TKUnit.waitUntilReady(() => { return topmost.currentPage === mainTestPage; });
}
-export var test_backToEntry = function () {
+export var test_backstackVisible = function () {
+ _test_backstackVisible();
+}
+
+export var test_backstackVisible_WithTransition = function () {
+ _test_backstackVisible({name: "fade"});
+}
+
+function _test_backToEntry(transition?: NavigationTransition) {
let page = (tag) => () => {
var p = new Page();
p["tag"] = tag;
@@ -44,7 +53,7 @@ export var test_backToEntry = function () {
let topmost = topmostFrame();
let wait = tag => TKUnit.waitUntilReady(() => topmost.currentPage["tag"] === tag, 1);
let navigate = tag => {
- topmost.navigate({ create: page(tag) });
+ topmost.navigate({ create: page(tag), transition: transition });
wait(tag)
}
let back = pages => {
@@ -75,42 +84,93 @@ export var test_backToEntry = function () {
back(1);
}
-// Clearing the history messes up the tests app.
-export var test_ClearHistory = function () {
- var mainTestPage = topmostFrame().currentPage;
- var mainPageFactory = function (): Page {
+export var test_backToEntry = function () {
+ _test_backToEntry();
+}
+
+export var test_backToEntry_WithTransition = function () {
+ _test_backToEntry({name: "flip"});
+}
+
+function _test_ClearHistory(transition?: NavigationTransition) {
+ let topmost = topmostFrame();
+ let mainTestPage = topmost.currentPage;
+ let mainPageFactory = function (): Page {
return mainTestPage;
};
var currentPage: Page;
- currentPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory, clearHistory: true });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== currentPage; });
+ currentPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, clearHistory: true, transition: transition});
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== currentPage; });
- currentPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== currentPage; });
+ currentPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== currentPage; });
- currentPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== currentPage; });
+ currentPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== currentPage; });
- currentPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== currentPage; });
+ currentPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== currentPage; });
- TKUnit.assert(topmostFrame().canGoBack(), "Frame should be able to go back.");
- TKUnit.assert(topmostFrame().backStack.length === 3, "Back stack should have 3 entries.");
+ TKUnit.assert(topmost.canGoBack(), "Frame should be able to go back.");
+ TKUnit.assert(topmost.backStack.length === 3, "Back stack should have 3 entries.");
// Navigate with clear history.
- currentPage = topmostFrame().currentPage;
- topmostFrame().navigate({ create: pageFactory, clearHistory: true });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage !== currentPage; });
+ currentPage = topmost.currentPage;
+ topmost.navigate({ create: pageFactory, clearHistory: true, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== currentPage; });
- TKUnit.assert(!topmostFrame().canGoBack(), "Frame should NOT be able to go back.");
- TKUnit.assert(topmostFrame().backStack.length === 0, "Back stack should have 0 entries.");
+ TKUnit.assert(!topmost.canGoBack(), "Frame should NOT be able to go back.");
+ TKUnit.assert(topmost.backStack.length === 0, "Back stack should have 0 entries.");
- topmostFrame().navigate({ create: mainPageFactory });
- TKUnit.waitUntilReady(() => { return topmostFrame().currentPage === mainTestPage; });
+ topmost.navigate({ create: mainPageFactory, transition: transition });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage === mainTestPage; });
+}
+
+// Clearing the history messes up the tests app.
+export var test_ClearHistory = function () {
+ _test_ClearHistory();
+}
+
+export var test_ClearHistory_WithTransition = function () {
+ _test_ClearHistory({ name: "slide" });
+}
+
+// Test case for https://github.com/NativeScript/NativeScript/issues/1948
+export var test_ClearHistoryWithTransitionDoesNotBreakNavigation = function () {
+ let topmost = topmostFrame();
+
+ let mainTestPage = topmost.currentPage;
+ let mainPageFactory = function (): Page {
+ return mainTestPage;
+ };
+
+ // Go to details-page
+ topmost.navigate({ create: pageFactory, clearHistory: false });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== mainTestPage; });
+
+ // Go back to main-page with clearHistory
+ var detailsPage: Page;
+ detailsPage = topmost.currentPage;
+ topmost.transition = { name: "fade" };
+ topmost.navigate({ create: mainPageFactory, clearHistory: true });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage === mainTestPage; });
+
+ // Go to details-page AGAIN
+ topmost.navigate({ create: pageFactory, clearHistory: false });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage !== mainTestPage; });
+
+ // Go back to main-page with clearHistory
+ detailsPage = topmost.currentPage;
+ topmost.transition = { name: "fade" };
+ topmost.navigate({ create: mainPageFactory, clearHistory: true });
+ TKUnit.waitUntilReady(() => { return topmost.currentPage === mainTestPage; });
+
+ // Clean up
+ topmost.transition = undefined;
}
diff --git a/ui/frame/frame-common.ts b/ui/frame/frame-common.ts
index 0354cab0d..0070b5646 100644
--- a/ui/frame/frame-common.ts
+++ b/ui/frame/frame-common.ts
@@ -431,6 +431,17 @@ export class Frame extends CustomLayoutView implements definition.Frame {
public _removeViewFromNativeVisualTree(child: View): void {
child._isAddedToNativeVisualTree = false;
}
+
+ public _printFrameBackStack() {
+ var length = this.backStack.length;
+ var i = length - 1;
+ console.log("---------------------------");
+ console.log("Frame Back Stack (" + length + ")");
+ while (i >= 0) {
+ var backstackEntry = this.backStack[i--];
+ console.log("[ " + backstackEntry.resolvedPage.id + " ]");
+ }
+ }
}
var _topmost = function (): Frame {
diff --git a/ui/frame/frame.android.ts b/ui/frame/frame.android.ts
index 5393c585b..88c77fe08 100644
--- a/ui/frame/frame.android.ts
+++ b/ui/frame/frame.android.ts
@@ -65,8 +65,9 @@ function onFragmentHidden(fragment: FragmentClass) {
trace.write(`HIDDEN ${fragment.getTag()}`, trace.categories.NativeLifecycle);
if (fragment[CLEARING_HISTORY]) {
- trace.write(`${fragment.getTag()} has been hidden, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle);
- return null;
+ trace.write(`${fragment.getTag()} has been hidden, but we are currently clearing history. Clearing any existing transitions.`, trace.categories.NativeLifecycle);
+ transitionModule._clearBackwardTransitions(fragment);
+ transitionModule._clearForwardTransitions(fragment);
}
var isBack = fragment.entry[IS_BACK];
@@ -188,10 +189,10 @@ export class Frame extends frameCommon.Frame {
if (currentFragment) {
// There might be transitions left over from previous forward navigations from the current page.
transitionModule._clearForwardTransitions(currentFragment);
- }
- if (animated && navigationTransition) {
- transitionModule._setAndroidFragmentTransitions(navigationTransition, currentFragment, newFragment, fragmentTransaction);
+ if (animated && navigationTransition) {
+ transitionModule._setAndroidFragmentTransitions(navigationTransition, currentFragment, newFragment, fragmentTransaction);
+ }
}
newFragment.frame = this;
@@ -328,17 +329,6 @@ export class Frame extends frameCommon.Frame {
}
}
- public _printFrameBackStack() {
- var length = this.backStack.length;
- var i = length - 1;
- console.log("---------------------------");
- console.log("Frame Back Stack (" + length + ")");
- while (i >= 0) {
- var backstackEntry = this.backStack[i--];
- console.log("[ " + backstackEntry.resolvedPage.id + " ]");
- }
- }
-
public _getNavBarVisible(page: pages.Page): boolean {
if (types.isDefined(page.actionBarHidden)) {
return !page.actionBarHidden;
diff --git a/ui/transition/transition.android.ts b/ui/transition/transition.android.ts
index 20829e2b6..010bb7b48 100644
--- a/ui/transition/transition.android.ts
+++ b/ui/transition/transition.android.ts
@@ -25,6 +25,26 @@ export module AndroidTransitionType {
export var popExit: string = "popExit";
}
+export function _clearBackwardTransitions(fragment: any): void {
+ if (fragment[ENTER_POPEXIT_TRANSITION]) {
+ trace.write(`Cleared ENTER_POPEXIT_TRANSITION ${fragment[ENTER_POPEXIT_TRANSITION]} for ${fragment.getTag()}`, trace.categories.Transition);
+ fragment[ENTER_POPEXIT_TRANSITION] = undefined;
+ }
+
+ if (_sdkVersion >= 21) {
+ var enterTransition = (fragment).getEnterTransition();
+ if (enterTransition) {
+ trace.write(`Cleared Enter ${enterTransition.getClass().getSimpleName()} transition for ${fragment.getTag()}`, trace.categories.Transition);
+ (fragment).setEnterTransition(null);
+ }
+ var returnTransition = (fragment).getReturnTransition();
+ if (returnTransition) {
+ trace.write(`Cleared Pop Exit ${returnTransition.getClass().getSimpleName()} transition for ${fragment.getTag()}`, trace.categories.Transition);
+ (fragment).setReturnTransition(null);
+ }
+ }
+}
+
export function _clearForwardTransitions(fragment: any): void {
if (fragment[EXIT_POPENTER_TRANSITION]) {
trace.write(`Cleared EXIT_POPENTER_TRANSITION ${fragment[EXIT_POPENTER_TRANSITION]} for ${fragment.getTag()}`, trace.categories.Transition);
@@ -265,9 +285,11 @@ function _completePageRemoval(fragment: android.app.Fragment, force: boolean = f
if (page.frame) {
frame._removeView(page);
page.onNavigatedFrom(isBack);
+ trace.write(`REMOVAL of ${page} completed`, trace.categories.Transition);
+ }
+ else {
+ trace.write(`REMOVAL of ${page} has already been done`, trace.categories.Transition);
}
-
- trace.write(`REMOVAL of ${page} completed`, trace.categories.Transition);
}
}
diff --git a/ui/transition/transition.d.ts b/ui/transition/transition.d.ts
index aba7adb17..1c5f38bde 100644
--- a/ui/transition/transition.d.ts
+++ b/ui/transition/transition.d.ts
@@ -18,6 +18,7 @@
}
//@private
+ export function _clearBackwardTransitions(fragment: any): void;
export function _clearForwardTransitions(fragment: any): void;
export function _setAndroidFragmentTransitions(navigationTransition: frame.NavigationTransition, currentFragment: any, newFragment: any, fragmentTransaction: any): void;
export function _onFragmentCreateAnimator(fragment: any, nextAnim: number): any;