Simulating low battery for iPhones - iphone

I am working on a mobile game, which appearantly crashes when the Low Battery alert is displayed. It works fine on low memory, incoming calls and other messages.
Its a pain to test and debug this, since I can find no terminal or iPhone simulator way of simulating this situation, so I have to charge my phone up a little bit, launch the app, wait for it to drain its power, and start all over again.
Does anyone know of a way to produce this error in a realistic way? Hopefully something that isn't too stressful on my iPhone battery.

Unfortunately, there is no good way to simulate a low-battery environment. You actually will most likely need to physically charge your device's battery until it is just above the "low battery" state and then debug your application.
To address what others have said:
There is no way to simulate low battery notifications. The project
that #Bo. provided does nothing more than schedule random
UILocalNotifications. It isn't all that much different than just
showing a UIAlertView in your app.
You could try what #Andrew R.
said and use the private methods found in the UIDevice header.
But it is doubtful that you will exactly mimic the effects of a real
low-battery environment.
Although it is a pain to have to wait for you device to actually hit the low-battery state, you could add some battery-draining code to your app to assist you. For example, using the GPS might drain the battery a bit quicker.
Good luck.

Did you try simulating the low battery notifications? There seems to be a project that does that: https://github.com/MegaEduX/LowBattery

Assuming this is for testing purposes only, you could give the following private UIDevice methods a try:
-(void)_setBatteryState:(int)state;
-(void)_setBatteryLevel:(float)level;
You'll have to experiment to see what parameters they expect, or whether they have an impact at all.

In iOS there is way to simulate "Low Battery"
Battery monitoring is enabled by setting to YES a property of the UIDevice singleton:
UIDevice *device = [UIDevice currentDevice];
device.batteryMonitoringEnabled = YES;
iOS provides two type of battery monitoring events, one for when the state changes (e.g., charging, unplugged, full charged) and one that updates when the battery’s charge level changes. As was the case with proximity monitoring, you register callbacks to receive notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryLevelDidChangeNotification" object:device];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryStateDidChangeNotification" object:device];

Related

How to disable iOS System Sounds

