Detecting device rotation when UIImagePicker is presented view - ios

I am using the UIImagePickerController class and my buttons are in the camera overlay.
I would like to adjust the orientation of my camera buttons dynamically depending on device orientation the way Apple's Camera.app does. I understand that UIImagePickerController is portrait mode only and should not be subclassed. Still, I would like to be able to trap and respond to the device rotation viewController events.
Is there any clean way to do this? The viewController which presents the UIImagePickerController no longer responds to events once the picker is presented.
There seem a few related questions on this topic but none that clarify if what I want to do is possible or not. Compounding confusion, there seems to be some differences with UIImagePickerController functionality between iOS versions. I am developing this on iOS6/iPhone4 but would like to be compatible with iOS5.

Here is a clean way to do it, tested on iPhone4s/iOS5.1 and iPhone3G/iOS6.1
I am using Apple's PhotoPicker sample and making a couple of small changes. I expect you can adapt this approach for your project. The basic idea is to use notifications to trigger a method every time we rotate. If that method is in the overlay's view controller, it can carry on manipulating the overlay while the imagePicker is showing.
In OverlayViewController.m add this into initWithNibName
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:#selector(didChangeOrientation)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
These notifications continue to be sent while the pickerController is showing. So here, in the overlay's view controller, you can continue to play with the interface, for example:
- (void) didChangeOrientation
{
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
self.cancelButton.image =[UIImage imageNamed:#"portait_image.png"];
} else {
self.cancelButton.image =[UIImage imageNamed:#"landscape_image.png"];
}
}
you will need to kill the notification and remove the observer in viewDidUnload:
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
Note the way this app is designed: the overlayViewController acts like a wrapper around imagePickerController. So you invoke the imagePicker through the overlayViewController:
[self presentModalViewController:self.overlayViewController.imagePickerController animated:YES];
The overlayViewController acts as the delegate for imagePickerController, and in turn has delegate methods to relay information back to the invoking view controller.
An alternative is not to use UIImagePickerController at all, but to use AVFoundation media capture instead which gives you much more fine-grained control over the picture-taking process, at the expense of (slightly) greater complexity.

Related

Fixed video capture orientation for RTCMTLVideoView webrtc

I have an iOS app that only supports portrait when rotating the device the video captured by the RTCMTLVideoView rotates to landscape orientation, even when the rest of the UI stays in portrait.
So far the only solution that I found is to listen for the UIDeviceOrientationDidChangeNotification notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
and disabling it
- (void)orientationChanged:(NSNotification *)notification{
NSLog(#"orientation changed");
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
Is there any way to prevent this behaviour and keep it locked to portrait without this ugly workaround?
The problem in my case was that the video captured with the front camera was no mirrored.
I fixed the issue flipping the RTCMTLVideoView
self.myRTCMTLVideoView.transform = CGAffineTransformMakeScale(-1.0, 1.0)
The answer assumes usage of the latest stable M70 branch of WebRTC at the moment, as it's a moving target and API of its internal classes changes frequently.
Looks like RTCMTLVideoView is still work in progress and doesn't handle all scenarios appropriately. It has a rotationOverride property, but no documentation or example on how to use it. There is a similar question on Google Groups, which hasn't yet received attention, I encourage you to participate in discussion there, so WebRTC developers would know about that issue relevancy and made actions to fix it.
In the meantime, I suggest to switch to RTCEAGLVideoView which should work fine in that case.

Presenting iOS 8 UIAlertController from Singleton Object

I currently have a locationManager (not CLLocationManager) singleton that is getting my location when the app starts and that manages the rest of the location services in the app.
When getting initialized the location manager if the state is denied triggers an alert prompting to change the authorization state. Since it is a nsobject I can't present it, and I've been looking for other options but most are hacks. Is it actually possible to present it this way?
Thanks in advance
I'm sure some will argue about whether or not you SHOULD. With that being said, you COULD by doing this:
[[(<#YourAppDelegate#> *)[UIApplication sharedApplication].delegate window].rootViewController presentViewController:<#(UIViewController *)#> animated:<#(BOOL)#> completion:<#^(void)completion#>];
It should be noted that if you're using a Mac app as opposed to iOS, multiple windows could be present and you may want to use the key window. This could occasionally be a system window so it's something you should be aware of. Here's a post explaining the differences:
https://stackoverflow.com/a/21698751/2611971
If you'd prefer to present on your keyWindow, you could use this:
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:<#(UIViewController *)#> animated:<#(BOOL)#> completion:<#^(void)completion#>];
You can set your main view controller object as an observer for a AuthorizationDenied notification via Notification Center. And post that notification when it's denied, and your view controller will get notified.
In your View Controller loading:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(authorizationDenied:) name:#"AuthorizationDenied" object:nil];
In your singleton class:
[[NSNotificationCenter defaultCenter] postNotificationName:#"AuthorizationDenied" object:nil];

How hide or close my app when i reveive a call?

I have a little bug. I'm developing an iOS App.
If i receive a call, my app stays open and the screen for my entering call appears on my app. I would like to close my app if i have a call.
How can i fix that?
Thanks,
J.
The green, in-call status bar is not a bug but a feature. You don't need to close the app when the call comes.
Instead, make sure your views are resized properly when the in-call status bar appears.
As Per Apple Human Interface guidelines
Never quit an iOS app programmatically because people tend to interpret this as a crash.
However, if external circumstances prevent your app from functioning as intended, you need
to tell your users about the situation and explain what they can do about it. Depending on
how severe the app malfunction is, you have two choices.
Display an attractive screen that describes the problem and suggests a correction. A
screen provides feedback that reassures users that there’s nothing wrong with your app. It
puts users in control, letting them decide whether they want to take corrective action and
continue using your app or press the Home button and open a different app
If only some of your app's features are unavailable, display either a screen or an alert
when people use the feature. Display the alert only when people try to access the feature
that isn’t functioning. `
But again you handle your app accordingly when call comes by using the following notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingCall:) name:CTCallStateIncoming object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callEnded:) name:CTCallStateDisconnected object:nil];
Srinivasan N's answer has the incorrect observer, you'll want to add this observer which will account for all scenarios: phone calls, Personal Hotspot, GPS/navigation, etc.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(adjustViews:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
}
- (void)adjustViews:(NSNotification *)notification
{
NSValue *rectValue = [[notification userInfo] valueForKey:UIApplicationStatusBarFrameUserInfoKey];
CGRect newFrame;
[rectValue getValue:&newFrame];
NSLog(#"Changed frame to: Width: %f, Height: %f", newFrame.size.width, newFrame.size.height);
// Adjust your views here
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

iPad App Crashes on Orientation change

I am developing an iPad app. I allow both landscape and portrait mode. My UI is fine in portrait mode but when I change it to landscape mode, my UI gets messed up. I saw some SO posts related to this and I added following code in initWith... in my UIView.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(abc)
name:UIDeviceOrientationDidChangeNotification
object:nil];
My UI is working fine in portrait mode after doing this. When I change it to landscape mode, my UI is fine. But after I change it back into portrait mode, my app crashes. I read some posts on SO related to app crashing an got to know about instruments. I enabled zombies and found that a message is being sent to already released object and this message is coming from NSNotificationCenter.
Is there something else that I need to handle apart from registering my device ? Also, is there any way where in I can change the implementation from UIView to UIViewController and implement the methods that UIViewController has regarding device orientation ? Please let me know the steps I need to follow in order to get this done. Thanks!
Where are you registering for the notifications? You need to remove the observer when you are about to change orientations (either in prepForSegue or willAnimateRotationToInterfaceOrientation depending on however you've got your setup) in order prevent messaging a no longer valid object. You also don't want to pile up several notifications if your registering in viewDidAppear/viewWillAppear.
Remove the observer using:
[[NSNotificationCenter defaultCenter] removeObserver:self];//removes all notifications for that object (the way I've used it before)
or if you want to be specific, do something like:
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice];//remove just that notification
The UIViewController class has several methods that deal with changes in orientation. See the docs for a discussion of those methods.
One method you should look into is viewWillLayoutSubviews. This is a common place to perform manual view layout. This is called anytime the view controller's orientation changes.
Using these methods is much more common than registering for device orientation change notifications. Based on your statements about the crash, a possible issue is that you never remove the observer that you add. For every call to addObserver there must be a corresponding call to removeObserver. Otherwise the observer is called even if it has long gone away. And this results in the crash you describe.

How to take a photo on the volume-up event when using UIImagePickerController with custom camera controls?

In iOS 5, the volume-up button will now take a photo in the camera app, and on a UIImagePickerController instance where .showsCameraControlls == YES. Happy days.
However, when I set showsCameraControlls to NO, and supply my own (which in turn triggers takePicture method), the volume-up button will no longer work. How can I detect the volume event while the UIImagePickerController is showing?
The old way to detect volume changes was like so:
AudioSessionSetActive(true);
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(volumeChanged:)
name:#"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
I added this code to my application delegate. Strangely volumeChanged: is not triggered until after I show the UIImagePickerController for the first time. More importantly, it isn't triggered while the UIImagePickerController is visible (nor is the usual volume HUD shown), I guess since Apple disabled it & hijacked the event.
So once again, is there any way to detect the volume-up button event, while the UIImagePickerController is being displayed, when using custom camera controls, for the purpose of taking a photo?
If you're wondering why I need to use custom camera controls, it is because I want the ability to take multiple photos, which the standard camera controls do not allow.
On iOS 8 you can add an observer to the notification _UIApplicationVolumeUpButtonDownNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(volumeChanged:)
name:#"_UIApplicationVolumeUpButtonDownNotification"
object:nil];
If you are using UIImagePickerController, I was able to capture the event and use it to call TakePicture with a custom view.
On top of that, UIImagePickerController ensures that pressing volume up won't change the volume.
I'm not sure if Apple would approve an app listening to that notification; this seems to be the cleanest approach.
Try using the AVCapture APIs instead of UIImagePicker. Here's a tutorial:
http://www.musicalgeometry.com/?p=1273
It's a lot lower level and it's harder to use, but it shouldn't block the volume controls.
You might also want to try a trick like playing a silent audio file to enable the volume controls during image capture.
Update: I also found this tutorial on using the volume button for camera shutter:
http://ios.biomsoft.com/2011/12/07/taking-control-of-the-volume-buttons-on-ios-like-camera/

Resources