Signal-iOS/SignalShareExtension/ShareAppExtensionContext.swift
Adam Sharp 03e018de09
Raise deployment target to iOS 15
The only remaining code using API deprecated in iOS 15 is navigation bar
styling code that never runs on iOS 15.
2024-07-08 16:04:03 -04:00

195 lines
6.8 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import SignalServiceKit
// This is _NOT_ a singleton and will be instantiated each time that the SAE is used.
final class ShareAppExtensionContext: NSObject {
private let rootViewController: UIViewController
var mainWindow: UIWindow?
@Atomic private var internalReportedApplicationState: UIApplication.State = .active
let appLaunchTime = Date()
let appForegroundTime = Date()
private var notificationCenterObservers = [NSObjectProtocol]()
static private let isRTL: Bool = {
// Borrowed from PureLayout's AppExtension compatible RTL support.
// App Extensions may not access UIApplication.sharedApplication.
// Fall back to checking the bundle's preferred localization character direction
guard let language = Bundle.main.preferredLocalizations.first else { return false }
return NSLocale.characterDirection(forLanguage: language) == .rightToLeft
}()
init(rootViewController: UIViewController) {
self.rootViewController = rootViewController
super.init()
let mainQueue = OperationQueue.main
notificationCenterObservers.append(NotificationCenter.default.addObserver(
forName: NSNotification.Name.NSExtensionHostDidBecomeActive,
object: nil,
queue: mainQueue) { [weak self] notification in
Logger.info("")
self?.internalReportedApplicationState = .active
BenchManager.bench(
title: "Slow post DidBecomeActive",
logIfLongerThan: 0.01,
logInProduction: true) {
NotificationCenter.default.post(name: NSNotification.Name.OWSApplicationDidBecomeActive, object: nil)
}
}
)
notificationCenterObservers.append(NotificationCenter.default.addObserver(
forName: NSNotification.Name.NSExtensionHostWillResignActive,
object: nil,
queue: mainQueue) { [weak self] notification in
Logger.info("")
self?.internalReportedApplicationState = .inactive
BenchManager.bench(
title: "Slow post WillResignActive",
logIfLongerThan: 0.01,
logInProduction: true) {
NotificationCenter.default.post(name: NSNotification.Name.OWSApplicationWillResignActive, object: nil)
}
}
)
notificationCenterObservers.append(NotificationCenter.default.addObserver(
forName: NSNotification.Name.NSExtensionHostDidEnterBackground,
object: nil,
queue: mainQueue) { [weak self] notification in
Logger.info("")
self?.internalReportedApplicationState = .background
BenchManager.bench(
title: "Slow post DidEnterBackground",
logIfLongerThan: 0.01,
logInProduction: true) {
NotificationCenter.default.post(name: NSNotification.Name.OWSApplicationDidEnterBackground, object: nil)
}
}
)
notificationCenterObservers.append(NotificationCenter.default.addObserver(
forName: NSNotification.Name.NSExtensionHostWillEnterForeground,
object: nil,
queue: mainQueue) { [weak self] notification in
Logger.info("")
self?.internalReportedApplicationState = .inactive
BenchManager.bench(
title: "Slow post WillEnterForeground",
logIfLongerThan: 0.01,
logInProduction: true) {
NotificationCenter.default.post(name: NSNotification.Name.OWSApplicationWillEnterForeground, object: nil)
}
}
)
}
deinit {
notificationCenterObservers.forEach { observer in
NotificationCenter.default.removeObserver(observer)
}
}
}
extension ShareAppExtensionContext: AppContext {
var isMainApp: Bool { false }
var isMainAppAndActive: Bool { false }
var isNSE: Bool { false }
var isRTL: Bool { Self.isRTL }
var isRunningTests: Bool { false }
var frame: CGRect { rootViewController.view.frame }
var reportedApplicationState: UIApplication.State {
internalReportedApplicationState
}
func isInBackground() -> Bool {
return reportedApplicationState == .background
}
func isAppForegroundAndActive() -> Bool {
return reportedApplicationState == .active
}
func beginBackgroundTask(with expirationHandler: BackgroundTaskExpirationHandler) -> UIBackgroundTaskIdentifier { .invalid }
func endBackgroundTask(_ backgroundTaskIdentifier: UIBackgroundTaskIdentifier) {
owsAssertBeta(backgroundTaskIdentifier == .invalid)
}
func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjectsDescription: String) {
Logger.debug("Ignoring request to block sleep.")
}
func frontmostViewController() -> UIViewController? {
return rootViewController.findFrontmostViewController(ignoringAlerts: true)
}
func openSystemSettings() { }
func open(_ url: URL, completion: ((Bool) -> Void)? = nil) { }
func runNowOrWhenMainAppIsActive(_ block: AppActiveBlock) {
owsFailBeta("Cannot run main app active blocks in share extension.")
}
func appDocumentDirectoryPath() -> String {
guard let documentDirectoryURL = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).last
else {
owsFail("Could not find documents directory.")
}
return documentDirectoryURL.path
}
func appSharedDataDirectoryPath() -> String {
guard let groupContainerDirectoryURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: TSConstants.applicationGroup
)
else {
owsFail("Could not find application group directory.")
}
return groupContainerDirectoryURL.path
}
func appDatabaseBaseDirectoryPath() -> String {
appSharedDataDirectoryPath()
}
func appUserDefaults() -> UserDefaults {
return UserDefaults(suiteName: TSConstants.applicationGroup)!
}
func mainApplicationStateOnLaunch() -> UIApplication.State {
owsFailBeta("Not main app.")
return .inactive
}
func canPresentNotifications() -> Bool { false }
var shouldProcessIncomingMessages: Bool { false }
var hasUI: Bool { true }
var debugLogsDirPath: String { DebugLogger.shareExtensionDebugLogsDirPath }
func resetAppDataAndExit() -> Never {
owsFail("Not main app.")
}
}