FrameClass implemented as TypeScript class

NativeActivity is now NativeScriptActivity and is real class
Added NativeScriptApplication class
Added JavaProxy attribute to FrameClass, NativeScriptActivity & NativeScriptApplication
This commit is contained in:
Hristo Hristov
2016-02-29 09:57:45 +02:00
parent 22631ce102
commit 6273bb8d2f
7 changed files with 316 additions and 358 deletions

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptToolsVersion>1.7</TypeScriptToolsVersion> <TypeScriptToolsVersion>1.8</TypeScriptToolsVersion>
<ProjectGuid>{2313F1BF-1F2D-4F11-806A-87927FA6A7C0}</ProjectGuid> <ProjectGuid>{2313F1BF-1F2D-4F11-806A-87927FA6A7C0}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>

View File

@ -8,6 +8,34 @@ import * as fileResolverModule from "file-system/file-name-resolver";
global.moduleMerge(appModule, exports); global.moduleMerge(appModule, exports);
var typedExports: typeof definition = exports; var typedExports: typeof definition = exports;
@JavaProxy("com.tns.NativeScriptApplication")
class NativeScriptApplication extends android.app.Application {
constructor() {
super();
return global.__native(this);
}
public onCreate(): void {
androidApp.init(this);
setupOrientationListener(androidApp);
}
public onLowMemory(): void {
gc();
java.lang.System.gc();
super.onLowMemory();
typedExports.notify(<definition.ApplicationEventData>{ eventName: typedExports.lowMemoryEvent, object: this, android: this });
}
public onTrimMemory(level: number): void {
gc();
java.lang.System.gc();
super.onTrimMemory(level);
}
}
// We are using the exports object for the common events since we merge the appModule with this module's exports, which is what users will receive when require("application") is called; // We are using the exports object for the common events since we merge the appModule with this module's exports, which is what users will receive when require("application") is called;
// TODO: This is kind of hacky and is "pure JS in TypeScript" // TODO: This is kind of hacky and is "pure JS in TypeScript"
@ -15,13 +43,8 @@ function initEvents() {
// TODO: Verify whether the logic for triggerring application-wide events based on Activity callbacks is working properly // TODO: Verify whether the logic for triggerring application-wide events based on Activity callbacks is working properly
var lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({ var lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({
onActivityCreated: function (activity: any, bundle: any) { onActivityCreated: function (activity: any, bundle: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
if (!androidApp.startActivity) { if (!androidApp.startActivity) {
androidApp.startActivity = activity; androidApp.startActivity = activity;
androidApp.notify(<definition.AndroidActivityBundleEventData>{ eventName: "activityCreated", object: androidApp, activity: activity, bundle: bundle }); androidApp.notify(<definition.AndroidActivityBundleEventData>{ eventName: "activityCreated", object: androidApp, activity: activity, bundle: bundle });
if (androidApp.onActivityCreated) { if (androidApp.onActivityCreated) {
@ -33,9 +56,6 @@ function initEvents() {
}, },
onActivityDestroyed: function (activity: any) { onActivityDestroyed: function (activity: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
// Clear the current activity reference to prevent leak // Clear the current activity reference to prevent leak
if (activity === androidApp.foregroundActivity) { if (activity === androidApp.foregroundActivity) {
@ -67,10 +87,6 @@ function initEvents() {
}, },
onActivityPaused: function (activity: any) { onActivityPaused: function (activity: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
androidApp.paused = true; androidApp.paused = true;
if (activity === androidApp.foregroundActivity) { if (activity === androidApp.foregroundActivity) {
@ -89,10 +105,6 @@ function initEvents() {
}, },
onActivityResumed: function (activity: any) { onActivityResumed: function (activity: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
androidApp.paused = false; androidApp.paused = false;
if (activity === androidApp.foregroundActivity) { if (activity === androidApp.foregroundActivity) {
@ -111,10 +123,6 @@ function initEvents() {
}, },
onActivitySaveInstanceState: function (activity: any, bundle: any) { onActivitySaveInstanceState: function (activity: any, bundle: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
androidApp.notify(<definition.AndroidActivityBundleEventData>{ eventName: "saveActivityState", object: androidApp, activity: activity, bundle: bundle }); androidApp.notify(<definition.AndroidActivityBundleEventData>{ eventName: "saveActivityState", object: androidApp, activity: activity, bundle: bundle });
if (androidApp.onSaveActivityState) { if (androidApp.onSaveActivityState) {
@ -123,10 +131,6 @@ function initEvents() {
}, },
onActivityStarted: function (activity: any) { onActivityStarted: function (activity: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
androidApp.foregroundActivity = activity; androidApp.foregroundActivity = activity;
androidApp.notify(<definition.AndroidActivityEventData>{ eventName: "activityStarted", object: androidApp, activity: activity }); androidApp.notify(<definition.AndroidActivityEventData>{ eventName: "activityStarted", object: androidApp, activity: activity });
@ -137,10 +141,6 @@ function initEvents() {
}, },
onActivityStopped: function (activity: any) { onActivityStopped: function (activity: any) {
if (!(activity instanceof (<any>com).tns.NativeScriptActivity)) {
return;
}
androidApp.notify(<definition.AndroidActivityEventData>{ eventName: "activityStopped", object: androidApp, activity: activity }); androidApp.notify(<definition.AndroidActivityEventData>{ eventName: "activityStopped", object: androidApp, activity: activity });
if (androidApp.onActivityStopped) { if (androidApp.onActivityStopped) {
@ -152,7 +152,7 @@ function initEvents() {
return lifecycleCallbacks; return lifecycleCallbacks;
} }
export class AndroidApplication extends observable.Observable implements definition.AndroidApplication { class AndroidApplication extends observable.Observable implements definition.AndroidApplication {
public static activityCreatedEvent = "activityCreated"; public static activityCreatedEvent = "activityCreated";
public static activityDestroyedEvent = "activityDestroyed"; public static activityDestroyedEvent = "activityDestroyed";
public static activityStartedEvent = "activityStarted"; public static activityStartedEvent = "activityStarted";
@ -190,10 +190,6 @@ export class AndroidApplication extends observable.Observable implements definit
private _eventsToken: any; private _eventsToken: any;
public getActivity(intent: android.content.Intent): Object {
return frame.getActivity();
}
public init(nativeApp: any) { public init(nativeApp: any) {
this.nativeApp = nativeApp; this.nativeApp = nativeApp;
this.packageName = nativeApp.getPackageName(); this.packageName = nativeApp.getPackageName();
@ -245,6 +241,10 @@ export class AndroidApplication extends observable.Observable implements definit
} }
} }
var androidApp = new AndroidApplication();
// use the exports object instead of 'export var' due to global namespace collision
typedExports.android = androidApp;
var BroadcastReceiverClass; var BroadcastReceiverClass;
function ensureBroadCastReceiverClass() { function ensureBroadCastReceiverClass() {
if (BroadcastReceiverClass) { if (BroadcastReceiverClass) {
@ -270,21 +270,6 @@ function ensureBroadCastReceiverClass() {
BroadcastReceiverClass = BroadcastReceiver; BroadcastReceiverClass = BroadcastReceiver;
} }
global.__onUncaughtError = function (error: definition.NativeScriptError) {
var types: typeof typesModule = require("utils/types");
// TODO: Obsolete this
if (types.isFunction(typedExports.onUncaughtError)) {
typedExports.onUncaughtError(error);
}
typedExports.notify({ eventName: typedExports.uncaughtErrorEvent, object: appModule.android, android: error });
}
function loadCss() {
typedExports.cssSelectorsCache = typedExports.loadCss(typedExports.cssFile);
}
var started = false; var started = false;
export function start(entry?: frame.NavigationEntry) { export function start(entry?: frame.NavigationEntry) {
if (started) { if (started) {
@ -292,31 +277,13 @@ export function start(entry?: frame.NavigationEntry) {
} }
started = true; started = true;
if (entry) { if (entry) {
typedExports.mainEntry = entry; typedExports.mainEntry = entry;
} }
// this should be the first call, to avoid issues when someone accesses the Application singleton prior to extending its onCreate method
app.init({
getActivity: function (activity: android.app.Activity) {
var intent = activity.getIntent()
return androidApp.getActivity(intent);
},
onCreate: function () {
androidApp.init(this);
setupOrientationListener(androidApp);
}
});
loadCss(); loadCss();
} }
var androidApp = new AndroidApplication();
// use the exports object instead of 'export var' due to global namespace collision
typedExports.android = androidApp;
var currentOrientation: number; var currentOrientation: number;
function setupOrientationListener(androidApp: AndroidApplication) { function setupOrientationListener(androidApp: AndroidApplication) {
androidApp.registerBroadcastReceiver(android.content.Intent.ACTION_CONFIGURATION_CHANGED, onConfigurationChanged); androidApp.registerBroadcastReceiver(android.content.Intent.ACTION_CONFIGURATION_CHANGED, onConfigurationChanged);
@ -353,6 +320,10 @@ function onConfigurationChanged(context: android.content.Context, intent: androi
} }
} }
function loadCss() {
typedExports.cssSelectorsCache = typedExports.loadCss(typedExports.cssFile);
}
global.__onLiveSync = function () { global.__onLiveSync = function () {
if (typedExports.android && typedExports.android.paused) { if (typedExports.android && typedExports.android.paused) {
return; return;
@ -368,4 +339,15 @@ global.__onLiveSync = function () {
// Reload current page. // Reload current page.
frame.reloadPage(); frame.reloadPage();
}
global.__onUncaughtError = function (error: definition.NativeScriptError) {
var types: typeof typesModule = require("utils/types");
// TODO: Obsolete this
if (types.isFunction(typedExports.onUncaughtError)) {
typedExports.onUncaughtError(error);
}
typedExports.notify({ eventName: typedExports.uncaughtErrorEvent, object: appModule.android, android: error });
} }

View File

@ -347,13 +347,6 @@ declare module "application" {
*/ */
paused: boolean; paused: boolean;
/**
* This method is called by the JavaScript Bridge when navigation to a new activity is triggered.
* @param intent - Native (android) intent used to create the activity.
* Returns com.tns.NativeScriptActivity.extend implementation.
*/
getActivity(intent: any /* android.content.Intent */): any;
/** /**
* [Deprecated. Please use the respective event instead.] Direct handler of the [onActivityCreated method](http://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html). * [Deprecated. Please use the respective event instead.] Direct handler of the [onActivityCreated method](http://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html).
*/ */

6
declarations.d.ts vendored
View File

@ -105,6 +105,12 @@ declare var require: NativeScriptRequire;
declare function Deprecated(target: Object, key?: string | symbol, value?: any): void; declare function Deprecated(target: Object, key?: string | symbol, value?: any): void;
declare function Experimental(target: Object, key?: string | symbol, value?: any): void; declare function Experimental(target: Object, key?: string | symbol, value?: any): void;
/**
* Decorates class that extends native Java class
* @param nativeClassName The name of the newly generated class. Must be unique in the application.
*/
declare function JavaProxy(nativeClassName: string): ClassDecorator;
declare function Log(data: any): void; declare function Log(data: any): void;
declare function log(data: any): void; declare function log(data: any): void;
declare function float(num: number): any; declare function float(num: number): any;

View File

@ -102,7 +102,7 @@ if (platform.device.os === platform.platformNames.android) {
if (typeof global.__decorate !== "function") { if (typeof global.__decorate !== "function") {
global.__decorate = function (decorators, target, key, desc) { global.__decorate = function (decorators, target, key, desc) {
var c = arguments.length var c = arguments.length;
var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") { if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") {

View File

@ -25,110 +25,7 @@ var navDepth = -1;
var activityInitialized = false; var activityInitialized = false;
var animationFixed; function onFragmentShown(fragment: FragmentClass) {
function ensureAnimationFixed() {
if (!animationFixed) {
animationFixed = android.os.Build.VERSION.SDK_INT >= 19 // android.os.Build.VERSION.KITKAT but we don't have definition for it
? 1 : -1;
}
}
var FragmentClass;
function ensureFragmentClass() {
if (FragmentClass) {
return;
}
FragmentClass = (<any>android.app.Fragment).extend({
onCreate: function (savedInstanceState: android.os.Bundle) {
trace.write(`${this.getTag()}.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle);
this.super.onCreate(savedInstanceState);
this.super.setHasOptionsMenu(true);
// There is no entry set to the fragment, so this must be destroyed fragment that was recreated by Android.
// We should find its corresponding page in our backstack and set it manually.
if (!(<any>this).entry) {
let frameId = (<android.app.Fragment>this).getArguments().getInt(FRAMEID);
let frame = getFrameById(frameId);
if (frame) {
this.frame = frame;
}
else {
throw new Error(`Cannot find Frame for ${this}`);
}
findPageForFragment(this, this.frame);
}
},
onCreateView: function (inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
trace.write(`${this.getTag()}.onCreateView(inflater, container, ${savedInstanceState})`, trace.categories.NativeLifecycle);
var entry = this.entry;
var page = entry.resolvedPage;
if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) {
this.super.getFragmentManager().beginTransaction().hide(this).commit();
page._onAttached(this.getActivity());
}
else {
onFragmentShown(this);
}
return page._nativeView;
},
onHiddenChanged: function (hidden: boolean) {
trace.write(`${this.getTag()}.onHiddenChanged(${hidden})`, trace.categories.NativeLifecycle);
this.super.onHiddenChanged(hidden);
if (hidden) {
onFragmentHidden(this);
}
else {
onFragmentShown(this);
}
},
onSaveInstanceState: function (outState: android.os.Bundle) {
trace.write(`${this.getTag()}.onSaveInstanceState(${outState})`, trace.categories.NativeLifecycle);
this.super.onSaveInstanceState(outState);
if (this.isHidden()) {
outState.putBoolean(HIDDEN, true);
}
},
onDestroyView: function () {
trace.write(`${this.getTag()}.onDestroyView()`, trace.categories.NativeLifecycle);
this.super.onDestroyView();
onFragmentHidden(this);
// When Fragment is destroyed we detach page even if cachePagesOnNavigate is true.
let entry: definition.BackstackEntry = this.entry;
let page = entry.resolvedPage;
if (page._context) {
page._onDetached(true);
}
},
onDestroy: function () {
trace.write(`${this.getTag()}.onDestroy()`, trace.categories.NativeLifecycle);
this.super.onDestroy();
utils.GC();
},
onCreateAnimator: function (transit: number, enter: boolean, nextAnim: number): android.animation.Animator {
var animator = transitionModule._onFragmentCreateAnimator(this, nextAnim);
if (!animator) {
animator = this.super.onCreateAnimator(transit, enter, nextAnim);
}
trace.write(`${this.getTag()}.onCreateAnimator(${transit}, ${enter}, ${nextAnim}): ${animator}`, trace.categories.NativeLifecycle);
return animator;
}
});
}
function onFragmentShown(fragment) {
trace.write(`SHOWN ${fragment.getTag()}`, trace.categories.NativeLifecycle); trace.write(`SHOWN ${fragment.getTag()}`, trace.categories.NativeLifecycle);
if (fragment[CLEARING_HISTORY]) { if (fragment[CLEARING_HISTORY]) {
trace.write(`${fragment.getTag()} has been shown, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle); trace.write(`${fragment.getTag()} has been shown, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle);
@ -142,7 +39,7 @@ function onFragmentShown(fragment) {
var page: pages.Page = entry.resolvedPage; var page: pages.Page = entry.resolvedPage;
let currentNavigationContext; let currentNavigationContext;
let navigationQueue = frame._navigationQueue; let navigationQueue = (<any>frame)._navigationQueue;
for (let i = 0; i < navigationQueue.length; i++) { for (let i = 0; i < navigationQueue.length; i++) {
if (navigationQueue[i].entry === entry) { if (navigationQueue[i].entry === entry) {
currentNavigationContext = navigationQueue[i]; currentNavigationContext = navigationQueue[i];
@ -165,7 +62,7 @@ function onFragmentShown(fragment) {
transitionModule._onFragmentShown(fragment, isBack); transitionModule._onFragmentShown(fragment, isBack);
} }
function onFragmentHidden(fragment) { function onFragmentHidden(fragment: FragmentClass) {
trace.write(`HIDDEN ${fragment.getTag()}`, trace.categories.NativeLifecycle); trace.write(`HIDDEN ${fragment.getTag()}`, trace.categories.NativeLifecycle);
if (fragment[CLEARING_HISTORY]) { if (fragment[CLEARING_HISTORY]) {
@ -175,7 +72,7 @@ function onFragmentHidden(fragment) {
var isBack = fragment.entry[IS_BACK]; var isBack = fragment.entry[IS_BACK];
fragment.entry[IS_BACK] = undefined; fragment.entry[IS_BACK] = undefined;
// Handle page transitions. // Handle page transitions.
transitionModule._onFragmentHidden(fragment, isBack); transitionModule._onFragmentHidden(fragment, isBack);
} }
@ -281,7 +178,6 @@ export class Frame extends frameCommon.Frame {
} }
var newFragmentTag = "fragment" + navDepth; var newFragmentTag = "fragment" + navDepth;
ensureFragmentClass();
let newFragment = new FragmentClass(); let newFragment = new FragmentClass();
let args = new android.os.Bundle(); let args = new android.os.Bundle();
@ -454,178 +350,6 @@ export class Frame extends frameCommon.Frame {
} }
} }
var NativeActivity = {
get rootView(): View {
return this[ROOT_VIEW];
},
onCreate: function (savedInstanceState: android.os.Bundle) {
trace.write(`NativeScriptActivity.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle);
let app = application.android;
let activity: android.app.Activity = this;
let intent = activity.getIntent();
if (application.onLaunch) {
application.onLaunch(intent);
}
let args: application.LaunchEventData = { eventName: application.launchEvent, object: app, android: intent };
application.notify(args);
let frameId = -1;
let rootView = args.root;
let extras = intent.getExtras();
// We have extras when we call - new Frame().navigate();
// savedInstanceState is used when activity is recreated.
if (extras) {
frameId = extras.getInt(INTENT_EXTRA, -1);
}
else if (savedInstanceState) {
frameId = savedInstanceState.getInt(INTENT_EXTRA, -1)
}
// 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)
// Only then we fallback to the view returned from the event. This is done in order to have backwards compatibility (remove it for 2.0.0).
let frame: Frame;
let navParam;
if (frameId >= 0) {
rootView = getFrameById(frameId);
}
else if (!rootView) {
navParam = application.mainEntry;
if (!navParam) {
navParam = application.mainModule;
}
if (navParam) {
frame = new Frame();
} else {
// TODO: Throw an exception?
throw new Error("A Frame must be used to navigate to a Page.");
}
rootView = frame;
}
// If there is savedInstanceState this call will recreate all fragments that were previously in the navigation.
// We take care of associating them with a Page from our backstack in the onAttachFragment callback.
// If there is savedInstanceState and activityInitialized is false we are restarted but process was killed.
// For now we treat it like first run (e.g. we are not passing savedInstanceState so no fragments are being restored).
// When we add support for application save/load state - revise this logic.
var isRestart = !!savedInstanceState && activityInitialized;
this.super.onCreate(isRestart ? savedInstanceState : null);
this[ROOT_VIEW] = rootView;
// Initialize native visual tree;
rootView._onAttached(this);
this.setContentView(rootView._nativeView, new org.nativescript.widgets.CommonLayoutParams());
// frameId is negative w
if (frame) {
frame.navigate(navParam);
}
activityInitialized = true;
// TODO: If the above fails because we call fragmentManager.beginTransition().commit() before
// we are added as content to activity - add if (rootview instanceof Frame) -> call navigate
//this.frame._onActivityCreated(isRestart);
},
onSaveInstanceState(outState: android.os.Bundle): void {
this.super.onSaveInstanceState(outState);
let view = this.rootView;
if (view instanceof Frame) {
outState.putInt(INTENT_EXTRA, (<Frame>view).android.frameId);
}
},
onActivityResult: function (requestCode: number, resultCode: number, data: android.content.Intent) {
this.super.onActivityResult(requestCode, resultCode, data);
trace.write(`NativeScriptActivity.onActivityResult(${requestCode}, ${resultCode}, ${data})`, trace.categories.NativeLifecycle);
var result = application.android.onActivityResult;
if (result) {
result(requestCode, resultCode, data);
}
application.android.notify(<application.AndroidActivityResultEventData>{
eventName: "activityResult",
object: application.android,
activity: this,
requestCode: requestCode,
resultCode: resultCode,
intent: data
});
},
onStart: function () {
this.super.onStart();
trace.write("NativeScriptActivity.onStart();", trace.categories.NativeLifecycle);
let rootView: View = this.rootView
if (rootView && !rootView.isLoaded) {
rootView.onLoaded();
}
},
onStop: function () {
this.super.onStop();
trace.write("NativeScriptActivity.onStop();", trace.categories.NativeLifecycle);
let rootView: View = this.rootView
if (rootView && rootView.isLoaded) {
rootView.onUnloaded();
}
},
onDestroy: function () {
let rootView: View = this.rootView
if (rootView && rootView._context) {
rootView._onDetached(true);
}
this.super.onDestroy();
trace.write("NativeScriptActivity.onDestroy();", trace.categories.NativeLifecycle);
},
onBackPressed: function () {
trace.write("NativeScriptActivity.onBackPressed;", trace.categories.NativeLifecycle);
var args = <application.AndroidActivityBackPressedEventData>{
eventName: "activityBackPressed",
object: application.android,
activity: this,
cancel: false,
};
application.android.notify(args);
if (args.cancel) {
return;
}
if (!frameCommon.goBack()) {
this.super.onBackPressed();
}
},
onLowMemory: function () {
trace.write("NativeScriptActivity.onLowMemory()", trace.categories.NativeLifecycle);
gc();
java.lang.System.gc();
this.super.onLowMemory();
application.notify(<application.ApplicationEventData>{ eventName: application.lowMemoryEvent, object: this, android: this });
},
onTrimMemory: function (level: number) {
trace.write(`NativeScriptActivity.onTrimMemory(${level})`, trace.categories.NativeLifecycle);
gc();
java.lang.System.gc();
this.super.onTrimMemory(level);
}
};
var framesCounter = 0; var framesCounter = 0;
var framesCache: Array<WeakRef<AndroidFrame>> = new Array<WeakRef<AndroidFrame>>(); var framesCache: Array<WeakRef<AndroidFrame>> = new Array<WeakRef<AndroidFrame>>();
@ -803,6 +527,260 @@ function getFrameById(frameId: number): Frame {
return null; return null;
} }
export function getActivity(): Object { var animationFixed;
return NativeActivity; function ensureAnimationFixed() {
if (!animationFixed) {
// android.os.Build.VERSION.KITKAT but we don't have definition for it
animationFixed = android.os.Build.VERSION.SDK_INT >= 19 ? 1 : -1;
}
} }
@JavaProxy("com.tns.FragmentClass")
class FragmentClass extends android.app.Fragment {
public frame: Frame;
public entry: definition.BackstackEntry;
constructor() {
super();
return global.__native(this);
}
public onHiddenChanged(hidden: boolean): void {
trace.write(`${this.getTag()}.onHiddenChanged(${hidden})`, trace.categories.NativeLifecycle);
super.onHiddenChanged(hidden);
if (hidden) {
onFragmentHidden(this);
}
else {
onFragmentShown(this);
}
}
public onCreateAnimator(transit: number, enter: boolean, nextAnim: number): android.animation.Animator {
var animator = transitionModule._onFragmentCreateAnimator(this, nextAnim);
if (!animator) {
animator = super.onCreateAnimator(transit, enter, nextAnim);
}
trace.write(`${this.getTag()}.onCreateAnimator(${transit}, ${enter}, ${nextAnim}): ${animator}`, trace.categories.NativeLifecycle);
return animator;
}
public onCreate(savedInstanceState: android.os.Bundle): void {
trace.write(`${this.getTag()}.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle);
super.onCreate(savedInstanceState);
super.setHasOptionsMenu(true);
// There is no entry set to the fragment, so this must be destroyed fragment that was recreated by Android.
// We should find its corresponding page in our backstack and set it manually.
if (!this.entry) {
let frameId = this.getArguments().getInt(FRAMEID);
let frame = getFrameById(frameId);
if (frame) {
this.frame = frame;
}
else {
throw new Error(`Cannot find Frame for ${this}`);
}
findPageForFragment(this, this.frame);
}
}
public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
trace.write(`${this.getTag()}.onCreateView(inflater, container, ${savedInstanceState})`, trace.categories.NativeLifecycle);
var entry = this.entry;
var page = entry.resolvedPage;
if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) {
this.getFragmentManager().beginTransaction().hide(this).commit();
page._onAttached(this.getActivity());
}
else {
onFragmentShown(this);
}
return page._nativeView;
}
public onSaveInstanceState(outState: android.os.Bundle): void {
trace.write(`${this.getTag()}.onSaveInstanceState(${outState})`, trace.categories.NativeLifecycle);
super.onSaveInstanceState(outState);
if (this.isHidden()) {
outState.putBoolean(HIDDEN, true);
}
}
public onDestroyView(): void {
trace.write(`${this.getTag()}.onDestroyView()`, trace.categories.NativeLifecycle);
super.onDestroyView();
onFragmentHidden(this);
// When Fragment is destroyed we detach page even if cachePagesOnNavigate is true.
let entry = this.entry;
let page = entry.resolvedPage;
if (page._context) {
page._onDetached(true);
}
}
public onDestroy(): void {
trace.write(`${this.getTag()}.onDestroy()`, trace.categories.NativeLifecycle);
super.onDestroy();
utils.GC();
}
}
@JavaProxy("com.tns.NativeScriptActivity")
class NativeScriptActivity extends android.app.Activity {
private rootView: View;
constructor() {
super();
return global.__native(this);
}
protected onCreate(savedInstanceState: android.os.Bundle): void {
trace.write(`NativeScriptActivity.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle);
let app = application.android;
let intent = this.getIntent();
if (application.onLaunch) {
application.onLaunch(intent);
}
let args: application.LaunchEventData = { eventName: application.launchEvent, object: app, android: intent };
application.notify(args);
let frameId = -1;
let rootView = args.root;
let extras = intent.getExtras();
// We have extras when we call - new Frame().navigate();
// savedInstanceState is used when activity is recreated.
if (extras) {
frameId = extras.getInt(INTENT_EXTRA, -1);
}
else if (savedInstanceState) {
frameId = savedInstanceState.getInt(INTENT_EXTRA, -1)
}
// 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)
// Only then we fallback to the view returned from the event. This is done in order to have backwards compatibility (remove it for 2.0.0).
let frame: Frame;
let navParam;
if (frameId >= 0) {
rootView = getFrameById(frameId);
}
else if (!rootView) {
navParam = application.mainEntry;
if (!navParam) {
navParam = application.mainModule;
}
if (navParam) {
frame = new Frame();
} else {
// TODO: Throw an exception?
throw new Error("A Frame must be used to navigate to a Page.");
}
rootView = frame;
}
// If there is savedInstanceState this call will recreate all fragments that were previously in the navigation.
// We take care of associating them with a Page from our backstack in the onAttachFragment callback.
// If there is savedInstanceState and activityInitialized is false we are restarted but process was killed.
// For now we treat it like first run (e.g. we are not passing savedInstanceState so no fragments are being restored).
// When we add support for application save/load state - revise this logic.
var isRestart = !!savedInstanceState && activityInitialized;
super.onCreate(isRestart ? savedInstanceState : null);
this[ROOT_VIEW] = rootView;
// Initialize native visual tree;
rootView._onAttached(this);
this.setContentView(rootView._nativeView, new org.nativescript.widgets.CommonLayoutParams());
// frameId is negative w
if (frame) {
frame.navigate(navParam);
}
activityInitialized = true;
}
protected onSaveInstanceState(outState: android.os.Bundle): void {
super.onSaveInstanceState(outState);
let view = this.rootView;
if (view instanceof Frame) {
outState.putInt(INTENT_EXTRA, view.android.frameId);
}
}
protected onStart(): void {
super.onStart();
trace.write("NativeScriptActivity.onStart();", trace.categories.NativeLifecycle);
let rootView = this.rootView
if (rootView && !rootView.isLoaded) {
rootView.onLoaded();
}
}
protected onStop(): void {
super.onStop();
trace.write("NativeScriptActivity.onStop();", trace.categories.NativeLifecycle);
let rootView = this.rootView
if (rootView && rootView.isLoaded) {
rootView.onUnloaded();
}
}
protected onDestroy(): void {
let rootView = this.rootView
if (rootView && rootView._context) {
rootView._onDetached(true);
}
super.onDestroy();
trace.write("NativeScriptActivity.onDestroy();", trace.categories.NativeLifecycle);
}
public onBackPressed(): void {
trace.write("NativeScriptActivity.onBackPressed;", trace.categories.NativeLifecycle);
var args = <application.AndroidActivityBackPressedEventData>{
eventName: "activityBackPressed",
object: application.android,
activity: this,
cancel: false,
};
application.android.notify(args);
if (args.cancel) {
return;
}
if (!frameCommon.goBack()) {
super.onBackPressed();
}
}
protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void {
super.onActivityResult(requestCode, resultCode, data);
trace.write(`NativeScriptActivity.onActivityResult(${requestCode}, ${resultCode}, ${data})`, trace.categories.NativeLifecycle);
var result = application.android.onActivityResult;
if (result) {
result(requestCode, resultCode, data);
}
application.android.notify(<application.AndroidActivityResultEventData>{
eventName: "activityResult",
object: application.android,
activity: this,
requestCode: requestCode,
resultCode: resultCode,
intent: data
});
}
}

1
ui/frame/frame.d.ts vendored
View File

@ -310,6 +310,5 @@ declare module "ui/frame" {
//@private //@private
function reloadPage(): void; function reloadPage(): void;
function resolvePageFromEntry(entry: NavigationEntry): pages.Page; function resolvePageFromEntry(entry: NavigationEntry): pages.Page;
function getActivity(): Object;
//@endprivate //@endprivate
} }