From 5e61307ce3c65faa4ab2243beb74e7f7c3451d4d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 7 Nov 2017 10:32:28 -0500 Subject: [PATCH] Don't ask for microphone permissions if app is not active. // FREEBIE --- Signal.xcodeproj/project.pbxproj | 24 ++++---- Signal/src/Signal-Bridging-Header.h | 2 +- .../ConversationViewController.m | 42 +++++++++---- .../FingerprintViewScanController.m | 2 +- .../OWSLinkedDevicesTableViewController.m | 2 +- Signal/src/call/OutboundCallInitiator.swift | 29 +++++---- .../src/util/UIViewController+Permissions.h | 18 ++++++ ...sions.m => UIViewController+Permissions.m} | 60 +++++++++++++------ 8 files changed, 125 insertions(+), 54 deletions(-) create mode 100644 Signal/src/util/UIViewController+Permissions.h rename Signal/src/util/{UIViewController+CameraPermissions.m => UIViewController+Permissions.m} (51%) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9ac095887..f882b863b 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -373,7 +373,7 @@ E1370BE518A0686C00826894 /* r.caf in Resources */ = {isa = PBXBuildFile; fileRef = E18AB40C18A05754001A532A /* r.caf */; }; E1370BE618A0686C00826894 /* sonarping.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = E18AB40D18A05754001A532A /* sonarping.mp3 */; }; E32B0699162419B7046BC643 /* libPods-Signal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DB8EE72F8522189E3E2CB45 /* libPods-Signal.a */; }; - EF764C351DB67CC5000D9A87 /* UIViewController+CameraPermissions.m in Sources */ = {isa = PBXBuildFile; fileRef = EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */; }; + EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */ = {isa = PBXBuildFile; fileRef = EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */; }; FC3BD9881A30A790005B96BB /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3BD9871A30A790005B96BB /* Social.framework */; }; FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC5CDF371A3393DD00B47253 /* error_white@2x.png */; }; FC5CDF3A1A3393DD00B47253 /* warning_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC5CDF381A3393DD00B47253 /* warning_white@2x.png */; }; @@ -870,8 +870,8 @@ E18AB40D18A05754001A532A /* sonarping.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = sonarping.mp3; sourceTree = ""; }; E1A0AD8B16E13FDD0071E604 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = ""; }; - EF764C331DB67CC5000D9A87 /* UIViewController+CameraPermissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+CameraPermissions.h"; path = "util/UIViewController+CameraPermissions.h"; sourceTree = ""; }; - EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+CameraPermissions.m"; path = "util/UIViewController+CameraPermissions.m"; sourceTree = ""; }; + EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+Permissions.h"; path = "util/UIViewController+Permissions.h"; sourceTree = ""; }; + EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+Permissions.m"; path = "util/UIViewController+Permissions.m"; sourceTree = ""; }; FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; FC5CDF371A3393DD00B47253 /* error_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "error_white@2x.png"; sourceTree = ""; }; FC5CDF381A3393DD00B47253 /* warning_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "warning_white@2x.png"; sourceTree = ""; }; @@ -1766,24 +1766,24 @@ FCFA64B11A24F29E0007FB87 /* UI Categories */ = { isa = PBXGroup; children = ( + 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */, + 450449371F45EE7D002D1ADA /* NSString+OWS.h */, + 450449381F45EE7D002D1ADA /* NSString+OWS.m */, + 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */, FCFA64B21A24F3880007FB87 /* UIColor+OWS.h */, FCFA64B31A24F3880007FB87 /* UIColor+OWS.m */, + 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */, FCFA64B51A24F6730007FB87 /* UIFont+OWS.h */, FCFA64B61A24F6730007FB87 /* UIFont+OWS.m */, B68112E81A4D9EC400BA82FF /* UIImage+OWS.h */, B68112E91A4D9EC400BA82FF /* UIImage+OWS.m */, + 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */, 34535D801E256BE9008A4747 /* UIView+OWS.h */, 34535D811E256BE9008A4747 /* UIView+OWS.m */, - EF764C331DB67CC5000D9A87 /* UIViewController+CameraPermissions.h */, - EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */, 344F2F651E57A932000D9322 /* UIViewController+OWS.h */, 344F2F661E57A932000D9322 /* UIViewController+OWS.m */, - 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */, - 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */, - 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */, - 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */, - 450449371F45EE7D002D1ADA /* NSString+OWS.h */, - 450449381F45EE7D002D1ADA /* NSString+OWS.m */, + EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */, + EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */, ); name = "UI Categories"; path = ..; @@ -2213,7 +2213,7 @@ 4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */, 34CCAF381F0C0599004084F4 /* AppUpdateNag.m in Sources */, 45387B041E36D650005D00B3 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */, - EF764C351DB67CC5000D9A87 /* UIViewController+CameraPermissions.m in Sources */, + EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */, 45CD81EF1DC030E7004C9430 /* AccountManager.swift in Sources */, 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */, 4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */, diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 8624413da..5abd45338 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -39,7 +39,7 @@ #import "UIImage+OWS.h" #import "UIUtil.h" #import "UIView+OWS.h" -#import "UIViewController+CameraPermissions.h" +#import "UIViewController+Permissions.h" #import "ViewControllerUtils.h" #import #import diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 0a7a864ec..ec34e7997 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -48,8 +48,8 @@ #import "ThreadUtil.h" #import "UIFont+OWS.h" #import "UIUtil.h" -#import "UIViewController+CameraPermissions.h" #import "UIViewController+OWS.h" +#import "UIViewController+Permissions.h" #import "ViewControllerUtils.h" #import #import @@ -3048,19 +3048,19 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { self.voiceMessageUUID = voiceMessageUUID; __weak typeof(self) weakSelf = self; - [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { - dispatch_async(dispatch_get_main_queue(), ^{ - __strong typeof(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } + [self ows_askForMicrophonePermissions:^(BOOL granted) { + __strong typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } - if (strongSelf.voiceMessageUUID != voiceMessageUUID) { - // This voice message recording has been cancelled - // before recording could begin. - return; - } + if (strongSelf.voiceMessageUUID != voiceMessageUUID) { + // This voice message recording has been cancelled + // before recording could begin. + return; + } +<<<<<<< HEAD if (granted) { [strongSelf startRecordingVoiceMemo]; } else { @@ -3069,6 +3069,24 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { [OWSAlerts showNoMicrophonePermissionAlert]; } }); +||||||| merged common ancestors + if (granted) { + [strongSelf startRecordingVoiceMemo]; + } else { + DDLogInfo(@"%@ we do not have recording permission.", self.tag); + [strongSelf cancelVoiceMemo]; + [OWSAlerts showNoMicrophonePermissionAlert]; + } + }); +======= + if (granted) { + [strongSelf startRecordingVoiceMemo]; + } else { + DDLogInfo(@"%@ we do not have recording permission.", self.tag); + [strongSelf cancelVoiceMemo]; + [OWSAlerts showNoMicrophonePermissionAlert]; + } +>>>>>>> Don't ask for microphone permissions if app is not active. }]; } diff --git a/Signal/src/ViewControllers/FingerprintViewScanController.m b/Signal/src/ViewControllers/FingerprintViewScanController.m index 594ee46c9..0436d7815 100644 --- a/Signal/src/ViewControllers/FingerprintViewScanController.m +++ b/Signal/src/ViewControllers/FingerprintViewScanController.m @@ -11,7 +11,7 @@ #import "UIFont+OWS.h" #import "UIUtil.h" #import "UIView+OWS.h" -#import "UIViewController+CameraPermissions.h" +#import "UIViewController+Permissions.h" #import #import #import diff --git a/Signal/src/ViewControllers/OWSLinkedDevicesTableViewController.m b/Signal/src/ViewControllers/OWSLinkedDevicesTableViewController.m index 5ea8c9ede..5ca3ed0fa 100644 --- a/Signal/src/ViewControllers/OWSLinkedDevicesTableViewController.m +++ b/Signal/src/ViewControllers/OWSLinkedDevicesTableViewController.m @@ -6,7 +6,7 @@ #import "OWSDeviceTableViewCell.h" #import "OWSLinkDeviceViewController.h" #import "Signal-Swift.h" -#import "UIViewController+CameraPermissions.h" +#import "UIViewController+Permissions.h" #import #import #import diff --git a/Signal/src/call/OutboundCallInitiator.swift b/Signal/src/call/OutboundCallInitiator.swift index 3b284ff05..1138082cb 100644 --- a/Signal/src/call/OutboundCallInitiator.swift +++ b/Signal/src/call/OutboundCallInitiator.swift @@ -44,6 +44,10 @@ import Foundation owsFail("\(TAG) can't initiate call because callUIAdapter is nil") return false } + guard let frontmostViewController = UIApplication.shared.frontmostViewController else { + owsFail("\(TAG) could not identify frontmostViewController in \(#function)") + return false + } let showedAlert = SafetyNumberConfirmationAlert.presentAlertIfNecessary(recipientId: recipientId, confirmationText: CallStrings.confirmAndCallButtonTitle, @@ -59,17 +63,22 @@ import Foundation // Check for microphone permissions // Alternative way without prompting for permissions: // if AVAudioSession.sharedInstance().recordPermission() == .denied { - AVAudioSession.sharedInstance().requestRecordPermission { isGranted in - DispatchQueue.main.async { - // Here the permissions are either granted or denied - guard isGranted == true else { - Logger.warn("\(self.TAG) aborting due to missing microphone permissions.") - OWSAlerts.showNoMicrophonePermissionAlert() - return - } - callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId) + frontmostViewController.ows_ask(forMicrophonePermissions: { [weak self] granted in + // Success callback; camera permissions are granted. + + guard let strongSelf = self else { + return } - } + + // Here the permissions are either granted or denied + guard granted == true else { + Logger.warn("\(strongSelf.TAG) aborting due to missing microphone permissions.") + OWSAlerts.showNoMicrophonePermissionAlert() + return + } + callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId) + }) + return true } } diff --git a/Signal/src/util/UIViewController+Permissions.h b/Signal/src/util/UIViewController+Permissions.h new file mode 100644 index 000000000..4d4387896 --- /dev/null +++ b/Signal/src/util/UIViewController+Permissions.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UIViewController (Permissions) + +- (void)ows_askForCameraPermissions:(void (^)())successCallback; +- (void)ows_askForCameraPermissions:(void (^)())successCallback failureCallback:(nullable void (^)())failureCallback; + +- (void)ows_askForMicrophonePermissions:(void (^)(BOOL granted))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/util/UIViewController+CameraPermissions.m b/Signal/src/util/UIViewController+Permissions.m similarity index 51% rename from Signal/src/util/UIViewController+CameraPermissions.m rename to Signal/src/util/UIViewController+Permissions.m index 5eda7b9b2..c27601563 100644 --- a/Signal/src/util/UIViewController+CameraPermissions.m +++ b/Signal/src/util/UIViewController+Permissions.m @@ -2,24 +2,23 @@ // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // -#import "UIViewController+CameraPermissions.h" #import "Signal-Swift.h" #import "UIUtil.h" +#import "UIViewController+Permissions.h" #import NS_ASSUME_NONNULL_BEGIN -@implementation UIViewController (CameraPermissions) +@implementation UIViewController (Permissions) -- (void)ows_askForCameraPermissions:(void (^)(void))permissionsGrantedCallback +- (void)ows_askForCameraPermissions:(void (^)(void))successCallback { - [self ows_askForCameraPermissions:permissionsGrantedCallback failureCallback:nil]; + [self ows_askForCameraPermissions:successCallback failureCallback:nil]; } -- (void)ows_askForCameraPermissions:(void (^)(void))permissionsGrantedCallback - failureCallback:(nullable void (^)(void))failureCallback +- (void)ows_askForCameraPermissions:(void (^)(void))successCallback failureCallback:(nullable void (^)(void))failureCallback { - DDLogVerbose(@"%@ ows_askForCameraPermissions", NSStringFromClass(self.class)); + DDLogVerbose(@"[%@] ows_askForCameraPermissions", NSStringFromClass(self.class)); // Avoid nil tests below. if (!failureCallback) { @@ -41,15 +40,20 @@ NS_ASSUME_NONNULL_BEGIN AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (status == AVAuthorizationStatusDenied) { - UIAlertController* alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"MISSING_CAMERA_PERMISSION_TITLE", @"Alert title") - message:NSLocalizedString(@"MISSING_CAMERA_PERMISSION_MESSAGE", @"Alert body") - preferredStyle:UIAlertControllerStyleAlert]; + UIAlertController *alert = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"MISSING_CAMERA_PERMISSION_TITLE", @"Alert title") + message:NSLocalizedString(@"MISSING_CAMERA_PERMISSION_MESSAGE", @"Alert body") + preferredStyle:UIAlertControllerStyleAlert]; - NSString *settingsTitle = NSLocalizedString(@"OPEN_SETTINGS_BUTTON", @"Button text which opens the settings app"); - UIAlertAction *openSettingsAction = [UIAlertAction actionWithTitle:settingsTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [[UIApplication sharedApplication] openSystemSettings]; - failureCallback(); - }]; + NSString *settingsTitle + = NSLocalizedString(@"OPEN_SETTINGS_BUTTON", @"Button text which opens the settings app"); + UIAlertAction *openSettingsAction = + [UIAlertAction actionWithTitle:settingsTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [[UIApplication sharedApplication] openSystemSettings]; + failureCallback(); + }]; [alert addAction:openSettingsAction]; UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.dismissButton @@ -61,13 +65,13 @@ NS_ASSUME_NONNULL_BEGIN [self presentViewController:alert animated:YES completion:nil]; } else if (status == AVAuthorizationStatusAuthorized) { - permissionsGrantedCallback(); + successCallback(); } else if (status == AVAuthorizationStatusNotDetermined) { [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { - permissionsGrantedCallback(); + successCallback(); } else { failureCallback(); } @@ -79,6 +83,28 @@ NS_ASSUME_NONNULL_BEGIN } } +- (void)ows_askForMicrophonePermissions:(void (^)(BOOL granted))callbackParam +{ + DDLogVerbose(@"[%@] ows_askForMicrophonePermissions", NSStringFromClass(self.class)); + + // Ensure callback is invoked on main thread. + void (^callback)(BOOL) = ^(BOOL granted) { + dispatch_async(dispatch_get_main_queue(), ^{ + callbackParam(granted); + }); + }; + + if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) { + DDLogError(@"Skipping microphone permissions request when app is not active."); + callback(NO); + return; + } + + [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { + callback(granted); + }]; +} + @end NS_ASSUME_NONNULL_END