How to use proximity sensor programmatically with iOS development? - ios

After some googling, I can understand that the "proximity sensor" which is used to on/off screen when the device is away/near from the user. I watched this video (watch from 30th sec) and surprised about this cool stuff. I want to implement it in my app.
But I come to know that there is no public API is available that can protect the screen lock when proximityMonitoringEnabled is YES. Then how can the above app did this?
For clear understanding, I'm copying some code.
Enable the proximity sensor:
[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
Setup an observer for sensor change:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sensorStateMonitor:) name:#"UIDeviceProximityStateDidChangeNotification" object:nil];
Finally you can find the state of proximity sensor from this method:
- (void)sensorStateMonitor:(NSNotificationCenter *)notification
{
if ([[UIDevice currentDevice] proximityState] == YES)
{
NSLog(#"Device is close to user.");
}
else
{
NSLog(#"Device is not closer to user.");
}
}
Question:
I want to show some view when the "Device is close to user" state was called. And want to remove the view if "Device is not closer to user" state was called.
So I added a view and removed inside the sensorStateMonitor: method. But the view was visible only for some fraction of seconds and the screen goes off.
Can I prevent the screen from auto off?
Just confused!!

The screen lock can be enabled/disabled.
[UIApplication sharedApplication].idleTimerDisabled = YES;

Related

IOS UIDeviceBatteryLevelDidChangeNotification not firing in background mode

I'm writing an IOS application which will record ( over time ) the current battery level of the iPhone device.
I have working code executing within the foreground using UIDeviceBatteryLevelDidChangeNotification, this fires a notification ( which is handled successfully ) when the app in in foreground mode.
Code is as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
return YES;
}
- (void)batteryChanged:(NSNotification *)notification
{
NSLog(#"Battery Changed From Observer");
[self UpdateBatteryStatus];
}
-(void)UpdateBatteryStatus
{
UIDevice *myDevice = [UIDevice currentDevice];
double batLeft = (float)[myDevice batteryLevel] * 100;
NSLog(#"Battery level: %f", batLeft);
// Do some stuff related to battery status
}
This executes ( output via log proves it ) every 1% increment ( or decrement ) on the battery status on the phone, which works exactly as expected.
When the app is moved to the background however, the events stop firing. Upon moving the app back to the foreground, the events fire ( it's almost like they are queued up until it reaches the foreground ).
I have searched stack overflow, and most answers are all the same, basically this is a background-mode permissions problem. So I ticked all the boxes:
I added everything just to make sure it wasn't a background persmission problem. Unfortunately, even after a clean, and rebuild ( also a shutdown of Xcode, and re-plugin of iPhone ) the events still do not fire.
Please bear in mind, I have no intention of releasing this to the app store, I'm aware that faking background-mode use cases is a quick and easy rejection. But I would like to get it working for personal usage.
Edit: ios target 11.3
Your app won't get NSNotificationCenter notifications while being in background/suspended. What you could try is to use fetch background mode to mimic remote downloads. Note however downsides of this approach - system itself will decide when to call the callback.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
UIDevice *myDevice = [UIDevice currentDevice];
double batLeft = (float)[myDevice batteryLevel] * 100;
NSLog(#"Battery level: %f", batLeft);
completionHandler(UIBackgroundFetchResultNewData);
}
If you as stated do not plan to release your app in AppStore you can try another hacks with background modes like infinite playing a muted sound in background.

how to fetch battery usage and level of my devices in ios

I want to get battery usage data from my iPhone. I used UIDevice currentDevice.batteryLevel code, but its returning -1.0000 in NSLog value.
Anyone please help me?
One more question, can I able to fetch other app battery usages in my app?
First, you must enable batteryStatus notification (in appDelegate.m for instance):
- (void)applicationDidBecomeActive:(UIApplication *)application {
...
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
// Now, the system will post UIDeviceBatteryStateDidChangeNotification notification when batteryStatus (or connection) will change
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryStatusDidChange:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
...
}
Then, you can check battery level calling:
[UIDevice currentDevice].batteryLevel;
that will return you a value between 0.0 (0% chareg) and 1.0 (100% charge).
Without calling first setBatteryMonitoringEnabled, battery state will return UIDeviceBatteryStateUnknown and the value of this property is –1.0. (from docs).

"Tap to focus" to "auto focus" when content in camera view changed. Logic like in the stock Camera app or the UIImagePickerController for iOS?

How do I handle the switch from "tap to focus" at a specific POI back to "auto focus" state automatically after lost focus when the contents in the view changed? If you notice the focus behavior in the stock Camera app or the UIImagePickerController, after you tap focus some area and you move the phone away, the camera can automatically switch to continuous auto focus at the center of the screen.
I need some more flexibility than what a UIImagePickerController can provide, so I need to use AVFoundation to mimic the UIImagePickerController behavior first...
This sounds very complex at first to me... but it turned super simple, Apple already did the 99% of work for us. All you need to do is to set "subjectAreaChangeMonitoringEnabled" on and register KVO on "AVCaptureDeviceSubjectAreaDidChangeNotification"! On the iOS 6.1 docs:
The value of this property indicates whether the receiver should
monitor the video subject area for changes, such as lighting changes,
substantial movement, and so on. If subject area change monitoring is
enabled, the capture device object sends an
AVCaptureDeviceSubjectAreaDidChangeNotification whenever it detects a
change to the subject area, at which time an interested client may
wish to re-focus, adjust exposure, white balance, etc.
Before changing the value of this property, you must call
lockForConfiguration: to acquire exclusive access to the device’s
configuration properties. If you do not, setting the value of this
property raises an exception. When you are done configuring the
device, call unlockForConfiguration to release the lock and allow
other devices to configure the settings.
You can observe changes to the value of this property using key-value
observing.
(Even better, you don't need to handle many corner cases. What if the device is in the middle of "adjustingFocus" at a POI and the content changed? You don't want the device fall back to auto focus at the center, and want the focus action to finish. The "area did change notification" is only triggered after the focus is done.)
Some sample code snippet from my project. (The structure follows the official AVFoundation example AVCam, so you can put them in easily and try out):
// CameraCaptureManager.m
#property (nonatomic, strong) AVCaptureDevice *backFacingCamera;
- (id) init{
self = [super init];
if (self){
// TODO: more of your setup code for AVFoundation capture session
for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
if (device.position == AVCaptureDevicePositionBack){
self.backFacingCamera = device;
}
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
void (^subjectAreaDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) {
if (self.videoInput.device.focusMode == AVCaptureFocusModeLocked ){
// All you need to do is set the continuous focus at the center. This is the same behavior as
// in the stock Camera app
[self continuousFocusAtPoint:CGPointMake(.5f, .5f)];
}
};
self.subjectAreaDidChangeObserver = [notificationCenter addObserverForName:AVCaptureDeviceSubjectAreaDidChangeNotification
object:nil
queue:nil
usingBlock:subjectAreaDidChangeBlock];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[self addObserver:self forKeyPath:keyPathAdjustingFocus options:NSKeyValueObservingOptionNew context:NULL];
}
return self;
}
-(void) dealloc{
// Remove the observer when done
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self.deviceOrientationDidChangeObserver];
}
- (BOOL) setupSession{
BOOL sucess = NO;
if ([self.backFacingCamera lockForConfiguration:nil]){
// Turn on subject area change monitoring
self.backFacingCamera.subjectAreaChangeMonitoringEnabled = YES;
}
[self.backFacingCamera unlockForConfiguration];
// TODO: Setup add input etc...
return sucess;
}
I just saw the comment of the answer of #Xiaochao Yang 's and I want to add some explain of the code CGPointMake(.5f, .5f). According to the apple's API ,the CGPoint you set to the camera is in the range of {0,0} to the {1,1} at the same time the CGPointMake(.5f, .5f)means the center of the camera.
This property represents a CGPoint where {0,0} corresponds to the top left of the picture area, and {1,1} corresponds to the bottom right in landscape mode with the home button on the right—this applies even if the device is in portrait mode
From AVCaptureDevice Class Reference

iPad launch orientation

After reading many posts, I still haven't got a clue how to solve this problem...
The first view of my app is a tableViewController. I override
(BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
and it always returns YES.
If I hold my iPad upright under landscape orientation, it rotates right after I launch the app. However, if I put my iPad flat on the table, even though my homepage is in landscape orientation, it launches in protrait orientation.
So I guess the problem is, how can I get the orientation of my homepage and launch my app with that orientation?
I had this same problem. There's some funky stuff that goes on with the first view controller you add to a window and whatever orientation it has. Make sure that the view controllers all return YES for orientations if you want the very first one to open with the right orientation
My app is openGL, but the way I handled this was to use notifications:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
// This is called right BEFORE the view is about to rotate. Here I'm using a notification message
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSNotification* notification = [NSNotification notificationWithName:#"orientationIsPortrait" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
else {
NSNotification* notification = [NSNotification notificationWithName:#"orientationIsLandscape" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
}
willRotateToInterfaceOrientation is called right BEFORE it actually starts rotating the orientation.
Then in my EAGLView initWithFrame: I set up observers..
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewBecamePortrait:) name:#"orientationIsPortrait" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewBecameLandscape:) name:#"orientationIsLandscape" object:nil];
and in viewBecamePortrait and viewBecameLandscape I handle the changes programatically.
On application start willRotateToInterfaceOrientation used only in case if "Home" screen in Landscape mode.
This way we can detect orientation when device is "Face Up" or "Face Down".
[UIDevice currentDevice].orientation work in case if device not parallel to ground.
I used the statusbar orientation to orient my openglview, like this:
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
NSLog(#"%s: orientation: %i", _cmd, (int)orientation);

Get current orientation of iPad?

In a given event handler (not the "shouldAutorotateToInterfaceOrientation" method) how do I detect the current iPad orientation? I have a text field I have to animate up (when keyboard appears) in the Landscape view, but not in the portrait view and want to know which orientation I'm in to see if the animation is necessary.
Orientation information isn't very consistent, and there are several approaches. If in a view controller, you can use the interfaceOrientation property. From other places you can call:
[[UIDevice currentDevice] orientation]
Alternatively, you can request to receive orientation change notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
Some people also like to check the status bar orientation:
[UIApplication sharedApplication].statusBarOrientation
I think
[[UIDevice currentDevice] orientation];
is not really reliable. Sometimes it works, sometimes not... In my apps, I use
[[UIApplication sharedApplication]statusBarOrientation];
and it works great!
One of:
Check the interfaceOrientation property of the active view controller.
[UIApplication sharedApplication].statusBarOrientation.
[UIDevice currentDevice].orientation. (You may need to call -beginGeneratingDeviceOrientationNotifications.)
I found a trick to solve the FaceUp orientation issue!!!
Delay the orientation check till AFTER the app has started running, then set variables, view sizes, etc.!!!
//CODE
- (void)viewDidLoad {
[super viewDidLoad];
//DELAY
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(delayedCheck)
userInfo:nil
repeats:NO];
}
-(void)delayedCheck{
//DETERMINE ORIENTATION
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ){
FACING = #"PU";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
FACING = #"PD";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
FACING = #"LL";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
FACING = #"LR";
}
//DETERMINE ORIENTATION
//START
[self setStuff];
//START
}
-(void)setStuff{
if( FACING == #"PU" ){
//logic for Portrait
}
else
if( FACING == #"PD" ){
//logic for PortraitUpsideDown
}
else{
if( FACING == #"LL"){
//logic for LandscapeLeft
}
else
if( FACING == #"LR" ){
//logic for LandscapeRight
}
}
//CODE
You can addSubviews, position elements, etc. in the 'setStuff' function ... anything that would initially depend on the orientation!!!
:D
-Chris Allinson
You can achieve this by two ways:
1- By using the following method:
**Put the following line in the -(void)viewDidLoad Method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceRotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
then put this method inside your class
-(void)deviceRotated:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation when the device will be rotated
2- The second way is by inserting the following notification inside -(void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkRotation:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
then put the following method inside your class
-(void)checkRotation:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation of the status bar of the ipad or iPhone and according to it you make do your animation in the required orientation.
For determining landscape vs portrait, there is a built-in function:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
BOOL inLandscape = UIDeviceOrientationIsLandscape(orientation);
[UIApplication sharedApplication].statusBarOrientation returns portrait when it's landscape, and landscape when it's portrait at launch, in iPad
I don't know why, but every time my app starts, the first 4 are right, but subsequently I get the opposite orientation. I use a static variable to count this, then have a BOOL to flip how I manually send this to subviews.
So while I'm not adding a new stand-alone answer, I'm saying use the above and keep this in mind. Note: I'm receiving the status bar orientation, as it's the only thing that gets called when the app starts and is "right enough" to help me move stuff.
The main problem with using this is the views being lazily loaded. Be sure to call the view property of your contained and subviews "Before" you set their positions in response to their orientation. Thank Apple for not crashing when we set variables that don't exist, forcing us to remember they break OO and force us to do it, too... gah, such an elegant system yet so broken! Seriously, I love Native, but it's just not good, encourages poor OO design. Not our fault, just reminding that your resize function might be working, but Apple's Way requires you load the view by use, not by creating and initializing it
In your view controller, get the read-only value of self.interfaceOrientation (the current orientation of the interface).
I've tried many of the above methods, but nothing seemed to work 100% for me.
My solution was to make an iVar called orientation of type UIInterfaceOrientation in the Root View Controller.
- (void)viewDidLoad {
[super viewDidLoad];
orientation = self.interfaceOrientation; // this is accurate in iOS 6 at this point but not iOS 5; iOS 5 always returns portrait on app launch through viewDidLoad and viewWillAppear no matter which technique you use.
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
orientation = toInterfaceOrientation;
}
Then, any place where you need to check the orientation you can do something like this:
if(UIInterfaceOrientationIsPortrait(orientation)){
// portrait
}else{
// landscape
}
There may still be a better way, but this seems to work 98% of the time (iOS5 notwithstanding) and isn't too hard. Note that iOS5 always launches iPad in portrait view, then sends a device the willRotateTo- and didRotateFromInterfaceOrientation: messages, so the value will still be inaccurate briefly.
[UIDevice currentDevice].orientation works great.
BUT!!!
... the trick is to add it to - (void)viewWillAppear:(BOOL)animated
exp:
(void)viewWillAppear:(BOOL)animated{
...
BOOL isLandscape = UIInterfaceOrientationIsLandscape(self.interfaceOrientation);
...
}
If you call it at - (void)viewDidLoad, it does not work reliable, especially if you use multiple threads (main UI thread, background thread to access massive external data, ...).
Comments:
1) Even if your app sets default orientation portrait, user can lock it at landscape. Thus setting the default is not really a solution to work around it.
2) There are other tasks like hiding the navigation bar, to be placed at viewWillAppear to make it work and at the same time prevent flickering. Same applies to other views like UITableView willDisplayCell -> use it to set cell.selected and cell.accessoryType.

Resources