I am working on an iPad app that connects with an accessory that plays sound. When the iPad is connected to the accessory, I would like to mute all system sounds but allow other sounds (iPod).
Part of the reason for this is that the accessory is such that it is intended to be used during a live performance. Clearly it would be annoying to have e-mail, alert, or any other system sound running through and amplified (crazy loud).
I have looked at using AVAudioSession (read Audio Sessions to learn more) and tried all of the AudioSessionCategories. None of these categories will mute the system sound, instead it will only allow you to mute application sounds (iPod) - not useful for my purposes.
I also found docs on "System Sound Services", but this only allows you to play system sounds. There is no api here to disable system sounds while your app is running.
A final note, we have made it easy to adjust the iPad level (volume) by including the MPVolumeView, but we expect the user to want to play iPod music. If while playing iPod music (or music from another app) and an e-mail comes through, you'd be amazed how LOUD / ANNOYING that e-mail suddenly becomes when going through our accessory. It's even possible it could damage equipment. :D
It is possible to change the system sounds, which turns out to be the ringer btw, using the AVSystemController. However, AVSystemController exists in the private Celestial framework. Since this framework is referenced by UIKit, it is still possible to use this class without directly referencing it.
Apple prohibits using private API's, so that alone makes this a bad idea. Given my circumstance, I think they may make an exception, BUT I will likely abandon this course since after taking it I realized that it didn't fix my problem. It does indeed mute the sounds, but as soon as I plug in to my accessory, the system sounds come out at max volume even though the ringer volume is set to 0. This leads me to believe the answer to solving my problem is in the MFI documentation.
Anyhow, here is how to change the ringer using private framework / api (which will get your app rejected without some kind of special permission).
short answer:
[[AVSystemController sharedAVSystemController] setVolumeTo:0 forCategory:#"Ringtone"];
answer without having to directly reference Celestial frameork / AVSystemController.h:
- (void) setSystemVolumeLevelTo:(float)newVolumeLevel
{
Class avSystemControllerClass = NSClassFromString(#"AVSystemController");
id avSystemControllerInstance = [avSystemControllerClass performSelector:#selector(sharedAVSystemController)];
NSString *soundCategory = #"Ringtone";
NSInvocation *volumeInvocation = [NSInvocation invocationWithMethodSignature:
[avSystemControllerClass instanceMethodSignatureForSelector:
#selector(setVolumeTo:forCategory:)]];
[volumeInvocation setTarget:avSystemControllerInstance];
[volumeInvocation setSelector:#selector(setVolumeTo:forCategory:)];
[volumeInvocation setArgument:&newVolumeLevel atIndex:2];
[volumeInvocation setArgument:&soundCategory atIndex:3];
[volumeInvocation invoke];
}
Using MediaPlayer framework, we can set the level of SYSTEM sound
[[MPMusicPlayerController applicationMusicPlayer] setVolume:0];
Best you can do is encourage your users to go into airplane mode.

Receiving Notifications with App in background mode

I have an app, that will keep track of everything the user do in the iPod app. To do this, I added few observers to NSNotificationCenter, like MPMusicPlayerControllerNowPlayingItemDidChangeNotification. But my problem is, I only get those notifications when my app is in the foreground, if its in the background, the system add the notification to a queue, and then the next time my app becomes active it delivers it to me. I have no interest in this queue, since I want to receive real-time notifications.
Is there any way for me to get those notifications even if my app is in suspended state? I want to run just 3 lines of code everytime I get this NowPlayingItemDidChange notifications for example.
Here is where I add the observer.
MPMusicPlayerController *iPodMediaPlayer = [MPMusicPlayerController iPodMusicPlayer];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self selector: #selector(handle_NowPlayingItemChanged:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object:iPodMediaPlayer];
[iPodMediaPlayer beginGeneratingPlaybackNotifications];
Also, if I add another kind of object to the observer instead of iPodMediaPlayer, the observer won't call the method.
Thanks a lot,
Abras
iOS applications are suspended when they are not in the foreground. There are three exceptions to this rule. You can have code execute in the background if your application is
a) Playing audio. This means the application itself is actually generating audio. My understanding is that the MPMediaPlayerController iPodMusicPlayer object only controls the playback of the external iPod process, rather than playing audio from the app itself. Perhaps you could have some success if you called applicationMusicPlayer instead of iPodMusicPlayer and set the appropriate background flags in your applications Info.plist. This seems like the most legitimate way to get your application to work, but you wouldn't be able to control iPod playback from the iPod app, only your app and the system audio controls.
b) Get your app to monitor the location. If the app is using the GPS it can continue to execute in the background. Downside to this is that the GPS will drain battery, and users might be creeped out that you're requesting their location.
c) Ask UIApplication for extra time. If you use UIApplication's beginBackgroundTask method, your application will continue to run for a finite amount of time in the background. If your users are going to come into your application once every ten minutes or so, this could work as well.
Hope that helps.
Multitasking in iOS is currently a very restricted one. You may start a background task using beginBackgroundTaskWithExpirationHandler: method (of an UIApplication object), but it is intended to finish a finite-length task before going suspended. All background tasks may expire (and get terminated) before it finishes its job. You can check how much longer your application can run by checking backgroundTimeRemaining property of the application object.
As I explained here iOS receive Media Player Notifications when app is in background, there seems no way to get notifications from iPodMusicPlayer.
About Omar Raul Qazi answer:
a) i tried and I had no success. The music kept going down when pressing home button. I think this background flag only works for normal AudioSessions and not for MPMusicPlayer...
b) I am not sure this would work and I don't think Apple would like it when looking for approval
c) You can run in background only synchronous task. You cannot wait there for a notification. Am I wrong?

