I've been trying to use SBSettings toggles to turn things on or off--like Airplane Mode, WiFi, SSH, etc--but I just can't figure out why my code works for some of these toggles and not all. Granted, I'm only talking about "simple" toggles; not toggles that bring up their own window with their own controls like for volume or brightness. I've been able to successfully turn on/off 3G, data, my ringer, the mywi toggle... things like that, but I can't figure why some of the toggles--Airplane Mode, Bluetooth, WiFi--on my phone won't respond to the same code that works with the other things mentioned above.
Here's some of the code I'm using:
//.h #import <UIKit/UIKit.h> #import <sys/stat.h> #include "/usr/include/dlfcn.h" typedef enum toggleTypes { SIMPLE, NOT_SIMPLE } ToggleTypes; typedef bool (*BoolFn)(); typedef void (*VoidBoolFn)(bool b); @interface Toggle : NSObject @property (strong, nonatomic) NSString *toggleName; @property (nonatomic) ToggleTypes toggleType; - (Toggle *) initWithFullPath:(NSString *) togglePath; - (BOOL) isEnabled; - (BOOL) isCapable; - (BOOL) getStateFast; - (void) setState:(BOOL) state; @end //.m @implementation Toggle { @private void *_dylibHandle; BoolFn _isCapable; BoolFn _isEnabled; BoolFn _getStateFast; VoidBoolFn _setState; } @synthesize toggleName = _toggleName; @synthesize toggleType = _toggleType; - (Toggle *) initWithFullPath:(NSString *) togglePath { self.toggleName = [[togglePath stringByDeletingLastPathComponent] lastPathComponent]; const char *fullName = [togglePath UTF8String]; struct stat fstat; if( stat(fullName, &fstat) != 0 ) { NSLog(@"Reading error for file %s", fullName); return nil; } dlerror(); _dylibHandle = dlopen(fullName, RTLD_LAZY | RTLD_LOCAL ); if( !_dylibHandle) { NSLog(@"dlopen encountered an error and did not open file: %s", fullName); return nil; } dlerror(); _isCapable = dlsym(_dylibHandle, "isCapable"); char *error = dlerror(); if( !_isCapable ) { NSLog(@"An error was encountered while loading symbol \"isCapable\"\nFile: %s\nError: %s", fullName, error); return nil; } _isEnabled = dlsym(_dylibHandle, "isEnabled"); error = dlerror(); if( !_isCapable ) { NSLog(@"An error was encountered while loading symbol \"isEnabled\"\nFile: %s\nError: %s", fullName, error); return nil; } _getStateFast = dlsym(_dylibHandle, "getStateFast"); error = dlerror(); if( !_isCapable ) { NSLog(@"An error was encountered while loading symbol \"getStateFast\"\nFile: %s\nError: %s", fullName, error); return nil; } _setState = dlsym(_dylibHandle, "setState"); error = dlerror(); if( !_isCapable ) { NSLog(@"An error was encountered while loading symbol \"getStateFast\"\nFile: %s\nError: %s", fullName, error); return nil; } NSArray *windowsBefore = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] subviews]; [self setState:[self isEnabled]]; NSArray *windowsAfter = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] subviews]; if( [windowsAfter count] > [windowsBefore count] ) { self.toggleType = NOT_SIMPLE; for (UIView *view in windowsAfter) { if( ![windowsBefore containsObject:view] ) [view removeFromSuperview]; } } else { self.toggleType = SIMPLE; } return self; } - (BOOL) isEnabled { return _isEnabled(); } - (BOOL) isCapable { return _isCapable(); } - (BOOL) getStateFast { return _getStateFast(); } - (void) setState:(BOOL) state { _setState(state); } - (void) dealloc { dlclose(_dylibHandle); } @end The code that calls initWithFullPath:
if( [directoryToggleNames objectForKey:toggleName] == nil ) { if ((strlen(SBTOGGLES_PATH) + strlen([toggleName UTF8String] + strlen("/Toggle.dylib")) + 1) > _POSIX_PATH_MAX) { NSLog(@"Toggle %@ has a path name that is too long", toggleName); return nil; } char fullName[_POSIX_PATH_MAX + 1]; strcpy(fullName, SBTOGGLES_PATH); strcat(fullName, [toggleName UTF8String]); strcat(fullName, "/Toggle.dylib"); NSString *fullPath = [NSString stringWithUTF8String:fullName]; return [[OSToggle alloc] initWithFullPath:fullPath]; } return [[OSToggle alloc] initWithFullPath:[directoryToggleNames objectForKey:toggleName]]; The code that uses the code above and the toggle class itself:
ToggleScanner *scanner = [ToggleScanner getInstance]; NSDictionary *toggleDict = [self getToggleDictionary]; for (ToggleBase *t in [toggleDict allValues] ) { OSToggle *toggle = [scanner getToggleByName:t.name]; if( [t.type isEqualToString:@"simple"] ) { NSLog(@"isCapable: %@; isEnabled: %@", ( [toggle isCapable] ? @"YES" : @"NO" ), ( [toggle isEnabled] ? @"YES" : @"NO" )); [toggle setState:t.state.boolValue]; NSLog(@"Set toggle, %@, to %@; result isEnabled: %@", t.name, ( t.state.boolValue ? @"YES" : @"NO" ), ( [toggle isEnabled] ? @"YES" : @"NO" ) ); } else { NSLog(@"Toggle is not a simple type"); } } ToggleScanner just looks in the SBSettings toggle directory and builds a dictionary based on the toggles it finds there. getToggleDict is a method that takes a NSData object out of CoreData and turns it into a set of toggles and state that I can, in turn, execute. ToggleBase is just an information holding class; it has no methods.
Its rough, but it works on some of the toggles. The question is: Is there something I'm doing wrong here? Both the Airplane Mode and the 3G toggle are simple on/off switches, yet this code works on the 3G toggle but not the Airplane Mode one. Any ideas, comments, and/or suggestions as to why this is?
Edit 1: Added code that calls the toggle class and some descriptions about it.