Exit SAE when complete.

pull/1/head
Matthew Chen 7 years ago
parent d374e6ab86
commit d13511ca7d

@ -76,4 +76,6 @@ typedef void (^BackgroundTaskExpirationHandler)(void);
id<AppContext> CurrentAppContext(void); id<AppContext> CurrentAppContext(void);
void SetCurrentAppContext(id<AppContext> appContext); void SetCurrentAppContext(id<AppContext> appContext);
void ExitShareExtension(void);
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -31,4 +31,11 @@ void SetCurrentAppContext(id<AppContext> appContext)
currentAppContext = appContext; currentAppContext = appContext;
} }
void ExitShareExtension(void)
{
DDLogInfo(@"ExitShareExtension");
[DDLog flushLog];
exit(0);
}
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -16,6 +16,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
case assertionError(description: String) case assertionError(description: String)
case unsupportedMedia case unsupportedMedia
case notRegistered() case notRegistered()
case obsoleteShare
} }
private var hasInitialRootViewController = false private var hasInitialRootViewController = false
@ -29,7 +30,6 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
override open func loadView() { override open func loadView() {
super.loadView() super.loadView()
Logger.debug("\(self.logTag) \(#function)")
// This should be the first thing we do. // This should be the first thing we do.
let appContext = ShareAppExtensionContext(rootViewController:self) let appContext = ShareAppExtensionContext(rootViewController:self)
@ -42,6 +42,8 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
DebugLogger.shared().enableFileLogging() DebugLogger.shared().enableFileLogging()
} }
Logger.info("\(self.logTag) \(#function)")
_ = AppVersion() _ = AppVersion()
startupLogging() startupLogging()
@ -80,14 +82,15 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
self.loadViewController = loadViewController self.loadViewController = loadViewController
// Don't display load screen immediately, in hopes that we can avoid it altogether. // Don't display load screen immediately, in hopes that we can avoid it altogether.
after(seconds: 0.5).then { () -> Void in after(seconds: 0.5).then { [weak self] () -> Void in
guard self.presentedViewController == nil else { guard let strongSelf = self else { return }
Logger.debug("\(self.logTag) setup completed quickly, no need to present load view controller.") guard strongSelf.presentedViewController == nil else {
Logger.debug("\(strongSelf.logTag) setup completed quickly, no need to present load view controller.")
return return
} }
Logger.debug("\(self.logTag) setup is slow - showing loading screen") Logger.debug("\(strongSelf.logTag) setup is slow - showing loading screen")
self.showPrimaryViewController(loadViewController) strongSelf.showPrimaryViewController(loadViewController)
}.retainUntilComplete() }.retainUntilComplete()
// We shouldn't set up our environment until after we've consulted isReadyForAppExtensions. // We shouldn't set up our environment until after we've consulted isReadyForAppExtensions.
@ -99,10 +102,12 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
// performUpdateCheck must be invoked after Environment has been initialized because // performUpdateCheck must be invoked after Environment has been initialized because
// upgrade process may depend on Environment. // upgrade process may depend on Environment.
VersionMigrations.performUpdateCheck(completion: { VersionMigrations.performUpdateCheck(completion: { [weak self] in
AssertIsOnMainThread() AssertIsOnMainThread()
self.versionMigrationsDidComplete() guard let strongSelf = self else { return }
strongSelf.versionMigrationsDidComplete()
}) })
// We don't need to use "screen protection" in the SAE. // We don't need to use "screen protection" in the SAE.
@ -123,14 +128,19 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
name: .OWSApplicationWillEnterForeground, name: .OWSApplicationWillEnterForeground,
object: nil) object: nil)
Logger.info("\(self.logTag) application: didFinishLaunchingWithOptions completed.") Logger.info("\(self.logTag) \(#function) completed.")
OWSAnalytics.appLaunchDidBegin() OWSAnalytics.appLaunchDidBegin()
} }
deinit { deinit {
Logger.info("\(self.logTag) dealloc") Logger.info("\(self.logTag) deinit")
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
// Share extensions reside in a process that may be reused between usages.
// That isn't safe; the codebase is full of statics (e.g. singletons) which
// can't easily clean up.
ExitShareExtension()
} }
private func activate() { private func activate() {
@ -356,8 +366,10 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
Logger.debug("\(self.logTag) \(#function)") Logger.debug("\(self.logTag) \(#function)")
if isReadyForAppExtensions { if isReadyForAppExtensions {
AppReadiness.runNowOrWhenAppIsReady { AppReadiness.runNowOrWhenAppIsReady { [weak self] in
self.activate() AssertIsOnMainThread()
guard let strongSelf = self else { return }
strongSelf.activate()
} }
} }
} }
@ -418,24 +430,30 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
public func shareViewWasCompleted() { public func shareViewWasCompleted() {
Logger.info("\(self.logTag) \(#function)") Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) { self.dismiss(animated: true) { [weak self] in
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) AssertIsOnMainThread()
guard let strongSelf = self else { return }
strongSelf.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
} }
} }
public func shareViewWasCancelled() { public func shareViewWasCancelled() {
Logger.info("\(self.logTag) \(#function)") Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) { self.dismiss(animated: true) { [weak self] in
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) AssertIsOnMainThread()
guard let strongSelf = self else { return }
strongSelf.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
} }
} }
public func shareViewFailed(error: Error) { public func shareViewFailed(error: Error) {
Logger.info("\(self.logTag) \(#function)") Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) { self.dismiss(animated: true) { [weak self] in
self.extensionContext!.cancelRequest(withError: error) AssertIsOnMainThread()
guard let strongSelf = self else { return }
strongSelf.extensionContext!.cancelRequest(withError: error)
} }
} }
@ -457,25 +475,34 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
Logger.debug("\(self.logTag) modal already presented. swapping modal content for: \(viewController)") Logger.debug("\(self.logTag) modal already presented. swapping modal content for: \(viewController)")
assert(self.presentedViewController == shareViewNavigationController) assert(self.presentedViewController == shareViewNavigationController)
} }
Logger.debug("\(self.logTag) self.view.frame: \(self.view.frame)")
Logger.debug("\(self.logTag) shareViewNavigationController.view.frame: \(shareViewNavigationController.view.frame)")
} }
private func presentConversationPicker() { private func presentConversationPicker() {
self.buildAttachment().then { attachment -> Void in self.buildAttachment().then { [weak self] attachment -> Void in
let conversationPicker = SharingThreadPickerViewController(shareViewDelegate: self) AssertIsOnMainThread()
guard let strongSelf = self else { return }
let conversationPicker = SharingThreadPickerViewController(shareViewDelegate: strongSelf)
Logger.debug("\(strongSelf.logTag) presentConversationPicker: \(conversationPicker)")
conversationPicker.attachment = attachment conversationPicker.attachment = attachment
self.progressPoller = nil strongSelf.progressPoller = nil
self.loadViewController = nil strongSelf.loadViewController = nil
self.showPrimaryViewController(conversationPicker) strongSelf.showPrimaryViewController(conversationPicker)
Logger.info("showing picker with attachment: \(attachment)") Logger.info("showing picker with attachment: \(attachment)")
}.catch { error in }.catch {[weak self] error in
AssertIsOnMainThread()
guard let strongSelf = self else { return }
let alertTitle = NSLocalizedString("SHARE_EXTENSION_UNABLE_TO_BUILD_ATTACHMENT_ALERT_TITLE", let alertTitle = NSLocalizedString("SHARE_EXTENSION_UNABLE_TO_BUILD_ATTACHMENT_ALERT_TITLE",
comment: "Shown when trying to share content to a Signal user for the share extension. Followed by failure details.") comment: "Shown when trying to share content to a Signal user for the share extension. Followed by failure details.")
OWSAlerts.showAlert(withTitle: alertTitle, OWSAlerts.showAlert(withTitle: alertTitle,
message: error.localizedDescription, message: error.localizedDescription,
buttonTitle: CommonStrings.cancelButton) { _ in buttonTitle: CommonStrings.cancelButton) { _ in
self.shareViewWasCancelled() strongSelf.shareViewWasCancelled()
} }
owsFail("\(self.logTag) building attachment failed with error: \(error)") owsFail("\(strongSelf.logTag) building attachment failed with error: \(error)")
}.retainUntilComplete() }.retainUntilComplete()
} }
@ -580,9 +607,11 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
var customFileName: String? var customFileName: String?
var isConvertibleToTextMessage = false var isConvertibleToTextMessage = false
let loadCompletion: NSItemProvider.CompletionHandler = { let loadCompletion: NSItemProvider.CompletionHandler = { [weak self]
(value, error) in (value, error) in
guard let strongSelf = self else { return }
guard error == nil else { guard error == nil else {
reject(error!) reject(error!)
return return
@ -594,7 +623,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
return return
} }
Logger.info("\(self.logTag) value type: \(type(of:value))") Logger.info("\(strongSelf.logTag) value type: \(type(of:value))")
if let data = value as? Data { if let data = value as? Data {
// Although we don't support contacts _yet_, when we do we'll want to make // Although we don't support contacts _yet_, when we do we'll want to make
@ -613,7 +642,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
let fileUrl = URL(fileURLWithPath:tempFilePath) let fileUrl = URL(fileURLWithPath:tempFilePath)
fulfill((itemUrl: fileUrl, utiType: srcUtiType)) fulfill((itemUrl: fileUrl, utiType: srcUtiType))
} else if let string = value as? String { } else if let string = value as? String {
Logger.debug("\(self.logTag) string provider: \(string)") Logger.debug("\(strongSelf.logTag) string provider: \(string)")
guard let data = string.data(using: String.Encoding.utf8) else { guard let data = string.data(using: String.Encoding.utf8) else {
let writeError = ShareViewControllerError.assertionError(description: "Error writing item data: \(String(describing: error))") let writeError = ShareViewControllerError.assertionError(description: "Error writing item data: \(String(describing: error))")
reject(writeError) reject(writeError)
@ -669,17 +698,21 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
// See comments on NSItemProvider+OWS.h. // See comments on NSItemProvider+OWS.h.
itemProvider.loadData(forTypeIdentifier: srcUtiType, options: nil, completionHandler: loadCompletion) itemProvider.loadData(forTypeIdentifier: srcUtiType, options: nil, completionHandler: loadCompletion)
return promise.then { (itemUrl: URL, utiType: String) -> Promise<SignalAttachment> in return promise.then { [weak self] (itemUrl: URL, utiType: String) -> Promise<SignalAttachment> in
guard let strongSelf = self else {
let error = ShareViewControllerError.obsoleteShare
return Promise(error: error)
}
let url: URL = try { let url: URL = try {
if self.isVideoNeedingRelocation(itemProvider: itemProvider, itemUrl: itemUrl) { if strongSelf.isVideoNeedingRelocation(itemProvider: itemProvider, itemUrl: itemUrl) {
return try SignalAttachment.copyToVideoTempDir(url: itemUrl) return try SignalAttachment.copyToVideoTempDir(url: itemUrl)
} else { } else {
return itemUrl return itemUrl
} }
}() }()
Logger.debug("\(self.logTag) building DataSource with url: \(url), utiType: \(utiType)") Logger.debug("\(strongSelf.logTag) building DataSource with url: \(url), utiType: \(utiType)")
guard let dataSource = ShareViewController.createDataSource(utiType: utiType, url: url, customFileName: customFileName) else { guard let dataSource = ShareViewController.createDataSource(utiType: utiType, url: url, customFileName: customFileName) else {
throw ShareViewControllerError.assertionError(description: "Unable to read attachment data") throw ShareViewControllerError.assertionError(description: "Unable to read attachment data")
@ -694,7 +727,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
} else if url.pathExtension.count > 0 { } else if url.pathExtension.count > 0 {
// Determine a more specific utiType based on file extension // Determine a more specific utiType based on file extension
if let typeExtension = MIMETypeUtil.utiType(forFileExtension: url.pathExtension) { if let typeExtension = MIMETypeUtil.utiType(forFileExtension: url.pathExtension) {
Logger.debug("\(self.logTag) utiType based on extension: \(typeExtension)") Logger.debug("\(strongSelf.logTag) utiType based on extension: \(typeExtension)")
specificUTIType = typeExtension specificUTIType = typeExtension
} }
} }
@ -709,15 +742,17 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
// when the user hits "send". // when the user hits "send".
if let exportSession = exportSession { if let exportSession = exportSession {
let progressPoller = ProgressPoller(timeInterval: 0.1, ratioCompleteBlock: { return exportSession.progress }) let progressPoller = ProgressPoller(timeInterval: 0.1, ratioCompleteBlock: { return exportSession.progress })
self.progressPoller = progressPoller strongSelf.progressPoller = progressPoller
progressPoller.startPolling() progressPoller.startPolling()
guard let loadViewController = self.loadViewController else { guard let loadViewController = strongSelf.loadViewController else {
owsFail("load view controller was unexpectedly nil") owsFail("load view controller was unexpectedly nil")
return promise return promise
} }
loadViewController.progress = progressPoller.progress DispatchQueue.main.async {
loadViewController.progress = progressPoller.progress
}
} }
return promise return promise
@ -725,7 +760,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: specificUTIType, imageQuality: .medium) let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: specificUTIType, imageQuality: .medium)
if isConvertibleToTextMessage { if isConvertibleToTextMessage {
Logger.info("\(self.logTag) isConvertibleToTextMessage") Logger.info("\(strongSelf.logTag) isConvertibleToTextMessage")
attachment.isConvertibleToTextMessage = isConvertibleToTextMessage attachment.isConvertibleToTextMessage = isConvertibleToTextMessage
} }
return Promise(value: attachment) return Promise(value: attachment)

Loading…
Cancel
Save