diff --git a/Scripts/debug_log_upload.py b/Scripts/debug_log_upload.py index 0c26aafb4..dd6a3239c 100755 --- a/Scripts/debug_log_upload.py +++ b/Scripts/debug_log_upload.py @@ -28,10 +28,13 @@ def execute_command(command): print e.output sys.exit(1) - +def add_field(curl_command, form_key, form_value): + curl_command.append('-F') + curl_command.append("%s=%s" % (form_key, form_value)) + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Precommit cleanup script.') - parser.add_argument('--file', help='used for starting a new version.') + parser.add_argument('--file', required=True, help='used for starting a new version.') args = parser.parse_args() @@ -41,24 +44,30 @@ if __name__ == '__main__': upload_url = params['url'] upload_fields = params['fields'] - upload_key = upload_fields['key'] + + upload_key = upload_fields.pop('key') upload_key = upload_key + os.path.splitext(args.file)[1] - upload_fields['key'] = upload_key download_url = 'https://debuglogs.org/' + upload_key print 'download_url:', download_url curl_command = ['curl', '-v', '-i', '-X', 'POST'] + + # key must appear before other fields + add_field(curl_command, 'key', upload_key) for field_name in upload_fields: - field_value = upload_fields[field_name] - curl_command.append('-F') - curl_command.append("'%s=%s'" % (field_name, field_value, )) + add_field(curl_command, field_name, upload_fields[field_name]) + + add_field(curl_command, "content-type", "application/octet-stream") + curl_command.append('-F') - curl_command.append("'file=@%s'" % (args.file,)) + curl_command.append("file=@%s" % (args.file,)) curl_command.append(upload_url) - # execute_command(curl_command) print ' '.join(curl_command) + print 'Running...' + execute_command(curl_command) + print 'download_url:', download_url - \ No newline at end of file + diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9246b3a5a..c1e4d9a1d 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -305,6 +305,8 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */; }; 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */; }; + 4598198E204E2F28009414F2 /* OWS108CallLoggingPreference.h in Headers */ = {isa = PBXBuildFile; fileRef = 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */; }; + 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */ = {isa = PBXBuildFile; fileRef = 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */; }; 45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; }; 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */; }; 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; @@ -886,6 +888,8 @@ 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; 4597E94E1D8313C100040CDE /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = translations/sq.lproj/Localizable.strings; sourceTree = ""; }; 4597E94F1D8313CB00040CDE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = translations/bg.lproj/Localizable.strings; sourceTree = ""; }; + 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWS108CallLoggingPreference.h; sourceTree = ""; }; + 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWS108CallLoggingPreference.m; sourceTree = ""; }; 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Signal/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupTableViewCell.swift; sourceTree = ""; }; 45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = ""; }; @@ -1357,6 +1361,8 @@ 346129F11FD5F31400532771 /* OWS106EnsureProfileComplete.swift */, 4503F1C2204711D200CEE724 /* OWS107LegacySounds.h */, 4503F1C1204711D200CEE724 /* OWS107LegacySounds.m */, + 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */, + 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */, 346129931FD1E30000532771 /* OWSDatabaseMigration.h */, 346129941FD1E30000532771 /* OWSDatabaseMigration.m */, 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */, @@ -2214,6 +2220,7 @@ 34480B611FD0A98800BC14EF /* UIColor+OWS.h in Headers */, 453518961FC63DBF00210559 /* SignalMessaging.h in Headers */, 3461295A1FD1D74C00532771 /* Environment.h in Headers */, + 4598198E204E2F28009414F2 /* OWS108CallLoggingPreference.h in Headers */, 34480B631FD0A98800BC14EF /* UIView+OWS.h in Headers */, 451F8A4B1FD715E1005CB9DA /* OWSGroupAvatarBuilder.h in Headers */, 347850721FDAEB17007B8332 /* OWSUserProfile.h in Headers */, @@ -2997,6 +3004,7 @@ 451F8A481FD715BA005CB9DA /* OWSContactAvatarBuilder.m in Sources */, 4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */, 346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */, + 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */, 346129D21FD2085A00532771 /* CommonStrings.swift in Sources */, 45F59A082028E4FB00E8D2B0 /* OWSAudioSession.swift in Sources */, 34612A071FD7238600532771 /* OWSContactsSyncing.m in Sources */, diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 27856a446..dd2b63c1f 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -38,7 +38,7 @@ CFBundleVersion - 2.21.0.5 + 2.21.0.9 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 4e8ecb5da..ae5cd69fc 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3203,7 +3203,7 @@ typedef enum : NSUInteger { NSURL *fileURL = [NSURL fileURLWithPath:filepath]; // Setup audio session - BOOL configuredAudio = [OWSAudioSession.shared setRecordCategoryWithAudioActivity:self.voiceNoteAudioActivity]; + BOOL configuredAudio = [OWSAudioSession.shared startRecordingAudioActivity:self.voiceNoteAudioActivity]; if (!configuredAudio) { OWSFail(@"%@ Couldn't configure audio session", self.logTag); [self cancelVoiceMemo]; diff --git a/Signal/src/ViewControllers/ExperienceUpgradesPageViewController.swift b/Signal/src/ViewControllers/ExperienceUpgradesPageViewController.swift index b5dc87592..a3b0365ee 100644 --- a/Signal/src/ViewControllers/ExperienceUpgradesPageViewController.swift +++ b/Signal/src/ViewControllers/ExperienceUpgradesPageViewController.swift @@ -9,13 +9,6 @@ private class IntroducingCustomNotificationAudioExperienceUpgradeViewController: var buttonAction: ((UIButton) -> Void)? - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - // Opt users in to the new default sound ("note") after they've seen the splash screen. - OWSSounds.setGlobalNotificationSound(.note) - } - override func loadView() { self.view = UIView.container() @@ -51,8 +44,8 @@ private class IntroducingCustomNotificationAudioExperienceUpgradeViewController: let button = addButton(title: buttonTitle) { _ in // dismiss the modally presented view controller, then proceed. self.experienceUpgradesPageViewController.dismiss(animated: true) { - guard let fromViewController = UIApplication.shared.frontmostViewController as? HomeViewController else { - owsFail("unexpected frontmostViewController: \(String(describing: UIApplication.shared.frontmostViewController))") + guard let fromViewController = UIApplication.shared.frontmostViewController else { + owsFail("frontmostViewController was unexectedly nil") return } @@ -497,12 +490,15 @@ class ExperienceUpgradesPageViewController: OWSViewController, UIPageViewControl let pageViewController: UIPageViewController + let editingDBConnection: YapDatabaseConnection + // MARK: - Initializers required init(experienceUpgrades: [ExperienceUpgrade]) { self.experienceUpgrades = experienceUpgrades setPageControlAppearance() + self.editingDBConnection = OWSPrimaryStorage.shared().newDatabaseConnection() self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) super.init(nibName: nil, bundle: nil) self.pageViewController.dataSource = self @@ -512,12 +508,7 @@ class ExperienceUpgradesPageViewController: OWSViewController, UIPageViewControl @available(*, unavailable, message:"unavailable, use initWithExperienceUpgrade instead") required init?(coder aDecoder: NSCoder) { - assert(false) - // This should never happen, but so as not to explode we give some bogus data - self.experienceUpgrades = [ExperienceUpgrade()] - self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) - super.init(coder: aDecoder) - self.pageViewController.dataSource = self + fatalError("unimplemented") } // MARK: - View lifecycle @@ -686,6 +677,16 @@ class ExperienceUpgradesPageViewController: OWSViewController, UIPageViewControl allViewControllers.append(viewController) } + override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { + // Blocking write before dismiss, to be sure they're marked as complete + // before HomeView.didAppear is re-fired. + self.editingDBConnection.readWrite { transaction in + Logger.info("\(self.logTag) marking all upgrades as seen.") + ExperienceUpgradeFinder.shared.markAllAsSeen(transaction: transaction) + } + super.dismiss(animated: flag, completion: completion) + } + func didTapDismissButton(sender: UIButton) { Logger.debug("\(TAG) in \(#function)") self.dismiss(animated: true) diff --git a/Signal/src/ViewControllers/HomeViewController.m b/Signal/src/ViewControllers/HomeViewController.m index 8bb3b1d6a..dccd63e15 100644 --- a/Signal/src/ViewControllers/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeViewController.m @@ -47,7 +47,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; @property (nonatomic) UISegmentedControl *segmentedControl; @property (nonatomic) id previewingContext; @property (nonatomic) NSSet *blockedPhoneNumberSet; -@property (nonatomic) BOOL hasShownAnyUnseenUpgradeExperiences; @property (nonatomic) BOOL isViewVisible; @property (nonatomic) BOOL isAppInBackground; @@ -287,6 +286,13 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; [self updateBarButtonItems]; } +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + [self displayAnyUnseenUpgradeExperience]; +} + - (void)updateBarButtonItems { const CGFloat kBarButtonSize = 44; @@ -510,19 +516,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; }); }]; } - - // We want to show the user the upgrade experience as soon as the app is visible to them. - // It cannot go in viewDidAppear, which is called while the app is in the background if - // we were launched from a voip notification. - if (!self.hasShownAnyUnseenUpgradeExperiences) { - dispatch_async(dispatch_get_main_queue(), ^{ - if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) { - return; - } - [self displayAnyUnseenUpgradeExperience]; - self.hasShownAnyUnseenUpgradeExperiences = YES; - }); - } } #pragma mark - startup @@ -532,21 +525,12 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; OWSAssertIsOnMainThread(); __block NSArray *unseenUpgrades; - [self.editingDbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { unseenUpgrades = [ExperienceUpgradeFinder.sharedManager allUnseenWithTransaction:transaction]; }]; return unseenUpgrades; } -- (void)markAllUpgradeExperiencesAsSeen -{ - OWSAssertIsOnMainThread(); - - [self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [ExperienceUpgradeFinder.sharedManager markAllAsSeenWithTransaction:transaction]; - }]; -} - - (void)displayAnyUnseenUpgradeExperience { OWSAssertIsOnMainThread(); @@ -556,11 +540,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; if (unseenUpgrades.count > 0) { ExperienceUpgradesPageViewController *experienceUpgradeViewController = [[ExperienceUpgradesPageViewController alloc] initWithExperienceUpgrades:unseenUpgrades]; - [self presentViewController:experienceUpgradeViewController - animated:YES - completion:^{ - [self markAllUpgradeExperiencesAsSeen]; - }]; + [self presentViewController:experienceUpgradeViewController animated:YES completion:nil]; } else if (!self.hasBeenPresented && [ProfileViewController shouldDisplayProfileViewOnLaunch]) { [ProfileViewController presentForUpgradeOrNag:self]; } else { diff --git a/Signal/src/environment/NotificationsManager.m b/Signal/src/environment/NotificationsManager.m index 3b65fac5b..7c2503dcf 100644 --- a/Signal/src/environment/NotificationsManager.m +++ b/Signal/src/environment/NotificationsManager.m @@ -25,6 +25,7 @@ @property (nonatomic, readonly) NotificationType notificationPreviewType; @property (nonatomic, readonly) NSMutableArray *notificationHistory; +@property (nonatomic, nullable) OWSAudioPlayer *audioPlayer; @end @@ -238,7 +239,8 @@ } else { if (shouldPlaySound && [Environment.preferences soundInForeground]) { OWSSound sound = [OWSSounds notificationSoundForThread:thread]; - [OWSSounds playSound:sound quiet:YES shouldRespectSilentSwitch:YES]; + self.audioPlayer = [OWSSounds audioPlayerForSound:sound]; + [self.audioPlayer playAsForegroundAlert]; } } }); @@ -343,8 +345,8 @@ } else { if (shouldPlaySound && [Environment.preferences soundInForeground]) { OWSSound sound = [OWSSounds notificationSoundForThread:thread]; - // We play the "quiet" variation of sounds if possible for notifications in the foreground. - [OWSSounds playSound:sound quiet:YES shouldRespectSilentSwitch:YES]; + self.audioPlayer = [OWSSounds audioPlayerForSound:sound]; + [self.audioPlayer playAsForegroundAlert]; } } }); diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index 805ea32df..4b15c4d82 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -12,6 +12,7 @@ #import #import #import +#import #import #import #import @@ -150,6 +151,9 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error NSString *fieldValue = fields[fieldName]; [formData appendPartWithFormData:[fieldValue dataUsingEncoding:NSUTF8StringEncoding] name:fieldName]; } + [formData appendPartWithFormData:[weakSelf.mimeType dataUsingEncoding:NSUTF8StringEncoding] + name:@"content-type"]; + NSError *error; BOOL success = [formData appendPartWithFileURL:weakSelf.fileUrl name:@"file" @@ -168,7 +172,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error [self succeedWithUrl:[NSURL URLWithString:urlString]]; } failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { - DDLogError(@"%@ failed: %@", weakSelf.logTag, uploadUrl); + DDLogError(@"%@ upload: %@ failed with error: %@", weakSelf.logTag, uploadUrl, error); [weakSelf failWithError:error]; }]; } @@ -427,7 +431,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error __weak Pastelog *weakSelf = self; self.currentUploader = [DebugLogUploader new]; [self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath] - mimeType:@"application/zip" + mimeType:OWSMimeTypeApplicationZip success:^(DebugLogUploader *uploader, NSURL *url) { if (uploader != weakSelf.currentUploader) { // Ignore events from obsolete uploaders. diff --git a/SignalMessaging/attachments/OWSVideoPlayer.swift b/SignalMessaging/attachments/OWSVideoPlayer.swift index f5405e64b..c5b86db31 100644 --- a/SignalMessaging/attachments/OWSVideoPlayer.swift +++ b/SignalMessaging/attachments/OWSVideoPlayer.swift @@ -38,7 +38,7 @@ public class OWSVideoPlayer: NSObject { } public func play() { - OWSAudioSession.shared.setPlaybackCategory(audioActivity: self.audioActivity) + OWSAudioSession.shared.startPlaybackAudioActivity(self.audioActivity) guard let item = avPlayer.currentItem else { owsFail("\(logTag) video player item was unexpectedly nil") diff --git a/SignalMessaging/environment/OWSAudioSession.swift b/SignalMessaging/environment/OWSAudioSession.swift index e892975ff..abcf9596b 100644 --- a/SignalMessaging/environment/OWSAudioSession.swift +++ b/SignalMessaging/environment/OWSAudioSession.swift @@ -33,13 +33,29 @@ public class OWSAudioSession: NSObject { private var currentActivities: [Weak] = [] - // Ignores hardware mute switch, plays through external speaker - public func setPlaybackCategory(audioActivity: AudioActivity) { + // Respects hardware mute switch, plays through external speaker, mixes with backround audio + // appropriate for foreground sound effects. + public func startAmbientAudioActivity(_ audioActivity: AudioActivity) { Logger.debug("\(logTag) in \(#function)") - // In general, we should have put the audio session back to it's default - // category when we were done with whatever activity required it to be modified - assert(avAudioSession.category == AVAudioSessionCategorySoloAmbient) + startAudioActivity(audioActivity) + + guard currentActivities.count == 1 else { + // We don't want to clobber the audio capabilities configured by (e.g.) media playback or an in-progress call + Logger.info("\(logTag) in \(#function) not touching audio session since another currentActivity exists.") + return + } + + do { + try avAudioSession.setCategory(AVAudioSessionCategoryAmbient) + } catch { + owsFail("\(logTag) in \(#function) failed with error: \(error)") + } + } + + // Ignores hardware mute switch, plays through external speaker + public func startPlaybackAudioActivity(_ audioActivity: AudioActivity) { + Logger.debug("\(logTag) in \(#function)") startAudioActivity(audioActivity) @@ -50,13 +66,9 @@ public class OWSAudioSession: NSObject { } } - public func setRecordCategory(audioActivity: AudioActivity) -> Bool { + public func startRecordingAudioActivity(_ audioActivity: AudioActivity) -> Bool { Logger.debug("\(logTag) in \(#function)") - // In general, we should have put the audio session back to it's default - // category when we were done with whatever activity required it to be modified - assert(avAudioSession.category == AVAudioSessionCategorySoloAmbient) - assert(avAudioSession.recordPermission() == .granted) startAudioActivity(audioActivity) @@ -104,8 +116,6 @@ public class OWSAudioSession: NSObject { } do { - try avAudioSession.setCategory(AVAudioSessionCategorySoloAmbient) - // When playing audio in Signal, other apps audio (e.g. Music) is paused. // By notifying when we deactivate, the other app can resume playback. try avAudioSession.setActive(false, with: [.notifyOthersOnDeactivation]) diff --git a/SignalMessaging/environment/OWSSounds.h b/SignalMessaging/environment/OWSSounds.h index 223ef11b1..506560d13 100644 --- a/SignalMessaging/environment/OWSSounds.h +++ b/SignalMessaging/environment/OWSSounds.h @@ -20,7 +20,7 @@ typedef NS_ENUM(NSUInteger, OWSSound) { OWSSound_Popcorn, OWSSound_Pulse, OWSSound_Synth, - OWSSound_ClassicNotification, + OWSSound_SignalClassic, // Ringtone Sounds OWSSound_Opening, @@ -48,9 +48,6 @@ typedef NS_ENUM(NSUInteger, OWSSound) { + (nullable NSString *)filenameForSound:(OWSSound)sound; -+ (void)playSound:(OWSSound)sound shouldRespectSilentSwitch:(BOOL)shouldRespectSilentSwitch; -+ (void)playSound:(OWSSound)sound quiet:(BOOL)quiet shouldRespectSilentSwitch:(BOOL)shouldRespectSilentSwitch; - #pragma mark - Notifications + (NSArray *)allNotificationSounds; diff --git a/SignalMessaging/environment/OWSSounds.m b/SignalMessaging/environment/OWSSounds.m index 1a4077fff..53c36daad 100644 --- a/SignalMessaging/environment/OWSSounds.m +++ b/SignalMessaging/environment/OWSSounds.m @@ -17,8 +17,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, nullable) OWSAudioPlayer *audioPlayer; - @end #pragma mark - @@ -70,13 +68,13 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob @(OWSSound_Bamboo), @(OWSSound_Chord), @(OWSSound_Circles), - @(OWSSound_ClassicNotification), @(OWSSound_Complete), @(OWSSound_Hello), @(OWSSound_Input), @(OWSSound_Keys), @(OWSSound_Popcorn), @(OWSSound_Pulse), + @(OWSSound_SignalClassic), @(OWSSound_Synth), ]; } @@ -114,8 +112,8 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return @"Pulse"; case OWSSound_Synth: return @"Synth"; - case OWSSound_ClassicNotification: - return @"Classic"; + case OWSSound_SignalClassic: + return @"Signal Classic"; // Call Audio case OWSSound_Opening: @@ -174,7 +172,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return (quiet ? @"pulse-quiet.aifc" : @"pulse.aifc"); case OWSSound_Synth: return (quiet ? @"synth-quiet.aifc" : @"synth.aifc"); - case OWSSound_ClassicNotification: + case OWSSound_SignalClassic: return (quiet ? @"classic-quiet.aifc" : @"classic.aifc"); // Ringtone Sounds @@ -209,27 +207,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return url; } -+ (void)playSound:(OWSSound)sound shouldRespectSilentSwitch:(BOOL)shouldRespectSilentSwitch -{ - [self.sharedManager playSound:sound quiet:NO shouldRespectSilentSwitch:shouldRespectSilentSwitch]; -} - -+ (void)playSound:(OWSSound)sound quiet:(BOOL)quiet shouldRespectSilentSwitch:(BOOL)shouldRespectSilentSwitch -{ - [self.sharedManager playSound:sound quiet:quiet shouldRespectSilentSwitch:shouldRespectSilentSwitch]; -} - -- (void)playSound:(OWSSound)sound quiet:(BOOL)quiet shouldRespectSilentSwitch:(BOOL)shouldRespectSilentSwitch -{ - [self.audioPlayer stop]; - self.audioPlayer = [OWSSounds audioPlayerForSound:sound quiet:quiet]; - if (shouldRespectSilentSwitch) { - [self.audioPlayer playWithCurrentAudioCategory]; - } else { - [self.audioPlayer playWithPlaybackAudioCategory]; - } -} - #pragma mark - Notifications + (OWSSound)defaultNotificationSound @@ -282,11 +259,18 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob DDLogDebug(@"%@ writing new default sound to %@", self.logTag, defaultSoundPath); NSURL *_Nullable soundURL = [OWSSounds soundURLForSound:sound quiet:NO]; - OWSAssert(soundURL); + + NSData *soundData = ^{ + if (soundURL) { + return [NSData dataWithContentsOfURL:soundURL]; + } else { + OWSAssert(sound == OWSSound_None); + return [NSData new]; + } + }(); // Quick way to achieve an atomic "copy" operation that allows overwriting if the user has previously specified // a default notification sound. - NSData *soundData = [NSData dataWithContentsOfURL:soundURL]; BOOL success = [soundData writeToFile:defaultSoundPath atomically:YES]; // The globally configured sound the user has configured is unprotected, so that we can still play the sound if the diff --git a/SignalMessaging/environment/migrations/OWS107LegacySounds.m b/SignalMessaging/environment/migrations/OWS107LegacySounds.m index 2c3214edb..20cb6c48a 100644 --- a/SignalMessaging/environment/migrations/OWS107LegacySounds.m +++ b/SignalMessaging/environment/migrations/OWS107LegacySounds.m @@ -22,7 +22,7 @@ static NSString *const OWS107LegacySoundsMigrationId = @"107"; { OWSAssert(transaction); - [OWSSounds setGlobalNotificationSound:OWSSound_ClassicNotification transaction:transaction]; + [OWSSounds setGlobalNotificationSound:OWSSound_SignalClassic transaction:transaction]; } @end diff --git a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h new file mode 100644 index 000000000..dce3b59e7 --- /dev/null +++ b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h @@ -0,0 +1,13 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWSDatabaseMigration.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS108CallLoggingPreference : OWSDatabaseMigration + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m new file mode 100644 index 000000000..04552234f --- /dev/null +++ b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWS108CallLoggingPreference.h" +#import "Environment.h" +#import "OWSPreferences.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +// Increment a similar constant for every future DBMigration +static NSString *const OWS108CallLoggingPreferenceId = @"108"; + +@implementation OWS108CallLoggingPreference + ++ (NSString *)migrationId +{ + return OWS108CallLoggingPreferenceId; +} + +- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + + [[Environment preferences] applyCallLoggingSettingsForLegacyUsersWithTransaction:transaction]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m index 6888e7951..1456c0d2e 100644 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m +++ b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m @@ -9,6 +9,7 @@ #import "OWS104CreateRecipientIdentities.h" #import "OWS105AttachmentFilePaths.h" #import "OWS107LegacySounds.h" +#import "OWS108CallLoggingPreference.h" #import "OWSDatabaseMigration.h" #import #import @@ -40,7 +41,8 @@ NS_ASSUME_NONNULL_BEGIN [[OWS104CreateRecipientIdentities alloc] initWithPrimaryStorage:primaryStorage], [[OWS105AttachmentFilePaths alloc] initWithPrimaryStorage:primaryStorage], [[OWS106EnsureProfileComplete alloc] initWithPrimaryStorage:primaryStorage], - [[OWS107LegacySounds alloc] initWithPrimaryStorage:primaryStorage] + [[OWS107LegacySounds alloc] initWithPrimaryStorage:primaryStorage], + [[OWS108CallLoggingPreference alloc] initWithPrimaryStorage:primaryStorage] ]; } diff --git a/SignalMessaging/utils/OWSAudioPlayer.h b/SignalMessaging/utils/OWSAudioPlayer.h index 98a9a2f13..10a5acfaa 100644 --- a/SignalMessaging/utils/OWSAudioPlayer.h +++ b/SignalMessaging/utils/OWSAudioPlayer.h @@ -38,6 +38,9 @@ typedef NS_ENUM(NSInteger, AudioPlaybackState) { // respects silent switch - (void)playWithCurrentAudioCategory; +// respects silent switch, mixes with others +- (void)playAsForegroundAlert; + // will ensure sound is audible, even if silent switch is enabled - (void)playWithPlaybackAudioCategory; diff --git a/SignalMessaging/utils/OWSAudioPlayer.m b/SignalMessaging/utils/OWSAudioPlayer.m index e01efcaab..4586aea1f 100644 --- a/SignalMessaging/utils/OWSAudioPlayer.m +++ b/SignalMessaging/utils/OWSAudioPlayer.m @@ -99,11 +99,20 @@ NS_ASSUME_NONNULL_BEGIN - (void)playWithPlaybackAudioCategory { OWSAssertIsOnMainThread(); - [OWSAudioSession.shared setPlaybackCategoryWithAudioActivity:self.audioActivity]; + [OWSAudioSession.shared startPlaybackAudioActivity:self.audioActivity]; [self play]; } +- (void)playAsForegroundAlert +{ + OWSAssertIsOnMainThread(); + [OWSAudioSession.shared startAmbientAudioActivity:self.audioActivity]; + + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); + [self play]; +} + - (void)play { OWSAssertIsOnMainThread(); diff --git a/SignalMessaging/utils/OWSPreferences.h b/SignalMessaging/utils/OWSPreferences.h index f68aeb28e..fe3a9a333 100644 --- a/SignalMessaging/utils/OWSPreferences.h +++ b/SignalMessaging/utils/OWSPreferences.h @@ -17,6 +17,8 @@ typedef NS_ENUM(NSUInteger, NotificationType) { extern NSString *const OWSPreferencesSignalDatabaseCollection; extern NSString *const OWSPreferencesKeyEnableDebugLog; +@class YapDatabaseReadWriteTransaction; + @interface OWSPreferences : NSObject #pragma mark - Helpers @@ -64,6 +66,8 @@ extern NSString *const OWSPreferencesKeyEnableDebugLog; #pragma mark - Legacy CallKit settings +- (void)applyCallLoggingSettingsForLegacyUsersWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; + - (BOOL)isCallKitEnabled; - (void)setIsCallKitEnabled:(BOOL)flag; diff --git a/SignalMessaging/utils/OWSPreferences.m b/SignalMessaging/utils/OWSPreferences.m index 6eef61105..73f44058b 100644 --- a/SignalMessaging/utils/OWSPreferences.m +++ b/SignalMessaging/utils/OWSPreferences.m @@ -7,6 +7,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -52,16 +53,35 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (nullable id)tryGetValueForKey:(NSString *)key { OWSAssert(key != nil); - return [OWSPrimaryStorage.dbReadConnection objectForKey:key inCollection:OWSPreferencesSignalDatabaseCollection]; + + __block id result; + [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { + result = [self tryGetValueForKey:key transaction:transaction]; + }]; + return result; +} + +- (nullable id)tryGetValueForKey:(NSString *)key transaction:(YapDatabaseReadTransaction *)transaction +{ + OWSAssert(key != nil); + return [transaction objectForKey:key inCollection:OWSPreferencesSignalDatabaseCollection]; } - (void)setValueForKey:(NSString *)key toValue:(nullable id)value +{ + [OWSPrimaryStorage.dbReadWriteConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self setValueForKey:key toValue:value transaction:transaction]; + }]; +} + +- (void)setValueForKey:(NSString *)key + toValue:(nullable id)value + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(key != nil); - [OWSPrimaryStorage.dbReadWriteConnection setObject:value - forKey:key - inCollection:OWSPreferencesSignalDatabaseCollection]; + [transaction setObject:value forKey:key inCollection:OWSPreferencesSignalDatabaseCollection]; } #pragma mark - Specific Preferences @@ -184,21 +204,7 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste } NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeySystemCallLogEnabled]; - - if (preference) { - return preference.boolValue; - } else { - // For legacy users, who may have previously intentionally disabled CallKit because they - // didn't want their calls showing up in the call log, we want to disable call logging - NSNumber *callKitPreference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled]; - if (callKitPreference && !callKitPreference.boolValue) { - // user explicitly opted out of callKit, so disable system call logging. - return NO; - } - } - - // For everyone else, including new users, enable by default. - return YES; + return preference ? preference.boolValue : YES; } - (void)setIsSystemCallLogEnabled:(BOOL)flag @@ -224,11 +230,42 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste // Therefore in versions of iOS after 11, we have no need of call privacy. #pragma mark Legacy CallKit +// Be a little conservative with system call logging with legacy users, even though it's +// not synced to iCloud, users could be concerned to suddenly see caller names in their +// recent calls list. +- (void)applyCallLoggingSettingsForLegacyUsersWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + NSNumber *_Nullable callKitPreference = + [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled transaction:transaction]; + BOOL wasUsingCallKit = callKitPreference ? [callKitPreference boolValue] : YES; + + NSNumber *_Nullable callKitPrivacyPreference = + [self tryGetValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled transaction:transaction]; + BOOL wasUsingCallKitPrivacy = callKitPrivacyPreference ? callKitPrivacyPreference.boolValue : YES; + + BOOL shouldLogCallsInRecents = ^{ + if (wasUsingCallKit && !wasUsingCallKitPrivacy) { + // User was using CallKit and explicitly opted in to showing names/numbers, + // so it's OK to continue to show names/numbers in the system recents list. + return YES; + } else { + // User was not previously showing names/numbers in the system + // recents list, so don't opt them in. + return NO; + } + }(); + + DDLogInfo(@"%@ Migrating setting - System Call Log Enabled: %d", self.logTag, shouldLogCallsInRecents); + [self setValueForKey:OWSPreferencesKeySystemCallLogEnabled + toValue:@(shouldLogCallsInRecents) + transaction:transaction]; +} + - (BOOL)isCallKitEnabled { if (@available(iOS 11, *)) { - OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag); - return NO; + OWSFail(@"%@ CallKit is always enabled for iOS11+", self.logTag); + return YES; } NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled]; @@ -238,7 +275,7 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)setIsCallKitEnabled:(BOOL)flag { if (@available(iOS 11, *)) { - OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag); + OWSFail(@"%@ CallKit is always enabled for iOS11+", self.logTag); return; } @@ -249,7 +286,7 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (BOOL)isCallKitEnabledSet { if (@available(iOS 11, *)) { - OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag); + OWSFail(@"%@ CallKit is always enabled for iOS11+", self.logTag); return NO; } diff --git a/SignalServiceKit/src/Util/MIMETypeUtil.h b/SignalServiceKit/src/Util/MIMETypeUtil.h index 4ecc7dfa7..f83a273b4 100644 --- a/SignalServiceKit/src/Util/MIMETypeUtil.h +++ b/SignalServiceKit/src/Util/MIMETypeUtil.h @@ -1,10 +1,11 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN extern NSString *const OWSMimeTypeApplicationOctetStream; +extern NSString *const OWSMimeTypeApplicationZip; extern NSString *const OWSMimeTypeImagePng; extern NSString *const OWSMimeTypeOversizeTextMessage; extern NSString *const OWSMimeTypeUnknownForTests; diff --git a/SignalServiceKit/src/Util/MIMETypeUtil.m b/SignalServiceKit/src/Util/MIMETypeUtil.m index cf26dd21f..786731ef1 100644 --- a/SignalServiceKit/src/Util/MIMETypeUtil.m +++ b/SignalServiceKit/src/Util/MIMETypeUtil.m @@ -19,6 +19,7 @@ NSString *const OWSMimeTypeApplicationOctetStream = @"application/octet-stream"; NSString *const OWSMimeTypeImagePng = @"image/png"; NSString *const OWSMimeTypeOversizeTextMessage = @"text/x-signal-plain"; NSString *const OWSMimeTypeUnknownForTests = @"unknown/mimetype"; +NSString *const OWSMimeTypeApplicationZip = @"application/zip"; NSString *const kOversizeTextAttachmentUTI = @"org.whispersystems.oversize-text-attachment"; NSString *const kOversizeTextAttachmentFileExtension = @"txt"; @@ -1250,7 +1251,7 @@ NSString *const kSyncMessageFileExtension = @"bin"; @"application/yang" : @"yang", @"application/yin+xml" : @"yin", @"application/ynd.ms-pkipko" : @"pko", - @"application/zip" : @"zip", + OWSMimeTypeApplicationZip : @"zip", @"audio/aac" : @"aac", @"audio/adpcm" : @"adp", @"audio/aiff" : @"aiff", @@ -2557,7 +2558,7 @@ NSString *const kSyncMessageFileExtension = @"bin"; @"z7" : @"application/x-zmachine", @"z8" : @"application/x-zmachine", @"zaz" : @"application/vnd.zzazz.deck+xml", - @"zip" : @"application/zip", + @"zip" : OWSMimeTypeApplicationZip, @"zir" : @"application/vnd.zul", @"zirz" : @"application/vnd.zul", @"zmm" : @"application/vnd.handheld-entertainment+xml", diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index e27813fbd..5fda82284 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.21.0 CFBundleVersion - 2.21.0.5 + 2.21.0.9 ITSAppUsesNonExemptEncryption NSAppTransportSecurity