1 /* Cydia Substrate - Powerful Code Insertion Platform
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Substrate is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * Substrate is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Substrate. If not, see <http://www.gnu.org/licenses/>.
22 %apt Package: com.saurik.substrate.safemode
23 %apt Author: Jay Freeman (saurik) <saurik@saurik.com>
25 %apt Name: Substrate Safe Mode
26 %apt Description: safe mode safety extension (safe)
28 %apt Depends: mobilesubstrate (>= 0.9.3367+38)
33 %bundle com.apple.springboard
35 %flag -framework Foundation
36 %flag -framework UIKit
38 #import <CoreFoundation/CoreFoundation.h>
39 #import <Foundation/Foundation.h>
40 #import <CoreGraphics/CGGeometry.h>
41 #import <UIKit/UIKit.h>
43 #include "CydiaSubstrate.h"
45 MSClassHook(UIStatusBar)
48 MSMetaClassHook(UIImage)
50 MSClassHook(AAAccountManager)
51 MSMetaClassHook(AAAccountManager)
53 MSClassHook(BBSectionInfo)
55 MSClassHook(SBAlertItemsController)
56 MSClassHook(SBButtonBar)
57 MSClassHook(SBIconController)
58 MSClassHook(SBStatusBar)
59 MSClassHook(SBStatusBarDataManager)
60 MSClassHook(SBStatusBarTimeView)
61 MSClassHook(SBUIController)
63 Class $SafeModeAlertItem;
65 @interface SBAlertItem : NSObject {
67 - (UIAlertView *) alertSheet;
71 @interface SBAlertItemsController : NSObject {
73 + (SBAlertItemsController *) sharedInstance;
74 - (void) activateAlertItem:(SBAlertItem *)item;
77 @interface SBStatusBarTimeView : UIView {
82 @interface UIApplication (CydiaSubstrate)
83 - (void) applicationOpenURL:(id)url;
86 @interface UIAlertView (CydiaSubstrate)
87 - (void) setForceHorizontalButtonsLayout:(BOOL)force;
88 - (void) setBodyText:(NSString *)body;
89 - (void) setNumberOfRows:(NSInteger)rows;
92 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
98 // XXX: there are better ways of restarting SpringBoard that would actually save state
103 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
110 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
111 UIAlertView *sheet([self alertSheet]);
113 [sheet setDelegate:self];
114 [sheet setBodyText:@"We apologize for the inconvenience, but SpringBoard has just crashed.\n\nMobileSubstrate /did not/ cause this problem: it has protected you from it.\n\nYour device is now running in Safe Mode. All extensions that support this safety system are disabled.\n\nReboot (or restart SpringBoard) to return to the normal mode. To return to this dialog touch the status bar.\n\nTap \"Help\" below for more tips."];
115 [sheet addButtonWithTitle:@"OK"];
116 [sheet addButtonWithTitle:@"Restart"];
117 [sheet addButtonWithTitle:@"Help"];
118 [sheet setNumberOfRows:1];
120 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
121 [sheet setForceHorizontalButtonsLayout:YES];
124 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
125 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
128 static void MSAlert() {
129 if ($SafeModeAlertItem == nil)
130 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
131 if ($SafeModeAlertItem == nil) {
132 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
133 if ($SafeModeAlertItem == nil)
136 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
137 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
138 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
139 objc_registerClassPair($SafeModeAlertItem);
142 if ($SBAlertItemsController != nil)
143 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
147 // XXX: on iOS 5.0, we really would prefer avoiding
149 MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
151 MSOldCall(touches, event);
154 MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
159 MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
161 MSOldCall(touches, event);
165 // this fairly complex code came from Grant, to solve the "it Safe Mode"-in-bar bug
167 MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
168 char *_data(&MSHookIvar<char>(self, "_data"));
172 Ivar _itemIsEnabled(object_getInstanceVariable(self, "_itemIsEnabled", NULL));
173 if (_itemIsEnabled == NULL)
176 Ivar _itemIsCloaked(object_getInstanceVariable(self, "_itemIsCloaked", NULL));
177 if (_itemIsCloaked == NULL)
180 size_t enabledOffset(ivar_getOffset(_itemIsEnabled));
181 size_t cloakedOffset(ivar_getOffset(_itemIsCloaked));
182 if (enabledOffset >= cloakedOffset)
185 size_t offset(cloakedOffset - enabledOffset);
186 char *timeString(_data + offset);
187 strcpy(timeString, "Exit Safe Mode");
191 static bool alerted_;
193 static void AlertIfNeeded() {
201 // on iOS 4.3 and above we can use this advertisement, which seems to check every time the user unlocks
202 // XXX: verify that this still works on iOS 5.0
204 MSClassMessageHook0(void, AAAccountManager, showMobileMeOfferIfNecessary) {
209 // -[SBIconController showInfoAlertIfNeeded] explains how to drag icons around the iPhone home screen
210 // it used to be shown to users when they unlocked their screen for the first time, and happened every unlock
211 // however, as of iOS 4.3, it got relegated to only appearing once the user installed an app or web clip
213 MSInstanceMessageHook0(void, SBIconController, showInfoAlertIfNeeded) {
218 // the icon state, including crazy configurations like Five Icon Dock, is stored in SpringBoard's defaults
219 // unfortunately, SpringBoard on iOS 2.0 and 2.1 (maybe 2.2 as well) buffer overrun with more than 4 icons
220 // there is a third party package called IconSupport that remedies this, but not everyone is using it yet
222 MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
226 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
227 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
228 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
229 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
230 if ([iconMatrix count] != 0)
231 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
232 int count([row count]);
240 MSInstanceMessageHook0(id, SBUIController, init) {
241 if ((self = MSOldCall()) != nil) {
242 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
243 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
246 if (&_contentLayer != NULL)
247 layer = _contentLayer;
248 else if (&_contentView != NULL)
249 layer = _contentView;
254 [layer setBackgroundColor:[UIColor darkGrayColor]];
258 #define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
260 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
261 return [UIImage imageWithContentsOfFile:@Paper_];
264 MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
265 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
266 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
269 _time = [@"Exit Safe Mode" retain];
270 id font([self textFont]);
271 CGSize size([_time sizeWithFont:font]);
272 CGRect frame([self frame]);
273 _textRect.size = size;
274 _textRect.origin.x = (frame.size.width - size.width) / 2;
275 _textRect.origin.y = (frame.size.height - size.height) / 2;
279 // notification widgets ("wee apps" or "bulletin board sections") are capable of crashing SpringBoard
280 // unfortunately, which ones are in use are stored in SpringBoard's defaults, so we need to turn them off
282 MSInstanceMessageHook0(BOOL, BBSectionInfo, showsInNotificationCenter) {