TM-SGNL-iOS/SignalShareExtension/ShareAppExtensionContext.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07: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 type: SignalServiceKit.AppContextType { .share }
var isMainAppAndActive: Bool { false }
var isMainAppAndActiveIsolated: 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 }
@MainActor
func resetAppDataAndExit() -> Never {
owsFail("Not main app.")
}
}