diff --git a/CompanionLib/FBIDBCommandExecutor.h b/CompanionLib/FBIDBCommandExecutor.h index 3329acc6d..593956a02 100644 --- a/CompanionLib/FBIDBCommandExecutor.h +++ b/CompanionLib/FBIDBCommandExecutor.h @@ -198,6 +198,13 @@ extern FBFileContainerKind const FBFileContainerKindFramework; */ - (FBFuture *)hid:(FBSimulatorHIDEvent *)event; +/** + Set the device orientation + + @return null future + */ +- (FBFuture *)set_device_orientation:(FBSimulatorDeviceOrientation)deviceOrientation; + /** Sets latitude and longitude of the Simulator. The behaviour of a directly-launched Simulator differs from Simulator.app slightly, in that the location isn't automatically set. diff --git a/CompanionLib/FBIDBCommandExecutor.m b/CompanionLib/FBIDBCommandExecutor.m index a44bd6334..8c0fa92d4 100644 --- a/CompanionLib/FBIDBCommandExecutor.m +++ b/CompanionLib/FBIDBCommandExecutor.m @@ -163,6 +163,17 @@ - (instancetype)initWithTarget:(id)target storageManager:(FBIDBStor }]; } +- (FBFuture *)set_device_orientation:(FBSimulatorDeviceOrientation)deviceOrientation +{ + id commands = (id) self.target; + if (![commands conformsToProtocol:@protocol(FBDeviceOrientationCommands)]) { + return [[FBIDBError + describeFormat:@"%@ does not conform to FBDeviceOrientationCommands", commands] + failFuture]; + } + return [commands setDeviceOrientation:deviceOrientation]; +} + - (FBFuture *)set_location:(double)latitude longitude:(double)longitude { id commands = (id) self.target; diff --git a/FBControlCore/Commands/FBDeviceOrientationCommands.h b/FBControlCore/Commands/FBDeviceOrientationCommands.h new file mode 100644 index 000000000..99caf8396 --- /dev/null +++ b/FBControlCore/Commands/FBDeviceOrientationCommands.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(unsigned int, FBSimulatorDeviceOrientation) { + FBSimulatorDeviceOrientationPortrait = 1, + FBSimulatorDeviceOrientationPortraitUpsideDown = 2, + FBSimulatorDeviceOrientationLandscapeLeft = 3, + FBSimulatorDeviceOrientationLandscapeRight = 4 +}; + + +/** + Commands to change the device orientation + */ +@protocol FBDeviceOrientationCommands + +/** + Sets the device orientation + + @return A future that when the orientation change has been dispatched + */ +- (FBFuture *)setDeviceOrientation:(FBSimulatorDeviceOrientation)deviceOrientation; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/FBControlCore/FBControlCore.h b/FBControlCore/FBControlCore.h index 3587d2703..35d874661 100644 --- a/FBControlCore/FBControlCore.h +++ b/FBControlCore/FBControlCore.h @@ -95,3 +95,4 @@ #import #import #import +#import diff --git a/FBSimulatorControl.xcodeproj/project.pbxproj b/FBSimulatorControl.xcodeproj/project.pbxproj index cbb0ae6db..1e8b0d117 100644 --- a/FBSimulatorControl.xcodeproj/project.pbxproj +++ b/FBSimulatorControl.xcodeproj/project.pbxproj @@ -49,6 +49,10 @@ A2FD7D0E2739922400542291 /* FBSimulatorMemoryCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = A2FD7D0C2739922400542291 /* FBSimulatorMemoryCommands.h */; settings = {ATTRIBUTES = (Public, ); }; }; A2FD7D11273992A400542291 /* FBSimulatorNotificationCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = A2FD7D0F273992A400542291 /* FBSimulatorNotificationCommands.h */; settings = {ATTRIBUTES = (Public, ); }; }; A2FD7D12273992A400542291 /* FBSimulatorNotificationCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = A2FD7D10273992A400542291 /* FBSimulatorNotificationCommands.m */; }; + A6F73D2D2E0ED14E00AAE67E /* FBDeviceOrientationCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = A6F73D2C2E0ED14E00AAE67E /* FBDeviceOrientationCommands.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A6F73D2F2E0ED97E00AAE67E /* FBSimulatorDeviceOrientationCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = A6F73D2E2E0ED97E00AAE67E /* FBSimulatorDeviceOrientationCommands.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A6F73D312E0ED9DE00AAE67E /* FBSimulatorDeviceOrientationCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = A6F73D302E0ED9DE00AAE67E /* FBSimulatorDeviceOrientationCommands.m */; }; + A6F73D332E0EEC8200AAE67E /* SimDevice+GSEventsPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = A6F73D322E0EEC8200AAE67E /* SimDevice+GSEventsPrivate.m */; }; AA0080D71DB4CCFD009A25CB /* FBProcessTerminationStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0080D51DB4CCFD009A25CB /* FBProcessTerminationStrategy.h */; settings = {ATTRIBUTES = (Public, ); }; }; AA0080D81DB4CCFD009A25CB /* FBProcessTerminationStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = AA0080D61DB4CCFD009A25CB /* FBProcessTerminationStrategy.m */; }; AA07B3451D531FEA007FB614 /* FBSimulatorInflationStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = AA07B3431D531FEA007FB614 /* FBSimulatorInflationStrategy.h */; }; @@ -777,6 +781,11 @@ A2FD7D0C2739922400542291 /* FBSimulatorMemoryCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorMemoryCommands.h; sourceTree = ""; }; A2FD7D0F273992A400542291 /* FBSimulatorNotificationCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorNotificationCommands.h; sourceTree = ""; }; A2FD7D10273992A400542291 /* FBSimulatorNotificationCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorNotificationCommands.m; sourceTree = ""; }; + A66FF9F42DF88FC5002A30D3 /* SimDevice+GSEventsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimDevice+GSEventsPrivate.h"; sourceTree = ""; }; + A6F73D2C2E0ED14E00AAE67E /* FBDeviceOrientationCommands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBDeviceOrientationCommands.h; sourceTree = ""; }; + A6F73D2E2E0ED97E00AAE67E /* FBSimulatorDeviceOrientationCommands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBSimulatorDeviceOrientationCommands.h; sourceTree = ""; }; + A6F73D302E0ED9DE00AAE67E /* FBSimulatorDeviceOrientationCommands.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorDeviceOrientationCommands.m; sourceTree = ""; }; + A6F73D322E0EEC8200AAE67E /* SimDevice+GSEventsPrivate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SimDevice+GSEventsPrivate.m"; sourceTree = ""; }; AA0080D51DB4CCFD009A25CB /* FBProcessTerminationStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBProcessTerminationStrategy.h; sourceTree = ""; }; AA0080D61DB4CCFD009A25CB /* FBProcessTerminationStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBProcessTerminationStrategy.m; sourceTree = ""; }; AA017F4C1BD7784700F45E9D /* libShimulator.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libShimulator.dylib; sourceTree = ""; }; @@ -1588,6 +1597,7 @@ A2FD7D032739887200542291 /* FBDapServerCommands.h */, AA2E38E021E626B10065C800 /* FBDebuggerCommands.h */, AA685CD22550299200E2DD9D /* FBDeveloperDiskImageCommands.h */, + A6F73D2C2E0ED14E00AAE67E /* FBDeviceOrientationCommands.h */, AA8D347124D04BD0000FAC59 /* FBDiagnosticInformationCommands.h */, AA59F46424912730007C1875 /* FBEraseCommands.h */, AA98266924E1348C006E05A9 /* FBFileCommands.h */, @@ -1633,6 +1643,8 @@ AAB475F620C8217F00B37634 /* FBSimulatorCrashLogCommands.m */, AA8ECA892254F301007925E6 /* FBSimulatorDebuggerCommands.h */, AA8ECA8A2254F301007925E6 /* FBSimulatorDebuggerCommands.m */, + A6F73D2E2E0ED97E00AAE67E /* FBSimulatorDeviceOrientationCommands.h */, + A6F73D302E0ED9DE00AAE67E /* FBSimulatorDeviceOrientationCommands.m */, AA3EA8511F31B20D003FBDC1 /* FBSimulatorFileCommands.h */, AA3EA8521F31B20D003FBDC1 /* FBSimulatorFileCommands.m */, AA56445C1E5F6ED0006C1077 /* FBSimulatorKeychainCommands.h */, @@ -1809,6 +1821,8 @@ AA386D251E44F04F005C6118 /* NSString-SimServiceContextExtras.h */, AA386D261E44F04F005C6118 /* NSUserDefaults-SimDefaults.h */, AA386D271E44F04F005C6118 /* SimDevice.h */, + A66FF9F42DF88FC5002A30D3 /* SimDevice+GSEventsPrivate.h */, + A6F73D322E0EEC8200AAE67E /* SimDevice+GSEventsPrivate.m */, AA386D281E44F04F005C6118 /* SimDevice+Removed.h */, AA386D291E44F04F005C6118 /* SimDeviceBootInfo.h */, AA386D2A1E44F04F005C6118 /* SimDeviceIO.h */, @@ -2945,6 +2959,7 @@ AA9517811C15F54600A89CAD /* FBSimulatorControl+PrincipalClass.h in Headers */, AA95177E1C15F54600A89CAD /* FBSimulator+Private.h in Headers */, AAE90BC21D2A4578004EE9E5 /* FBSimulatorControlFrameworkLoader.h in Headers */, + A6F73D2F2E0ED97E00AAE67E /* FBSimulatorDeviceOrientationCommands.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3024,6 +3039,7 @@ EEBD607E1C9062E900298A07 /* FBControlCoreError.h in Headers */, AA685CD32550299200E2DD9D /* FBDeveloperDiskImageCommands.h in Headers */, AA5B3DD61FE3134D00B77376 /* FBScreenshotCommands.h in Headers */, + A6F73D2D2E0ED14E00AAE67E /* FBDeviceOrientationCommands.h in Headers */, AABBF3231DAC110000E2B6AF /* FBProcessBuilder.h in Headers */, AA805F7F1F0D0E0000AB31DE /* FBLogCommands.h in Headers */, A2FD7D042739887200542291 /* FBDapServerCommands.h in Headers */, @@ -3444,6 +3460,7 @@ AA9517521C15F54600A89CAD /* FBSimulatorConfiguration.m in Sources */, AA9517541C15F54600A89CAD /* FBSimulatorControlConfiguration.m in Sources */, AA1B5D921CF6DD800073A203 /* FBSimulatorDeletionStrategy.m in Sources */, + A6F73D312E0ED9DE00AAE67E /* FBSimulatorDeviceOrientationCommands.m in Sources */, AA6F824821639857007AAF19 /* FBAppleSimctlCommandExecutor.m in Sources */, AAAB13291C74EC0300F3B083 /* FBSimulatorSet.m in Sources */, A2FD7D012739885300542291 /* FBSimulatorDapServerCommands.m in Sources */, @@ -3484,6 +3501,7 @@ A2FD7D12273992A400542291 /* FBSimulatorNotificationCommands.m in Sources */, AA6A3B401CC1597000E016C4 /* FBSimulatorBootStrategy.m in Sources */, AAF7B0DA1DDB1CD60079ED11 /* FBSimulatorShutdownStrategy.m in Sources */, + A6F73D332E0EEC8200AAE67E /* SimDevice+GSEventsPrivate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.h b/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.h new file mode 100644 index 000000000..d2d7f4eba --- /dev/null +++ b/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + An Implementation of FBSimulatorAccessibilityCommands. + */ +@interface FBSimulatorDeviceOrientationCommands : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.m b/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.m new file mode 100644 index 000000000..ced45f1ed --- /dev/null +++ b/FBSimulatorControl/Commands/FBSimulatorDeviceOrientationCommands.m @@ -0,0 +1,56 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "FBSimulatorDeviceOrientationCommands.h" + +#import "FBSimulator.h" +#import "SimulatorApp/Purple.h" +#import "CoreSimulator/SimDevice+GSEventsPrivate.h" + +@interface FBSimulatorDeviceOrientationCommands () + +@property (nonatomic, weak, readonly) FBSimulator *simulator; + +@end + +@implementation FBSimulatorDeviceOrientationCommands + +#pragma mark Initializers + ++ (nonnull instancetype)commandsWithTarget:(FBSimulator *)target +{ + return [[self alloc] initWithSimulator:target]; +} + +- (instancetype)initWithSimulator:(FBSimulator *)simulator +{ + self = [super init]; + if (!self) { + return nil; + } + + _simulator = simulator; + + return self; +} + +- (nonnull FBFuture *)setDeviceOrientation:(FBSimulatorDeviceOrientation)deviceOrientation +{ + PurpleMessage *purpleMessage = malloc(sizeof(PurpleMessage)); + memset(purpleMessage, 0, sizeof(PurpleMessage)); + purpleMessage->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); + purpleMessage->header.msgh_size = sizeof(PurpleMessage); + purpleMessage->header.msgh_id = 0x7b; + purpleMessage->message.field1 = 0x20032; + purpleMessage->message.field9 = 0x4; + purpleMessage->message.field10 = (unsigned int)deviceOrientation; + return sendPurpleMessage(self.simulator.device, purpleMessage); +} + +@end diff --git a/FBSimulatorControl/Management/FBSimulator.h b/FBSimulatorControl/Management/FBSimulator.h index 246475fa1..0b32af926 100644 --- a/FBSimulatorControl/Management/FBSimulator.h +++ b/FBSimulatorControl/Management/FBSimulator.h @@ -17,6 +17,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -31,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN /** An implementation of FBiOSTarget for iOS Simulators. */ -@interface FBSimulator : NSObject +@interface FBSimulator : NSObject #pragma mark Properties diff --git a/FBSimulatorControl/Management/FBSimulator.m b/FBSimulatorControl/Management/FBSimulator.m index 9f469fdc3..2a84adad4 100644 --- a/FBSimulatorControl/Management/FBSimulator.m +++ b/FBSimulatorControl/Management/FBSimulator.m @@ -40,6 +40,7 @@ #import "FBSimulatorSettingsCommands.h" #import "FBSimulatorVideoRecordingCommands.h" #import "FBSimulatorXCTestCommands.h" +#import "FBSimulatorDeviceOrientationCommands.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wprotocol" @@ -311,6 +312,7 @@ - (void)forwardInvocation:(NSInvocation *)invocation FBXCTraceRecordCommands.class, FBSimulatorNotificationCommands.class, FBSimulatorMemoryCommands.class, + FBSimulatorDeviceOrientationCommands.class ]; }); return commandClasses; diff --git a/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.h b/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.h new file mode 100644 index 000000000..6c9cc2104 --- /dev/null +++ b/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import +#import + +#import + +@interface SimDevice (GSEventsPrivate) +- (NSMachPort*)gsEventsPort; +- (dispatch_queue_t)gsEventsQueue; +- (void)sendPurpleMessage:(PurpleMessage*)purpleMessage; +@end + +FBFuture *sendPurpleMessage(SimDevice *self, PurpleMessage *purpleMessage); diff --git a/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.m b/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.m new file mode 100644 index 000000000..a540b940f --- /dev/null +++ b/PrivateHeaders/CoreSimulator/SimDevice+GSEventsPrivate.m @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "SimDevice+GSEventsPrivate.h" + +#import + +#import + +NSMachPort *gsEventsPort(SimDevice* self, SEL _cmd); +dispatch_queue_t gsEventsQueue(SimDevice *self, SEL _cmd); + +NSMachPort *gsEventsPort(SimDevice* self, SEL _cmd) +{ + NSMachPort *gsEventsPort = objc_getAssociatedObject(self, _cmd); + if (gsEventsPort.isValid) { + return gsEventsPort; + } + + NSError *error; + mach_port_name_t purpleWorkspacePort = [self lookup:@"PurpleWorkspacePort" error:&error]; + gsEventsPort = (NSMachPort*)[NSMachPort portWithMachPort:purpleWorkspacePort options:NSMachPortDeallocateSendRight]; + if (!gsEventsPort) { + mach_port_deallocate(mach_task_self(), purpleWorkspacePort); + return nil; + } + + objc_setAssociatedObject(self, _cmd, gsEventsPort, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return gsEventsPort; +} + +dispatch_queue_t gsEventsQueue(SimDevice *self, SEL _cmd) +{ + dispatch_queue_t gsEventsQueue = objc_getAssociatedObject(self, _cmd); + if (gsEventsQueue) { + return gsEventsQueue; + } + + @synchronized (self) { + gsEventsQueue = objc_getAssociatedObject(self, _cmd); + if (gsEventsQueue) { + return gsEventsQueue; + } + + gsEventsQueue = dispatch_queue_create("com.apple.iphonesimulator.SimDeviceSimulatorBridge.gsEventsQueue", DISPATCH_QUEUE_SERIAL); + if (!gsEventsQueue) { + return nil; + } + + objc_setAssociatedObject(self, _cmd, gsEventsQueue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return gsEventsQueue; + } +} + +FBFuture *sendPurpleMessage(SimDevice *self, PurpleMessage *purpleMessage) +{ + return [FBFuture onQueue:gsEventsQueue(self, @selector(gsEventsQueue)) resolve:^FBFuture *{ + if (!MACH_PORT_VALID(purpleMessage->header.msgh_remote_port)) { + NSMachPort *port = gsEventsPort(self, @selector(gsEventsPort)); + purpleMessage->header.msgh_remote_port = [port machPort]; + } + mach_msg_return_t result = mach_msg_send((mach_msg_header_t*)&purpleMessage->header); + free(purpleMessage); + if (result != MACH_MSG_SUCCESS) { + return [[FBControlCoreError + describeFormat:@"Could not send purple message, mach_msg_send() failed with %0x08x", result] + failFuture]; + } + return FBFuture.empty; + }]; +} diff --git a/idb_companion.xcodeproj/project.pbxproj b/idb_companion.xcodeproj/project.pbxproj index 5ae468f7f..7fd54b953 100644 --- a/idb_companion.xcodeproj/project.pbxproj +++ b/idb_companion.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 717AFB7528328C11009714AB /* XCTestListBundlesMethodHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717AFB7428328C11009714AB /* XCTestListBundlesMethodHandler.swift */; }; 7185380C2B22884200D2C033 /* BridgeFuture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7185380A2B22884200D2C033 /* BridgeFuture.swift */; }; 7185380D2B22884200D2C033 /* BridgeQueues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7185380B2B22884200D2C033 /* BridgeQueues.swift */; }; + A6F73D3B2E0F064200AAE67E /* SetDeviceOrientationMethodHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F73D3A2E0F063A00AAE67E /* SetDeviceOrientationMethodHandler.swift */; }; AA0DB08223CF0DCB00E8CDEE /* FBIDBXCTestReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0DB08023CF0DCB00E8CDEE /* FBIDBXCTestReporter.h */; }; AA8F751F249116B700F3BF18 /* FBiOSTargetDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = AA8F751D249116B700F3BF18 /* FBiOSTargetDescription.h */; }; AA8F7520249116B700F3BF18 /* FBiOSTargetDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = AA8F751E249116B700F3BF18 /* FBiOSTargetDescription.m */; }; @@ -246,6 +247,7 @@ 717AFB7428328C11009714AB /* XCTestListBundlesMethodHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestListBundlesMethodHandler.swift; sourceTree = ""; }; 7185380A2B22884200D2C033 /* BridgeFuture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgeFuture.swift; sourceTree = ""; }; 7185380B2B22884200D2C033 /* BridgeQueues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgeQueues.swift; sourceTree = ""; }; + A6F73D3A2E0F063A00AAE67E /* SetDeviceOrientationMethodHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeviceOrientationMethodHandler.swift; sourceTree = ""; }; AA0DB08023CF0DCB00E8CDEE /* FBIDBXCTestReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBIDBXCTestReporter.h; sourceTree = ""; }; AA8F751D249116B700F3BF18 /* FBiOSTargetDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBiOSTargetDescription.h; sourceTree = ""; }; AA8F751E249116B700F3BF18 /* FBiOSTargetDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBiOSTargetDescription.m; sourceTree = ""; }; @@ -648,6 +650,7 @@ DB6177CA2819501E00C33A0A /* MvMethodHandler.swift */, DB6177D3281A956600C33A0A /* HidMethodHandler.swift */, DB9B072F281A985700F2C119 /* OpenUrlMethodHandler.swift */, + A6F73D3A2E0F063A00AAE67E /* SetDeviceOrientationMethodHandler.swift */, DBCAE6AA2816C8F700C15D07 /* PushMethodHandler.swift */, DB6E6C442824152600144D97 /* TailMethodHandler.swift */, DBF88BBB282900D1003B1494 /* UninstallMethodHandler.swift */, @@ -992,6 +995,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A6F73D3B2E0F064200AAE67E /* SetDeviceOrientationMethodHandler.swift in Sources */, DB5C38E227B54FCA00401F91 /* GRPCSwiftServer.swift in Sources */, DBF88BC22829057F003B1494 /* SendNotificationMethodHandler.swift in Sources */, DBF88BBE2829032A003B1494 /* FocusMethodHandler.swift in Sources */, diff --git a/idb_companion/SwiftServer/CompanionServiceProvider.swift b/idb_companion/SwiftServer/CompanionServiceProvider.swift index 5d7abc04f..fbc5b5e48 100644 --- a/idb_companion/SwiftServer/CompanionServiceProvider.swift +++ b/idb_companion/SwiftServer/CompanionServiceProvider.swift @@ -131,6 +131,12 @@ final class CompanionServiceProvider: Idb_CompanionServiceAsyncProvider { } } + func set_device_orientation(request: Idb_SetDeviceOrientationRequest, context: GRPCAsyncServerCallContext) async throws -> Idb_SetDeviceOrientationResponse { + return try await FBTeardownContext.withAutocleanup { + try await SetDeviceOrientationMethodHandler(commandExecutor: commandExecutor).handle(request: request, context: context) + } + } + func set_location(request: Idb_SetLocationRequest, context: GRPCAsyncServerCallContext) async throws -> Idb_SetLocationResponse { return try await FBTeardownContext.withAutocleanup { try await SetLocationMethodHandler(commandExecutor: commandExecutor) diff --git a/idb_companion/SwiftServer/Interceptors/CompanionServiceInterceptors.swift b/idb_companion/SwiftServer/Interceptors/CompanionServiceInterceptors.swift index 817db5dcd..dfe9454a2 100644 --- a/idb_companion/SwiftServer/Interceptors/CompanionServiceInterceptors.swift +++ b/idb_companion/SwiftServer/Interceptors/CompanionServiceInterceptors.swift @@ -78,6 +78,10 @@ final class CompanionServiceInterceptors: Idb_CompanionServiceServerInterceptorF commonInterceptors() } + func makeset_device_orientationInterceptors() -> [ServerInterceptor] { + commonInterceptors() + } + func makeset_locationInterceptors() -> [ServerInterceptor] { commonInterceptors() } diff --git a/idb_companion/SwiftServer/MethodHandlers/SetDeviceOrientationMethodHandler.swift b/idb_companion/SwiftServer/MethodHandlers/SetDeviceOrientationMethodHandler.swift new file mode 100644 index 000000000..6bb04b579 --- /dev/null +++ b/idb_companion/SwiftServer/MethodHandlers/SetDeviceOrientationMethodHandler.swift @@ -0,0 +1,37 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import CompanionLib +import GRPC +import IDBGRPCSwift +import FBSimulatorControl + +struct SetDeviceOrientationMethodHandler { + + let commandExecutor: FBIDBCommandExecutor + + func handle(request: Idb_SetDeviceOrientationRequest, context: GRPCAsyncServerCallContext) async throws -> Idb_SetDeviceOrientationResponse { + try await BridgeFuture.await(commandExecutor.set_device_orientation(fbSimulatorDeviceOrientation(from: request.deviceOrientation))) + return .init() + } + + private func fbSimulatorDeviceOrientation(from request: Idb_SetDeviceOrientationRequest.DeviceOrientation) throws -> FBSimulatorDeviceOrientation { + switch request { + case .portrait: + return .portrait + case .portraitUpsideDown: + return .portraitUpsideDown + case .landscapeLeft: + return .landscapeLeft + case .landscapeRight: + return .landscapeRight + default: + throw GRPCStatus(code: .invalidArgument, message: "Unrecognized deviceOrientation") + } + } +} + diff --git a/proto/idb.proto b/proto/idb.proto index dcafa5ee9..0aa7d58d3 100644 --- a/proto/idb.proto +++ b/proto/idb.proto @@ -29,6 +29,7 @@ service CompanionService { rpc focus(FocusRequest) returns (FocusResponse) {} rpc hid(stream HIDEvent) returns (HIDResponse) {} rpc open_url(OpenUrlRequest) returns (OpenUrlRequest) {} + rpc set_device_orientation(SetDeviceOrientationRequest) returns (SetDeviceOrientationResponse) {}; rpc set_location(SetLocationRequest) returns (SetLocationResponse) {} rpc send_notification(SendNotificationRequest) returns (SendNotificationResponse) {} @@ -314,6 +315,18 @@ message OpenUrlRequest { message OpenUrlResponse {} +message SetDeviceOrientationRequest { + enum DeviceOrientation { + PORTRAIT = 0; + PORTRAIT_UPSIDE_DOWN = 1; + LANDSCAPE_RIGHT = 2; + LANDSCAPE_LEFT = 3; + } + DeviceOrientation device_orientation = 1; +} + +message SetDeviceOrientationResponse {} + message ContactsUpdateRequest { Payload payload = 1; }