diff --git a/Resources/iOSEinstein Storyboards-Info.plist b/Resources/iOSEinstein Storyboards-Info.plist index 39c3197ee..e82080af1 100644 --- a/Resources/iOSEinstein Storyboards-Info.plist +++ b/Resources/iOSEinstein Storyboards-Info.plist @@ -8,6 +8,29 @@ iOSEinstein CFBundleExecutable iOSEinstein + CFBundleDocumentTypes + + + CFBundleTypeName + Newton Package Data + LSHandlerRank + Owner + LSItemContentTypes + + com.newton-inc.pkg + + + + CFBundleTypeName + Newton ROM Image + LSHandlerRank + Owner + LSItemContentTypes + + com.newton-inc.rom + + + CFBundleIconFile CFBundleIdentifier @@ -31,8 +54,12 @@ LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + UIFileSharingEnabled + UISupportsDocumentBrowser + UILaunchStoryboardName Launch Screen UIMainStoryboardFile @@ -48,5 +75,49 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UTExportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Newton Package Data + UTTypeIconFiles + + UTTypeIdentifier + com.newton-inc.pkg + UTTypeTagSpecification + + public.filename-extension + + pkg + PKG + newtonpkg + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Newton ROM Image + UTTypeIconFiles + + UTTypeIdentifier + com.newton-inc.rom + UTTypeTagSpecification + + public.filename-extension + + rom + ROM + + + + diff --git a/Resources/iOSEinstein-Info.plist b/Resources/iOSEinstein-Info.plist index 0402782b1..d944fd345 100644 --- a/Resources/iOSEinstein-Info.plist +++ b/Resources/iOSEinstein-Info.plist @@ -33,8 +33,12 @@ MainWindow NSMainNibFile~ipad MainWindow_iPad + LSSupportsOpeningDocumentsInPlace + UIFileSharingEnabled + UISupportsDocumentBrowser + UIStatusBarHidden diff --git a/app/iEinstein/Classes/iEinsteinAppDelegate.mm b/app/iEinstein/Classes/iEinsteinAppDelegate.mm index de89a50d8..5b9703e34 100644 --- a/app/iEinstein/Classes/iEinsteinAppDelegate.mm +++ b/app/iEinstein/Classes/iEinsteinAppDelegate.mm @@ -66,6 +66,14 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N [window makeKeyAndVisible]; #endif + // Check if app was launched by opening a file + NSURL *url = launchOptions[UIApplicationLaunchOptionsURLKey]; + if (url) { + fprintf(stderr, "App launched with URL: %s\n", [[url absoluteString] UTF8String]); + // Handle the file immediately before emulator initialization + [self handleIncomingFile:url]; + } + NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults]; bool clearFlash = [(NSNumber*) [prefs objectForKey:@"clear_flash_ram"] boolValue]; if (clearFlash) @@ -88,6 +96,77 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N return YES; } +- (void)handleIncomingFile:(NSURL *)url +{ + if (![url.scheme isEqualToString:@"file"]) { + return; + } + + [url startAccessingSecurityScopedResource]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *srcPath = url.path; + NSString *filename = [srcPath lastPathComponent]; + NSString *dstPath = [documentsDirectory stringByAppendingPathComponent:filename]; + NSError *error = nil; + + // Determine file type + NSString *fileExtension = [[filename pathExtension] lowercaseString]; + BOOL isROMFile = [fileExtension isEqualToString:@"rom"]; + BOOL isPkgFile = [fileExtension isEqualToString:@"pkg"] || [fileExtension isEqualToString:@"newtonpkg"]; + + if(![srcPath isEqualToString:dstPath]) { + if ([[NSFileManager defaultManager] fileExistsAtPath:dstPath]) { + [[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error]; + if(error){ + NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]); + } + else{ + NSLog(@"File removed."); + } + } + [[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:dstPath error:&error]; + } + + if(error){ + NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]); + } + else if (isPkgFile) { + NSLog(@"Pkg File copied."); + [viewController installNewPackages]; + + // Remove the pkg file after installation + [[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error]; + if(error){ + NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]); + } + else{ + NSLog(@"Installed Pkg file removed."); + } + } + else if (isROMFile) { + NSLog(@"ROM File copied to Documents directory: %@", filename); + // Dismiss the "missing ROM" action sheet if it's showing and restart the emulator + [viewController checkForROMImage]; + } + + [url stopAccessingSecurityScopedResource]; +} + +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options +{ + if ([url.scheme isEqualToString:@"file"]) { + [self handleIncomingFile:url]; + return YES; + } + else { + [[UIApplication sharedApplication] openURL:url options:options completionHandler:nil]; + return YES; + } + return NO; +} + - (void)applicationWillResignActive:(UIApplication*)application { [viewController stopEmulator]; @@ -95,6 +174,10 @@ - (void)applicationWillResignActive:(UIApplication*)application - (void)applicationDidBecomeActive:(UIApplication*)application { + // Check if ROM was added while app was in background + // This will dismiss the missing ROM sheet if ROM is now available + [viewController checkForROMImage]; + if (![viewController allResourcesFound]) return; diff --git a/app/iEinstein/Classes/iEinsteinViewController.h b/app/iEinstein/Classes/iEinsteinViewController.h index 957abd6ac..c0781af7c 100644 --- a/app/iEinstein/Classes/iEinsteinViewController.h +++ b/app/iEinstein/Classes/iEinsteinViewController.h @@ -47,6 +47,7 @@ class TLog; TPlatformManager* mPlatformManager; TLog* mLog; int lastKnownScreenResolution; + UIAlertView* mMissingROMAlertView; } @property (retain, nonatomic) IBOutlet iEinsteinView* einsteinView; @@ -95,6 +96,7 @@ class TLog; - (void)verifyDeleteFlashRAM:(int)withTag; - (void)explainMissingROM; +- (BOOL)checkForROMImage; //- (void)openEinsteinMenu; - (int)allResourcesFound; diff --git a/app/iEinstein/Classes/iEinsteinViewController.mm b/app/iEinstein/Classes/iEinsteinViewController.mm index 9acc50054..aff854fc2 100644 --- a/app/iEinstein/Classes/iEinsteinViewController.mm +++ b/app/iEinstein/Classes/iEinsteinViewController.mm @@ -54,6 +54,11 @@ - (void)viewDidAppear:(BOOL)animated [super viewDidAppear:animated]; } +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + [[UIApplication sharedApplication] performSelector:@selector(terminateWithSuccess)]; +} + + // Action sheet delegate method. - (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { @@ -90,9 +95,6 @@ - (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger) break; } break; - case 3: - [[UIApplication sharedApplication] performSelector:@selector(terminateWithSuccess)]; - break; default: break; } @@ -118,22 +120,125 @@ - (void)verifyDeleteFlashRAM:(int)withTag; - (void)explainMissingROM:(id)sender { - UIActionSheet* actionSheet = [[UIActionSheet alloc] - initWithTitle:@"Newton ROM not found.\r\r" - "Einstein Emulator requires an MP2x00 US ROM image. " - "The ROM file must be named 717006.rom and copied to " - "this device using the iTunes File Sharing feature.\r\r" - "For more information please read the instructions at " - "https://github.com/pguyot/Einstein/wiki/Build-Instructions" - delegate:self - cancelButtonTitle:nil - destructiveButtonTitle:@"Quit Einstein" - otherButtonTitles:nil]; - [actionSheet setTag:3]; - [actionSheet showInView:self.view]; + NSString *message = + @"Einstein Emulator requires an MP2x00 US ROM image. " + "The ROM file must be named 717006.rom and copied to this device " + "using the Files app or the iOS share sheet.\n\n" + "For more information please read the instructions at " + "https://github.com/pguyot/Einstein/wiki/Build-Instructions"; + + mMissingROMAlertView = [[UIAlertView alloc] + initWithTitle:@"Newton ROM not found!" message:message delegate:self cancelButtonTitle:nil otherButtonTitles:@"Quit Einstein", nil]; + [mMissingROMAlertView show]; +} + +- (void)dismissMissingROMAlertAndReset +{ + if (mMissingROMAlertView) { + [mMissingROMAlertView dismissWithClickedButtonIndex:-1 animated:YES]; #if !__has_feature(objc_arc) - [actionSheet release]; + [mMissingROMAlertView release]; +#endif + mMissingROMAlertView = nil; + + // Reset the emulator now that we have a ROM + [self resetEmulator]; + } +} + +- (TROMImage*)loadROMImage +{ + // Create the ROM. + TROMImage* romImage = nil; + NSString* einsteinRExPath = nil; + NSBundle* thisBundle = [NSBundle mainBundle]; + + if (!(einsteinRExPath = [thisBundle pathForResource:@"Einstein" ofType:@"rex"])) + { + //[self abortWithMessage: @"Couldn't load Einstein REX"]; + mLog->LogLine("Couldn't load Einstein REX"); + return nil; + } + + NSString* docdir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + + NSString* theROMPath = [docdir stringByAppendingPathComponent:@"717006.rom"]; + NSString* theDebugROMPath = [docdir stringByAppendingPathComponent:@"717006.aif"]; + NSString* theDebugHighROMPath = [docdir stringByAppendingPathComponent:@"717006.rex"]; + NSString* theImagePath = [docdir stringByAppendingPathComponent:@"717006.img"]; + + NSFileManager* theFileManager = [NSFileManager defaultManager]; + + if ([theFileManager fileExistsAtPath:theROMPath]) + { +#if 0 + romImage = new TFlatROMImageWithREX( + [theROMPath fileSystemRepresentation], + [einsteinRExPath fileSystemRepresentation], + "717006", false, + [theImagePath fileSystemRepresentation]); +#else + romImage = new TFlatROMImageWithREX( + [theROMPath fileSystemRepresentation], + [einsteinRExPath fileSystemRepresentation]); +#endif + } else if ([theFileManager fileExistsAtPath:theDebugROMPath] + && [theFileManager fileExistsAtPath:theDebugHighROMPath]) + { +#if 0 + romImage = new TAIFROMImageWithREXes( + [theDebugROMPath fileSystemRepresentation], + [theDebugHighROMPath fileSystemRepresentation], + [einsteinRExPath fileSystemRepresentation], + "717006" ); +#else + romImage = new TAIFROMImageWithREXes( + [theDebugROMPath fileSystemRepresentation], + [theDebugHighROMPath fileSystemRepresentation], + [einsteinRExPath fileSystemRepresentation]); #endif + } + + NSString* theTempFilePath = [docdir stringByAppendingPathComponent:@"INSTALL ROM HERE.txt"]; + if (romImage) { + // Remove the temporary file to make the Documents folder appear in the Files app + if([theFileManager fileExistsAtPath:theTempFilePath]) { + [theFileManager removeItemAtPath:theTempFilePath error:nil]; + } + // Return the ROM image + return romImage; + } else { + // Add a temporary file to make the Documents folder appear in the Files app + if(![theFileManager fileExistsAtPath:theTempFilePath]) { + [theFileManager createFileAtPath:theTempFilePath contents:nil attributes:nil]; + } + // Print a log message with the ROM location esp. for emulator users + fprintf(stderr, "ROM file required here:\n %s\nor here:\n %s\n %s\n\n", + [theROMPath fileSystemRepresentation], + [theDebugROMPath fileSystemRepresentation], + [theDebugHighROMPath fileSystemRepresentation]); + } + return nil; +} + +- (BOOL)checkForROMImage +{ + // If we have a ROM already, do nothing + if (mROMImage) { + return YES; + } + + // Try loading the ROM + mROMImage = [self loadROMImage]; + if (mROMImage) { + if (mMissingROMAlertView) { + // ROM now exists and action sheet is showing - dismiss it and reset + [self dismissMissingROMAlertAndReset]; + } + return YES; + } + + return NO; } //- (void)setNeedsDisplayInNewtonRect:(NSValue*)v @@ -207,7 +312,7 @@ - (void)dealloc delete mSoundManager; mSoundManager = NULL; } - + delete mPrinterManager; mPrinterManager = NULL; @@ -252,62 +357,10 @@ - (int)initEmulator mLog = new TStdOutLog(); //#endif - NSString* docdir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - - // Create the ROM. - - NSString* einsteinRExPath = nil; - NSBundle* thisBundle = [NSBundle mainBundle]; - - if (!(einsteinRExPath = [thisBundle pathForResource:@"Einstein" ofType:@"rex"])) - { - //[self abortWithMessage: @"Couldn't load Einstein REX"]; - mLog->LogLine("Couldn't load Einstein REX"); - return 0; - } - - NSString* theROMPath = [docdir stringByAppendingPathComponent:@"717006.rom"]; - NSString* theDebugROMPath = [docdir stringByAppendingPathComponent:@"717006.aif"]; - NSString* theDebugHighROMPath = [docdir stringByAppendingPathComponent:@"717006.rex"]; - NSString* theImagePath = [docdir stringByAppendingPathComponent:@"717006.img"]; - - NSFileManager* theFileManager = [NSFileManager defaultManager]; - - if ([theFileManager fileExistsAtPath:theROMPath]) + // Load the ROM + mROMImage = [self loadROMImage]; + if (!mROMImage) { -#if 0 - mROMImage = new TFlatROMImageWithREX( - [theROMPath fileSystemRepresentation], - [einsteinRExPath fileSystemRepresentation], - "717006", false, - [theImagePath fileSystemRepresentation]); -#else - mROMImage = new TFlatROMImageWithREX( - [theROMPath fileSystemRepresentation], - [einsteinRExPath fileSystemRepresentation]); -#endif - } else if ([theFileManager fileExistsAtPath:theDebugROMPath] - && [theFileManager fileExistsAtPath:theDebugHighROMPath]) - { -#if 0 - mROMImage = new TAIFROMImageWithREXes( - [theDebugROMPath fileSystemRepresentation], - [theDebugHighROMPath fileSystemRepresentation], - [einsteinRExPath fileSystemRepresentation], - "717006" ); -#else - mROMImage = new TAIFROMImageWithREXes( - [theDebugROMPath fileSystemRepresentation], - [theDebugHighROMPath fileSystemRepresentation], - [einsteinRExPath fileSystemRepresentation]); -#endif - } else - { - fprintf(stderr, "ROM file required here:\n %s\nor here:\n %s\n %s\n\n", - [theROMPath fileSystemRepresentation], - [theDebugROMPath fileSystemRepresentation], - [theDebugHighROMPath fileSystemRepresentation]); - // Defer this call to explainMissingROM because self.view is not in the // visible view hierarchy yet. (We arrive here from viewWillAppear due to // other order-of-operations issues -- see issue #31) @@ -361,7 +414,7 @@ - (int)initEmulator mPrinterManager = new TIOSPrinterManager(mLog); // Create the emulator. - + NSString* docdir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString* theFlashPath = [docdir stringByAppendingPathComponent:@"flash"]; printf("Flash file is %s\n", [theFlashPath fileSystemRepresentation]);