├── .gitignore ├── LICENSE ├── RBVolumeButtons.podspec ├── VolumeSnap.xcodeproj └── project.pbxproj └── VolumeSnap ├── AppDelegate.h ├── AppDelegate.m ├── Default-568h@2x.png ├── RBVolumeButtons.h ├── RBVolumeButtons.m ├── ViewController.h ├── ViewController.m ├── VolumeSnap-Info.plist ├── VolumeSnap-Prefix.pch ├── en.lproj ├── InfoPlist.strings └── MainStoryboard.storyboard └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | xcuserdata 4 | VolumeSnap.xcodeproj/project.xcworkspace/contents.xcworkspacedata 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Licensed under the Apache License, Version 2.0 (the "License"); 2 | you may not use this file except in compliance with the License. 3 | You may obtain a copy of the License at 4 | 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. -------------------------------------------------------------------------------- /RBVolumeButtons.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "RBVolumeButtons" 4 | s.version = "0.1.0" 5 | s.summary = "This lets you steal the volume up and volume down buttons on iOS." 6 | s.homepage = "https://github.com/blladnar/RBVolumeButtons" 7 | s.license = { :type => 'Apache License, Version 2.0', :file => 'LICENSE' } 8 | s.author = { "Randall Brown" => "" } 9 | 10 | s.platform = :ios 11 | s.requires_arc = false 12 | 13 | s.source = { :git => "https://github.com/blladnar/RBVolumeButtons.git" } 14 | s.source_files = 'VolumeSnap/RBVolumeButtons.{h,m}' 15 | 16 | s.frameworks = 'AudioToolbox', 'MediaPlayer' 17 | 18 | end -------------------------------------------------------------------------------- /VolumeSnap.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 70C2EB411475EF4F00751AE8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70C2EB401475EF4F00751AE8 /* UIKit.framework */; }; 11 | 70C2EB431475EF4F00751AE8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70C2EB421475EF4F00751AE8 /* Foundation.framework */; }; 12 | 70C2EB4B1475EF4F00751AE8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 70C2EB491475EF4F00751AE8 /* InfoPlist.strings */; }; 13 | 70C2EB4D1475EF4F00751AE8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C2EB4C1475EF4F00751AE8 /* main.m */; }; 14 | 70C2EB511475EF4F00751AE8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C2EB501475EF4F00751AE8 /* AppDelegate.m */; }; 15 | 70C2EB541475EF4F00751AE8 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70C2EB521475EF4F00751AE8 /* MainStoryboard.storyboard */; }; 16 | 70C2EB571475EF4F00751AE8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C2EB561475EF4F00751AE8 /* ViewController.m */; }; 17 | 70C2EB601475F07400751AE8 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70C2EB5F1475F07400751AE8 /* AudioToolbox.framework */; }; 18 | 70C2EB621475FE4900751AE8 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70C2EB611475FE4900751AE8 /* MediaPlayer.framework */; }; 19 | 70C2EB6514760B5A00751AE8 /* RBVolumeButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C2EB6414760B5A00751AE8 /* RBVolumeButtons.m */; }; 20 | E5B0D1E71721150E00BD79DF /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E5B0D1E61721150E00BD79DF /* Default-568h@2x.png */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 70C2EB3C1475EF4F00751AE8 /* VolumeSnap.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VolumeSnap.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 70C2EB401475EF4F00751AE8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 26 | 70C2EB421475EF4F00751AE8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 27 | 70C2EB481475EF4F00751AE8 /* VolumeSnap-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "VolumeSnap-Info.plist"; sourceTree = ""; }; 28 | 70C2EB4A1475EF4F00751AE8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 29 | 70C2EB4C1475EF4F00751AE8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | 70C2EB4E1475EF4F00751AE8 /* VolumeSnap-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "VolumeSnap-Prefix.pch"; sourceTree = ""; }; 31 | 70C2EB4F1475EF4F00751AE8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 32 | 70C2EB501475EF4F00751AE8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 33 | 70C2EB531475EF4F00751AE8 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; 34 | 70C2EB551475EF4F00751AE8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 35 | 70C2EB561475EF4F00751AE8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 36 | 70C2EB5F1475F07400751AE8 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 37 | 70C2EB611475FE4900751AE8 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 38 | 70C2EB6314760B5A00751AE8 /* RBVolumeButtons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RBVolumeButtons.h; sourceTree = ""; }; 39 | 70C2EB6414760B5A00751AE8 /* RBVolumeButtons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RBVolumeButtons.m; sourceTree = ""; }; 40 | E5B0D1E61721150E00BD79DF /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 70C2EB391475EF4F00751AE8 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | 70C2EB621475FE4900751AE8 /* MediaPlayer.framework in Frameworks */, 49 | 70C2EB601475F07400751AE8 /* AudioToolbox.framework in Frameworks */, 50 | 70C2EB411475EF4F00751AE8 /* UIKit.framework in Frameworks */, 51 | 70C2EB431475EF4F00751AE8 /* Foundation.framework in Frameworks */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 70C2EB311475EF4F00751AE8 = { 59 | isa = PBXGroup; 60 | children = ( 61 | 70C2EB461475EF4F00751AE8 /* VolumeSnap */, 62 | 70C2EB3F1475EF4F00751AE8 /* Frameworks */, 63 | 70C2EB3D1475EF4F00751AE8 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | 70C2EB3D1475EF4F00751AE8 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 70C2EB3C1475EF4F00751AE8 /* VolumeSnap.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | 70C2EB3F1475EF4F00751AE8 /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 70C2EB5F1475F07400751AE8 /* AudioToolbox.framework */, 79 | 70C2EB421475EF4F00751AE8 /* Foundation.framework */, 80 | 70C2EB611475FE4900751AE8 /* MediaPlayer.framework */, 81 | 70C2EB401475EF4F00751AE8 /* UIKit.framework */, 82 | ); 83 | name = Frameworks; 84 | sourceTree = ""; 85 | }; 86 | 70C2EB461475EF4F00751AE8 /* VolumeSnap */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 70C2EB4F1475EF4F00751AE8 /* AppDelegate.h */, 90 | 70C2EB501475EF4F00751AE8 /* AppDelegate.m */, 91 | 70C2EB521475EF4F00751AE8 /* MainStoryboard.storyboard */, 92 | 70C2EB6314760B5A00751AE8 /* RBVolumeButtons.h */, 93 | 70C2EB6414760B5A00751AE8 /* RBVolumeButtons.m */, 94 | 70C2EB551475EF4F00751AE8 /* ViewController.h */, 95 | 70C2EB561475EF4F00751AE8 /* ViewController.m */, 96 | 70C2EB471475EF4F00751AE8 /* Supporting Files */, 97 | ); 98 | path = VolumeSnap; 99 | sourceTree = ""; 100 | }; 101 | 70C2EB471475EF4F00751AE8 /* Supporting Files */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 70C2EB481475EF4F00751AE8 /* VolumeSnap-Info.plist */, 105 | 70C2EB491475EF4F00751AE8 /* InfoPlist.strings */, 106 | 70C2EB4C1475EF4F00751AE8 /* main.m */, 107 | 70C2EB4E1475EF4F00751AE8 /* VolumeSnap-Prefix.pch */, 108 | E5B0D1E61721150E00BD79DF /* Default-568h@2x.png */, 109 | ); 110 | name = "Supporting Files"; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXNativeTarget section */ 116 | 70C2EB3B1475EF4F00751AE8 /* VolumeSnap */ = { 117 | isa = PBXNativeTarget; 118 | buildConfigurationList = 70C2EB5A1475EF4F00751AE8 /* Build configuration list for PBXNativeTarget "VolumeSnap" */; 119 | buildPhases = ( 120 | 70C2EB381475EF4F00751AE8 /* Sources */, 121 | 70C2EB391475EF4F00751AE8 /* Frameworks */, 122 | 70C2EB3A1475EF4F00751AE8 /* Resources */, 123 | ); 124 | buildRules = ( 125 | ); 126 | dependencies = ( 127 | ); 128 | name = VolumeSnap; 129 | productName = VolumeSnap; 130 | productReference = 70C2EB3C1475EF4F00751AE8 /* VolumeSnap.app */; 131 | productType = "com.apple.product-type.application"; 132 | }; 133 | /* End PBXNativeTarget section */ 134 | 135 | /* Begin PBXProject section */ 136 | 70C2EB331475EF4F00751AE8 /* Project object */ = { 137 | isa = PBXProject; 138 | attributes = { 139 | LastUpgradeCheck = 0700; 140 | }; 141 | buildConfigurationList = 70C2EB361475EF4F00751AE8 /* Build configuration list for PBXProject "VolumeSnap" */; 142 | compatibilityVersion = "Xcode 3.2"; 143 | developmentRegion = English; 144 | hasScannedForEncodings = 0; 145 | knownRegions = ( 146 | en, 147 | ); 148 | mainGroup = 70C2EB311475EF4F00751AE8; 149 | productRefGroup = 70C2EB3D1475EF4F00751AE8 /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | 70C2EB3B1475EF4F00751AE8 /* VolumeSnap */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | 70C2EB3A1475EF4F00751AE8 /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 70C2EB4B1475EF4F00751AE8 /* InfoPlist.strings in Resources */, 164 | 70C2EB541475EF4F00751AE8 /* MainStoryboard.storyboard in Resources */, 165 | E5B0D1E71721150E00BD79DF /* Default-568h@2x.png in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXSourcesBuildPhase section */ 172 | 70C2EB381475EF4F00751AE8 /* Sources */ = { 173 | isa = PBXSourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 70C2EB4D1475EF4F00751AE8 /* main.m in Sources */, 177 | 70C2EB511475EF4F00751AE8 /* AppDelegate.m in Sources */, 178 | 70C2EB571475EF4F00751AE8 /* ViewController.m in Sources */, 179 | 70C2EB6514760B5A00751AE8 /* RBVolumeButtons.m in Sources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXSourcesBuildPhase section */ 184 | 185 | /* Begin PBXVariantGroup section */ 186 | 70C2EB491475EF4F00751AE8 /* InfoPlist.strings */ = { 187 | isa = PBXVariantGroup; 188 | children = ( 189 | 70C2EB4A1475EF4F00751AE8 /* en */, 190 | ); 191 | name = InfoPlist.strings; 192 | sourceTree = ""; 193 | }; 194 | 70C2EB521475EF4F00751AE8 /* MainStoryboard.storyboard */ = { 195 | isa = PBXVariantGroup; 196 | children = ( 197 | 70C2EB531475EF4F00751AE8 /* en */, 198 | ); 199 | name = MainStoryboard.storyboard; 200 | sourceTree = ""; 201 | }; 202 | /* End PBXVariantGroup section */ 203 | 204 | /* Begin XCBuildConfiguration section */ 205 | 70C2EB581475EF4F00751AE8 /* Debug */ = { 206 | isa = XCBuildConfiguration; 207 | buildSettings = { 208 | ALWAYS_SEARCH_USER_PATHS = NO; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_UNREACHABLE_CODE = YES; 215 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 216 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 217 | COPY_PHASE_STRIP = NO; 218 | ENABLE_STRICT_OBJC_MSGSEND = YES; 219 | GCC_C_LANGUAGE_STANDARD = gnu99; 220 | GCC_DYNAMIC_NO_PIC = NO; 221 | GCC_NO_COMMON_BLOCKS = YES; 222 | GCC_OPTIMIZATION_LEVEL = 0; 223 | GCC_PREPROCESSOR_DEFINITIONS = ( 224 | "DEBUG=1", 225 | "$(inherited)", 226 | ); 227 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 228 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 229 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 230 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 237 | ONLY_ACTIVE_ARCH = YES; 238 | SDKROOT = iphoneos; 239 | }; 240 | name = Debug; 241 | }; 242 | 70C2EB591475EF4F00751AE8 /* Release */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_CONSTANT_CONVERSION = YES; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN_ENUM_CONVERSION = YES; 250 | CLANG_WARN_INT_CONVERSION = YES; 251 | CLANG_WARN_UNREACHABLE_CODE = YES; 252 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 253 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 254 | COPY_PHASE_STRIP = YES; 255 | ENABLE_STRICT_OBJC_MSGSEND = YES; 256 | GCC_C_LANGUAGE_STANDARD = gnu99; 257 | GCC_NO_COMMON_BLOCKS = YES; 258 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 259 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 260 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 261 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 262 | GCC_WARN_UNDECLARED_SELECTOR = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 264 | GCC_WARN_UNUSED_FUNCTION = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 267 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 268 | SDKROOT = iphoneos; 269 | VALIDATE_PRODUCT = YES; 270 | }; 271 | name = Release; 272 | }; 273 | 70C2EB5B1475EF4F00751AE8 /* Debug */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ENABLE_BITCODE = NO; 277 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 278 | GCC_PREFIX_HEADER = "VolumeSnap/VolumeSnap-Prefix.pch"; 279 | INFOPLIST_FILE = "VolumeSnap/VolumeSnap-Info.plist"; 280 | PRODUCT_BUNDLE_IDENTIFIER = "com.FARP.${PRODUCT_NAME:rfc1034identifier}"; 281 | PRODUCT_NAME = "$(TARGET_NAME)"; 282 | WRAPPER_EXTENSION = app; 283 | }; 284 | name = Debug; 285 | }; 286 | 70C2EB5C1475EF4F00751AE8 /* Release */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ENABLE_BITCODE = NO; 290 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 291 | GCC_PREFIX_HEADER = "VolumeSnap/VolumeSnap-Prefix.pch"; 292 | INFOPLIST_FILE = "VolumeSnap/VolumeSnap-Info.plist"; 293 | PRODUCT_BUNDLE_IDENTIFIER = "com.FARP.${PRODUCT_NAME:rfc1034identifier}"; 294 | PRODUCT_NAME = "$(TARGET_NAME)"; 295 | WRAPPER_EXTENSION = app; 296 | }; 297 | name = Release; 298 | }; 299 | /* End XCBuildConfiguration section */ 300 | 301 | /* Begin XCConfigurationList section */ 302 | 70C2EB361475EF4F00751AE8 /* Build configuration list for PBXProject "VolumeSnap" */ = { 303 | isa = XCConfigurationList; 304 | buildConfigurations = ( 305 | 70C2EB581475EF4F00751AE8 /* Debug */, 306 | 70C2EB591475EF4F00751AE8 /* Release */, 307 | ); 308 | defaultConfigurationIsVisible = 0; 309 | defaultConfigurationName = Release; 310 | }; 311 | 70C2EB5A1475EF4F00751AE8 /* Build configuration list for PBXNativeTarget "VolumeSnap" */ = { 312 | isa = XCConfigurationList; 313 | buildConfigurations = ( 314 | 70C2EB5B1475EF4F00751AE8 /* Debug */, 315 | 70C2EB5C1475EF4F00751AE8 /* Release */, 316 | ); 317 | defaultConfigurationIsVisible = 0; 318 | defaultConfigurationName = Release; 319 | }; 320 | /* End XCConfigurationList section */ 321 | }; 322 | rootObject = 70C2EB331475EF4F00751AE8 /* Project object */; 323 | } 324 | -------------------------------------------------------------------------------- /VolumeSnap/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /VolumeSnap/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (void)dealloc 16 | { 17 | [_window release]; 18 | [super dealloc]; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /VolumeSnap/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blladnar/RBVolumeButtons/a500aca0dcea697f96915d711cbd80a36ad0217b/VolumeSnap/Default-568h@2x.png -------------------------------------------------------------------------------- /VolumeSnap/RBVolumeButtons.h: -------------------------------------------------------------------------------- 1 | // 2 | // RBVolumeButtons.h 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RBVolumeButtons : NSObject 12 | 13 | @property (nonatomic, copy) dispatch_block_t upBlock; 14 | @property (nonatomic, copy) dispatch_block_t downBlock; 15 | @property (nonatomic, readonly) float launchVolume; 16 | 17 | - (void)startStealingVolumeButtonEvents; 18 | - (void)stopStealingVolumeButtonEvents; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /VolumeSnap/RBVolumeButtons.m: -------------------------------------------------------------------------------- 1 | // 2 | // RBVolumeButtons.m 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "RBVolumeButtons.h" 10 | #import 11 | #import 12 | 13 | @interface RBVolumeButtons() 14 | 15 | @property (nonatomic) BOOL isStealingVolumeButtons; 16 | @property (nonatomic) BOOL hadToLowerVolume; 17 | @property (nonatomic) BOOL hadToRaiseVolume; 18 | @property (nonatomic) BOOL suspended; 19 | @property (nonatomic, readwrite) float launchVolume; 20 | @property (nonatomic, retain) UIView *volumeView; 21 | 22 | @end 23 | 24 | @implementation RBVolumeButtons 25 | 26 | static void volumeListenerCallback ( 27 | void *inClientData, 28 | AudioSessionPropertyID inID, 29 | UInt32 inDataSize, 30 | const void *inData 31 | ){ 32 | const float *volumePointer = inData; 33 | float volume = *volumePointer; 34 | 35 | if (volume > [(RBVolumeButtons*)inClientData launchVolume]) 36 | { 37 | [(RBVolumeButtons*)inClientData volumeUp]; 38 | } 39 | else if (volume < [(RBVolumeButtons*)inClientData launchVolume]) 40 | { 41 | [(RBVolumeButtons*)inClientData volumeDown]; 42 | } 43 | } 44 | 45 | - (void)volumeDown 46 | { 47 | AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, volumeListenerCallback, self); 48 | 49 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:self.launchVolume]; 50 | 51 | [self performSelector:@selector(initializeVolumeButtonStealer) withObject:self afterDelay:0.1]; 52 | 53 | if (self.downBlock) 54 | { 55 | self.downBlock(); 56 | } 57 | } 58 | 59 | - (void)volumeUp 60 | { 61 | AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, volumeListenerCallback, self); 62 | 63 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:self.launchVolume]; 64 | 65 | [self performSelector:@selector(initializeVolumeButtonStealer) withObject:self afterDelay:0.1]; 66 | 67 | if (self.upBlock) 68 | { 69 | self.upBlock(); 70 | } 71 | } 72 | 73 | - (void)startStealingVolumeButtonEvents 74 | { 75 | NSAssert([[NSThread currentThread] isMainThread], @"This must be called from the main thread"); 76 | 77 | if (self.isStealingVolumeButtons) 78 | { 79 | return; 80 | } 81 | 82 | self.isStealingVolumeButtons = YES; 83 | 84 | AudioSessionInitialize(NULL, NULL, NULL, NULL); 85 | 86 | const UInt32 sessionCategory = kAudioSessionCategory_AmbientSound; 87 | AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); 88 | 89 | AudioSessionSetActive(YES); 90 | 91 | self.launchVolume = [[MPMusicPlayerController applicationMusicPlayer] volume]; 92 | self.hadToLowerVolume = self.launchVolume == 1.0; 93 | self.hadToRaiseVolume = self.launchVolume == 0.0; 94 | 95 | // Avoid flashing the volume indicator 96 | if (self.hadToLowerVolume || self.hadToRaiseVolume) 97 | { 98 | dispatch_async(dispatch_get_main_queue(), ^{ 99 | if (self.hadToLowerVolume) 100 | { 101 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.95]; 102 | self.launchVolume = 0.95; 103 | } 104 | 105 | if (self.hadToRaiseVolume) 106 | { 107 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.05]; 108 | self.launchVolume = 0.05; 109 | } 110 | }); 111 | } 112 | 113 | CGRect frame = CGRectMake(0, -100, 10, 0); 114 | self.volumeView = [[[MPVolumeView alloc] initWithFrame:frame] autorelease]; 115 | [self.volumeView sizeToFit]; 116 | [[[[UIApplication sharedApplication] windows] firstObject] insertSubview:self.volumeView atIndex:0]; 117 | 118 | [self initializeVolumeButtonStealer]; 119 | 120 | if (!self.suspended) 121 | { 122 | // Observe notifications that trigger suspend 123 | [[NSNotificationCenter defaultCenter] addObserver:self 124 | selector:@selector(suspendStealingVolumeButtonEvents:) 125 | name:UIApplicationWillResignActiveNotification // -> Inactive 126 | object:nil]; 127 | 128 | // Observe notifications that trigger resume 129 | [[NSNotificationCenter defaultCenter] addObserver:self 130 | selector:@selector(resumeStealingVolumeButtonEvents:) 131 | name:UIApplicationDidBecomeActiveNotification // <- Active 132 | object:nil]; 133 | } 134 | } 135 | 136 | - (void)suspendStealingVolumeButtonEvents:(NSNotification *)notification 137 | { 138 | if (self.isStealingVolumeButtons) 139 | { 140 | self.suspended = YES; // Call first! 141 | [self stopStealingVolumeButtonEvents]; 142 | } 143 | } 144 | 145 | - (void)resumeStealingVolumeButtonEvents:(NSNotification *)notification 146 | { 147 | if (self.suspended) 148 | { 149 | [self startStealingVolumeButtonEvents]; 150 | self.suspended = NO; // Call last! 151 | } 152 | } 153 | 154 | - (void)stopStealingVolumeButtonEvents 155 | { 156 | NSAssert([[NSThread currentThread] isMainThread], @"This must be called from the main thread"); 157 | 158 | if (!self.isStealingVolumeButtons) 159 | { 160 | return; 161 | } 162 | 163 | // Stop observing all notifications 164 | if (!self.suspended) 165 | { 166 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 167 | } 168 | 169 | AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, volumeListenerCallback, self); 170 | 171 | if (self.hadToLowerVolume) 172 | { 173 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:1.0]; 174 | } 175 | 176 | if (self.hadToRaiseVolume) 177 | { 178 | [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.0]; 179 | } 180 | 181 | [self.volumeView removeFromSuperview]; 182 | self.volumeView = nil; 183 | 184 | AudioSessionSetActive(NO); 185 | 186 | self.isStealingVolumeButtons = NO; 187 | } 188 | 189 | - (void)dealloc 190 | { 191 | self.suspended = NO; 192 | [self stopStealingVolumeButtonEvents]; 193 | 194 | self.upBlock = nil; 195 | self.downBlock = nil; 196 | [super dealloc]; 197 | } 198 | 199 | - (void)initializeVolumeButtonStealer 200 | { 201 | AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume, volumeListenerCallback, self); 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /VolumeSnap/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class RBVolumeButtons; 12 | 13 | @interface ViewController : UIViewController 14 | { 15 | float _launchVolume; 16 | IBOutlet UILabel *_counterLabel; 17 | int _counter; 18 | } 19 | 20 | @property (nonatomic, retain) RBVolumeButtons *buttonStealer; 21 | 22 | - (IBAction)startStealing:(id)sender; 23 | - (IBAction)stopStealing:(id)sender; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /VolumeSnap/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "RBVolumeButtons.h" 12 | 13 | @implementation ViewController 14 | 15 | #pragma mark - View lifecycle 16 | 17 | - (void)viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | _counter = 0; 21 | 22 | self.buttonStealer = [[[RBVolumeButtons alloc] init] autorelease]; 23 | self.buttonStealer.upBlock = ^{ 24 | _counter++; 25 | [_counterLabel setText:[NSString stringWithFormat:@"%td", _counter]]; 26 | }; 27 | self.buttonStealer.downBlock = ^{ 28 | _counter--; 29 | [_counterLabel setText:[NSString stringWithFormat:@"%td", _counter]]; 30 | }; 31 | } 32 | 33 | - (void)viewDidUnload 34 | { 35 | [_counterLabel release]; 36 | _counterLabel = nil; 37 | self.buttonStealer = nil; 38 | [super viewDidUnload]; 39 | } 40 | 41 | - (void)dealloc 42 | { 43 | [_counterLabel release]; 44 | [super dealloc]; 45 | } 46 | 47 | - (IBAction)startStealing:(id)sender 48 | { 49 | [self.buttonStealer startStealingVolumeButtonEvents]; 50 | } 51 | 52 | - (IBAction)stopStealing:(id)sender 53 | { 54 | [self.buttonStealer stopStealingVolumeButtonEvents]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /VolumeSnap/VolumeSnap-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFiles 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UIMainStoryboardFile 30 | MainStoryboard 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /VolumeSnap/VolumeSnap-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'VolumeSnap' target in the 'VolumeSnap' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /VolumeSnap/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /VolumeSnap/en.lproj/MainStoryboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 34 | 35 | 36 | 37 | 44 | 59 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /VolumeSnap/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VolumeSnap 4 | // 5 | // Created by Randall Brown on 11/17/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | --------------------------------------------------------------------------------