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

@@ -25,110 +25,7 @@ var navDepth = -1;
var activityInitialized = false;
var animationFixed;
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) {
function onFragmentShown(fragment: FragmentClass) {
trace.write(`SHOWN ${fragment.getTag()}`, trace.categories.NativeLifecycle);
if (fragment[CLEARING_HISTORY]) {
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;
let currentNavigationContext;
let navigationQueue = frame._navigationQueue;
let navigationQueue = (<any>frame)._navigationQueue;
for (let i = 0; i < navigationQueue.length; i++) {
if (navigationQueue[i].entry === entry) {
currentNavigationContext = navigationQueue[i];
@@ -165,7 +62,7 @@ function onFragmentShown(fragment) {
transitionModule._onFragmentShown(fragment, isBack);
}
function onFragmentHidden(fragment) {
function onFragmentHidden(fragment: FragmentClass) {
trace.write(`HIDDEN ${fragment.getTag()}`, trace.categories.NativeLifecycle);
if (fragment[CLEARING_HISTORY]) {
@@ -175,7 +72,7 @@ function onFragmentHidden(fragment) {
var isBack = fragment.entry[IS_BACK];
fragment.entry[IS_BACK] = undefined;
// Handle page transitions.
transitionModule._onFragmentHidden(fragment, isBack);
}
@@ -281,7 +178,6 @@ export class Frame extends frameCommon.Frame {
}
var newFragmentTag = "fragment" + navDepth;
ensureFragmentClass();
let newFragment = new FragmentClass();
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 framesCache: Array<WeakRef<AndroidFrame>> = new Array<WeakRef<AndroidFrame>>();
@@ -803,6 +527,260 @@ function getFrameById(frameId: number): Frame {
return null;
}
export function getActivity(): Object {
return NativeActivity;
var animationFixed;
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
function reloadPage(): void;
function resolvePageFromEntry(entry: NavigationEntry): pages.Page;
function getActivity(): Object;
//@endprivate
}