Detecting the type of iPhone interrupt

I can detect that the iPhone went to sleep and came back from sleep, by using the applicationWillResignActive and applicationDidBecomeActive. But how do I find out what kind of interrupt it was. I am making an audio player application, and need to keep the audio playing when the iPhone goes to sleep (which I know how to do). But I need to interrupt the audio when a message, alarm or low battery interrupt occurs. Also I need to resume the audio when the event is over.
So how do I differentiate between these different interrupts.
That information is probably not available to your app, but here's some things to try.
In applicationWillResignActive:, check the NSNotification's object and userInfo properties to see if there are any hints there.
Register to receive all notifications posted to the default notification center:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveNotification:) name:nil object:nil];
Your method will be called when anything is posted. Log the notification object and userInfo dictionary and maybe you will see a useful notification being posted. If you find one, you can register just for that.
This is the most hacky, but you might be able to get access to the alert that is displayed if it is a message or battery warning. Alerts are displayed in a UIWindow over your app's main UIWindow. You could register for UIWindowDidBecomeVisibleNotification, then look at the window's subviews to see if you can find an alert or some other useful clue.
All of the above methods would be relying on undocumented behavior to work, and could possibly get your submission rejected from the App Store. None of them involve private method calls, though you could argue that observing an undocumented notification name counts as private API. In the end, Apple's opinion is the only one that will matter.
Personally, I'd try it, making sure the code fails gracefully if and when the system changes.
Use an audio session?

Finding Capacity Remaining In An iPhone Battery

