Are there APIs for custom vibrations in iOS?
After serval hours' digging in the Contact App, I have figured out how it works.
ABNewPersonViewControlle invoke some class in ToneLibrary framework to do this.
The call stack looks like this:
0 CoreFoundation 0x3359a1d4 CFGetTypeID + 0
1 CoreFoundation 0x33596396 __CFPropertyListIsValidAux + 46
2 CoreFoundation 0x33517090 CFPropertyListCreateData + 124
3 AudioToolbox 0x38ac255a AudioServicesPlaySystemSoundWithVibration + 158
5 ToneLibrary 0x35a7811a -[TLVibrationRecorderView vibrationComponentDidStartForVibrationRecorderTouchSurface:] + 38
6 ToneLibrary 0x35a772b2 -[TLVibrationRecorderTouchSurface touchesBegan:withEvent:] + 342
7 UIKit 0x3610f526 -[UIWindow _sendTouchesForEvent:] + 314
8 UIKit 0x360fc804 -[UIApplication sendEvent:] + 376
After search "AudioServicesPlaySystemSoundWithVibration" on the web , I found nothing.
So I decide to look into it myself. It's a private function in AudioToolbox framework.
the declaration of the function is like
void AudioServicesPlaySystemSoundWithVibration(SystemSoundID inSystemSoundID,id arg,NSDictionary* vibratePattern)
"inSystemSoundID" is SystemSoundID .just like "AudioServicesPlaySystemSound", pass "kSystemSoundID_Vibrate".
"arg" is not important, pass nil to it , everything will still work fine.
"vibratePattern" is a pointer of "NSDictionary", the Contact App pass into { Intensity = 1; OffDuration = 1; OnDuration = 10; } for recording user input.
But only call this function will make a vibration never stop. So I have to found some function to stop it.
The answer is "AudioServicesStopSystemSound". It's also a private function in AudioToolbox framework.
the declaration of the function is like
void AudioServicesStopSystemSound(SystemSoundID inSystemSoundID)
I guess the Contact App use AudioServicesPlaySystemSoundWithVibration in touchesBegan method, and AudioServicesStopSystemSound in touchEnd method to reach this effect.
TLVibrationController will manager a vibrate pattern object to record the process you input.
At last it generate a dictionary to pass into AudioServicesPlaySystemSoundWithVibration to replay the whole process like below:
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
NSMutableArray* arr = [NSMutableArray array ];
[arr addObject:[NSNumber numberWithBool:YES]]; //vibrate for 2000ms
[arr addObject:[NSNumber numberWithInt:2000]];
[arr addObject:[NSNumber numberWithBool:NO]]; //stop for 1000ms
[arr addObject:[NSNumber numberWithInt:1000]];
[arr addObject:[NSNumber numberWithBool:YES]]; //vibrate for 1000ms
[arr addObject:[NSNumber numberWithInt:1000]];
[arr addObject:[NSNumber numberWithBool:NO]]; //stop for 500ms
[arr addObject:[NSNumber numberWithInt:500]];
[dict setObject:arr forKey:@"VibePattern"];
[dict setObject:[NSNumber numberWithInt:1] forKey:@"Intensity"];
AudioServicesPlaySystemSoundWithVibration(4095,nil,dict);
So if you want a custom vibrations in iOS. Use AudioServicesPlaySystemSoundWithVibration and AudioServicesStopSystemSound.
There's a project called HapticKeyboard that does this. See: http://code.google.com/p/zataangstuff/source/browse/trunk/HapticKeyboard/Classes/HapticKeyboard.m?r=93
Specifically, look at the last set of functions
_CTServerConnectionSetVibratorState(&x, connection, 0, 0, 0, 0, 0);
There are two problems:
- I doubt you'd get your app allowed into the app store. Apple will see this as a battery drain for users and they are pretty strict about the user experience
- This may require jailbreaking. There have been several new iOS versions since I've last played with this, so it's hard to tell