Fix notification % escaping, debug UI

Consolidated the notifications debug UI (and fixed it) to make testing
this a bit easier.

// FREEBIE
This commit is contained in:
Michael Kirk 2018-02-12 17:18:37 -08:00
parent 9ad437a04c
commit debd556e09
6 changed files with 150 additions and 43 deletions

View File

@ -282,6 +282,7 @@
4574A5D61DD6704700C6B692 /* CallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4574A5D51DD6704700C6B692 /* CallService.swift */; };
4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */; };
45794E861E00620000066731 /* CallUIAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45794E851E00620000066731 /* CallUIAdapter.swift */; };
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457C87B72032645C008D52D6 /* DebugUINotifications.swift */; };
45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */; };
458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458967101DC117CC00E9DD21 /* AccountManagerTest.swift */; };
@ -818,6 +819,7 @@
4579431C1E7C8CE9008ED0C0 /* Pastelog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pastelog.h; sourceTree = "<group>"; };
4579431D1E7C8CE9008ED0C0 /* Pastelog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pastelog.m; sourceTree = "<group>"; };
45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallUIAdapter.swift; path = UserInterface/CallUIAdapter.swift; sourceTree = "<group>"; };
457C87B72032645C008D52D6 /* DebugUINotifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugUINotifications.swift; sourceTree = "<group>"; };
45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactAvatarBuilder.h; sourceTree = "<group>"; };
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactAvatarBuilder.m; sourceTree = "<group>"; };
@ -1464,6 +1466,7 @@
34D8C0241ED3673300188D7C /* DebugUIMessages.m */,
341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */,
341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */,
457C87B72032645C008D52D6 /* DebugUINotifications.swift */,
34E3EF0E1EFC2684007F6822 /* DebugUIPage.h */,
34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */,
4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */,
@ -2933,6 +2936,7 @@
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
34D1F0B71F87F8850066283D /* OWSGenericAttachmentView.m in Sources */,
34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */,
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */,
34B3F8871E8DF1700035BE1A /* NotificationSettingsViewController.m in Sources */,
347E0B7B2003CD7500BC2F76 /* OWSBackupImportViewController.m in Sources */,
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
@ -3152,7 +3156,11 @@
"DEBUG=1",
"$(inherited)",
);
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DEBUG=1 $(inherited) SSK_BUILDING_FOR_TESTS=1";
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = (
"DEBUG=1",
"$(inherited)",
"SSK_BUILDING_FOR_TESTS=1",
);
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -8,13 +8,8 @@ import SignalMessaging
class DebugUICalling: DebugUIPage {
let TAG = "[DebugUICalling]"
// MARK: Dependencies
var notificationsAdapter: CallNotificationsAdapter {
return SignalApp.shared().callService.notificationsAdapter
}
var messageSender: MessageSender {
return Environment.current().messageSender
}
@ -32,30 +27,15 @@ class DebugUICalling: DebugUIPage {
}
let sectionItems = [
OWSTableItem(title:"⚠️ Missed Call") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCall(call, callerName: thread.name())
}
},
OWSTableItem(title:"⚠️ New Safety Number (rejected)") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNewIdentity(call: call, callerName: thread.name())
}
},
OWSTableItem(title:"⚠️ No Longer Verified (rejected)") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: thread.name())
}
},
OWSTableItem(title:"Send 'hangup' for old call") {
let kFakeCallId = UInt64(12345)
let hangupMessage = OWSCallHangupMessage(callId: kFakeCallId)
let callMessage = OWSOutgoingCallMessage(thread: thread, hangupMessage: hangupMessage)
self.messageSender.sendPromise(message: callMessage).then {
Logger.debug("\(self.TAG) Successfully sent hangup call message to \(thread.contactIdentifier())")
Logger.debug("\(self.logTag) Successfully sent hangup call message to \(thread.contactIdentifier())")
}.catch { error in
Logger.error("\(self.TAG) failed to send hangup call message to \(thread.contactIdentifier()) with error: \(error)")
Logger.error("\(self.logTag) failed to send hangup call message to \(thread.contactIdentifier()) with error: \(error)")
}
},
OWSTableItem(title:"Send 'busy' for old call") {
@ -64,27 +44,13 @@ class DebugUICalling: DebugUIPage {
let callMessage = OWSOutgoingCallMessage(thread: thread, busyMessage: busyMessage)
self.messageSender.sendPromise(message: callMessage).then {
Logger.debug("\(self.TAG) Successfully sent busy call message to \(thread.contactIdentifier())")
Logger.debug("\(self.logTag) Successfully sent busy call message to \(thread.contactIdentifier())")
}.catch { error in
Logger.error("\(self.TAG) failed to send busy call message to \(thread.contactIdentifier()) with error: \(error)")
Logger.error("\(self.logTag) failed to send busy call message to \(thread.contactIdentifier()) with error: \(error)")
}
}
]
return OWSTableSection(title: "Call Notifications (⚠️) have delay: \(kNotificationDelay)s", items: sectionItems)
}
// MARK: Helpers
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
// we give a little delay.
let kNotificationDelay: TimeInterval = 5
func delayedDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (SignalCall) -> Void) {
let call = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: 0)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + kNotificationDelay) {
callBlock(call)
}
return OWSTableSection(title: "Call Debug", items: sectionItems)
}
}

