Merge branch 'master' into feat/webpack5

This commit is contained in:
Igor Randjelovic
2020-11-25 12:14:13 +01:00
9 changed files with 72 additions and 11 deletions

View File

@ -171,6 +171,40 @@ export function test_setInterval_callbackCalledWithExtraArgs(done) {
); );
} }
export function test_setInterval_callbackNotDelayedByBusyWork() {
let calls = 0;
let firstCall = true;
const id = timer.setInterval(() => {
calls++;
if (firstCall) {
firstCall = false;
TKUnit.wait(0.025);
}
}, 50);
TKUnit.wait(0.11);
timer.clearInterval(id);
TKUnit.assertEqual(calls, 2, 'Callback should be called multiple times with busy wait');
}
export function test_setInterval_callbackSkippedByBusyWork() {
let calls = 0;
let firstCall = true;
const id = timer.setInterval(() => {
calls++;
if (firstCall) {
firstCall = false;
TKUnit.wait(0.051);
}
}, 50);
TKUnit.wait(0.16);
timer.clearInterval(id);
TKUnit.assertEqual(calls, 2, 'Callback should be called skipped when it takes too long to process');
}
export function test_setInterval_callbackShouldBeCleared(done) { export function test_setInterval_callbackShouldBeCleared(done) {
const start = TKUnit.time(); const start = TKUnit.time();
// >> timer-set-interval // >> timer-set-interval

View File

@ -20,7 +20,7 @@ export interface ApplicationEventData extends EventData {
} }
export interface LaunchEventData extends ApplicationEventData { export interface LaunchEventData extends ApplicationEventData {
root?: View; root?: View | null;
savedInstanceState?: any /* android.os.Bundle */; savedInstanceState?: any /* android.os.Bundle */;
} }

View File

@ -191,7 +191,7 @@ export function addCss(cssText: string, attributeScoped?: boolean): void {
const CALLBACKS = '_callbacks'; const CALLBACKS = '_callbacks';
export function _resetRootView(entry?: NavigationEntry | string): void { export function _resetRootView(entry?: NavigationEntry | string): void {
const activity = androidApp.foregroundActivity; const activity = androidApp.foregroundActivity || androidApp.startActivity;
if (!activity) { if (!activity) {
throw new Error('Cannot find android activity.'); throw new Error('Cannot find android activity.');
} }

View File

@ -103,8 +103,9 @@ export interface LaunchEventData extends ApplicationEventData {
/** /**
* The root view for this Window on iOS or Activity for Android. * The root view for this Window on iOS or Activity for Android.
* If not set a new Frame will be created as a root view in order to maintain backwards compatibility. * If not set a new Frame will be created as a root view in order to maintain backwards compatibility.
* If explicitly set to null, there will be no root view.
*/ */
root?: View; root?: View | null;
savedInstanceState?: any /* android.os.Bundle */; savedInstanceState?: any /* android.os.Bundle */;
} }

View File

@ -207,7 +207,9 @@ export class iOSApplication implements iOSApplicationDefinition {
// this._window will be undefined when NS app is embedded in a native one // this._window will be undefined when NS app is embedded in a native one
if (this._window) { if (this._window) {
this.setWindowContent(args.root); if (args.root !== null) {
this.setWindowContent(args.root);
}
} else { } else {
this._window = UIApplication.sharedApplication.delegate.window; this._window = UIApplication.sharedApplication.delegate.window;
} }

View File

@ -12,6 +12,13 @@ export interface EventData {
object: Observable; object: Observable;
} }
export interface NotifyData extends Partial<EventData> {
eventName: string;
object?: Observable;
}
/** /**
* Data for the "propertyChange" event. * Data for the "propertyChange" event.
*/ */
@ -136,7 +143,7 @@ export class Observable {
* Notifies all the registered listeners for the event provided in the data.eventName. * Notifies all the registered listeners for the event provided in the data.eventName.
* @param data The data associated with the event. * @param data The data associated with the event.
*/ */
notify<T extends EventData>(data: T): void; notify<T extends NotifyData>(data: T): void;
/** /**
* Notifies all the registered listeners for the property change event. * Notifies all the registered listeners for the property change event.

View File

@ -5,6 +5,11 @@ export interface EventData {
object: Observable; object: Observable;
} }
export interface NotifyData extends Partial<EventData> {
eventName: string;
object?: Observable;
}
export interface PropertyChangeData extends EventData { export interface PropertyChangeData extends EventData {
propertyName: string; propertyName: string;
value: any; value: any;
@ -262,16 +267,18 @@ export class Observable implements ObservableDefinition {
} }
} }
public notify<T extends EventData>(data: T): void { public notify<T extends NotifyData>(data: T): void {
const eventData = data as EventData;
eventData.object = eventData.object || this;
const eventClass = this.constructor.name; const eventClass = this.constructor.name;
this._globalNotify(eventClass, 'First', data); this._globalNotify(eventClass, 'First', eventData);
const observers = <Array<ListenerEntry>>this._observers[data.eventName]; const observers = <Array<ListenerEntry>>this._observers[data.eventName];
if (observers) { if (observers) {
Observable._handleEvent(observers, data); Observable._handleEvent(observers, eventData);
} }
this._globalNotify(eventClass, '', data); this._globalNotify(eventClass, '', eventData);
} }
private static _handleEvent<T extends EventData>(observers: Array<ListenerEntry>, data: T): void { private static _handleEvent<T extends EventData>(observers: Array<ListenerEntry>, data: T): void {

View File

@ -58,12 +58,16 @@ export function setInterval(callback: Function, milliseconds = 0, ...args): numb
const handler = timeoutHandler; const handler = timeoutHandler;
const invoke = () => callback(...args); const invoke = () => callback(...args);
const zoneBound = zonedCallback(invoke); const zoneBound = zonedCallback(invoke);
const startOffset = milliseconds > 0 ? Date.now() % milliseconds : 0;
function nextCallMs() {
return milliseconds > 0 ? milliseconds - ((Date.now() - startOffset) % milliseconds) : milliseconds;
}
const runnable = new java.lang.Runnable({ const runnable = new java.lang.Runnable({
run: () => { run: () => {
zoneBound(); zoneBound();
if (timeoutCallbacks[id]) { if (timeoutCallbacks[id]) {
handler.postDelayed(runnable, long(milliseconds)); handler.postDelayed(runnable, long(nextCallMs()));
} }
}, },
}); });
@ -72,7 +76,7 @@ export function setInterval(callback: Function, milliseconds = 0, ...args): numb
timeoutCallbacks[id] = runnable; timeoutCallbacks[id] = runnable;
} }
timeoutHandler.postDelayed(runnable, long(milliseconds)); timeoutHandler.postDelayed(runnable, long(nextCallMs()));
return id; return id;
} }

View File

@ -1301,13 +1301,19 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
if (!rootView) { if (!rootView) {
const mainEntry = application.getMainEntry(); const mainEntry = application.getMainEntry();
const intent = activity.getIntent(); const intent = activity.getIntent();
// useful for integrations that would like to set rootView asynchronously after app launch
let shouldRootViewBeEmpty = false;
if (fireLaunchEvent) { if (fireLaunchEvent) {
// entry point for Angular and Vue frameworks // entry point for Angular and Vue frameworks
rootView = notifyLaunch(intent, <any>savedInstanceState, null); rootView = notifyLaunch(intent, <any>savedInstanceState, null);
shouldRootViewBeEmpty = rootView === null;
} }
if (!rootView) { if (!rootView) {
if (shouldRootViewBeEmpty) {
return;
}
// entry point for NS Core // entry point for NS Core
if (!mainEntry) { if (!mainEntry) {
// Also handles scenarios with Angular and Vue where the notifyLaunch didn't return a root view. // Also handles scenarios with Angular and Vue where the notifyLaunch didn't return a root view.