在我上次博文发出后,我始终对此耿耿于怀,因为之前提供的解决禁用Statusbar问题在ICS中依然存在问题,即不能自动隐现,需要重启。因此在搜索几个月之后发现,依然难有进展。
这个Hide Bar也是一国外小团队做的禁用statusbar工具,六月份之前,仍然没有给出适用ICS版本的更新。于是在这次重新搜索中,我欣然发现它偷偷支持了,等不及下载,看源码,一会功夫我就将这些代码抠到项目中。
说说原理吧,原理很简单,我之前也知道过一部分,他是将com.android.systemui名称的进程杀掉,不过这个杀不同,它是每隔一秒杀一回。之前我也试过kill这个进程,但因为每次kill后隔几秒就会重启,可能因为内核保护吧,当时就没再继续。而Hide Bar跑了个循环,隔一秒杀一下,这下内核想保护也没用了。
当然我手上平板众多,也发现一些小问题,比如一秒有点长,有的板子在这一秒间隔重启了com.android.systemui进程,界面显示出加载的画面,但是不一会又被杀了,界面抖了一下又没了那个进程,因为这样显得有点不稳定,我减小了kill的间隔;还有就是因为调用杀进程的命令是killall,在有的板子上却不支持这个命令,于是我又将其他板子上/system/xbin/下的killall和usleep拿了过来,增加了这个代码的适用性。
1 package transight.tablet.android.util;
2 3 import java.io.BufferedInputStream;
4 import java.io.BufferedReader;
5 import java.io.DataOutputStream;
6 import java.io.File;
7 import java.io.FileNotFoundException;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.io.InputStreamReader;
12 import java.util.ArrayList;
13 import java.util.Map;
14 15 import android.content.Context;
16 import android.content.res.AssetManager;
17 import android.util.Log;
18 19 /** 20 * Class with global information about the specific device. 21 */ 22 public enum Device {
23 24 INSTANCE;
25 26 private static String TAG = Device.
class.getSimpleName();
27 28 private boolean mHasRootBeenChecked =
false;
29 private boolean mIsDeviceRooted =
false;
30 31 private boolean mHasBeenInitialized =
false;
32 private Context mAppContext =
null;
33 34 // flag if the systembar is currently visible, assume at start this is true 35 private boolean mSystembarVisible =
true;
36 37 static public void initialize(Context appContext) {
38 if (INSTANCE.mHasBeenInitialized ==
true) {
39 Log.e(TAG, "Initializing already initialized class " + TAG);
40 // throw new IllegalStateException( 41 // "Trying to initialize already initialized class " + TAG); 42 }
43 INSTANCE.mHasBeenInitialized =
true;
44 INSTANCE.mAppContext = appContext;
45 AddKillAll(appContext, "killall");
46 AddKillAll(appContext, "usleep");
47 }
48 49 private static void AddKillAll(Context appContext, String commandFileName) {
50 File killAllFile =
new File("/system/xbin/"+commandFileName);
51 if (!killAllFile.exists()) {
52 AssetManager assetManager = appContext.getAssets();
53 InputStream inputStream =
null;
54 String commandFilePath =
null;
55 try {
56 inputStream = assetManager.open(commandFileName);
57 commandFilePath = appContext.getApplicationContext().getFilesDir()
58 .getAbsolutePath() + File.separator + commandFileName;
59 saveToFile(commandFilePath, inputStream);
60 }
catch (IOException e) {
61 Log.e("tag", e.toString());
62 }
63 try {
64 Process p;
65 p = Runtime.getRuntime().exec("su");
66 67 // Attempt to write a file to a root-only 68 DataOutputStream os =
new DataOutputStream(p.getOutputStream());
69 os.writeBytes("cd system/xbin\n");
70 os.writeBytes("cat " + commandFilePath + " > " + commandFileName + "\n");
71 os.writeBytes("chmod 755 " + commandFileName + "\n");
72 73 // Close the terminal 74 os.writeBytes("exit\n");
75 os.flush();
76 p.waitFor();
77 }
catch (Exception e) {
78 Log.e(TAG, e.toString());
79 }
80 }
81 }
82 83 static public Device getInstance() {
84 INSTANCE.checkInitialized();
85 return INSTANCE;
86 }
87 88 private void checkInitialized() {
89 if (mHasBeenInitialized ==
false)
90 throw new IllegalStateException("Singleton class " + TAG
91 + " is not yet initialized");
92 }
93 94 public boolean isRooted() {
95 96 checkInitialized();
97 98 Log.v(TAG, "isRooted called");
99 100 if (mHasRootBeenChecked) {
101 Log.v(TAG, "Result for isRooted is cached: " + mIsDeviceRooted);
102 return mIsDeviceRooted;
103 }
104 105 // first try 106 Log.v(TAG, "Checking if device is rooted by checking if Superuser is available");
107 try {
108 File file =
new File("/system/app/Superuser.apk");
109 if (file.exists()) {
110 Log.v(TAG, "Device seems rooted");
111 mHasRootBeenChecked =
true;
112 mIsDeviceRooted =
true;
113 return true;
114 }
115 }
catch (Exception e) {
116 e.printStackTrace();
117 }
118 119 // second try 120 Log.v(TAG, "Checking if device is rooted by checking if su is available");
121 try {
122 // get the existing environment 123 ArrayList<String> envlist =
new ArrayList<String>();
124 Map<String, String> env = System.getenv();
125 for (String envName : env.keySet()) {
126 envlist.add(envName + "=" + env.get(envName));
127 }
128 String[] envp = (String[]) envlist.toArray(
new String[0]);
129 // execute which su 130 Process proc = Runtime.getRuntime()
131 .exec(
new String[] { "which", "su" }, envp);
132 BufferedReader in =
new BufferedReader(
new InputStreamReader(
133 proc.getInputStream()));
134 // if we receive location, we are on a rooted device 135 // TODO: can break if the executable is on the device, but non working 136 if (in.readLine() !=
null) {
137 Log.v(TAG, "Device seems rooted");
138 mHasRootBeenChecked =
true;
139 mIsDeviceRooted =
true;
140 return true;
141 }
142 }
catch (Exception e) {
143 e.printStackTrace();
144 }
145 146 mHasRootBeenChecked =
true;
147 mIsDeviceRooted =
false;
148 return false;
149 150 }
151 152 public enum AndroidVersion {
153 HC, ICS, JB, UNKNOWN
154 };
155 156 public AndroidVersion getAndroidVersion() {
157 checkInitialized();
158 Log.v(TAG, "getAndroidVersion called");
159 int sdk = android.os.Build.VERSION.SDK_INT;
160 if (11 <= sdk && sdk <= 13) {
161 Log.v(TAG, "We are running on HoneyComb");
162 return AndroidVersion.HC;
163 }
else if (14 <= sdk && sdk <= 15) {
164 Log.v(TAG, "We are running on IceCreamSandwich");
165 return AndroidVersion.ICS;
166 }
else if (16 == sdk) {
167 Log.v(TAG, "We are running on JellyBean");
168 return AndroidVersion.JB;
169 }
else {
170 Log.v(TAG, "We don't know what we are running on");
171 return AndroidVersion.UNKNOWN;
172 }
173 }
174 175 public void showSystembar(
boolean makeVisible) {
176 checkInitialized();
177 try {
178 // get the existing environment 179 ArrayList<String> envlist =
new ArrayList<String>();
180 Map<String, String> env = System.getenv();
181 for (String envName : env.keySet()) {
182 envlist.add(envName + "=" + env.get(envName));
183 }
184 String[] envp = (String[]) envlist.toArray(
new String[0]);
185 // depending on makeVisible, show or hide the bar 186 if (makeVisible) {
187 Log.v(TAG, "showBar will show systembar");
188 // execute in correct environment 189 String command;
190 Device dev = Device.getInstance();
191 if (dev.getAndroidVersion() == AndroidVersion.HC) {
192 command = "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
193 }
else {
194 command = "rm /sdcard/hidebar-lock\n"
195 + "sleep 5\n"
196 + "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
197 }
198 Runtime.getRuntime().exec(
new String[] { "su", "-c", command }, envp);
199 // no proc.waitFor(); 200 // we just shown the bar, set flag to visible 201 mSystembarVisible =
true;
202 }
else {
203 Log.v(TAG, "showBar will hide the systembar");
204 // execute in correct environment 205 String command;
206 Device dev = Device.getInstance();
207 if (dev.getAndroidVersion() == AndroidVersion.HC) {
208 command = "LD_LIBRARY_PATH=/vendor/lib:/system/lib service call activity 79 s16 com.android.systemui";
209 }
else {
210 command = "touch /sdcard/hidebar-lock\n"
211 + "while [ -f /sdcard/hidebar-lock ]\n"
212 + "do\n"
213 + "killall com.android.systemui\n"
214 // + "sleep 1\n" 215 + "usleep 600000\n"
216 + "done\n"
217 + "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
218 }
219 Runtime.getRuntime().exec(
new String[] { "su", "-c", command }, envp);
220 // no proc.waitFor(); 221 // we just hide the bar, set flag to not visible 222 mSystembarVisible =
false;
223 }
224 }
catch (Exception e) {
225 e.printStackTrace();
226 }
227 }
228 229 /** 230 * @return true is the systembar is visible or false when it is not visible 231 */ 232 public boolean isSystembarVisible() {
233 checkInitialized();
234 // TODO: this might be improved by using 'ps ...' to see if the systemui process 235 // is running and by checking the /sdcard/hidebar-lock file 236 return mSystembarVisible;
237 }
238 239 public void sendBackEvent() {
240 Log.v(TAG, "sendBackEvent");
241 try {
242 // get the existing environment 243 ArrayList<String> envlist =
new ArrayList<String>();
244 Map<String, String> env = System.getenv();
245 for (String envName : env.keySet()) {
246 envlist.add(envName + "=" + env.get(envName));
247 }
248 String[] envp = (String[]) envlist.toArray(
new String[0]);
249 Runtime.getRuntime().exec(
250 new String[] { "su", "-c",
251 "LD_LIBRARY_PATH=/vendor/lib:/system/lib input keyevent 4" },
252 envp);
253 }
catch (Exception e) {
254 e.printStackTrace();
255 }
256 }
257 258 public static void saveToFile(String filePath, InputStream in){
259 FileOutputStream fos =
null;
260 BufferedInputStream bis =
null;
261 int BUFFER_SIZE = 1024;
262 byte[] buf =
new byte[BUFFER_SIZE];
263 int size = 0;
264 bis =
new BufferedInputStream(in);
265 try {
266 fos =
new FileOutputStream(filePath);
267 while ((size = bis.read(buf)) != -1)
268 fos.write(buf, 0, size);
269 }
catch (FileNotFoundException e) {
270 e.printStackTrace();
271 }
catch (IOException e) {
272 e.printStackTrace();
273 }
finally {
274 try {
275 if (fos !=
null) {
276 fos.close();
277 }
278 if (bis !=
null) {
279 bis.close();
280 }
281 }
catch (IOException e) {
282 e.printStackTrace();
283 }
284 }
285 }
286