mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
feat: Add methods to get the root view and set a different root view at run time (#5386)
* feat: add option to set a different root view at run time * feat: expose application getRootView method * refactor: Introduce ViewEntry interface * fix: Respect root view rturned from launch event in Android * refactor: getRootView() code + caching root view per activity. * refactor: add app-root.xml in apps * refactor: http test made async
This commit is contained in:

committed by
Alexander Vakrilov

parent
0c8275fa06
commit
b113b0021a
1
apps/app/ui-tests-app/app-root.xml
Normal file
1
apps/app/ui-tests-app/app-root.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<Frame defaultPage="ui-tests-app/main-page" />
|
@ -1,13 +1,11 @@
|
|||||||
console.log("####### ------ APP MODULES START ")
|
console.log("####### ------ APP MODULES START ");
|
||||||
|
|
||||||
import * as application from "tns-core-modules/application";
|
import * as application from "tns-core-modules/application";
|
||||||
import * as trace from "tns-core-modules/trace";
|
import * as trace from "tns-core-modules/trace";
|
||||||
|
trace.addCategories(trace.categories.NativeLifecycle);
|
||||||
|
trace.addCategories(trace.categories.Navigation);
|
||||||
|
trace.addCategories(trace.categories.Transition);
|
||||||
trace.enable();
|
trace.enable();
|
||||||
trace.setCategories(trace.categories.concat(
|
|
||||||
trace.categories.NativeLifecycle,
|
|
||||||
trace.categories.Navigation,
|
|
||||||
trace.categories.Transition
|
|
||||||
));
|
|
||||||
|
|
||||||
var countResume = 0;
|
var countResume = 0;
|
||||||
var countSuspend = 0;
|
var countSuspend = 0;
|
||||||
@ -25,7 +23,7 @@ application.on("uncaughtError", args => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.launchEvent, function (args: application.ApplicationEventData) {
|
application.on(application.launchEvent, function(args: application.LaunchEventData) {
|
||||||
if (args.android) {
|
if (args.android) {
|
||||||
// For Android applications, args.android is an android.content.Intent class.
|
// For Android applications, args.android is an android.content.Intent class.
|
||||||
console.log("### Launched application with: " + args.android + ".");
|
console.log("### Launched application with: " + args.android + ".");
|
||||||
@ -35,7 +33,7 @@ application.on(application.launchEvent, function (args: application.ApplicationE
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.suspendEvent, function (args: application.ApplicationEventData) {
|
application.on(application.suspendEvent, function(args: application.ApplicationEventData) {
|
||||||
if (args.android) {
|
if (args.android) {
|
||||||
// For Android applications, args.android is an android activity class.
|
// For Android applications, args.android is an android activity class.
|
||||||
console.log("#" + ++countSuspend + "# SuspendEvent Activity: " + args.android);
|
console.log("#" + ++countSuspend + "# SuspendEvent Activity: " + args.android);
|
||||||
@ -45,7 +43,7 @@ application.on(application.suspendEvent, function (args: application.Application
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.resumeEvent, function (args: application.ApplicationEventData) {
|
application.on(application.resumeEvent, function(args: application.ApplicationEventData) {
|
||||||
if (args.android) {
|
if (args.android) {
|
||||||
// For Android applications, args.android is an android activity class.
|
// For Android applications, args.android is an android activity class.
|
||||||
console.log("#" + ++countResume + "# ResumeEvent Activity: " + args.android);
|
console.log("#" + ++countResume + "# ResumeEvent Activity: " + args.android);
|
||||||
@ -55,7 +53,7 @@ application.on(application.resumeEvent, function (args: application.ApplicationE
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.exitEvent, function (args: application.ApplicationEventData) {
|
application.on(application.exitEvent, function(args: application.ApplicationEventData) {
|
||||||
if (args.android) {
|
if (args.android) {
|
||||||
// For Android applications, args.android is an android activity class.
|
// For Android applications, args.android is an android activity class.
|
||||||
console.log("### ExitEvent Activity: " + args.android);
|
console.log("### ExitEvent Activity: " + args.android);
|
||||||
@ -65,7 +63,7 @@ application.on(application.exitEvent, function (args: application.ApplicationEve
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.lowMemoryEvent, function (args: application.ApplicationEventData) {
|
application.on(application.lowMemoryEvent, function(args: application.ApplicationEventData) {
|
||||||
if (args.android) {
|
if (args.android) {
|
||||||
// For Android applications, args.android is an android activity class.
|
// For Android applications, args.android is an android activity class.
|
||||||
console.log("### LowMemoryEvent Activity: " + args.android);
|
console.log("### LowMemoryEvent Activity: " + args.android);
|
||||||
@ -75,12 +73,15 @@ application.on(application.lowMemoryEvent, function (args: application.Applicati
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.on(application.uncaughtErrorEvent, function (args: application.UnhandledErrorEventData) {
|
application.on(application.uncaughtErrorEvent, function(args: application.UnhandledErrorEventData) {
|
||||||
console.log("### NativeScriptError: " + args.error);
|
console.log("### NativeScriptError: " + args.error);
|
||||||
console.log("### nativeException: " + (<any>args.error).nativeException);
|
console.log("### nativeException: " + (<any>args.error).nativeException);
|
||||||
console.log("### stackTace: " + (<any>args.error).stackTrace);
|
console.log("### stackTrace: " + (<any>args.error).stackTrace);
|
||||||
console.log("### stack: " + args.error.stack);
|
console.log("### stack: " + args.error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
application.setCssFileName("ui-tests-app/app.css");
|
application.setCssFileName("ui-tests-app/app.css");
|
||||||
|
|
||||||
application.start({ moduleName: "ui-tests-app/main-page" });
|
application.start({ moduleName: "ui-tests-app/main-page" });
|
||||||
|
// application.run({ moduleName: "ui-tests-app/app-root" });
|
||||||
|
// application.run();
|
||||||
|
@ -634,20 +634,12 @@ export var test_request_jsonAsContentSentAndReceivedProperly = function (done) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
declare var Worker: any;
|
declare var Worker: any;
|
||||||
export var test_getString_WorksProperlyInWorker = function () {
|
export var test_getString_WorksProperlyInWorker = function(done) {
|
||||||
var ready;
|
let worker = new Worker("./http-string-worker");
|
||||||
|
worker.onmessage = function(msg) {
|
||||||
var worker = new Worker("./http-string-worker");
|
done();
|
||||||
|
};
|
||||||
worker.onmessage = function (msg) {
|
worker.onerror = function(e) {
|
||||||
TKUnit.assert(typeof msg.data === "string", "Result from getString() should be valid string object!");
|
done(e);
|
||||||
ready = true;
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
worker.onerror = function (e) {
|
|
||||||
ready = true;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
TKUnit.waitUntilReady(() => ready);
|
|
||||||
}
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
require("globals");
|
require("globals");
|
||||||
|
|
||||||
import { Observable, EventData } from "../data/observable";
|
import { Observable, EventData } from "../data/observable";
|
||||||
|
// types
|
||||||
|
import { View } from "../ui/core/view";
|
||||||
import {
|
import {
|
||||||
trace as profilingTrace,
|
trace as profilingTrace,
|
||||||
time,
|
time,
|
||||||
|
@ -13,7 +13,8 @@ import { profile } from "../profiling";
|
|||||||
// First reexport so that app module is initialized.
|
// First reexport so that app module is initialized.
|
||||||
export * from "./application-common";
|
export * from "./application-common";
|
||||||
|
|
||||||
import { NavigationEntry } from "../ui/frame";
|
// types
|
||||||
|
import { NavigationEntry, View, AndroidActivityCallbacks } from "../ui/frame";
|
||||||
|
|
||||||
const ActivityCreated = "activityCreated";
|
const ActivityCreated = "activityCreated";
|
||||||
const ActivityDestroyed = "activityDestroyed";
|
const ActivityDestroyed = "activityDestroyed";
|
||||||
@ -53,7 +54,7 @@ export class AndroidApplication extends Observable implements AndroidApplication
|
|||||||
if (this.nativeApp === nativeApp) {
|
if (this.nativeApp === nativeApp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.nativeApp) {
|
if (this.nativeApp) {
|
||||||
throw new Error("application.android already initialized.");
|
throw new Error("application.android already initialized.");
|
||||||
}
|
}
|
||||||
@ -148,10 +149,35 @@ export function run(entry?: NavigationEntry | string) {
|
|||||||
start(entry);
|
start(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CALLBACKS = "_callbacks";
|
||||||
|
|
||||||
|
export function _resetRootView(entry?: NavigationEntry | string) {
|
||||||
|
const activity = androidApp.foregroundActivity;
|
||||||
|
if (!activity) {
|
||||||
|
throw new Error("Cannot find android activity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mainEntry = typeof entry === "string" ? { moduleName: entry } : entry;
|
||||||
|
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
|
||||||
|
callbacks.resetActivityContent(activity);
|
||||||
|
}
|
||||||
|
|
||||||
export function getMainEntry() {
|
export function getMainEntry() {
|
||||||
return mainEntry;
|
return mainEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRootView() {
|
||||||
|
// Use start activity as a backup when foregroundActivity is still not set
|
||||||
|
// in cases when we are getting the root view before activity.onResumed event is fired
|
||||||
|
const activity = androidApp.foregroundActivity || androidApp.startActivity;
|
||||||
|
if (!activity) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
|
||||||
|
|
||||||
|
return callbacks ? callbacks.getRootView() : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function getNativeApplication(): android.app.Application {
|
export function getNativeApplication(): android.app.Application {
|
||||||
// Try getting it from module - check whether application.android.init has been explicitly called
|
// Try getting it from module - check whether application.android.init has been explicitly called
|
||||||
let nativeApp = androidApp.nativeApp;
|
let nativeApp = androidApp.nativeApp;
|
||||||
@ -202,11 +228,11 @@ function initLifecycleCallbacks() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const notifyActivityCreated = profile("notifyActivityCreated", function(activity: android.app.Activity, savedInstanceState: android.os.Bundle) {
|
const notifyActivityCreated = profile("notifyActivityCreated", function (activity: android.app.Activity, savedInstanceState: android.os.Bundle) {
|
||||||
androidApp.notify(<AndroidActivityBundleEventData>{ eventName: ActivityCreated, object: androidApp, activity, bundle: savedInstanceState });
|
androidApp.notify(<AndroidActivityBundleEventData>{ eventName: ActivityCreated, object: androidApp, activity, bundle: savedInstanceState });
|
||||||
});
|
});
|
||||||
|
|
||||||
const subscribeForGlobalLayout = profile("subscribeForGlobalLayout", function(activity: android.app.Activity) {
|
const subscribeForGlobalLayout = profile("subscribeForGlobalLayout", function (activity: android.app.Activity) {
|
||||||
const rootView = activity.getWindow().getDecorView().getRootView();
|
const rootView = activity.getWindow().getDecorView().getRootView();
|
||||||
let onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({
|
let onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({
|
||||||
onGlobalLayout() {
|
onGlobalLayout() {
|
||||||
|
11
tns-core-modules/application/application.d.ts
vendored
11
tns-core-modules/application/application.d.ts
vendored
@ -116,6 +116,11 @@ export interface CssChangedEventData extends EventData {
|
|||||||
*/
|
*/
|
||||||
export function getMainEntry(): NavigationEntry;
|
export function getMainEntry(): NavigationEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current application root view.
|
||||||
|
*/
|
||||||
|
export function getRootView(): View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get application level static resources.
|
* Get application level static resources.
|
||||||
*/
|
*/
|
||||||
@ -178,6 +183,12 @@ export function start(entry?: NavigationEntry | string);
|
|||||||
*/
|
*/
|
||||||
export function run(entry?: NavigationEntry | string);
|
export function run(entry?: NavigationEntry | string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this method to change the root view of your application. Important: Your application must already be running.
|
||||||
|
* This method won't create Frame as root view.
|
||||||
|
*/
|
||||||
|
export function _resetRootView(entry?: NavigationEntry | string);
|
||||||
|
|
||||||
//@private
|
//@private
|
||||||
/**
|
/**
|
||||||
* Internal method use to check if a root Frame should be automatically created as root view.
|
* Internal method use to check if a root Frame should be automatically created as root view.
|
||||||
|
@ -100,6 +100,10 @@ class IOSApplication implements IOSApplicationDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rootView() : View {
|
||||||
|
return this._rootView;
|
||||||
|
}
|
||||||
|
|
||||||
public addNotificationObserver(notificationName: string, onReceiveCallback: (notification: NSNotification) => void): NotificationObserver {
|
public addNotificationObserver(notificationName: string, onReceiveCallback: (notification: NSNotification) => void): NotificationObserver {
|
||||||
const observer = NotificationObserver.initWithCallback(onReceiveCallback);
|
const observer = NotificationObserver.initWithCallback(onReceiveCallback);
|
||||||
utils.ios.getter(NSNotificationCenter, NSNotificationCenter.defaultCenter).addObserverSelectorNameObject(observer, "onReceive", notificationName, null);
|
utils.ios.getter(NSNotificationCenter, NSNotificationCenter.defaultCenter).addObserverSelectorNameObject(observer, "onReceive", notificationName, null);
|
||||||
@ -263,6 +267,10 @@ export function getMainEntry() {
|
|||||||
return mainEntry;
|
return mainEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRootView() {
|
||||||
|
return iosApp.rootView;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: for backwards compatibility. Remove for 4.0.0.
|
// NOTE: for backwards compatibility. Remove for 4.0.0.
|
||||||
let createRootFrame = true;
|
let createRootFrame = true;
|
||||||
let started: boolean = false;
|
let started: boolean = false;
|
||||||
@ -296,6 +304,12 @@ export function run(entry?: string | NavigationEntry) {
|
|||||||
start(entry);
|
start(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function _resetRootView(entry?: NavigationEntry | string) {
|
||||||
|
createRootFrame = false;
|
||||||
|
mainEntry = typeof entry === "string" ? { moduleName: entry } : entry;
|
||||||
|
iosApp.setWindowContent();
|
||||||
|
}
|
||||||
|
|
||||||
export function getNativeApplication(): UIApplication {
|
export function getNativeApplication(): UIApplication {
|
||||||
return iosApp.nativeApp;
|
return iosApp.nativeApp;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Definitions.
|
// Definitions.
|
||||||
import { LoadOptions } from ".";
|
import { LoadOptions } from ".";
|
||||||
import { View, ViewBase, Template, KeyedTemplate } from "../core/view";
|
import { View, ViewBase, Template, KeyedTemplate } from "../core/view";
|
||||||
import { NavigationEntry } from "../frame";
|
import { ViewEntry } from "../frame";
|
||||||
|
|
||||||
// Types.
|
// Types.
|
||||||
import { debug, ScopeError, SourceError, Source } from "../../utils/debug";
|
import { debug, ScopeError, SourceError, Source } from "../../utils/debug";
|
||||||
@ -62,7 +62,7 @@ export function loadPage(moduleNamePath: string, fileName: string, context?: any
|
|||||||
return componentModule && componentModule.component;
|
return componentModule && componentModule.component;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadModule = profile("loadModule", (moduleNamePath: string, entry: NavigationEntry): ModuleExports => {
|
const loadModule = profile("loadModule", (moduleNamePath: string, entry: ViewEntry): ModuleExports => {
|
||||||
// web-pack case where developers register their page JS file manually.
|
// web-pack case where developers register their page JS file manually.
|
||||||
if (global.moduleExists(entry.moduleName)) {
|
if (global.moduleExists(entry.moduleName)) {
|
||||||
return global.loadModule(entry.moduleName);
|
return global.loadModule(entry.moduleName);
|
||||||
@ -94,7 +94,7 @@ const viewFromBuilder = profile("viewFromBuilder", (moduleNamePath: string, modu
|
|||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
|
||||||
export const createViewFromEntry = profile("createViewFromEntry", (entry: NavigationEntry): View => {
|
export const createViewFromEntry = profile("createViewFromEntry", (entry: ViewEntry): View => {
|
||||||
if (entry.create) {
|
if (entry.create) {
|
||||||
return createView(entry);
|
return createView(entry);
|
||||||
} else if (entry.moduleName) {
|
} else if (entry.moduleName) {
|
||||||
@ -116,7 +116,7 @@ export const createViewFromEntry = profile("createViewFromEntry", (entry: Naviga
|
|||||||
throw new Error("Failed to load page XML file for module: " + entry.moduleName);
|
throw new Error("Failed to load page XML file for module: " + entry.moduleName);
|
||||||
});
|
});
|
||||||
|
|
||||||
const createView = profile("entry.create", (entry: NavigationEntry): View => {
|
const createView = profile("entry.create", (entry: ViewEntry): View => {
|
||||||
const view = entry.create();
|
const view = entry.create();
|
||||||
if (!view) {
|
if (!view) {
|
||||||
throw new Error("Failed to create Page with entry.create() function.");
|
throw new Error("Failed to create Page with entry.create() function.");
|
||||||
|
@ -19,7 +19,7 @@ class NativeScriptActivity extends android.app.Activity {
|
|||||||
appModule.android.init(this.getApplication());
|
appModule.android.init(this.getApplication());
|
||||||
|
|
||||||
// Set isNativeScriptActivity in onCreate.
|
// Set isNativeScriptActivity in onCreate.
|
||||||
// The JS construcotr might not be called beacuse the activity is created from Andoird.
|
// The JS constructor might not be called because the activity is created from Android.
|
||||||
this.isNativeScriptActivity = true;
|
this.isNativeScriptActivity = true;
|
||||||
if (!this._callbacks) {
|
if (!this._callbacks) {
|
||||||
setActivityCallbacks(this);
|
setActivityCallbacks(this);
|
||||||
|
@ -25,10 +25,12 @@ import { createViewFromEntry } from "../builder";
|
|||||||
export * from "./frame-common";
|
export * from "./frame-common";
|
||||||
|
|
||||||
const INTENT_EXTRA = "com.tns.activity";
|
const INTENT_EXTRA = "com.tns.activity";
|
||||||
|
const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId";
|
||||||
const FRAMEID = "_frameId";
|
const FRAMEID = "_frameId";
|
||||||
const CALLBACKS = "_callbacks";
|
const CALLBACKS = "_callbacks";
|
||||||
|
|
||||||
const ownerSymbol = Symbol("_owner");
|
const ownerSymbol = Symbol("_owner");
|
||||||
|
const activityRootViewsMap = new Map<number, WeakRef<View>>();
|
||||||
|
|
||||||
let navDepth = -1;
|
let navDepth = -1;
|
||||||
let fragmentId = -1;
|
let fragmentId = -1;
|
||||||
@ -73,11 +75,12 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function reloadPage(): void {
|
export function reloadPage(): void {
|
||||||
const app = application.android;
|
const activity = application.android.foregroundActivity;
|
||||||
const rootView: View = (<any>app).rootView;
|
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
|
||||||
|
const rootView: View = callbacks.getRootView();
|
||||||
|
|
||||||
if (!rootView || !rootView._onLivesync()) {
|
if (!rootView || !rootView._onLivesync()) {
|
||||||
// Delete previously cached root view in order to recreate it.
|
callbacks.resetActivityContent(activity);
|
||||||
resetActivityContent(application.android.foregroundActivity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +291,7 @@ export class Frame extends FrameBase {
|
|||||||
const newFragment = this.createFragment(newEntry, newFragmentTag);
|
const newFragment = this.createFragment(newEntry, newFragmentTag);
|
||||||
const transaction = manager.beginTransaction();
|
const transaction = manager.beginTransaction();
|
||||||
const animated = this._getIsAnimatedNavigation(newEntry.entry);
|
const animated = this._getIsAnimatedNavigation(newEntry.entry);
|
||||||
// NOTE: Don't use transition for the initial nagivation (same as on iOS)
|
// NOTE: Don't use transition for the initial navigation (same as on iOS)
|
||||||
// On API 21+ transition won't be triggered unless there was at least one
|
// On API 21+ transition won't be triggered unless there was at least one
|
||||||
// layout pass so we will wait forever for transitionCompleted handler...
|
// layout pass so we will wait forever for transitionCompleted handler...
|
||||||
// https://github.com/NativeScript/NativeScript/issues/4895
|
// https://github.com/NativeScript/NativeScript/issues/4895
|
||||||
@ -754,7 +757,11 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
||||||
public _rootView: View;
|
private _rootView: View;
|
||||||
|
|
||||||
|
public getRootView(): View {
|
||||||
|
return this._rootView;
|
||||||
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onCreate(activity: android.app.Activity, savedInstanceState: android.os.Bundle, superFunc: Function): void {
|
public onCreate(activity: android.app.Activity, savedInstanceState: android.os.Bundle, superFunc: Function): void {
|
||||||
@ -770,18 +777,29 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
let isRestart = !!savedInstanceState && moduleLoaded;
|
let isRestart = !!savedInstanceState && moduleLoaded;
|
||||||
superFunc.call(activity, isRestart ? savedInstanceState : null);
|
superFunc.call(activity, isRestart ? savedInstanceState : null);
|
||||||
|
|
||||||
setActivityContent(activity, savedInstanceState);
|
// Try to get the rootViewId form the saved state in case the activity
|
||||||
|
// was destroyed and we are now recreating it.
|
||||||
|
if (savedInstanceState) {
|
||||||
|
const rootViewId = savedInstanceState.getInt(ROOT_VIEW_ID_EXTRA, -1);
|
||||||
|
if (rootViewId !== -1 && activityRootViewsMap.has(rootViewId)) {
|
||||||
|
this._rootView = activityRootViewsMap.get(rootViewId).get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setActivityContent(activity, savedInstanceState, true);
|
||||||
moduleLoaded = true;
|
moduleLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onSaveInstanceState(activity: android.app.Activity, outState: android.os.Bundle, superFunc: Function): void {
|
public onSaveInstanceState(activity: android.app.Activity, outState: android.os.Bundle, superFunc: Function): void {
|
||||||
superFunc.call(activity, outState);
|
superFunc.call(activity, outState);
|
||||||
const frame = this._rootView;
|
const rootView = this._rootView;
|
||||||
if (frame instanceof Frame) {
|
if (rootView instanceof Frame) {
|
||||||
outState.putInt(INTENT_EXTRA, frame.android.frameId);
|
outState.putInt(INTENT_EXTRA, rootView.android.frameId);
|
||||||
frame._saveFragmentsState();
|
rootView._saveFragmentsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outState.putInt(ROOT_VIEW_ID_EXTRA, rootView._domId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
@ -870,7 +888,13 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onRequestPermissionsResult(activity: any, requestCode: number, permissions: Array<String>, grantResults: Array<number>, superFunc: Function): void {
|
public onRequestPermissionsResult(
|
||||||
|
activity: any,
|
||||||
|
requestCode: number,
|
||||||
|
permissions: Array<String>,
|
||||||
|
grantResults: Array<number>,
|
||||||
|
superFunc: Function
|
||||||
|
): void {
|
||||||
if (traceEnabled()) {
|
if (traceEnabled()) {
|
||||||
traceWrite("NativeScriptActivity.onRequestPermissionsResult;", traceCategories.NativeLifecycle);
|
traceWrite("NativeScriptActivity.onRequestPermissionsResult;", traceCategories.NativeLifecycle);
|
||||||
}
|
}
|
||||||
@ -886,7 +910,13 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onActivityResult(activity: any, requestCode: number, resultCode: number, data: android.content.Intent, superFunc: Function): void {
|
public onActivityResult(
|
||||||
|
activity: any,
|
||||||
|
requestCode: number,
|
||||||
|
resultCode: number,
|
||||||
|
data: android.content.Intent,
|
||||||
|
superFunc: Function
|
||||||
|
): void {
|
||||||
superFunc.call(activity, requestCode, resultCode, data);
|
superFunc.call(activity, requestCode, resultCode, data);
|
||||||
if (traceEnabled()) {
|
if (traceEnabled()) {
|
||||||
traceWrite(`NativeScriptActivity.onActivityResult(${requestCode}, ${resultCode}, ${data})`, traceCategories.NativeLifecycle);
|
traceWrite(`NativeScriptActivity.onActivityResult(${requestCode}, ${resultCode}, ${data})`, traceCategories.NativeLifecycle);
|
||||||
@ -901,78 +931,98 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
intent: data
|
intent: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function resetActivityContent(activity: android.app.Activity): void {
|
public resetActivityContent(activity: android.app.Activity): void {
|
||||||
const callbacks: ActivityCallbacksImplementation = activity[CALLBACKS];
|
// Delete previously cached root view in order to recreate it.
|
||||||
const app = application.android;
|
this._rootView = null;
|
||||||
|
this.setActivityContent(activity, null, false);
|
||||||
|
this._rootView.callLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
// Delete previously cached root view in order to recreate it.
|
// Paths that go trough this method:
|
||||||
callbacks._rootView = (<any>app).rootView = null;
|
// 1. Application initial start - there is no rootView in callbacks.
|
||||||
setActivityContent(activity, null);
|
// 2. Application revived after Activity is destroyed. this._rootView should have been restored by id in onCreate.
|
||||||
callbacks._rootView.callLoaded();
|
// 3. Livesync if rootView has no custom _onLivesync. this._rootView should have been cleared upfront. Launch event should not fired
|
||||||
}
|
// 4. _resetRootView method. this._rootView should have been cleared upfront. Launch event should not fired
|
||||||
|
private setActivityContent(
|
||||||
|
activity: android.app.Activity,
|
||||||
|
savedInstanceState: android.os.Bundle,
|
||||||
|
fireLaunchEvent: boolean
|
||||||
|
): void {
|
||||||
|
const shouldCreateRootFrame = application.shouldCreateRootFrame();
|
||||||
|
let rootView = this._rootView;
|
||||||
|
|
||||||
function setActivityContent(activity: android.app.Activity, savedInstanceState: android.os.Bundle): void {
|
if (traceEnabled()) {
|
||||||
const callbacks: ActivityCallbacksImplementation = activity[CALLBACKS];
|
traceWrite(
|
||||||
|
`Frame.setActivityContent rootView: ${rootView} shouldCreateRootFrame: ${shouldCreateRootFrame} fireLaunchEvent: ${fireLaunchEvent}`,
|
||||||
const shouldCreateRootFrame = application.shouldCreateRootFrame();
|
traceCategories.NativeLifecycle
|
||||||
const app = application.android;
|
);
|
||||||
|
|
||||||
// TODO: this won't work if we open more than one activity!!!
|
|
||||||
let rootView = callbacks._rootView = (<any>app).rootView;
|
|
||||||
if (!rootView) {
|
|
||||||
const mainEntry = application.getMainEntry();
|
|
||||||
const intent = activity.getIntent();
|
|
||||||
rootView = notifyLaunch(intent, savedInstanceState);
|
|
||||||
if (shouldCreateRootFrame) {
|
|
||||||
const extras = intent.getExtras();
|
|
||||||
let frameId = -1;
|
|
||||||
|
|
||||||
// We have extras when we call - new Frame().navigate();
|
|
||||||
// savedInstanceState is used when activity is recreated.
|
|
||||||
// NOTE: On API 23+ we get extras on first run.
|
|
||||||
// Check changed - first try to get frameId from Extras if not from saveInstanceState.
|
|
||||||
if (extras) {
|
|
||||||
frameId = extras.getInt(INTENT_EXTRA, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (savedInstanceState && frameId < 0) {
|
|
||||||
frameId = savedInstanceState.getInt(INTENT_EXTRA, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rootView) {
|
|
||||||
// If we have frameId from extras - we are starting a new activity from navigation (e.g. new Frame().navigate()))
|
|
||||||
// Then we check if we have frameId from savedInstanceState - this happens when Activity is destroyed but app was not (e.g. suspend)
|
|
||||||
rootView = getFrameById(frameId) || new Frame();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rootView instanceof Frame) {
|
|
||||||
rootView.navigate(mainEntry);
|
|
||||||
} else {
|
|
||||||
throw new Error("A Frame must be used to navigate to a Page.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rootView = createViewFromEntry(mainEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks._rootView = (<any>app).rootView = rootView;
|
if (!rootView) {
|
||||||
}
|
const mainEntry = application.getMainEntry();
|
||||||
|
const intent = activity.getIntent();
|
||||||
|
|
||||||
// Initialize native visual tree;
|
if (fireLaunchEvent) {
|
||||||
if (shouldCreateRootFrame) {
|
rootView = notifyLaunch(intent, savedInstanceState);
|
||||||
// Don't setup as styleScopeHost
|
}
|
||||||
rootView._setupUI(activity);
|
|
||||||
} else {
|
|
||||||
// setup view as styleScopeHost
|
|
||||||
rootView._setupAsRootView(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
activity.setContentView(rootView.nativeViewProtected, new org.nativescript.widgets.CommonLayoutParams());
|
if (shouldCreateRootFrame) {
|
||||||
|
const extras = intent.getExtras();
|
||||||
|
let frameId = -1;
|
||||||
|
|
||||||
|
// We have extras when we call - new Frame().navigate();
|
||||||
|
// savedInstanceState is used when activity is recreated.
|
||||||
|
// NOTE: On API 23+ we get extras on first run.
|
||||||
|
// Check changed - first try to get frameId from Extras if not from saveInstanceState.
|
||||||
|
if (extras) {
|
||||||
|
frameId = extras.getInt(INTENT_EXTRA, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedInstanceState && frameId < 0) {
|
||||||
|
frameId = savedInstanceState.getInt(INTENT_EXTRA, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rootView) {
|
||||||
|
// If we have frameId from extras - we are starting a new activity from navigation (e.g. new Frame().navigate()))
|
||||||
|
// Then we check if we have frameId from savedInstanceState - this happens when Activity is destroyed but app was not (e.g. suspend)
|
||||||
|
rootView = getFrameById(frameId) || new Frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootView instanceof Frame) {
|
||||||
|
rootView.navigate(mainEntry);
|
||||||
|
} else {
|
||||||
|
throw new Error("A Frame must be used to navigate to a Page.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create the root view if the notifyLaunch didn't return it
|
||||||
|
rootView = rootView || createViewFromEntry(mainEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._rootView = rootView;
|
||||||
|
activityRootViewsMap.set(rootView._domId, new WeakRef(rootView));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize native visual tree;
|
||||||
|
if (shouldCreateRootFrame) {
|
||||||
|
// Don't setup as styleScopeHost
|
||||||
|
rootView._setupUI(activity);
|
||||||
|
} else {
|
||||||
|
// setup view as styleScopeHost
|
||||||
|
rootView._setupAsRootView(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.setContentView(rootView.nativeViewProtected, new org.nativescript.widgets.CommonLayoutParams());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notifyLaunch = profile("notifyLaunch", function notifyLaunch(intent: android.content.Intent, savedInstanceState: android.os.Bundle): View {
|
const notifyLaunch = profile("notifyLaunch", function notifyLaunch(intent: android.content.Intent, savedInstanceState: android.os.Bundle): View {
|
||||||
const launchArgs: application.LaunchEventData = { eventName: application.launchEvent, object: application.android, android: intent, savedInstanceState };
|
const launchArgs: application.LaunchEventData = {
|
||||||
|
eventName: application.launchEvent,
|
||||||
|
object: application.android,
|
||||||
|
android: intent, savedInstanceState
|
||||||
|
};
|
||||||
|
|
||||||
application.notify(launchArgs);
|
application.notify(launchArgs);
|
||||||
application.notify(<application.LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: application.getCssFileName() });
|
application.notify(<application.LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: application.getCssFileName() });
|
||||||
return launchArgs.root;
|
return launchArgs.root;
|
||||||
|
19
tns-core-modules/ui/frame/frame.d.ts
vendored
19
tns-core-modules/ui/frame/frame.d.ts
vendored
@ -187,19 +187,23 @@ export function goBack();
|
|||||||
export function stack(): Array<Frame>;
|
export function stack(): Array<Frame>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an entry in passed to navigate method.
|
* Represents an entry to be used to create a view or load it form file
|
||||||
*/
|
*/
|
||||||
export interface NavigationEntry {
|
export interface ViewEntry {
|
||||||
/**
|
/**
|
||||||
* The name of the module containing the Page instance to load. Optional.
|
* The name of the module containing the View instance to load. Optional.
|
||||||
*/
|
*/
|
||||||
moduleName?: string;
|
moduleName?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function used to create the Page instance. Optional.
|
* A function used to create the View instance. Optional.
|
||||||
*/
|
*/
|
||||||
create?: () => Page;
|
create?: () => View;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Represents an entry in passed to navigate method.
|
||||||
|
*/
|
||||||
|
export interface NavigationEntry extends ViewEntry {
|
||||||
/**
|
/**
|
||||||
* An object passed to the onNavigatedTo callback of the Page. Typically this is used to pass some data among pages. Optional.
|
* An object passed to the onNavigatedTo callback of the Page. Typically this is used to pass some data among pages. Optional.
|
||||||
*/
|
*/
|
||||||
@ -377,6 +381,9 @@ export interface AndroidFrame extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AndroidActivityCallbacks {
|
export interface AndroidActivityCallbacks {
|
||||||
|
getRootView(): View;
|
||||||
|
resetActivityContent(activity: any): void;
|
||||||
|
|
||||||
onCreate(activity: any, savedInstanceState: any, superFunc: Function): void;
|
onCreate(activity: any, savedInstanceState: any, superFunc: Function): void;
|
||||||
onSaveInstanceState(activity: any, outState: any, superFunc: Function): void;
|
onSaveInstanceState(activity: any, outState: any, superFunc: Function): void;
|
||||||
onStart(activity: any, superFunc: Function): void;
|
onStart(activity: any, superFunc: Function): void;
|
||||||
|
Reference in New Issue
Block a user