View File

@ -0,0 +1,117 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalServiceKit
import SignalMessaging
class DebugUINotifications: DebugUIPage {
// MARK: Dependencies
var notificationsManager: NotificationsManager {
return SignalApp.shared().notificationsManager
}
var notificationsAdapter: CallNotificationsAdapter {
return SignalApp.shared().callService.notificationsAdapter
}
var messageSender: MessageSender {
return Environment.current().messageSender
}
var contactsManager: OWSContactsManager {
return Environment.current().contactsManager
}
// MARK: Overrides
override func name() -> String {
return "Notifications"
}
override func section(thread aThread: TSThread?) -> OWSTableSection? {
guard let thread = aThread else {
owsFail("\(logTag) Notifications must specify thread.")
return nil
}
var sectionItems = [
OWSTableItem(title:"Last Incoming Message") {
Logger.info("\(self.logTag) scheduling notification for incoming message.")
self.delayedNotificationDispatch {
Logger.info("\(self.logTag) dispatching")
TSStorageManager.shared().newDatabaseConnection().read({ (transaction) in
guard let viewTransaction = transaction.ext(TSMessageDatabaseViewExtensionName) as? YapDatabaseViewTransaction else {
owsFail("unable to build view transaction")
return
}
guard let threadId = thread.uniqueId else {
owsFail("thread had no uniqueId")
return
}
guard let incomingMessage = viewTransaction.lastObject(inGroup: threadId) as? TSIncomingMessage else {
owsFail("last message was not an incoming message.")
return
}
Logger.info("\(self.logTag) notifying user of incoming message")
self.notificationsManager.notifyUser(for: incomingMessage, in: thread, contactsManager: self.contactsManager, transaction: transaction)
})
}
}
]
if let contactThread = thread as? TSContactThread {
sectionItems += [
OWSTableItem(title:"Call Missed") {
self.delayedNotificationDispatchWithFakeCall(thread: contactThread) { call in
self.notificationsAdapter.presentMissedCall(call, callerName: thread.name())
}
},
OWSTableItem(title:"Call Rejected: New Safety Number") {
self.delayedNotificationDispatchWithFakeCall(thread: contactThread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNewIdentity(call: call, callerName: thread.name())
}
},
OWSTableItem(title:"Call Rejected: No Longer Verified") {
self.delayedNotificationDispatchWithFakeCall(thread: contactThread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: thread.name())
}
}
]
}
return OWSTableSection(title: "Notifications have delay: \(kNotificationDelay)s", items: sectionItems)
}
// MARK: Helpers
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
// we give a little delay.
let kNotificationDelay: TimeInterval = 5
func delayedNotificationDispatch(block: @escaping () -> Void) {
// Notifications won't sound if the app is suspended.
let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + kNotificationDelay) {
block()
// We don't want to endBackgroundTask until *after* the notifications manager is done,
// but it dispatches async without a completion handler, so we just wait a while extra.
// This is fragile, but it's only for debug UI.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0) {
UIApplication.shared.endBackgroundTask(taskIdentifier)
}
}
}
func delayedNotificationDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (SignalCall) -> Void) {
let call = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: 0)
delayedNotificationDispatch {
callBlock(call)
}
}
}

View File

@ -85,6 +85,8 @@ NS_ASSUME_NONNULL_BEGIN
[subsectionItems
addObject:[self itemForSubsection:[DebugUICalling new] viewController:viewController thread:thread]];
}
[subsectionItems
addObject:[self itemForSubsection:[DebugUINotifications new] viewController:viewController thread:thread]];
[subsectionItems addObject:[self itemForSubsection:[DebugUIProfile new] viewController:viewController thread:thread]];
[subsectionItems
addObject:[self itemForSubsection:[DebugUIStress new] viewController:viewController thread:thread]];

View File

@ -312,9 +312,12 @@ NSString *const kNotificationsManagerNewMesssageSoundName = @"NewMessage.aifc";
[NSString stringWithFormat:NSLocalizedString(@"APN_MESSAGE_IN_GROUP_DETAILED", nil),
senderName,
threadName,
messageDescription];
[DisplayableText filterNotificationText:messageDescription]];
} else {
notification.alertBody = [NSString stringWithFormat:@"%@: %@", senderName, messageDescription];
notification.alertBody = [NSString stringWithFormat:@"%@: %@",
senderName,
[DisplayableText filterNotificationText:messageDescription]];
}
break;
}

View File

@ -215,6 +215,17 @@ extension String {
return text.ows_stripped()
}
@objc
public class func filterNotificationText(_ text: String?) -> String? {
guard let text = self.filterText(text) else {
return nil
}
// Notifications strip anything that looks lik a printf formatting character,
// so literal "%" must be escaped in order to appear in notification text.
return text.replacingOccurrences(of: "%", with: "%%")
}
private class func hasExcessiveDiacriticals(text: String) -> Bool {
// discard any zalgo style text, by detecting maximum number of glyphs per character
for char in text.enumerated() {