Does anyone know how (if possible) I can find out how much capacity (mAh) is remaining in an iPhone battery at any given time?
Something like the program above?
Is there a value stored in a plist somewhere??
couple ways,
pre 3.0 sdk: http://blog.coriolis.ch/reading-the-battery-level-programmatically/
with 3.0 sdk - the UIDevice batteryLevel property (example: http://blog.coriolis.ch/reading-the-battery-level-programmatically/#comment-4607)
to gauge the mAh you could check the battery level over time using that method.
3.0 has added an event to do that:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(batteryChanged:)
name:#”UIDeviceBatteryLevelDidChangeNotification” object:device];
in general, measuring the open circuit voltage or current is used to gauge the state of charge by the hardware. the capacity of the bat will shrink over time, so 100% will indicate no more charge can be stored, even tho the capacity is lower than a new iphone battery.
The UIDevice API includes a property relating to battery level.

iPhone Proximity Sensor

Can the iPhone SDK take advantage of the iPhone's proximity sensors? If so, why hasn't anyone taken advantage of them? I could picture a few decent uses.
For example, in a racing game, you could put your finger on the proximity sensor to go instead of taking up screen real-estate with your thumb. Of course though, if this was your only option, then iPod touch users wouldn't be able to use the application.
Does the proximity sensor tell how close you are, or just that something is in front of it?
There is a public API for this. -[UIApplication setProximitySensingEnabled:(BOOL)] will turn the feature on. BTW, it doesn't seem to be using the light sensor, because proximity sensing would tweak out in a dark room.
However, the API call basically blanks the screen when you hold the phone up to your face. Not useful for interaction, sadly.
Assuming you mean the sensor that shuts off the screen when you hold it to your ear, I'm pretty sure that is just an infrared sensor inside the ear speaker. If you start the phone app (you don't have to be making a call) and hold something to cast a shadow over the ear speaker, you can make the display shut off.
When you asked this question it was not accessible via the public API. You can now access the sensor's state via UIDevice's proximityState property. However, it wouldn't be that useful for games, since it is only an on/off thing, not a near/far measure. Plus, it's only available on the iPhone and not the iPod touch.
Evidently the proximity sensor will never turn on if the status bar is in landscape orientation.
i.e, if you call:
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
You will no longer get the proximity:ON notifications.
This definitely happens on OS 3.0, I can't test it on a 2.X device since I don't have one with a proximity sensor.
This seems like a bug.
The proximity sensor works via measuring IR reflectance. If you hold the iPhone up to a webcam, you can see a small, pulsing IR LED.
There's a lot of confusion between the proximity sensor and the ambient light sensor. The iPhone has both. The Touch does not have a proximity sensor, making it a poor choice for user input. It would be a bad idea anyway since Apple isn't obligated to locate it in the same place in future devices; you aren't supposed to know or care where it is.
The proximity sensor works by pulsing an infrared LED and measuring the amount of reflectance. You can see this using your iSight camera (most digital cameras are sensitive to IR.) Just launch Photo Booth, initiate a call (or play a voicemail) on the phone and point it at your iSight camera. Note the flashing light next to the earpiece; cover it with your finger and the screen will go black.
The ambient light sensor's API is evidently private at this point.
Just to update, this is possible.
device = [UIDevice currentDevice];
// Turn on proximity monitoring
[device setProximityMonitoringEnabled:YES];
// 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.
// Detect whether device supports proximity monitoring
proxySupported = [device isProximityMonitoringEnabled];
// Register for proximity notifications
[notificationCenter addObserver:self selector:#selector(proximityChanged:) name:UIDeviceProximityStateDidChangeNotification object:device];
As benzado points out, you can use:
// Returns a BOOL, YES if device is proximate
[device proximityState];
There is no public API for this.
In iPhone 3.0 there is official support for the proximity sensor. Have a look at UIDevice proximityMonitoringEnabled in the docs.
If you aren't aiming for the AppStore, you can read my articles here on getting access to those:
Proximity Sensor: http://iphonedevwiki.net/index.php/AppleProxShim
Ambient Light Sensor: http://iphonedevwiki.net/index.php/AppleISL29003
Evidently the proximity sensor will never turn on if the status bar is in landscape orientation.
i.e. if you call:
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
You will no longer get proximity:ON notifications.
This definitely happens on OS 3.0, I can't test it on a 2.X device since I don't have one with a proximity sensor.
This seems like a bug.
answered Jul 22 '09 at 5:49
Kevin Lambert
I've encoutered this problem too. It took me a long time to figure out the real reason of why the proximity sensor is not working. When orientation is UIInterfaceOrientationLandscapeLeft or UIInterfaceOrientationLandscapeRight, proximity sensor does not work; while in portrait mode it works well. My iPhone is iPhone 4S (iOS SDK 5.0).
Those proximity sensors are basically a matrix of conductors. The vertical "wires" are tracks on one side of a thin sheet of insulator, the horizontal ones are on the other side. The intersections function as capacitors. Your finger carries an electrostatic charge, so capacitance of each junction varies with proximity. FETs amplify the signal and biasing sets a threshold. In practice the circuit is more complex than that because it has to detect a relative change and reject noise.
But anyway, what the sensor grid tells you is that a field effect has been sensed, and that field effect is characteristic of object about the size of a fingertip and resting on the surface of the display. The centroid of the capacitive disturbance is computed (probably by hardware) and the coordinates are (presumably) reported as numbers on a port most likely brought to the attention of the device OS by an interrupt. In something as sexy as an iPhone there's probably a buffer of the last dozen or so positions so it can work out direction and speed. Probably these are also computed by hardware and presented as numbers on the same port.
#Dipak Patel & #Coderer
You can download working code at
http://spazout.com/google_cheats_independent_iphone_developers_screwed
It has a working implementation of proximityStateChanged a undocumented method in UIApplication.
Hope this helps.
To turn the screen off it's conceivable that more than one sensors is used to figure out if the screen should be turned off or not. The IR proximity sensor described by Cryptognome in conjunction with the Touch screen sensor described by Peter Wone could work out if the iphone is being held close to your face (or something else with a slight electric charge) or if its just very close to something in-animate.