diff --git a/tests/app/navigation/custom-transition.android.ts b/tests/app/navigation/custom-transition.android.ts index 24434118f..d8f1b453d 100644 --- a/tests/app/navigation/custom-transition.android.ts +++ b/tests/app/navigation/custom-transition.android.ts @@ -5,8 +5,9 @@ export class CustomTransition extends transition.Transition { super(duration, curve); } - public createAndroidAnimator(transitionType: string): android.animation.Animator { - var scaleValues = Array.create("float", 2); + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + const scaleValues = []; + switch (transitionType) { case transition.AndroidTransitionType.enter: case transition.AndroidTransitionType.popEnter: @@ -19,18 +20,22 @@ export class CustomTransition extends transition.Transition { scaleValues[1] = 0; break; } - var objectAnimators = Array.create(android.animation.Animator, 2); - objectAnimators[0] = android.animation.ObjectAnimator.ofFloat(null, "scaleX", scaleValues); - objectAnimators[1] = android.animation.ObjectAnimator.ofFloat(null, "scaleY", scaleValues); - var animatorSet = new android.animation.AnimatorSet(); - animatorSet.playTogether(objectAnimators); - - var duration = this.getDuration(); + + const animationSet = new android.view.animation.AnimationSet(false); + const duration = this.getDuration(); if (duration !== undefined) { - animatorSet.setDuration(duration); + animationSet.setDuration(duration); } - animatorSet.setInterpolator(this.getCurve()); - return animatorSet; + animationSet.setInterpolator(this.getCurve()); + animationSet.addAnimation( + new android.view.animation.ScaleAnimation( + scaleValues[0], + scaleValues[1], + scaleValues[0], + scaleValues[1] + )); + + return animationSet; } } diff --git a/tns-core-modules/application/application.android.ts b/tns-core-modules/application/application.android.ts index a3eae29cd..0b33bba80 100644 --- a/tns-core-modules/application/application.android.ts +++ b/tns-core-modules/application/application.android.ts @@ -42,8 +42,8 @@ export class AndroidApplication extends Observable implements AndroidApplication public paused: boolean; public nativeApp: android.app.Application; public context: android.content.Context; - public foregroundActivity: android.app.Activity; - public startActivity: android.app.Activity; + public foregroundActivity: android.support.v7.app.AppCompatActivity; + public startActivity: android.support.v7.app.AppCompatActivity; public packageName: string; // we are using these property to store the callbacks to avoid early GC collection which would trigger MarkReachableObjects private callbacks: any = {}; @@ -221,7 +221,7 @@ global.__onLiveSync = function () { }; function initLifecycleCallbacks() { - const setThemeOnLaunch = profile("setThemeOnLaunch", (activity: android.app.Activity) => { + const setThemeOnLaunch = profile("setThemeOnLaunch", (activity: android.support.v7.app.AppCompatActivity) => { // Set app theme after launch screen was used during startup const activityInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), android.content.pm.PackageManager.GET_META_DATA); if (activityInfo.metaData) { @@ -232,11 +232,11 @@ function initLifecycleCallbacks() { } }); - const notifyActivityCreated = profile("notifyActivityCreated", function (activity: android.app.Activity, savedInstanceState: android.os.Bundle) { + const notifyActivityCreated = profile("notifyActivityCreated", function (activity: android.support.v7.app.AppCompatActivity, savedInstanceState: android.os.Bundle) { androidApp.notify({ eventName: ActivityCreated, object: androidApp, activity, bundle: savedInstanceState }); }); - const subscribeForGlobalLayout = profile("subscribeForGlobalLayout", function (activity: android.app.Activity) { + const subscribeForGlobalLayout = profile("subscribeForGlobalLayout", function (activity: android.support.v7.app.AppCompatActivity) { const rootView = activity.getWindow().getDecorView().getRootView(); // store the listener not to trigger GC collection before collecting the method this.onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({ @@ -250,7 +250,7 @@ function initLifecycleCallbacks() { }); const lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({ - onActivityCreated: profile("onActivityCreated", function (activity: android.app.Activity, savedInstanceState: android.os.Bundle) { + onActivityCreated: profile("onActivityCreated", function (activity: android.support.v7.app.AppCompatActivity, savedInstanceState: android.os.Bundle) { setThemeOnLaunch(activity); if (!androidApp.startActivity) { @@ -264,7 +264,7 @@ function initLifecycleCallbacks() { } }), - onActivityDestroyed: profile("onActivityDestroyed", function (activity: android.app.Activity) { + onActivityDestroyed: profile("onActivityDestroyed", function (activity: android.support.v7.app.AppCompatActivity) { if (activity === androidApp.foregroundActivity) { androidApp.foregroundActivity = undefined; } @@ -278,7 +278,7 @@ function initLifecycleCallbacks() { gc(); }), - onActivityPaused: profile("onActivityPaused", function (activity: android.app.Activity) { + onActivityPaused: profile("onActivityPaused", function (activity: android.support.v7.app.AppCompatActivity) { if ((activity).isNativeScriptActivity) { androidApp.paused = true; notify({ eventName: suspendEvent, object: androidApp, android: activity }); @@ -287,7 +287,7 @@ function initLifecycleCallbacks() { androidApp.notify({ eventName: ActivityPaused, object: androidApp, activity: activity }); }), - onActivityResumed: profile("onActivityResumed", function (activity: android.app.Activity) { + onActivityResumed: profile("onActivityResumed", function (activity: android.support.v7.app.AppCompatActivity) { androidApp.foregroundActivity = activity; if ((activity).isNativeScriptActivity) { @@ -298,15 +298,15 @@ function initLifecycleCallbacks() { androidApp.notify({ eventName: ActivityResumed, object: androidApp, activity: activity }); }), - onActivitySaveInstanceState: profile("onActivityResumed", function (activity: android.app.Activity, outState: android.os.Bundle) { + onActivitySaveInstanceState: profile("onActivityResumed", function (activity: android.support.v7.app.AppCompatActivity, outState: android.os.Bundle) { androidApp.notify({ eventName: SaveActivityState, object: androidApp, activity: activity, bundle: outState }); }), - onActivityStarted: profile("onActivityStarted", function (activity: android.app.Activity) { + onActivityStarted: profile("onActivityStarted", function (activity: android.support.v7.app.AppCompatActivity) { androidApp.notify({ eventName: ActivityStarted, object: androidApp, activity: activity }); }), - onActivityStopped: profile("onActivityStopped", function (activity: android.app.Activity) { + onActivityStopped: profile("onActivityStopped", function (activity: android.support.v7.app.AppCompatActivity) { androidApp.notify({ eventName: ActivityStopped, object: androidApp, activity: activity }); }) }); diff --git a/tns-core-modules/application/application.d.ts b/tns-core-modules/application/application.d.ts index 99ffa04ba..92ac02946 100644 --- a/tns-core-modules/application/application.d.ts +++ b/tns-core-modules/application/application.d.ts @@ -288,7 +288,7 @@ export interface AndroidActivityEventData { /** * The activity. */ - activity: any /* android.app.Activity */; + activity: any /* android.support.v7.app.AppCompatActivity */; /** * The name of the event. @@ -378,7 +378,7 @@ export class AndroidApplication extends Observable { /** * The currently active (loaded) [android Activity](http://developer.android.com/reference/android/app/Activity.html). This property is automatically updated upon Activity events. */ - foregroundActivity: any /* android.app.Activity */; + foregroundActivity: any /* android.support.v7.app.AppCompatActivity */; /** * Deprecated. Please use startActivity, foregroundActivity or context property. @@ -388,7 +388,7 @@ export class AndroidApplication extends Observable { /** * The main (start) Activity for the application. */ - startActivity: any /* android.app.Activity */; + startActivity: any /* android.support.v7.app.AppCompatActivity */; /** * The name of the application package. diff --git a/tns-core-modules/ui/core/view/view.android.ts b/tns-core-modules/ui/core/view/view.android.ts index 4fba96d75..cca6cf8b1 100644 --- a/tns-core-modules/ui/core/view/view.android.ts +++ b/tns-core-modules/ui/core/view/view.android.ts @@ -47,7 +47,7 @@ interface TouchListener { } interface DialogFragment { - new(): android.app.DialogFragment; + new(): android.support.v4.app.DialogFragment; } function initializeDisabledListener(): void { @@ -120,7 +120,7 @@ function initializeDialogFragment() { } } - class DialogFragmentImpl extends android.app.DialogFragment { + class DialogFragmentImpl extends android.support.v4.app.DialogFragment { public owner: View; private _fullscreen: boolean; private _stretched: boolean; @@ -141,7 +141,7 @@ function initializeDialogFragment() { this._dismissCallback = options.dismissCallback; this._shownCallback = options.shownCallback; this.owner._dialogFragment = this; - this.setStyle(android.app.DialogFragment.STYLE_NO_TITLE, 0); + this.setStyle(android.support.v4.app.DialogFragment.STYLE_NO_TITLE, 0); const dialog = new DialogImpl(this, this.getActivity(), this.getTheme()); @@ -225,13 +225,13 @@ function getModalOptions(domId: number): DialogOptions { export class View extends ViewCommon { public static androidBackPressedEvent = androidBackPressedEvent; - public _dialogFragment: android.app.DialogFragment; + public _dialogFragment: android.support.v4.app.DialogFragment; private _isClickable: boolean; private touchListenerIsSet: boolean; private touchListener: android.view.View.OnTouchListener; private layoutChangeListenerIsSet: boolean; private layoutChangeListener: android.view.View.OnLayoutChangeListener; - private _manager: android.app.FragmentManager; + private _manager: android.support.v4.app.FragmentManager; nativeViewProtected: android.view.View; @@ -263,7 +263,7 @@ export class View extends ViewCommon { } } - public _getFragmentManager(): android.app.FragmentManager { + public _getFragmentManager(): android.support.v4.app.FragmentManager { let manager = this._manager; if (!manager) { let view: View = this; @@ -280,7 +280,7 @@ export class View extends ViewCommon { } if (!manager && this._context) { - manager = (this._context).getFragmentManager(); + manager = (this._context).getSupportFragmentManager(); } this._manager = manager; diff --git a/tns-core-modules/ui/core/view/view.d.ts b/tns-core-modules/ui/core/view/view.d.ts index 8fccb6425..b475e60e6 100644 --- a/tns-core-modules/ui/core/view/view.d.ts +++ b/tns-core-modules/ui/core/view/view.d.ts @@ -659,7 +659,7 @@ export abstract class View extends ViewBase { /** * @private */ - _getFragmentManager(): any; /* android.app.FragmentManager */ + _getFragmentManager(): any; /* android.support.v4.app.FragmentManager */ /** * Updates styleScope or create new styleScope. diff --git a/tns-core-modules/ui/editable-text-base/editable-text-base.android.ts b/tns-core-modules/ui/editable-text-base/editable-text-base.android.ts index 0767442e9..cc7ecad6b 100644 --- a/tns-core-modules/ui/editable-text-base/editable-text-base.android.ts +++ b/tns-core-modules/ui/editable-text-base/editable-text-base.android.ts @@ -36,7 +36,7 @@ function dismissSoftInput(owner: EditableTextBase): void { if (!dismissKeyboardTimeoutId) { dismissKeyboardTimeoutId = setTimeout(() => { const owner = dismissKeyboardOwner && dismissKeyboardOwner.get(); - const activity = (owner && owner._context) as android.app.Activity; + const activity = (owner && owner._context) as android.support.v7.app.AppCompatActivity; const nativeView = owner && owner.nativeViewProtected; dismissKeyboardTimeoutId = null; dismissKeyboardOwner = null; diff --git a/tns-core-modules/ui/frame/activity.android.ts b/tns-core-modules/ui/frame/activity.android.ts index fcee46022..55d9118a9 100644 --- a/tns-core-modules/ui/frame/activity.android.ts +++ b/tns-core-modules/ui/frame/activity.android.ts @@ -8,7 +8,7 @@ if ((global).__snapshot || (global).__snapshotEnabled) { //@ts-ignore @JavaProxy("com.tns.NativeScriptActivity") -class NativeScriptActivity extends android.app.Activity { +class NativeScriptActivity extends android.support.v7.app.AppCompatActivity { private _callbacks: AndroidActivityCallbacks; public isNativeScriptActivity; constructor() { @@ -54,7 +54,7 @@ class NativeScriptActivity extends android.app.Activity { this._callbacks.onBackPressed(this, super.onBackPressed); } - public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { + public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); } diff --git a/tns-core-modules/ui/frame/fragment.android.ts b/tns-core-modules/ui/frame/fragment.android.ts index cc6b8f960..f659ce0aa 100644 --- a/tns-core-modules/ui/frame/fragment.android.ts +++ b/tns-core-modules/ui/frame/fragment.android.ts @@ -1,7 +1,7 @@ import { AndroidFragmentCallbacks, setFragmentCallbacks, setFragmentClass } from "./frame"; @JavaProxy("com.tns.FragmentClass") -class FragmentClass extends android.app.Fragment { +class FragmentClass extends android.support.v4.app.Fragment { // This field is updated in the frame module upon `new` (although hacky this eases the Fragment->callbacks association a lot) private _callbacks: AndroidFragmentCallbacks; @@ -14,9 +14,8 @@ class FragmentClass extends android.app.Fragment { this._callbacks.onHiddenChanged(this, hidden, super.onHiddenChanged); } - public onCreateAnimator(transit: number, enter: boolean, nextAnim: number): android.animation.Animator { - let result = this._callbacks.onCreateAnimator(this, transit, enter, nextAnim, super.onCreateAnimator); - return result; + public onCreateAnimation(transit: number, enter: boolean, nextAnim: number): android.view.animation.Animation { + return this._callbacks.onCreateAnimation(this, transit, enter, nextAnim, super.onCreateAnimation); } public onStop(): void { diff --git a/tns-core-modules/ui/frame/fragment.transitions.android.ts b/tns-core-modules/ui/frame/fragment.transitions.android.ts index 22cb40b93..74eee202b 100644 --- a/tns-core-modules/ui/frame/fragment.transitions.android.ts +++ b/tns-core-modules/ui/frame/fragment.transitions.android.ts @@ -19,7 +19,7 @@ interface TransitionListener { new(entry: ExpandedEntry, transition: android.transition.Transition): ExpandedTransitionListener; } -interface ExpandedAnimator extends android.animation.Animator { +interface ExpandedAnimation extends android.view.animation.Animation { entry: ExpandedEntry; transitionType?: string; } @@ -35,13 +35,13 @@ interface ExpandedEntry extends BackstackEntry { reenterTransitionListener: ExpandedTransitionListener; returnTransitionListener: ExpandedTransitionListener; - enterAnimator: ExpandedAnimator; - exitAnimator: ExpandedAnimator; - popEnterAnimator: ExpandedAnimator; - popExitAnimator: ExpandedAnimator; + enterAnimation: ExpandedAnimation; + exitAnimation: ExpandedAnimation; + popEnterAnimation: ExpandedAnimation; + popExitAnimation: ExpandedAnimation; - defaultEnterAnimator: ExpandedAnimator; - defaultExitAnimator: ExpandedAnimator; + defaultEnterAnimation: ExpandedAnimation; + defaultExitAnimation: ExpandedAnimation; transition: Transition; transitionName: string; @@ -49,7 +49,6 @@ interface ExpandedEntry extends BackstackEntry { } const sdkVersion = lazy(() => parseInt(device.sdkVersion)); -const intEvaluator = lazy(() => new android.animation.IntEvaluator()); const defaultInterpolator = lazy(() => new android.view.animation.AccelerateDecelerateInterpolator()); const isAndroidP = lazy(() => sdkVersion() > 27); @@ -57,23 +56,23 @@ export const waitingQueue = new Map>(); export const completedEntries = new Map(); let TransitionListener: TransitionListener; -let AnimationListener: android.animation.Animator.AnimatorListener; -let loadAnimatorMethod: java.lang.reflect.Method; +let AnimationListener: android.view.animation.Animation.AnimationListener; +let loadAnimationMethod: java.lang.reflect.Method; let reflectionDone: boolean; -let defaultEnterAnimatorStatic: android.animation.Animator; -let defaultExitAnimatorStatic: android.animation.Animator; +let defaultEnterAnimationStatic: android.view.animation.Animation; +let defaultExitAnimationStatic: android.view.animation.Animation; export function _setAndroidFragmentTransitions( animated: boolean, navigationTransition: NavigationTransition, currentEntry: ExpandedEntry, newEntry: ExpandedEntry, - fragmentTransaction: android.app.FragmentTransaction, - manager: android.app.FragmentManager, + fragmentTransaction: android.support.v4.app.FragmentTransaction, + manager: android.support.v4.app.FragmentManager, frameId: number): void { - const currentFragment: android.app.Fragment = currentEntry ? currentEntry.fragment : null; - const newFragment: android.app.Fragment = newEntry.fragment; + const currentFragment: android.support.v4.app.Fragment = currentEntry ? currentEntry.fragment : null; + const newFragment: android.support.v4.app.Fragment = newEntry.fragment; const entries = waitingQueue.get(frameId); if (entries && entries.size > 0) { throw new Error("Calling navigation before previous navigation finish."); @@ -189,39 +188,39 @@ export function _setAndroidFragmentTransitions( printTransitions(newEntry); } -export function _onFragmentCreateAnimator(entry: ExpandedEntry, fragment: android.app.Fragment, nextAnim: number, enter: boolean): android.animation.Animator { - let animator: android.animation.Animator; +export function _onFragmentCreateAnimation(entry: ExpandedEntry, fragment: android.support.v4.app.Fragment, nextAnim: number, enter: boolean): android.view.animation.Animation { + let animation: android.view.animation.Animation; switch (nextAnim) { case AnimationType.enterFakeResourceId: - animator = entry.enterAnimator; + animation = entry.enterAnimation; break; case AnimationType.exitFakeResourceId: - animator = entry.exitAnimator; + animation = entry.exitAnimation; break; case AnimationType.popEnterFakeResourceId: - animator = entry.popEnterAnimator; + animation = entry.popEnterAnimation; break; case AnimationType.popExitFakeResourceId: - animator = entry.popExitAnimator; + animation = entry.popExitAnimation; break; } - if (!animator && sdkVersion() >= 21) { + if (!animation && sdkVersion() >= 21) { const view = fragment.getView(); const jsParent = entry.resolvedPage.parent; const parent = view.getParent() || (jsParent && jsParent.nativeViewProtected); const animatedEntries = _getAnimatedEntries(entry.frameId); if (!animatedEntries || !animatedEntries.has(entry)) { if (parent && !(parent).isLaidOut()) { - animator = enter ? entry.defaultEnterAnimator : entry.defaultExitAnimator; + animation = enter ? entry.defaultEnterAnimation : entry.defaultExitAnimation; } } } - return animator; + return animation; } export function _getAnimatedEntries(frameId: number): Set { @@ -331,45 +330,45 @@ function getTransitionListener(entry: ExpandedEntry, transition: android.transit return new TransitionListener(entry, transition); } -function getAnimationListener(): android.animation.Animator.AnimatorListener { +function getAnimationListener(): android.view.animation.Animation.AnimationListener { if (!AnimationListener) { - @Interfaces([android.animation.Animator.AnimatorListener]) - class AnimationListnerImpl extends java.lang.Object implements android.animation.Animator.AnimatorListener { + @Interfaces([android.view.animation.Animation.AnimationListener]) + class AnimationListenerImpl extends java.lang.Object implements android.view.animation.Animation.AnimationListener { constructor() { super(); return global.__native(this); } - onAnimationStart(animator: ExpandedAnimator): void { - const entry = animator.entry; + onAnimationStart(animation: ExpandedAnimation): void { + const entry = animation.entry; addToWaitingQueue(entry); if (traceEnabled()) { - traceWrite(`START ${animator.transitionType} for ${entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`START ${animation.transitionType} for ${entry.fragmentTag}`, traceCategories.Transition); } } - onAnimationRepeat(animator: ExpandedAnimator): void { + onAnimationRepeat(animation: ExpandedAnimation): void { if (traceEnabled()) { - traceWrite(`REPEAT ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`REPEAT ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); } } - onAnimationEnd(animator: ExpandedAnimator): void { + onAnimationEnd(animation: ExpandedAnimation): void { if (traceEnabled()) { - traceWrite(`END ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`END ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); } - transitionOrAnimationCompleted(animator.entry); + transitionOrAnimationCompleted(animation.entry); } - onAnimationCancel(animator: ExpandedAnimator): void { + onAnimationCancel(animation: ExpandedAnimation): void { if (traceEnabled()) { - traceWrite(`CANCEL ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`CANCEL ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); } } } - AnimationListener = new AnimationListnerImpl(); + AnimationListener = new AnimationListenerImpl(); } return AnimationListener; @@ -386,24 +385,23 @@ function addToWaitingQueue(entry: ExpandedEntry): void { entries.add(entry); } -function clearAnimationListener(animator: ExpandedAnimator, listener: android.animation.Animator.AnimatorListener): void { - if (!animator) { +function clearAnimationListener(animation: ExpandedAnimation): void { + if (!animation) { return; } - animator.removeListener(listener); - if (traceEnabled()) { - const entry = animator.entry; - traceWrite(`Clear ${animator.transitionType} - ${entry.transition} for ${entry.fragmentTag}`, traceCategories.Transition); + const entry = animation.entry; + traceWrite(`Clear ${animation.transitionType} - ${entry.transition} for ${entry.fragmentTag}`, traceCategories.Transition); } - animator.entry = null; + animation.setAnimationListener(null); + animation.entry = null; } function clearExitAndReenterTransitions(entry: ExpandedEntry, removeListener: boolean): void { if (sdkVersion() >= 21) { - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; const exitListener = entry.exitTransitionListener; if (exitListener) { const exitTransition = fragment.getExitTransition(); @@ -456,7 +454,7 @@ function clearEntry(entry: ExpandedEntry, removeListener: boolean): void { clearExitAndReenterTransitions(entry, removeListener); if (sdkVersion() >= 21) { - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; const enterListener = entry.enterTransitionListener; if (enterListener) { const enterTransition = fragment.getEnterTransition(); @@ -497,15 +495,14 @@ function clearEntry(entry: ExpandedEntry, removeListener: boolean): void { } if (removeListener) { - const listener = getAnimationListener(); - clearAnimationListener(entry.enterAnimator, listener); - clearAnimationListener(entry.exitAnimator, listener); - clearAnimationListener(entry.popEnterAnimator, listener); - clearAnimationListener(entry.popExitAnimator, listener); + clearAnimationListener(entry.enterAnimation); + clearAnimationListener(entry.exitAnimation); + clearAnimationListener(entry.popEnterAnimation); + clearAnimationListener(entry.popExitAnimation); } } -function allowTransitionOverlap(fragment: android.app.Fragment): void { +function allowTransitionOverlap(fragment: android.support.v4.app.Fragment): void { if (fragment) { fragment.setAllowEnterTransitionOverlap(true); fragment.setAllowReturnTransitionOverlap(true); @@ -518,7 +515,7 @@ function setEnterTransition(navigationTransition: NavigationTransition, entry: E // attach listener to JS object so that it will be alive as long as entry. entry.enterTransitionListener = listener; - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; fragment.setEnterTransition(transition); } @@ -528,7 +525,7 @@ function setExitTransition(navigationTransition: NavigationTransition, entry: Ex // attach listener to JS object so that it will be alive as long as entry. entry.exitTransitionListener = listener; - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; fragment.setExitTransition(transition); } @@ -538,7 +535,7 @@ function setReenterTransition(navigationTransition: NavigationTransition, entry: // attach listener to JS object so that it will be alive as long as entry. entry.reenterTransitionListener = listener; - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; fragment.setReenterTransition(transition); } @@ -548,7 +545,7 @@ function setReturnTransition(navigationTransition: NavigationTransition, entry: // attach listener to JS object so that it will be alive as long as entry. entry.returnTransitionListener = listener; - const fragment: android.app.Fragment = entry.fragment; + const fragment: android.support.v4.app.Fragment = entry.fragment; fragment.setReturnTransition(transition); } @@ -638,21 +635,21 @@ function setupNewFragmentExplodeTransition(navTransition: NavigationTransition, function setupExitAndPopEnterAnimation(entry: ExpandedEntry, transition: Transition): void { const listener = getAnimationListener(); - // remove previous listener if we are changing the animator. - clearAnimationListener(entry.exitAnimator, listener); - clearAnimationListener(entry.popEnterAnimator, listener); + // remove previous listener if we are changing the animation. + clearAnimationListener(entry.exitAnimation); + clearAnimationListener(entry.popEnterAnimation); - const exitAnimator = transition.createAndroidAnimator(AndroidTransitionType.exit); - exitAnimator.transitionType = AndroidTransitionType.exit; - exitAnimator.entry = entry; - exitAnimator.addListener(listener); - entry.exitAnimator = exitAnimator; + const exitAnimation = transition.createAndroidAnimation(AndroidTransitionType.exit); + exitAnimation.transitionType = AndroidTransitionType.exit; + exitAnimation.entry = entry; + exitAnimation.setAnimationListener(listener); + entry.exitAnimation = exitAnimation; - const popEnterAnimator = transition.createAndroidAnimator(AndroidTransitionType.popEnter); - popEnterAnimator.transitionType = AndroidTransitionType.popEnter; - popEnterAnimator.entry = entry; - popEnterAnimator.addListener(listener); - entry.popEnterAnimator = popEnterAnimator; + const popEnterAnimation = transition.createAndroidAnimation(AndroidTransitionType.popEnter); + popEnterAnimation.transitionType = AndroidTransitionType.popEnter; + popEnterAnimation.entry = entry; + popEnterAnimation.setAnimationListener(listener); + entry.popEnterAnimation = popEnterAnimation; } function setupAllAnimation(entry: ExpandedEntry, transition: Transition): void { @@ -661,33 +658,33 @@ function setupAllAnimation(entry: ExpandedEntry, transition: Transition): void { // setupAllAnimation is called only for new fragments so we don't // need to clearAnimationListener for enter & popExit animators. - const enterAnimator = transition.createAndroidAnimator(AndroidTransitionType.enter); - enterAnimator.transitionType = AndroidTransitionType.enter; - enterAnimator.entry = entry; - enterAnimator.addListener(listener); - entry.enterAnimator = enterAnimator; + const enterAnimation = transition.createAndroidAnimation(AndroidTransitionType.enter); + enterAnimation.transitionType = AndroidTransitionType.enter; + enterAnimation.entry = entry; + enterAnimation.setAnimationListener(listener); + entry.enterAnimation = enterAnimation; - const popExitAnimator = transition.createAndroidAnimator(AndroidTransitionType.popExit); - popExitAnimator.transitionType = AndroidTransitionType.popExit; - popExitAnimator.entry = entry; - popExitAnimator.addListener(listener); - entry.popExitAnimator = popExitAnimator; + const popExitAnimation = transition.createAndroidAnimation(AndroidTransitionType.popExit); + popExitAnimation.transitionType = AndroidTransitionType.popExit; + popExitAnimation.entry = entry; + popExitAnimation.setAnimationListener(listener); + entry.popExitAnimation = popExitAnimation; } function setupDefaultAnimations(entry: ExpandedEntry, transition: Transition): void { const listener = getAnimationListener(); - const enterAnimator = transition.createAndroidAnimator(AndroidTransitionType.enter); - enterAnimator.transitionType = AndroidTransitionType.enter; - enterAnimator.entry = entry; - enterAnimator.addListener(listener); - entry.defaultEnterAnimator = enterAnimator; + const enterAnimation = transition.createAndroidAnimation(AndroidTransitionType.enter); + enterAnimation.transitionType = AndroidTransitionType.enter; + enterAnimation.entry = entry; + enterAnimation.setAnimationListener(listener); + entry.defaultEnterAnimation = enterAnimation; - const exitAnimator = transition.createAndroidAnimator(AndroidTransitionType.exit); - exitAnimator.transitionType = AndroidTransitionType.exit; - exitAnimator.entry = entry; - exitAnimator.addListener(listener); - entry.defaultExitAnimator = exitAnimator; + const exitAnimation = transition.createAndroidAnimation(AndroidTransitionType.exit); + exitAnimation.transitionType = AndroidTransitionType.exit; + exitAnimation.entry = entry; + exitAnimation.setAnimationListener(listener); + entry.defaultExitAnimation = exitAnimation; } function setUpNativeTransition(navigationTransition: NavigationTransition, nativeTransition: android.transition.Transition) { @@ -754,38 +751,41 @@ function javaClassArray(...params: java.lang.Class[]) { return nativeArray; } -function initDefaultAnimations(manager: android.app.FragmentManager): void { +function initDefaultAnimations(manager: android.support.v4.app.FragmentManager): void { if (reflectionDone) { return; } reflectionDone = true; - loadAnimatorMethod = manager.getClass().getDeclaredMethod("loadAnimator", javaClassArray(android.app.Fragment.class, java.lang.Integer.TYPE, java.lang.Boolean.TYPE, java.lang.Integer.TYPE)); - if (loadAnimatorMethod != null) { - loadAnimatorMethod.setAccessible(true); + loadAnimationMethod = manager.getClass().getDeclaredMethod("loadAnimation", javaClassArray(android.support.v4.app.Fragment.class, java.lang.Integer.TYPE, java.lang.Boolean.TYPE, java.lang.Integer.TYPE)); + if (loadAnimationMethod != null) { + loadAnimationMethod.setAccessible(true); - const fragment_open = java.lang.Integer.valueOf(android.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + const fragment_open = java.lang.Integer.valueOf(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN); const zero = java.lang.Integer.valueOf(0); - const fragment = new android.app.Fragment(); + const fragment = new android.support.v4.app.Fragment(); // Get default enter transition. - defaultEnterAnimatorStatic = loadAnimatorMethod.invoke(manager, javaObjectArray(fragment, fragment_open, java.lang.Boolean.TRUE, zero)); + defaultEnterAnimationStatic = loadAnimationMethod.invoke(manager, javaObjectArray(fragment, fragment_open, java.lang.Boolean.TRUE, zero)); // Get default exit transition. - defaultExitAnimatorStatic = loadAnimatorMethod.invoke(manager, javaObjectArray(fragment, fragment_open, java.lang.Boolean.FALSE, zero)); + defaultExitAnimationStatic = loadAnimationMethod.invoke(manager, javaObjectArray(fragment, fragment_open, java.lang.Boolean.FALSE, zero)); } } -function getDefaultAnimation(enter: boolean): android.animation.Animator { - const defaultAnimator = enter ? defaultEnterAnimatorStatic : defaultExitAnimatorStatic; - return defaultAnimator ? defaultAnimator.clone() : null; +function getDefaultAnimation(enter: boolean): android.view.animation.Animation { + const defaultAnimation = enter ? defaultEnterAnimationStatic : defaultExitAnimationStatic; + return defaultAnimation ? defaultAnimation.clone() : null; } -function createDummyZeroDurationAnimator(): android.animation.Animator { - const animator = android.animation.ValueAnimator.ofObject(intEvaluator(), javaObjectArray(java.lang.Integer.valueOf(0), java.lang.Integer.valueOf(1))); - animator.setDuration(0); - return animator; +function createDummyZeroDurationAnimation(): android.view.animation.Animation { + // NOTE: returning the dummy AlphaAnimation directly does not work for some reason; + // animationEnd is fired first, then some animationStart (but for a different animation?) + const animationSet = new android.view.animation.AnimationSet(false); + animationSet.addAnimation(new android.view.animation.AlphaAnimation(1, 1)); + + return animationSet; } function printTransitions(entry: ExpandedEntry) { @@ -796,10 +796,10 @@ function printTransitions(entry: ExpandedEntry) { } if (entry.transition) { - result += `enterAnimator=${entry.enterAnimator}, `; - result += `exitAnimator=${entry.exitAnimator}, `; - result += `popEnterAnimator=${entry.popEnterAnimator}, `; - result += `popExitAnimator=${entry.popExitAnimator}, `; + result += `enterAnimator=${entry.enterAnimation}, `; + result += `exitAnimator=${entry.exitAnimation}, `; + result += `popEnterAnimator=${entry.popEnterAnimation}, `; + result += `popExitAnimator=${entry.popExitAnimation}, `; } if (sdkVersion() >= 21) { const fragment = entry.fragment; @@ -813,13 +813,13 @@ function printTransitions(entry: ExpandedEntry) { } class NoTransition extends Transition { - public createAndroidAnimator(transitionType: string): android.animation.Animator { - return createDummyZeroDurationAnimator(); + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + return createDummyZeroDurationAnimation(); } } class DefaultTransition extends Transition { - public createAndroidAnimator(transitionType: string): android.animation.Animator { + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { switch (transitionType) { case AndroidTransitionType.enter: case AndroidTransitionType.popEnter: diff --git a/tns-core-modules/ui/frame/fragment.transitions.d.ts b/tns-core-modules/ui/frame/fragment.transitions.d.ts index 4d8709fb7..f94e9fcc5 100644 --- a/tns-core-modules/ui/frame/fragment.transitions.d.ts +++ b/tns-core-modules/ui/frame/fragment.transitions.d.ts @@ -24,12 +24,12 @@ export function _setAndroidFragmentTransitions( currentEntry: BackstackEntry, newEntry: BackstackEntry, fragmentTransaction: any, - manager: any /* android.app.FragmentManager */, + manager: any /* android.support.v4.app.FragmentManager */, frameId: number): void; /** * @private */ -export function _onFragmentCreateAnimator(entry: BackstackEntry, fragment: any, nextAnim: number, enter: boolean): any; +export function _onFragmentCreateAnimation(entry: BackstackEntry, fragment: any, nextAnim: number, enter: boolean): any; /** * @private */ diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index 1a7f3df3e..b3d080eb9 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -13,7 +13,7 @@ import { } from "./frame-common"; import { - _setAndroidFragmentTransitions, _onFragmentCreateAnimator, _getAnimatedEntries, + _setAndroidFragmentTransitions, _onFragmentCreateAnimation, _getAnimatedEntries, _updateTransitions, _reverseTransitions, _clearEntry, _clearFragment, AnimationType } from "./fragment.transitions"; @@ -195,7 +195,7 @@ export class Frame extends FrameBase { return; } - const manager: android.app.FragmentManager = this._getFragmentManager(); + const manager: android.support.v4.app.FragmentManager = this._getFragmentManager(); const transaction = manager.beginTransaction(); const androidSdkVersion = sdkVersion(); @@ -214,7 +214,7 @@ export class Frame extends FrameBase { transaction.commitAllowingStateLoss(); } - private createFragment(backstackEntry: BackstackEntry, fragmentTag: string): android.app.Fragment { + private createFragment(backstackEntry: BackstackEntry, fragmentTag: string): android.support.v4.app.Fragment { ensureFragmentClass(); const newFragment = new fragmentClass(); const args = new android.os.Bundle(); @@ -316,7 +316,7 @@ export class Frame extends FrameBase { return; } - const manager: android.app.FragmentManager = this._getFragmentManager(); + const manager: android.support.v4.app.FragmentManager = this._getFragmentManager(); const clearHistory = newEntry.entry.clearHistory; const currentEntry = this._currentEntry; @@ -343,7 +343,7 @@ export class Frame extends FrameBase { // } if (currentEntry && animated && !navigationTransition) { - transaction.setTransition(android.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + transaction.setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN); } transaction.replace(this.containerViewId, newFragment, newFragmentTag); @@ -355,7 +355,7 @@ export class Frame extends FrameBase { super._goBackCore(backstackEntry); navDepth = backstackEntry.navDepth; - const manager: android.app.FragmentManager = this._getFragmentManager(); + const manager: android.support.v4.app.FragmentManager = this._getFragmentManager(); const transaction = manager.beginTransaction(); if (!backstackEntry.fragment) { @@ -509,8 +509,8 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition { } } - public get activity(): android.app.Activity { - let activity: android.app.Activity = this.owner._context; + public get activity(): android.support.v7.app.AppCompatActivity { + let activity: android.support.v7.app.AppCompatActivity = this.owner._context; if (activity) { return activity; } @@ -542,7 +542,7 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition { return bar; } - public get currentActivity(): android.app.Activity { + public get currentActivity(): android.support.v7.app.AppCompatActivity { let activity = this.activity; if (activity) { return activity; @@ -582,7 +582,7 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition { } } -function findPageForFragment(fragment: android.app.Fragment, frame: Frame) { +function findPageForFragment(fragment: android.support.v4.app.Fragment, frame: Frame) { const fragmentTag = fragment.getTag(); if (traceEnabled()) { traceWrite(`Finding page for ${fragmentTag}.`, traceCategories.NativeLifecycle); @@ -615,7 +615,7 @@ function findPageForFragment(fragment: android.app.Fragment, frame: Frame) { } } -function startActivity(activity: android.app.Activity, frameId: number) { +function startActivity(activity: android.support.v7.app.AppCompatActivity, frameId: number) { // TODO: Implicitly, we will open the same activity type as the current one const intent = new android.content.Intent(activity, activity.getClass()); intent.setAction(android.content.Intent.ACTION_DEFAULT); @@ -646,7 +646,7 @@ function ensureFragmentClass() { require("ui/frame/fragment"); if (!fragmentClass) { - throw new Error("Failed to initialize the extended android.app.Fragment class"); + throw new Error("Failed to initialize the extended android.support.v4.app.Fragment class"); } } @@ -664,7 +664,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { public entry: BackstackEntry; @profile - public onHiddenChanged(fragment: android.app.Fragment, hidden: boolean, superFunc: Function): void { + public onHiddenChanged(fragment: android.support.v4.app.Fragment, hidden: boolean, superFunc: Function): void { if (traceEnabled()) { traceWrite(`${fragment}.onHiddenChanged(${hidden})`, traceCategories.NativeLifecycle); } @@ -672,28 +672,29 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onCreateAnimator(fragment: android.app.Fragment, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.animation.Animator { + public onCreateAnimation(fragment: android.support.v4.app.Fragment, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.view.animation.Animation { let nextAnimString: string; switch (nextAnim) { - case -10: nextAnimString = "enter"; break; - case -20: nextAnimString = "exit"; break; - case -30: nextAnimString = "popEnter"; break; - case -40: nextAnimString = "popExit"; break; + case AnimationType.enterFakeResourceId: nextAnimString = "enter"; break; + case AnimationType.exitFakeResourceId: nextAnimString = "exit"; break; + case AnimationType.popEnterFakeResourceId: nextAnimString = "popEnter"; break; + case AnimationType.popExitFakeResourceId: nextAnimString = "popExit"; break; } - let animator = _onFragmentCreateAnimator(this.entry, fragment, nextAnim, enter); - if (!animator) { - animator = superFunc.call(fragment, transit, enter, nextAnim); + let animation = _onFragmentCreateAnimation(this.entry, fragment, nextAnim, enter); + if (!animation) { + animation = superFunc.call(fragment, transit, enter, nextAnim); } if (traceEnabled()) { - traceWrite(`${fragment}.onCreateAnimator(${transit}, ${enter ? "enter" : "exit"}, ${nextAnimString}): ${animator ? "animator" : "no animator"}`, traceCategories.NativeLifecycle); + traceWrite(`${fragment}.onCreateAnimation(${transit}, ${enter ? "enter" : "exit"}, ${nextAnimString}): ${animation ? "animation" : "no animation"}`, traceCategories.NativeLifecycle); } - return animator; + + return animation; } @profile - public onCreate(fragment: android.app.Fragment, savedInstanceState: android.os.Bundle, superFunc: Function): void { + public onCreate(fragment: android.support.v4.app.Fragment, savedInstanceState: android.os.Bundle, superFunc: Function): void { if (traceEnabled()) { traceWrite(`${fragment}.onCreate(${savedInstanceState})`, traceCategories.NativeLifecycle); } @@ -714,7 +715,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onCreateView(fragment: android.app.Fragment, inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle, superFunc: Function): android.view.View { + public onCreateView(fragment: android.support.v4.app.Fragment, inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle, superFunc: Function): android.view.View { if (traceEnabled()) { traceWrite(`${fragment}.onCreateView(inflater, container, ${savedInstanceState})`, traceCategories.NativeLifecycle); } @@ -752,7 +753,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onSaveInstanceState(fragment: android.app.Fragment, outState: android.os.Bundle, superFunc: Function): void { + public onSaveInstanceState(fragment: android.support.v4.app.Fragment, outState: android.os.Bundle, superFunc: Function): void { if (traceEnabled()) { traceWrite(`${fragment}.onSaveInstanceState(${outState})`, traceCategories.NativeLifecycle); } @@ -760,7 +761,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onDestroyView(fragment: android.app.Fragment, superFunc: Function): void { + public onDestroyView(fragment: android.support.v4.app.Fragment, superFunc: Function): void { if (traceEnabled()) { traceWrite(`${fragment}.onDestroyView()`, traceCategories.NativeLifecycle); } @@ -768,7 +769,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onDestroy(fragment: android.app.Fragment, superFunc: Function): void { + public onDestroy(fragment: android.support.v4.app.Fragment, superFunc: Function): void { if (traceEnabled()) { traceWrite(`${fragment}.onDestroy()`, traceCategories.NativeLifecycle); } @@ -776,12 +777,12 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onStop(fragment: android.app.Fragment, superFunc: Function): void { + public onStop(fragment: android.support.v4.app.Fragment, superFunc: Function): void { superFunc.call(fragment); } @profile - public toStringOverride(fragment: android.app.Fragment, superFunc: Function): string { + public toStringOverride(fragment: android.support.v4.app.Fragment, superFunc: Function): string { const entry = this.entry; if (entry) { return `${entry.fragmentTag}<${entry.resolvedPage}>`; @@ -799,7 +800,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { } @profile - public onCreate(activity: android.app.Activity, savedInstanceState: android.os.Bundle, superFunc: Function): void { + public onCreate(activity: android.support.v7.app.AppCompatActivity, savedInstanceState: android.os.Bundle, superFunc: Function): void { if (traceEnabled()) { traceWrite(`Activity.onCreate(${savedInstanceState})`, traceCategories.NativeLifecycle); } @@ -826,7 +827,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { } @profile - public onSaveInstanceState(activity: android.app.Activity, outState: android.os.Bundle, superFunc: Function): void { + public onSaveInstanceState(activity: android.support.v7.app.AppCompatActivity, outState: android.os.Bundle, superFunc: Function): void { superFunc.call(activity, outState); const rootView = this._rootView; if (rootView instanceof Frame) { @@ -967,7 +968,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { }); } - public resetActivityContent(activity: android.app.Activity): void { + public resetActivityContent(activity: android.support.v7.app.AppCompatActivity): void { if (this._rootView) { const manager = this._rootView._getFragmentManager(); manager.executePendingTransactions(); @@ -986,7 +987,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { // 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, + activity: android.support.v7.app.AppCompatActivity, savedInstanceState: android.os.Bundle, fireLaunchEvent: boolean ): void { @@ -1069,10 +1070,10 @@ const notifyLaunch = profile("notifyLaunch", function notifyLaunch(intent: andro return launchArgs.root; }); -export function setActivityCallbacks(activity: android.app.Activity): void { +export function setActivityCallbacks(activity: android.support.v7.app.AppCompatActivity): void { activity[CALLBACKS] = new ActivityCallbacksImplementation(); } -export function setFragmentCallbacks(fragment: android.app.Fragment): void { +export function setFragmentCallbacks(fragment: android.support.v4.app.Fragment): void { fragment[CALLBACKS] = new FragmentCallbacksImplementation(); } diff --git a/tns-core-modules/ui/frame/frame.d.ts b/tns-core-modules/ui/frame/frame.d.ts index 1e3d989b3..b18af7387 100644 --- a/tns-core-modules/ui/frame/frame.d.ts +++ b/tns-core-modules/ui/frame/frame.d.ts @@ -174,7 +174,7 @@ export class Frame extends View { } /** - * Sets the extended android.app.Fragment class to the Frame and navigation routine. An instance of this class will be created to represent the Page currently visible on the srceen. This method is available only for the Android platform. + * Sets the extended android.support.v4.app.Fragment class to the Frame and navigation routine. An instance of this class will be created to represent the Page currently visible on the srceen. This method is available only for the Android platform. */ export function setFragmentClass(clazz: any): void; @@ -364,12 +364,12 @@ export interface AndroidFrame extends Observable { /** * Gets the native [android Activity](http://developer.android.com/reference/android/app/Activity.html) instance associated with this Frame. In case of nested Frame objects, this property points to the activity of the root Frame. */ - activity: any /* android.app.Activity */; + activity: any /* android.support.v7.app.AppCompatActivity */; /** * Gets the current (foreground) activity for the application. This property will recursively traverse all existing Frame objects and check for own Activity property. */ - currentActivity: any /* android.app.Activity */; + currentActivity: any /* android.support.v7.app.AppCompatActivity */; /** * Gets the actionBar property of the currentActivity. @@ -388,7 +388,7 @@ export interface AndroidFrame extends Observable { cachePagesOnNavigate: boolean; /** - * Finds the native android.app.Fragment instance created for the specified Page. + * Finds the native android.support.v4.app.Fragment instance created for the specified Page. * @param page The Page instance to search for. */ fragmentForPage(entry: BackstackEntry): any; @@ -410,7 +410,7 @@ export interface AndroidActivityCallbacks { export interface AndroidFragmentCallbacks { onHiddenChanged(fragment: any, hidden: boolean, superFunc: Function): void; - onCreateAnimator(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any; + onCreateAnimation(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any; onCreate(fragment: any, savedInstanceState: any, superFunc: Function): void; onCreateView(fragment: any, inflater: any, container: any, savedInstanceState: any, superFunc: Function): any; onSaveInstanceState(fragment: any, outState: any, superFunc: Function): void; @@ -446,7 +446,7 @@ export interface iOSFrame { //@endprivate } -export function setActivityCallbacks(activity: any /*android.app.Activity*/): void; +export function setActivityCallbacks(activity: any /*android.support.v7.app.AppCompatActivity*/): void; //@private /** * @private @@ -455,5 +455,5 @@ export function reloadPage(): void; /** * @private */ -export function setFragmentCallbacks(fragment: any /*android.app.Fragment*/): void; +export function setFragmentCallbacks(fragment: any /*android.support.v4.app.Fragment*/): void; //@endprivate diff --git a/tns-core-modules/ui/page/page.android.ts b/tns-core-modules/ui/page/page.android.ts index 4e4adbb0f..92720e252 100644 --- a/tns-core-modules/ui/page/page.android.ts +++ b/tns-core-modules/ui/page/page.android.ts @@ -59,7 +59,7 @@ export class Page extends PageBase { [statusBarStyleProperty.getDefault](): { color: number, systemUiVisibility: number } { if (device.sdkVersion >= "21") { - const window = (this._context).getWindow(); + const window = (this._context).getWindow(); const decorView = window.getDecorView(); return { @@ -72,7 +72,7 @@ export class Page extends PageBase { } [statusBarStyleProperty.setNative](value: "dark" | "light" | { color: number, systemUiVisibility: number }) { if (device.sdkVersion >= "21") { - const window = (this._context).getWindow(); + const window = (this._context).getWindow(); const decorView = window.getDecorView(); if (value === "light") { @@ -91,7 +91,7 @@ export class Page extends PageBase { [androidStatusBarBackgroundProperty.getDefault](): number { if (device.sdkVersion >= "21") { - const window = (this._context).getWindow(); + const window = (this._context).getWindow(); return (window).getStatusBarColor(); } @@ -99,7 +99,7 @@ export class Page extends PageBase { } [androidStatusBarBackgroundProperty.setNative](value: number | Color) { if (device.sdkVersion >= "21") { - const window = (this._context).getWindow(); + const window = (this._context).getWindow(); const color = value instanceof Color ? value.android : value; (window).setStatusBarColor(color); } diff --git a/tns-core-modules/ui/tab-view/tab-view.android.ts b/tns-core-modules/ui/tab-view/tab-view.android.ts index 738e037c6..1ef75d83f 100644 --- a/tns-core-modules/ui/tab-view/tab-view.android.ts +++ b/tns-core-modules/ui/tab-view/tab-view.android.ts @@ -45,7 +45,7 @@ function initializeNativeClasses() { return; } - class TabFragmentImplementation extends android.app.Fragment { + class TabFragmentImplementation extends android.support.v4.app.Fragment { private tab: TabView; private index: number; @@ -90,8 +90,8 @@ function initializeNativeClasses() { class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter { public items: Array; - private mCurTransaction: android.app.FragmentTransaction; - private mCurrentPrimaryItem: android.app.Fragment; + private mCurTransaction: android.support.v4.app.FragmentTransaction; + private mCurrentPrimaryItem: android.support.v4.app.Fragment; constructor(public owner: TabView) { super(); @@ -127,7 +127,7 @@ function initializeNativeClasses() { const itemId = this.getItemId(position); const name = makeFragmentName(container.getId(), itemId); - let fragment: android.app.Fragment = fragmentManager.findFragmentByTag(name); + let fragment: android.support.v4.app.Fragment = fragmentManager.findFragmentByTag(name); if (fragment != null) { this.mCurTransaction.attach(fragment); } else { @@ -159,7 +159,7 @@ function initializeNativeClasses() { this.mCurTransaction = fragmentManager.beginTransaction(); } - const fragment: android.app.Fragment = object; + const fragment: android.support.v4.app.Fragment = object; this.mCurTransaction.detach(fragment); if (this.mCurrentPrimaryItem === fragment) { @@ -174,7 +174,7 @@ function initializeNativeClasses() { } setPrimaryItem(container: android.view.ViewGroup, position: number, object: java.lang.Object): void { - const fragment = object; + const fragment = object; if (fragment !== this.mCurrentPrimaryItem) { if (this.mCurrentPrimaryItem != null) { this.mCurrentPrimaryItem.setMenuVisibility(false); @@ -213,7 +213,7 @@ function initializeNativeClasses() { } isViewFromObject(view: android.view.View, object: java.lang.Object): boolean { - return (object).getView() === view; + return (object).getView() === view; } saveState(): android.os.Parcelable { diff --git a/tns-core-modules/ui/transition/fade-transition.android.ts b/tns-core-modules/ui/transition/fade-transition.android.ts index f96c035e0..244ae7f64 100644 --- a/tns-core-modules/ui/transition/fade-transition.android.ts +++ b/tns-core-modules/ui/transition/fade-transition.android.ts @@ -1,28 +1,29 @@ import { Transition, AndroidTransitionType } from "./transition"; export class FadeTransition extends Transition { - public createAndroidAnimator(transitionType: string): android.animation.Animator { - const alphaValues = Array.create("float", 2); + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + const alphaValues = []; switch (transitionType) { case AndroidTransitionType.enter: case AndroidTransitionType.popEnter: - alphaValues[0] = 0; - alphaValues[1] = 1; + alphaValues[0] = 0.0; + alphaValues[1] = 1.0; break; case AndroidTransitionType.exit: case AndroidTransitionType.popExit: - alphaValues[0] = 1; - alphaValues[1] = 0; + alphaValues[0] = 1.0; + alphaValues[1] = 0.0; break; } - const animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", alphaValues); + const animation = new android.view.animation.AlphaAnimation(alphaValues[0], alphaValues[1]); const duration = this.getDuration(); if (duration !== undefined) { - animator.setDuration(duration); + animation.setDuration(duration); } - animator.setInterpolator(this.getCurve()); - return animator; + animation.setInterpolator(this.getCurve()); + + return animation; } } diff --git a/tns-core-modules/ui/transition/flip-transition.android.ts b/tns-core-modules/ui/transition/flip-transition.android.ts index 612ab0117..6c5d989a7 100644 --- a/tns-core-modules/ui/transition/flip-transition.android.ts +++ b/tns-core-modules/ui/transition/flip-transition.android.ts @@ -1,6 +1,6 @@ import { Transition, AndroidTransitionType } from "./transition"; -//http://developer.android.com/training/animation/cardflip.html +// http://developer.android.com/training/animation/cardflip.html export class FlipTransition extends Transition { private _direction: string; @@ -9,109 +9,117 @@ export class FlipTransition extends Transition { this._direction = direction; } - public createAndroidAnimator(transitionType: string): android.animation.Animator { - let objectAnimators; - let values; - let animator: android.animation.ObjectAnimator; - const animatorSet = new android.animation.AnimatorSet(); + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + ensureRotate3dAnimationClass(); + + let animation: android.view.animation.Animation; + let animationSet: android.view.animation.AnimationSet + let rotateAnimation: android.view.animation.Animation; + let alphaAnimation: android.view.animation.Animation; const fullDuration = this.getDuration() || 300; const interpolator = this.getCurve(); const rotationY = this._direction === "right" ? 180 : -180; switch (transitionType) { case AndroidTransitionType.enter: // card_flip_right_in - objectAnimators = Array.create(android.animation.Animator, 3); - - values = Array.create("float", 2); - values[0] = 1.0; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setDuration(0); - objectAnimators[0] = animator; - - values = Array.create("float", 2); - values[0] = rotationY; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); - animator.setInterpolator(interpolator); - animator.setDuration(fullDuration); - objectAnimators[1] = animator; - - values = Array.create("float", 2); - values[0] = 0.0; - values[1] = 1.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setStartDelay(fullDuration / 2); - animator.setDuration(1); - objectAnimators[2] = animator; + animation = new Rotate3dAnimationClass(rotationY, 0.0, 0.5, 0.5); + animation.setInterpolator(interpolator); + animation.setDuration(fullDuration); break; case AndroidTransitionType.exit: // card_flip_right_out - objectAnimators = Array.create(android.animation.Animator, 2); + animation = animationSet = new android.view.animation.AnimationSet(false /* shareInterpolator */); + + rotateAnimation = new Rotate3dAnimationClass(0.0, -rotationY, 0.5, 0.5); + rotateAnimation.setInterpolator(interpolator); + rotateAnimation.setDuration(fullDuration); + animationSet.addAnimation(rotateAnimation); - values = Array.create("float", 2); - values[0] = 0.0; - values[1] = -rotationY; - animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); - animator.setInterpolator(interpolator); - animator.setDuration(fullDuration); - objectAnimators[0] = animator; - - values = Array.create("float", 2); - values[0] = 1.0; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setStartDelay(fullDuration / 2); - animator.setDuration(1); - objectAnimators[1] = animator; + alphaAnimation = new android.view.animation.AlphaAnimation(1.0, 0.0); + alphaAnimation.setStartOffset(fullDuration / 2); + alphaAnimation.setDuration(1); + animationSet.addAnimation(alphaAnimation); break; case AndroidTransitionType.popEnter: // card_flip_left_in - objectAnimators = Array.create(android.animation.Animator, 3); - - values = Array.create("float", 2); - values[0] = 1.0; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setDuration(0); - objectAnimators[0] = animator; - - values = Array.create("float", 2); - values[0] = -rotationY; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); - animator.setInterpolator(interpolator); - animator.setDuration(fullDuration); - objectAnimators[1] = animator; - - values = Array.create("float", 2); - values[0] = 0.0; - values[1] = 1.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setStartDelay(fullDuration / 2); - animator.setDuration(1); - objectAnimators[2] = animator; + animation = new Rotate3dAnimationClass(-rotationY, 0.0, 0.5, 0.5); + animation.setInterpolator(interpolator); + animation.setDuration(fullDuration); break; case AndroidTransitionType.popExit: // card_flip_left_out - objectAnimators = Array.create(android.animation.Animator, 2); + animation = animationSet = new android.view.animation.AnimationSet(false /* shareInterpolator */); + + rotateAnimation = new Rotate3dAnimationClass(0.0, rotationY, 0.5, 0.5); + rotateAnimation.setInterpolator(interpolator); + rotateAnimation.setDuration(fullDuration); + animationSet.addAnimation(rotateAnimation); - values = Array.create("float", 2); - values[0] = 0.0; - values[1] = rotationY; - animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); - animator.setInterpolator(interpolator); - animator.setDuration(fullDuration); - objectAnimators[0] = animator; - - values = Array.create("float", 2); - values[0] = 1.0; - values[1] = 0.0; - animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); - animator.setStartDelay(fullDuration / 2); - animator.setDuration(1); - objectAnimators[1] = animator; + alphaAnimation = new android.view.animation.AlphaAnimation(1.0, 0.0); + alphaAnimation.setStartOffset(fullDuration / 2); + alphaAnimation.setDuration(1); + animationSet.addAnimation(alphaAnimation); break; } - animatorSet.playTogether(objectAnimators); - return animatorSet; + return animation; } } + +let Rotate3dAnimationClass; +function ensureRotate3dAnimationClass() { + if (Rotate3dAnimationClass) { + return; + } + + /** + * Creates a new 3D rotation on the Y axis. The rotation is defined by its + * start angle and its end angle. Both angles are in degrees. The rotation + * is performed around a center point on the 2D space, definied by a pair + * of X and Y coordinates, called centerX and centerY. + * + * @param fromDegrees the start angle of the 3D rotation + * @param toDegrees the end angle of the 3D rotation + * @param centerX the X center of the 3D rotation (relative to self) + * @param centerY the Y center of the 3D rotation (relative to self) + */ + class Rotate3dAnimation extends android.view.animation.Animation { + private _camera: android.graphics.Camera; + private _pivotX: number; + private _pivotY: number; + + constructor( + private _fromDegrees: number, + private _toDegrees: number, + private _centerX: number, + private _centerY: number) { + super(); + return global.__native(this); + } + + public initialize(width: number, height: number, parentWidth: number, parentHeight: number) { + super.initialize(width, height, parentWidth, parentHeight); + this._pivotX = this.resolveSize(android.view.animation.Animation.RELATIVE_TO_SELF, this._centerX, width, parentWidth); + this._pivotY = this.resolveSize(android.view.animation.Animation.RELATIVE_TO_SELF, this._centerY, height, parentHeight); + this._camera = new android.graphics.Camera(); + } + + public applyTransformation(interpolatedTime: number, t: android.view.animation.Transformation) { + const fromDegrees = this._fromDegrees; + const degrees = fromDegrees + ((this._toDegrees - fromDegrees) * interpolatedTime); + + const pivotX = this._pivotX; + const pivotY = this._pivotY; + const camera = this._camera; + + const matrix: android.graphics.Matrix = t.getMatrix(); + + camera.save(); + camera.rotateY(degrees); + camera.getMatrix(matrix); + camera.restore(); + + matrix.preTranslate(-pivotX, -pivotY); + matrix.postTranslate(pivotX, pivotY); + } + } + + Rotate3dAnimationClass = Rotate3dAnimation; +} \ No newline at end of file diff --git a/tns-core-modules/ui/transition/slide-transition.android.ts b/tns-core-modules/ui/transition/slide-transition.android.ts index aab917aa2..3cb0c1365 100644 --- a/tns-core-modules/ui/transition/slide-transition.android.ts +++ b/tns-core-modules/ui/transition/slide-transition.android.ts @@ -13,8 +13,8 @@ export class SlideTransition extends transition.Transition { this._direction = direction; } - public createAndroidAnimator(transitionType: string): android.animation.Animator { - const translationValues = Array.create("float", 2); + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + const translationValues = []; switch (this._direction) { case "left": switch (transitionType) { @@ -97,23 +97,25 @@ export class SlideTransition extends transition.Transition { } break; } - let prop; + + let animation; if (this._direction === "left" || this._direction === "right") { - prop = "translationX"; + animation = new android.view.animation.TranslateAnimation(translationValues[0], translationValues[1], 0, 0); } else { - prop = "translationY"; + animation = new android.view.animation.TranslateAnimation(0, 0, translationValues[0], translationValues[1]); } - const animator = android.animation.ObjectAnimator.ofFloat(null, prop, translationValues); const duration = this.getDuration(); if (duration !== undefined) { - animator.setDuration(duration); + animation.setDuration(duration); } - animator.setInterpolator(this.getCurve()); - return animator; + + animation.setInterpolator(this.getCurve()); + + return animation; } - + public toString(): string { return `${super.toString()} ${this._direction}`; } diff --git a/tns-core-modules/ui/transition/transition.android.ts b/tns-core-modules/ui/transition/transition.android.ts index 95ddfa7a0..e9d9d6d36 100644 --- a/tns-core-modules/ui/transition/transition.android.ts +++ b/tns-core-modules/ui/transition/transition.android.ts @@ -38,7 +38,7 @@ export class Transition implements TransitionDefinition { throw new Error("Abstract method call"); } - public createAndroidAnimator(transitionType: string): android.animation.Animator { + public createAndroidAnimation(transitionType: string): android.view.animation.Animation { throw new Error("Abstract method call"); } diff --git a/tns-core-modules/ui/transition/transition.d.ts b/tns-core-modules/ui/transition/transition.d.ts index ffbc94ba4..f963b3c3e 100644 --- a/tns-core-modules/ui/transition/transition.d.ts +++ b/tns-core-modules/ui/transition/transition.d.ts @@ -14,6 +14,6 @@ export class Transition { public getDuration(): number; public getCurve(): any; public animateIOSTransition(containerView: any, fromView: any, toView: any, operation: any, completion: (finished: boolean) => void): void; - public createAndroidAnimator(transitionType: string): any; + public createAndroidAnimation(transitionType: string): any; public toString(): string; } \ No newline at end of file diff --git a/tns-core-modules/ui/transition/transition.ios.ts b/tns-core-modules/ui/transition/transition.ios.ts index b146fd59f..e6021999d 100644 --- a/tns-core-modules/ui/transition/transition.ios.ts +++ b/tns-core-modules/ui/transition/transition.ios.ts @@ -24,7 +24,7 @@ export class Transition implements TransitionDefinition { throw new Error("Abstract method call"); } - public createAndroidAnimator(transitionType: string): any { + public createAndroidAnimation(transitionType: string): any { throw new Error("Abstract method call"); } diff --git a/tns-core-modules/utils/utils.android.ts b/tns-core-modules/utils/utils.android.ts index 1d2eb9b47..1407209d0 100644 --- a/tns-core-modules/utils/utils.android.ts +++ b/tns-core-modules/utils/utils.android.ts @@ -113,7 +113,7 @@ export module ad { if (nativeView instanceof android.view.View) { windowToken = nativeView.getWindowToken() - } else if (androidApp.foregroundActivity instanceof android.app.Activity) { + } else if (androidApp.foregroundActivity instanceof android.support.v7.app.AppCompatActivity) { const decorView = androidApp.foregroundActivity.getWindow().getDecorView(); windowToken = decorView ? decorView.getWindowToken() : null; }