+
+@interface CDVOrientation () {}
+@end
+
+@implementation CDVOrientation
+
+-(void)screenOrientation:(CDVInvokedUrlCommand *)command
+{
+ CDVPluginResult* pluginResult;
+ NSInteger orientationMask = [[command argumentAtIndex:0] integerValue];
+ CDVViewController* vc = (CDVViewController*)self.viewController;
+ NSMutableArray* result = [[NSMutableArray alloc] init];
+
+ if(orientationMask & 1) {
+ [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]];
+ }
+ if(orientationMask & 2) {
+ [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]];
+ }
+ if(orientationMask & 4) {
+ [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]];
+ }
+ if(orientationMask & 8) {
+ [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]];
+ }
+
+ SEL selector = NSSelectorFromString(@"setSupportedOrientations:");
+
+ if([vc respondsToSelector:selector]) {
+ if (orientationMask != 15 || [UIDevice currentDevice] == nil) {
+ ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result);
+ }
+
+ if ([UIDevice currentDevice] != nil){
+ NSNumber *value = nil;
+ if (orientationMask != 15) {
+ if (!_isLocked) {
+ _lastOrientation = [UIApplication sharedApplication].statusBarOrientation;
+ }
+ UIInterfaceOrientation deviceOrientation = [UIApplication sharedApplication].statusBarOrientation;
+ if(orientationMask == 8 || (orientationMask == 12 && !UIInterfaceOrientationIsLandscape(deviceOrientation))) {
+ value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
+ } else if (orientationMask == 4){
+ value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
+ } else if (orientationMask == 1 || (orientationMask == 3 && !UIInterfaceOrientationIsPortrait(deviceOrientation))) {
+ value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
+ } else if (orientationMask == 2) {
+ value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown];
+ }
+ } else {
+ if (_lastOrientation != UIInterfaceOrientationUnknown) {
+ [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:_lastOrientation] forKey:@"orientation"];
+ ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result);
+ [UINavigationController attemptRotationToDeviceOrientation];
+ }
+ }
+ if (value != nil) {
+ _isLocked = true;
+ if (@available(iOS 16.0, *)) {
+ #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_15_5 // Xcode 14 and iOS 16, or greater
+ [self.viewController setNeedsUpdateOfSupportedInterfaceOrientations];
+ #endif
+ } else {
+ [UINavigationController attemptRotationToDeviceOrientation];
+ }
+ } else {
+ _isLocked = false;
+ }
+ }
+
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+ }
+ else {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_INVALID_ACTION messageAsString:@"Error calling to set supported orientations"];
+ }
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+
+}
+
+@end
diff --git a/src/windows/CDVOrientationProxy.js b/src/windows/CDVOrientationProxy.js
new file mode 100644
index 0000000..0bb7259
--- /dev/null
+++ b/src/windows/CDVOrientationProxy.js
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* global Windows, WinJS */
+
+var DisplayInfo = Windows.Graphics.Display.DisplayInformation;
+var Orientations = Windows.Graphics.Display.DisplayOrientations;
+
+if (!window.Promise) {
+ window.Promise = WinJS.Promise;
+}
+
+module.exports = {
+ screenOrientation: function (win, fail, args) {
+ // console.log("screenOrientation proxy called with " + args);
+
+ try {
+ var prefOrients = args[0];
+ var winPrefs = 0;
+
+ if (prefOrients & 1) {
+ // UIInterfaceOrientationPortrait
+ winPrefs = winPrefs | Orientations.portrait;
+ }
+ if (prefOrients & 2) {
+ // UIInterfaceOrientationPortraitUpsideDown
+ winPrefs = winPrefs | Orientations.portraitFlipped;
+ }
+ if (prefOrients & 4) {
+ // UIInterfaceOrientationLandscapeLeft
+ winPrefs = winPrefs | Orientations.landscape;
+ }
+ if (prefOrients & 8) {
+ // UIInterfaceOrientationLandscapeRight
+ winPrefs = winPrefs | Orientations.landscapeFlipped;
+ }
+ setTimeout(function () {
+ DisplayInfo.autoRotationPreferences = winPrefs;
+ win();
+ }, 0);
+ } catch (err) {
+ console.log('error :: ' + err);
+ fail();
+ }
+ }
+};
+
+require('cordova/exec/proxy').add('CDVOrientation', module.exports);
diff --git a/tests/package.json b/tests/package.json
new file mode 100644
index 0000000..a0cf489
--- /dev/null
+++ b/tests/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "cordova-plugin-screen-orientation-tests",
+ "version": "3.0.3-dev",
+ "description": "",
+ "cordova": {
+ "id": "cordova-plugin-screen-orientation-tests",
+ "platforms": []
+ },
+ "keywords": [
+ "ecosystem:cordova"
+ ],
+ "author": "",
+ "license": "Apache 2.0"
+}
diff --git a/tests/plugin.xml b/tests/plugin.xml
new file mode 100644
index 0000000..87170cf
--- /dev/null
+++ b/tests/plugin.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ Cordova Screen Orientation Plugin Tests
+ Apache 2.0
+
+
+
+
diff --git a/tests/tests.js b/tests/tests.js
new file mode 100644
index 0000000..60c1d98
--- /dev/null
+++ b/tests/tests.js
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+exports.defineAutoTests = function () {
+ describe('window.screen', function () {
+ it('should be defined', function () {
+ expect(window.screen).toBeDefined();
+ });
+ });
+
+ describe('window.screen.orientation', function () {
+ it('should be defined', function () {
+ expect(window.screen.orientation).toBeDefined();
+ });
+
+ it('should have a `lock` function', function () {
+ expect(window.screen.orientation.lock).toBeDefined();
+ expect(typeof window.screen.orientation.lock).toBe('function');
+ });
+
+ it('should have an `unlock` function', function () {
+ expect(window.screen.orientation.unlock).toBeDefined();
+ expect(typeof window.screen.orientation.unlock).toBe('function');
+ });
+
+ it('should have a `type` property (string)', function () {
+ expect(window.screen.orientation.type).toBeDefined();
+ expect(typeof window.screen.orientation.type).toBe('string');
+ });
+
+ it('should have an `angle` property (number)', function () {
+ expect(window.screen.orientation.angle).toBeDefined();
+ expect(typeof window.screen.orientation.angle).toBe('number');
+ });
+
+ it('should have an `onchange` settable function', function () {
+ // it should be null to start
+ expect(window.screen.orientation.onchange).toBe(null);
+ // then we set it
+ var funk = function () {};
+ window.screen.orientation.onchange = funk;
+ // now it should exist
+ expect(window.screen.orientation.onchange).toBeDefined();
+ expect(window.screen.orientation.onchange).toBe(funk);
+ // clear it
+ window.screen.orientation.onchange = null;
+ // it should be null again
+ expect(window.screen.orientation.onchange).toBe(null);
+ });
+
+ it('should have an eventListener interface', function () {
+ expect(window.screen.orientation.addEventListener).toBeDefined();
+ expect(typeof window.screen.orientation.addEventListener).toBe('function');
+
+ expect(window.screen.orientation.removeEventListener).toBeDefined();
+ expect(typeof window.screen.orientation.removeEventListener).toBe('function');
+ });
+ });
+
+ describe('OrientationType', function () {
+ it('should be defined', function () {
+ expect(window.OrientationType).toBeDefined();
+ });
+
+ it('should have defined types', function () {
+ expect(window.OrientationType['portrait-primary']).toBeDefined();
+ expect(window.OrientationType['portrait-secondary']).toBeDefined();
+ expect(window.OrientationType['landscape-primary']).toBeDefined();
+ expect(window.OrientationType['landscape-secondary']).toBeDefined();
+ });
+ });
+
+ describe('OrientationLockType', function () {
+ it('should be defined', function () {
+ expect(window.OrientationLockType).toBeDefined();
+ });
+
+ it('should have defined types', function () {
+ expect(window.OrientationLockType['portrait-primary']).toBeDefined();
+ expect(window.OrientationLockType['portrait-secondary']).toBeDefined();
+ expect(window.OrientationLockType['landscape-primary']).toBeDefined();
+ expect(window.OrientationLockType['landscape-secondary']).toBeDefined();
+ expect(window.OrientationLockType.portrait).toBeDefined();
+ expect(window.OrientationLockType.landscape).toBeDefined();
+ expect(window.OrientationLockType.any).toBeDefined();
+ });
+ });
+
+ // TODO:
+ // test addEventListener('change') works
+ // test onchange works
+ describe('window.screen.orientation', function () {
+ it('should successfully lock and unlock screen orientation', function () {
+ return window.screen.orientation.lock('portrait').then(function () {
+ expect(window.screen.orientation.type).toMatch(/^portrait-/);
+ expect(window.screen.orientation.unlock).not.toThrow();
+ });
+ });
+ });
+};
+exports.defineManualTests = function (contentEl, createActionButton) {
+ createActionButton('Listen to orientationchange events', function () {
+ window.addEventListener('orientationchange', function () {
+ contentEl.innerHTML += 'Orientation changed! ' + screen.orientation.type + '
';
+ });
+ });
+ createActionButton('Unlock orientation', function () {
+ screen.orientation.unlock();
+ contentEl.innerHTML += 'Orientation unlocked.
';
+ });
+ createActionButton('Lock to portrait', function () {
+ screen.orientation.lock('portrait');
+ contentEl.innerHTML += 'Orientation locked to portrait.
';
+ });
+ createActionButton('Lock to landscape', function () {
+ screen.orientation.lock('landscape');
+ contentEl.innerHTML += 'Orientation locked to landscape.
';
+ });
+};
diff --git a/www/screenorientation.js b/www/screenorientation.js
new file mode 100644
index 0000000..4e98e9a
--- /dev/null
+++ b/www/screenorientation.js
@@ -0,0 +1,155 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* global cordova, OrientationLockType */
+
+var screenOrientation = {};
+if (!window.OrientationType) {
+ window.OrientationType = {
+ 'portrait-primary': 0,
+ 'portrait-secondary': 180,
+ 'landscape-primary': 90,
+ 'landscape-secondary': -90
+ };
+}
+if (!window.OrientationLockType) {
+ window.OrientationLockType = {
+ 'portrait-primary': 1,
+ 'portrait-secondary': 2,
+ 'landscape-primary': 4,
+ 'landscape-secondary': 8,
+ portrait: 3, // either portrait-primary or portrait-secondary.
+ landscape: 12, // either landscape-primary or landscape-secondary.
+ any: 15 // All orientations are supported (unlocked orientation)
+ };
+}
+var orientationMask = 1;
+screenOrientation.setOrientation = function (orientation) {
+ orientationMask = window.OrientationLockType[orientation];
+ cordova.exec(null, null, 'CDVOrientation', 'screenOrientation', [orientationMask, orientation]);
+};
+
+if (!screen.orientation) {
+ screen.orientation = {};
+}
+
+setOrientationProperties();
+
+function addScreenOrientationApi (screenObject) {
+ if (screenObject.unlock || screenObject.lock) {
+ screenObject.nativeLock = screenObject.lock;
+ }
+
+ screenObject.lock = function (orientation) {
+ var promiseLock;
+ var p = new Promise(function (resolve, reject) {
+ if (screenObject.nativeLock) {
+ promiseLock = screenObject.nativeLock(orientation);
+ promiseLock.then(
+ function success (_) {
+ resolve();
+ },
+ function error (_) {
+ screenObject.nativeLock = null;
+ resolveOrientation(orientation, resolve, reject);
+ }
+ );
+ } else {
+ resolveOrientation(orientation, resolve, reject);
+ }
+ });
+ return p;
+ };
+ screenObject.unlock = function () {
+ screenOrientation.setOrientation('any');
+ };
+}
+
+function resolveOrientation (orientation, resolve, reject) {
+ if (!Object.prototype.hasOwnProperty.call(OrientationLockType, orientation)) {
+ var err = new Error();
+ err.name = 'NotSupportedError';
+ reject(err); // "cannot change orientation");
+ } else {
+ screenOrientation.setOrientation(orientation);
+ resolve('Orientation set'); // orientation change successful
+ }
+}
+
+addScreenOrientationApi(screen.orientation);
+
+var onChangeListener = null;
+
+Object.defineProperty(screen.orientation, 'onchange', {
+ set: function (listener) {
+ if (onChangeListener) {
+ screen.orientation.removeEventListener('change', onChangeListener);
+ }
+ onChangeListener = listener;
+ if (onChangeListener) {
+ screen.orientation.addEventListener('change', onChangeListener);
+ }
+ },
+ get: function () {
+ return onChangeListener || null;
+ },
+ enumerable: true
+});
+
+var evtTarget = new XMLHttpRequest(); // document.createElement('div');
+var orientationchange = function () {
+ setOrientationProperties();
+ var event = document.createEvent('Events');
+ event.initEvent('change', false, false);
+ evtTarget.dispatchEvent(event);
+};
+
+screen.orientation.addEventListener = function (a, b, c) {
+ return evtTarget.addEventListener(a, b, c);
+};
+
+screen.orientation.removeEventListener = function (a, b, c) {
+ return evtTarget.removeEventListener(a, b, c);
+};
+
+function setOrientationProperties () {
+ switch (window.orientation) {
+ case 0:
+ screen.orientation.type = 'portrait-primary';
+ break;
+ case 90:
+ screen.orientation.type = 'landscape-primary';
+ break;
+ case 180:
+ screen.orientation.type = 'portrait-secondary';
+ break;
+ case -90:
+ screen.orientation.type = 'landscape-secondary';
+ break;
+ default:
+ screen.orientation.type = 'portrait-primary';
+ break;
+ }
+ screen.orientation.angle = window.orientation || 0;
+}
+window.addEventListener('orientationchange', orientationchange, true);
+
+module.exports = screenOrientation;