How to Detect Flip of iPhone? - iphone

is there a logic to detect if the user has flipped their phone like from battery side to screen side and vice versa in horizontal plane? I have tried getting raw values to determine if the device is in the horizontal position on both faces but how to detect the whole motion , could someone point me in right direction.

If you take a look at the UIDevice class reference, you'll see the orientation enum. Two of it's values are UIDeviceOrientationFaceDown and UIDeviceOrientationFaceUp. That being said, all you have to do is register an observer to the UIDeviceOrientationDidChangeNotification notification, and upon call you can check the devices current orientation and handle this accordingly.
[[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationFaceDown) {
// device facing down
}else if (orientation == UIDeviceOrientationFaceUp) {
// device facing up
}else{
// facing some other direction
}
}];
Be sure to use the following to start generating the device notifications you'll need to observe.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
If you want to get more specific information about the orientation of the device, you'll need to use the Core Motion framework to get gyro data directly. With this, you can track the exact current direction the device is facing in 3D space.
_motionManager = [CMMotionManager new];
NSOperationQueue *queue = [NSOperationQueue new];
[_motionManager setGyroUpdateInterval:1.0/20.0];
[_motionManager startGyroUpdatesToQueue:queue withHandler:^(CMGyroData *gyroData, NSError *error) {
NSLog(#"%#",gyroData);
}];

Related

In iOS, how to move UI elements when a device rotate?

In iOS, how to move UI elements (buttons and labels) when a device rotate to landscape mode from portrait mode?
There are so many ways.
In my case, I'm using notification
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(rotated:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
In rotated method
-(void) rotated: (NSNotification*) notification
{
orientation = [[UIDevice currentDevice] orientation];
if(UIDeviceOrientationPortraitUpsideDown==orientation)
// UI relocation
else if(UIDeviceOrientationPortrait==orientation)
// UI relocation
else if(UIDeviceOrientationLandscapeRight==orientation)
// UI relocation
else if(UIDeviceOrientationLandscapeLeft==orientation)
// UI relocation
}

UIDeviceOrientationFaceDown in iphone

I want to detect UIDeviceOrientationFaceDown. How can i do this???
Actually i want to perform some action when my iphone face is down on flat surface.
how is it possible??? plz help me to do this.
i have this code, but don't know where and how apply this code
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
BOOL getOrientationUpdates = [[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications];
NSLog(#"will receive orientation notifications: %#", getOrientationUpdates?#"YES":#"NO");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
if there is any tutorial then please suggest me that
Thanks in Advance and most welcome to your precious help and suggestions.
You can accomplish this by detecting the ProximityState of iPhone. Using the [UIDevice currentDevice] singleton, setting the proximityMonitoringEnabled to YES. you can access the proximity information through the proximityState property.
[[UIDevice currentDevice]proximityState];
iPhone has a sensor turns off the screen when you put it on your ear during a call, AFAIK that is an infrared sensor. and you can access it.
EDIT:
You can also accomplish it using the below code. UIDeviceOrientationFaceDown
The device is held parallel to the ground with the screen facing downwards. (regardless if it touched any object) if you want to know if the iPhone touched an object, detect the proximity state of device.
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
-(void)detectOrientation;{
switch ([[UIDevice currentDevice] orientation]) {
case UIDeviceOrientationPortrait:
{
NSLog(#"portrait");
}
break;
case UIDeviceOrientationPortraitUpsideDown:
{
NSLog(#"portraitUpSideDown");
}
break;
case UIDeviceOrientationLandscapeLeft:
{
NSLog(#"landscapeLeft");
}
break;
case UIDeviceOrientationLandscapeRight:
{
NSLog(#"landscapeRight");
}
break;
case UIDeviceOrientationFaceDown:
{
NSLog(#"facedown!!");
}
break;
default:
break;
}
}
}
EDIT: to answer the question in comment. add this line in your viewDidLoad
[UIDevice currentDevice].proximityMonitoringEnabled = YES;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleProximityChangeNotification:) name:UIDeviceProximityStateDidChangeNotification object:nil];
then write a method
-(void)handleProximityChangeNotification{
if([[UIDevice currentDevice]proximityState]){
NSLog(#"...");
}
}
You can use the z value from accelerometer sensor (-1 <= z <= 1). If your device is facing down, the z value will be in 0 < z <=1 (0 when it's facing parallel to the ground, 1 when it's facing perpendicular to the ground). To get this data you can use CMMotionManager
#import <CoreMotion/CoreMotion.h>
CMMotionManager *cm=[[CMMotionManager alloc] init];
cm.deviceMotionUpdateInterval=0.2f;
[cm startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion *data, NSError *error) {
if(data.gravity.z>=0.3f)//
{
//DO something
}
}];
Don't forget to add CoreMotion framework to your project.

Notification about iphone oriention

I want to get notification when a user is rotate the screen to landscape or portrait,
it is possible?
I find couple of article but i didn't found answer for this.
If you want to be notified when the device has been rotated you can either implement the shouldAutorotateToInterfaceOrientation: method in your view controller or you can register to receive the UIDeviceOrientationDidChangeNotification.
Before we start, the device orientation and the interface orientation can be different. The device may be landscape but the interface may remain portrait depending on how the app has been written. Device notifications are sent shortly before the interface orientation is changed to match the device orientation. If you don't want the interface orientation to change you should implement the shouldAutorotateToInterfaceOrientation: method in your view controller to return NO. This will stop the interface orientation being updated.
From your question it sounds like you want to receive notifications so I think you want to use the second method. You can enable UIDeviceOrientationChangeNotifications using:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
There is a corresponding:
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
You can register to receive the notifications in the normal way, using the NSNotificationCenter and registering to receive the UIDeviceOrientationDidChangeNotification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Finally, you would implement the method to be called when the notification is received as follows:
- (void)orientationChanged:(NSNotication *)notification {
UIDeviceOrientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait ||
orientation == UIDeviceOrientationPortraitUpsideDown) {
// Portrait
} else {
// Landscape
}
}
As you can see, the orientation can be accessed using the orientation instance method of UIDevice.
You need to add local notification in the landscape orientation in shouldAutorotateToInterfaceOrientation method
try like this:
if(interfaceOrientation == UIInterfaceOrientationLandscapeRight || UIInterfaceOrientationLandscapeLeft)
{
here schedule your local notification
}

Proximity Sensor is not working in iPhone 4 device

//I have created below snippet to let the sensor to be detected.
-(void)addProximitySensorControl {
UIDevice *device = [UIDevice currentDevice];
device.proximityMonitoringEnabled = YES;
BOOL state = device.proximityState;
if(state)
NSLog(#"YES");
else
NSLog(#"NO");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(proximityChanged:)
name:#"UIDeviceProximityStateDidChangeNotification"
object:nil];
}
In the iPhone 3GS or earlier proximityChanged: method is called successfully but in iPhone 4 while I am hovering object from upwards the sensor(screen) its not being detected. Any idea Guys?
I can see a few problems with this code. The first is that you use
name:#"UIDeviceProximityStateDidChangeNotification"
instead of
name:UIDeviceProximityStateDidChangeNotification
Both work, but using the bare version will give you a compiler error if you make a typo. (You want to get a compiler error with typos, it prevents silent errors).
The next thing is that you aren't actually checking for the proximity sensor being available before adding the notification. Your code:
BOOL state = device.proximityState
But this just checks whether or not the device is close to the users face. What you really want is to set proximityEnabled to YES, then check that it actually got set. It's a little counterintuitive.
UIDevice *device = [UIDevice currentDevice];
[device setProximityMonitoringEnabled:YES];
if ([device isProximityMonitoringEnabled]) {
// Do your stuff
}
Here's a full code sample:
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
UIDevice *device = [UIDevice currentDevice];
// Register for proximity notifications
[device setProximityMonitoringEnabled:YES];
if ([device isProximityMonitoringEnabled]) {
[notificationCenter addObserver:self
selector:#selector(proximityChanged:)
name:UIDeviceProximityStateDidChangeNotification
object:device];
} else {
NSLog(#"No Proximity Sensor");
}
Apple Docs: "Not all iOS devices have proximity sensors. To determine if proximity monitoring is available, attempt to enable it. If the value of the proximityMonitoringEnabled property remains NO, proximity monitoring is not available."
There is nothing wrong with your code (assuming that you did implement proximityChanged: of course). I tested your code on an iPhone 4 and it responds to my hand moving in front of the proximity sensor.
Maybe the hardware is slightly different on the 3GS, meaning it is more sensitive to what you are doing? Can you try on a different iPhone 4 device (or at least verify that the proximity sensor works at all e.g. by using the phone app)?
Check out this one :
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIDevice_Class/Reference/UIDevice.html
You should always check whether the particular device have proximity sensor or not.
Not all iOS devices have proximity sensors.
BOOL state = device.proximityState;
if(state)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(proximityChanged:)
name:#"UIDeviceProximityStateDidChangeNotification" object:nil];
else
NSLog(#"NO");

how do I detect the iPhone orientation before rotating

In my program I'm moving things based on rotation, but I'm not rotating the entire view. I'm Using :
static UIDeviceOrientation previousOrientation = UIDeviceOrientationPortrait;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
- (void) didRotate:(NSNotification *)notification{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
[self doRotationStuff:orientation: previousOrientation];
previousOrientation = orientation;
}
This works as long as, when the program is launched, the device orientation is portrait, but not if the initial orientation is landscape or upside down, because [self doRotationStuff] makes changes relative to the difference from the previous orientation.
Is there a way to detect the orientation either at launch, or right before the device is rotated?
Depending on your circumstances, a simpler option may be the interfaceOrientation property of the UIViewController class. This is correct before a rotation.
Updated:
So, from the comment discussion, it appears that you can't rely on [UIDevice currentDevice].orientation until the orientation actually changes for the first time. If so, you could probably hack it by getting raw accelerometer readings.
#define kUpdateFrequency 30 // Hz
#define kUpdateCount 15 // So we init after half a second
#define kFilteringFactor (1.0f / kUpdateCount)
- (void)applicationDidFinishLaunching:(UIApplication *)app
{
[UIAccelerometer sharedAccelerometer].updateInterval = (1.0 / kUpdateFrequency);
[UIAccelerometer sharedAccelerometer].delegate = self;
accelerometerCounter = 0;
...
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)accel
{
// Average out the first kUpdateCount readings
// acceleration_[xyz] are ivars typed float
acceleration_x = (float)accel.x * kFilteringFactor + acceleration_x * (1.0f - kFilteringFactor);
acceleration_y = (float)accel.y * kFilteringFactor + acceleration_y * (1.0f - kFilteringFactor);
acceleration_z = (float)accel.z * kFilteringFactor + acceleration_z * (1.0f - kFilteringFactor);
accelerometerCounter++;
if (accelerometerCounter == kUpdateCount)
{
[self initOrientation];
[UIAccelerometer sharedAccelerometer].delegate = nil;
}
}
- (void)initOrientation
{
// Figure out orientation from acceleration_[xyz] and set up your UI...
}
Original response:
Does [UIDevice currentDevice].orientation return the correct orientation during applicationDidFinishLaunching:? If so, you can set up your initial UI according to that orientation.
If that property doesn't get set until some later time, you might try experimenting with performSelector:afterDelay: to initialize the UI after a small delay.
This code sample is from Kendall's answer below, added here for completeness:
[self performSelector:#selector(getOriented) withObject:nil afterDelay:0.0f];
I'm not sure if a zero-second delay is sufficient -- this means the code for getOriented will run during the first pass through the event run loop. You may need to wait longer for the accelerometer readings to register on UIDevice.
Mort, these answers seem somewhat of a red herring; I can't see why you can't use the following built-in method for a UIViewController class:
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {}
This method gets called automatically after a rotation has occurred (rather than with shouldAutorotateToInterfaceOrientation which only tells you it's about to happen). Handily, the variable 'fromInterfaceOrientation' contains the previous orientation. As the documentation also says, you can assume that the interfaceOrientation property of the view has already been set to the new orientation, so you then have one method with access to the old orientation and the new!
If I've missed something and you've already dismissed being able to use this method, my apologies! It just seems odd that you're creating and storing a variable for the "previous orientation" when it's provided for free in the above method.
Hope that helps!
Use this for the orientation of the UI if you need to determine what way are you pointing.
Not 100% sure this is right but going off the top of my head:
[[[UIApplication sharedApplication] statusBar] orientation]
Here's one way to get the orientation when the app first loads and the UIDeviceOrientation is set to UIDeviceOrientationUnknown. You can look at the transform property of the rotated view.
if(toInterface == UIDeviceOrientationUnknown) {
CGAffineTransform trans = navigationController.view.transform;
if(trans.b == 1 && trans.c == -1)
toInterface = UIDeviceOrientationLandscapeLeft;
else if(trans.b == -1 && trans.c == 1)
toInterface = UIDeviceOrientationLandscapeRight;
else if(trans.a == -1 && trans.d == -1)
toInterface = UIDeviceOrientationPortraitUpsideDown;
else
toInterface = UIDeviceOrientationPortrait;
}
A more complete example on how to obtain device orientation from accelerator readings can be found here
As the solution relies on accelerator readings, it wouldn't work on the simulator, so you'll have to work on the device... still looking myself for a solution that works on the simulator.
In response to your comment, I thought I could better put code here than in a comment (though really Daniel deserves credit here):
in applicationDidFinishLaunching:
[self performSelector:#selector(getOriented) withObject:nil afterDelay:0.0f];
Then you just need the method to call:
- (void) getOriented
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
// save orientation somewhere
}