feat: expose application orientation (#7602)

This commit is contained in:
Vasil Chimev
2019-08-14 13:47:15 +03:00
committed by GitHub
parent a14bc9f86d
commit e2c3c8c084
15 changed files with 161 additions and 155 deletions

View File

@@ -1,21 +1,16 @@
// >> application-require
import * as app from "tns-core-modules/application";
import * as app from "tns-core-modules/application";
import * as platform from "tns-core-modules/platform";
// << application-require
// >> application-app-check
if (app.android) {
console.log("We are running on Android device!");
} else if (app.ios) {
console.log("We are running on iOS device");
}
// << application-app-check
import * as TKUnit from "../tk-unit";
if (app.android) {
console.log("We are running on an Android device!");
} else if (app.ios) {
console.log("We are running on an iOS device!");
}
export function testInitialized() {
if (platform.device.os === platform.platformNames.android) {
// we have the android defined
TKUnit.assert(app.android, "Application module not properly intialized");
} else if (platform.device.os === platform.platformNames.ios) {
TKUnit.assert(app.ios, "Application module not properly intialized");

View File

@@ -37,12 +37,13 @@ if (app.android) {
}
// << application-app-android-broadcast
export var testAndroidApplicationInitialized = function () {
export function testAndroidApplicationInitialized() {
TKUnit.assert(app.android, "Android application not initialized.");
TKUnit.assert(app.android.context, "Android context not initialized.");
TKUnit.assert(app.android.foregroundActivity, "Android foregroundActivity not initialized.");
TKUnit.assert(app.android.foregroundActivity.isNativeScriptActivity, "Andorid foregroundActivity.isNativeScriptActivity is true");
TKUnit.assert(app.android.foregroundActivity.isNativeScriptActivity, "Andorid foregroundActivity.isNativeScriptActivity is false.");
TKUnit.assert(app.android.startActivity, "Android startActivity not initialized.");
TKUnit.assert(app.android.nativeApp, "Android nativeApp not initialized.");
TKUnit.assert(app.android.orientation, "Android orientation not initialized.");
TKUnit.assert(app.android.packageName, "Android packageName not initialized.");
};
}

View File

@@ -1,4 +1,2 @@
/* tslint:disable */
//@private
import * as android from "./application-tests.android";
import * as iOS from "./application-tests.ios";

View File

@@ -1,5 +1,6 @@
/* tslint:disable:no-unused-variable */
import * as app from "tns-core-modules/application";
import * as TKUnit from "../tk-unit";
export * from "./application-tests-common";
@@ -39,3 +40,12 @@ if (app.ios) {
}
// << application-ios-delegate
export function testIOSApplicationInitialized() {
TKUnit.assert(app.ios, "iOS application not initialized.");
TKUnit.assert(app.ios.delegate, "iOS delegate not initialized.");
TKUnit.assert(app.ios.nativeApp, "iOS nativeApp not initialized.");
TKUnit.assert(app.ios.orientation, "iOS orientation not initialized.");
TKUnit.assert(app.ios.window, "iOS window not initialized.");
TKUnit.assert(app.ios.rootController, "iOS root controller not initialized.");
}

View File

@@ -1,34 +0,0 @@
---
nav-title: "application How-To"
title: "application"
environment: nativescript
description: "Examples for using application"
previous_url: /ApiReference/application/HOW-TO
---
# Application
The Application module provides abstraction over the platform-specific Application implementations.
It is the main BCL module and is required for other BCL modules to work properly.
The default bootstrap.js implementation for each platform loads and initializes this module.
{%snippet application-require%}
The pre-required `app` module is used throughout the following code snippets.
### Checking the target platform
Use the following code in case you need to check somewhere in your code the platform you are running against:
{%snippet application-app-check%}
### Using the Android-specific implementation
Accessing the Android-specific object instance (will be undefined if running on iOS)
{%snippet application-app-android%}
### Using the Android Application context
{%snippet application-app-android-context%}
### Tracking the current Activity
{%snippet application-app-android-current%}
### Registering a Broadcast Receiver (Android)
{%snippet application-app-android-broadcast%}
### Adding a Notification Observer (iOS)
{%snippet application-ios-observer%}

View File

@@ -1,46 +1,41 @@
import * as TKUnit from "../tk-unit";
import * as app from "tns-core-modules/application";
import { isIOS, isAndroid } from "tns-core-modules/platform";
// >> platform-require
import * as platformModule from "tns-core-modules/platform";
// << platform-require
export function test_setTimeout_isDefined() {
var expected;
export function test_platform() {
let expectedPlatform;
if (app.android) {
expected = "Android";
expectedPlatform = "Android";
} else {
expectedPlatform = "iOS";
}
else {
expected = "iOS";
}
TKUnit.assertEqual(platformModule.device.os, expected, "device.os");
TKUnit.assertEqual(platformModule.device.os, expectedPlatform);
}
export function snippet_print_all() {
// >> platform-current
console.log("Device model: " + platformModule.device.model);
console.log("Device type: " + platformModule.device.deviceType);
console.log("Device manufacturer: " + platformModule.device.manufacturer);
console.log("Preferred language: " + platformModule.device.language);
console.log("Preferred region: " + platformModule.device.region);
console.log("OS: " + platformModule.device.os);
console.log("OS version: " + platformModule.device.osVersion);
console.log("SDK version: " + platformModule.device.sdkVersion);
console.log("Device UUID: " + platformModule.device.uuid);
export function test_device_screen() {
TKUnit.assert(platformModule.device.model, "Device model not initialized.");
TKUnit.assert(platformModule.device.manufacturer, "Device manufacturer not initialized.");
TKUnit.assert(platformModule.device.deviceType, "Device type not initialized.");
TKUnit.assert(platformModule.device.uuid, "Device UUID not initialized.");
console.log("Screen width (px): " + platformModule.screen.mainScreen.widthPixels);
console.log("Screen height (px): " + platformModule.screen.mainScreen.heightPixels);
console.log("Screen width (DIPs): " + platformModule.screen.mainScreen.widthDIPs);
console.log("Screen height (DIPs): " + platformModule.screen.mainScreen.heightDIPs);
console.log("Screen scale: " + platformModule.screen.mainScreen.scale);
// << platform-current
TKUnit.assert(platformModule.device.language, "Preferred language not initialized.");
TKUnit.assert(platformModule.device.region, "Preferred region not initialized.");
TKUnit.assert(platformModule.device.os, "OS not initialized.");
TKUnit.assert(platformModule.device.osVersion, "OS version not initialized.");
TKUnit.assert(platformModule.device.sdkVersion, "SDK version not initialized.");
TKUnit.assert(platformModule.screen.mainScreen.widthPixels, "Screen width (px) not initialized.");
TKUnit.assert(platformModule.screen.mainScreen.heightPixels, "Screen height (px) not initialized.");
TKUnit.assert(platformModule.screen.mainScreen.widthDIPs, "Screen width (DIPs) not initialized.");
TKUnit.assert(platformModule.screen.mainScreen.heightDIPs, "Screen height (DIPs) not initialized.");
TKUnit.assert(platformModule.screen.mainScreen.scale, "Screen scale not initialized.");
}
export function testIsIOSandIsAndroid() {
if (isIOS) {
export function test_IsAndroid_IsIOS() {
if (platformModule.isIOS) {
TKUnit.assertTrue(!!NSObject, "isIOS is true-ish but common iOS APIs are not available.");
} else if (isAndroid) {
TKUnit.assertTrue(!!android, "isAndroid is true but common 'android' package is not available.");
} else if (platformModule.isAndroid) {
TKUnit.assertTrue(!!android, "isAndroid is true-ish but common 'android' package is not available.");
}
}

View File

@@ -35,10 +35,10 @@ export { Observable };
import {
AndroidApplication,
CssChangedEventData,
DiscardedErrorEventData,
iOSApplication,
LoadAppCSSEventData,
UnhandledErrorEventData,
DiscardedErrorEventData,
UnhandledErrorEventData
} from "./application";
export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData };

View File

@@ -42,6 +42,7 @@ export class AndroidApplication extends Observable implements AndroidApplication
public static activityNewIntentEvent = ActivityNewIntent;
public static activityRequestPermissionsEvent = ActivityRequestPermissions;
private _orientation: "portrait" | "landscape" | "unknown";
public paused: boolean;
public nativeApp: android.app.Application;
public context: android.content.Context;
@@ -80,6 +81,22 @@ export class AndroidApplication extends Observable implements AndroidApplication
this._pendingReceiverRegistrations.length = 0;
}
get orientation(): "portrait" | "landscape" | "unknown" {
if (!this._orientation) {
const resources = this.context.getResources();
const configuration = <android.content.res.Configuration>resources.getConfiguration();
const orientation = configuration.orientation;
this._orientation = getOrientationValue(orientation);
}
return this._orientation;
}
set orientation(value: "portrait" | "landscape" | "unknown") {
this._orientation = value;
}
public registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) {
ensureBroadCastReceiverClass();
const that = this;
@@ -232,6 +249,17 @@ global.__onLiveSync = function __onLiveSync(context?: ModuleContext) {
livesync(rootView, context);
};
function getOrientationValue(orientation: number): "portrait" | "landscape" | "unknown" {
switch (orientation) {
case android.content.res.Configuration.ORIENTATION_LANDSCAPE:
return "landscape";
case android.content.res.Configuration.ORIENTATION_PORTRAIT:
return "portrait";
default:
return "unknown";
}
}
function initLifecycleCallbacks() {
const setThemeOnLaunch = profile("setThemeOnLaunch", (activity: androidx.appcompat.app.AppCompatActivity) => {
// Set app theme after launch screen was used during startup
@@ -321,7 +349,6 @@ function initLifecycleCallbacks() {
return lifecycleCallbacks;
}
let currentOrientation: number;
function initComponentCallbacks() {
let componentCallbacks = new android.content.ComponentCallbacks2({
onLowMemory: profile("onLowMemory", function () {
@@ -335,32 +362,19 @@ function initComponentCallbacks() {
}),
onConfigurationChanged: profile("onConfigurationChanged", function (newConfig: android.content.res.Configuration) {
const newOrientation = newConfig.orientation;
if (newOrientation === currentOrientation) {
return;
const newConfigOrientation = newConfig.orientation;
const newOrientation = getOrientationValue(newConfigOrientation);
if (androidApp.orientation !== newOrientation) {
androidApp.orientation = newOrientation;
notify(<OrientationChangedEventData>{
eventName: orientationChangedEvent,
android: androidApp.nativeApp,
newValue: androidApp.orientation,
object: androidApp
});
}
currentOrientation = newOrientation;
let newValue;
switch (newOrientation) {
case android.content.res.Configuration.ORIENTATION_LANDSCAPE:
newValue = "landscape";
break;
case android.content.res.Configuration.ORIENTATION_PORTRAIT:
newValue = "portrait";
break;
default:
newValue = "unknown";
break;
}
notify(<OrientationChangedEventData>{
eventName: orientationChangedEvent,
android: androidApp.nativeApp,
newValue: newValue,
object: androidApp
});
})
});

View File

@@ -413,6 +413,12 @@ export class AndroidApplication extends Observable {
*/
startActivity: any /* androidx.appcompat.app.AppCompatActivity */;
/**
* Gets the orientation of the application.
* Available values: "portrait", "landscape", "unknown".
*/
orientation: "portrait" | "landscape" | "unknown";
/**
* The name of the application package.
*/
@@ -581,16 +587,22 @@ export interface iOSApplication {
*/
window: any /* UIWindow */;
/**
* The [UIApplication](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html).
*/
nativeApp: any /* UIApplication */;
/**
* The [UIApplicationDelegate](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html) class.
*/
delegate: any /* typeof UIApplicationDelegate */;
/**
* Gets or sets the orientation of the application.
* Available values: "portrait", "landscape", "unknown".
*/
orientation: "portrait" | "landscape" | "unknown";
/**
* The [UIApplication](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html).
*/
nativeApp: any /* UIApplication */;
/**
* Adds an observer to the default notification center for the specified notification.
* For more information, please visit 'https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/#//apple_ref/occ/instm/NSNotificationCenter/addObserver:selector:name:object:'

View File

@@ -78,9 +78,9 @@ class CADisplayLinkTarget extends NSObject {
class IOSApplication implements IOSApplicationDefinition {
private _delegate: typeof UIApplicationDelegate;
private _currentOrientation = UIDevice.currentDevice.orientation;
private _window: UIWindow;
private _observers: Array<NotificationObserver>;
private _orientation: "portrait" | "landscape" | "unknown";
private _rootView: View;
constructor() {
@@ -90,7 +90,16 @@ class IOSApplication implements IOSApplicationDefinition {
this.addNotificationObserver(UIApplicationDidEnterBackgroundNotification, this.didEnterBackground.bind(this));
this.addNotificationObserver(UIApplicationWillTerminateNotification, this.willTerminate.bind(this));
this.addNotificationObserver(UIApplicationDidReceiveMemoryWarningNotification, this.didReceiveMemoryWarning.bind(this));
this.addNotificationObserver(UIDeviceOrientationDidChangeNotification, this.orientationDidChange.bind(this));
this.addNotificationObserver(UIApplicationDidChangeStatusBarOrientationNotification, this.didChangeStatusBarOrientation.bind(this));
}
get orientation(): "portrait" | "landscape" | "unknown" {
if (!this._orientation) {
const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
this._orientation = this.getOrientationValue(statusBarOrientation);
}
return this._orientation;
}
get rootController(): UIViewController {
@@ -197,40 +206,39 @@ class IOSApplication implements IOSApplicationDefinition {
}
}
private didReceiveMemoryWarning(notification: NSNotification) {
notify(<ApplicationEventData>{ eventName: lowMemoryEvent, object: this, ios: UIApplication.sharedApplication });
}
private didChangeStatusBarOrientation(notification: NSNotification) {
const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
const newOrientation = this.getOrientationValue(statusBarOrientation);
private orientationDidChange(notification: NSNotification) {
const orientation = UIDevice.currentDevice.orientation;
if (this._currentOrientation !== orientation) {
this._currentOrientation = orientation;
let newValue: "portrait" | "landscape" | "unknown";
switch (orientation) {
case UIDeviceOrientation.LandscapeRight:
case UIDeviceOrientation.LandscapeLeft:
newValue = "landscape";
break;
case UIDeviceOrientation.Portrait:
case UIDeviceOrientation.PortraitUpsideDown:
newValue = "portrait";
break;
default:
newValue = "unknown";
break;
}
if (this._orientation !== newOrientation) {
this._orientation = newOrientation;
notify(<OrientationChangedEventData>{
eventName: orientationChangedEvent,
ios: this,
newValue: newValue,
newValue: this._orientation,
object: this
});
}
}
private didReceiveMemoryWarning(notification: NSNotification) {
notify(<ApplicationEventData>{ eventName: lowMemoryEvent, object: this, ios: UIApplication.sharedApplication });
}
private getOrientationValue(orientation: number): "portrait" | "landscape" | "unknown" {
switch (orientation) {
case UIInterfaceOrientation.LandscapeRight:
case UIInterfaceOrientation.LandscapeLeft:
return "landscape";
case UIInterfaceOrientation.PortraitUpsideDown:
case UIInterfaceOrientation.Portrait:
return "portrait";
case UIInterfaceOrientation.Unknown:
return "unknown";
}
}
public _onLivesync(context?: ModuleContext): void {
// Handle application root module
const isAppRootModuleChanged = context && context.path && context.path.includes(getMainEntry().moduleName) && context.type !== "style";

View File

@@ -19,10 +19,6 @@ class Device implements DeviceDefinition {
private _language: string;
private _region: string;
get os(): string {
return platformNames.android;
}
get manufacturer(): string {
if (!this._manufacturer) {
this._manufacturer = android.os.Build.MANUFACTURER;
@@ -31,6 +27,10 @@ class Device implements DeviceDefinition {
return this._manufacturer;
}
get os(): string {
return platformNames.android;
}
get osVersion(): string {
if (!this._osVersion) {
this._osVersion = android.os.Build.VERSION.RELEASE;

View File

@@ -215,6 +215,8 @@ export module ios {
}
/**
* @deprecated use application.orientation instead
*
* Gets an information about if current mode is Landscape.
*/
export function isLandscape(): boolean;

View File

@@ -8,7 +8,8 @@ export * from "./utils-common";
let mainScreenScale;
function isOrientationLandscape(orientation: number) {
return orientation === UIDeviceOrientation.LandscapeLeft || orientation === UIDeviceOrientation.LandscapeRight;
return orientation === UIDeviceOrientation.LandscapeLeft /* 3 */ ||
orientation === UIDeviceOrientation.LandscapeRight /* 4 */;
}
export module layout {
@@ -79,11 +80,15 @@ export module ios {
}
export function isLandscape(): boolean {
const device = UIDevice.currentDevice;
console.log("utils.ios.isLandscape() is deprecated; use application.orientation instead");
const deviceOrientation = UIDevice.currentDevice.orientation;
const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
const isDeviceOrientationLandscape = isOrientationLandscape(deviceOrientation);
const isStatusBarOrientationLandscape = isOrientationLandscape(statusBarOrientation);
return isOrientationLandscape(device.orientation) || isStatusBarOrientationLandscape;
return isDeviceOrientationLandscape || isStatusBarOrientationLandscape;
}
export const MajorVersion = NSString.stringWithString(UIDevice.currentDevice.systemVersion).intValue;
@@ -153,7 +158,7 @@ export function openFile(filePath: string): boolean {
}
// Need this so that we can use this function inside the ios module (avoid name clashing).
const openFileAtRootModule = openFile;
const openFileAtRootModule = openFile;
export function GC() {
__collect();