在我上次博文发出后,我始终对此耿耿于怀,因为之前提供的解决禁用Statusbar问题在ICS中依然存在问题,即不能自动隐现,需要重启。因此在搜索几个月之后发现,依然难有进展。
就在前几天,我发现在Acer A510 这个平板上之前的方法已经完全行不通,于是重新搜索整个互联网。茫茫大海,亏我之前做的功课甚多,在Hide Bar (http://ppareit.github.com/HideBar/
)这个小工具上得到启发,很巧妙的解决了这个问题。
这个Hide Bar也是一国外小团队做的禁用statusbar工具,六月份之前,仍然没有给出适用ICS版本的更新。于是在这次重新搜索中,我欣然发现它偷偷支持了,等不及下载,看源码,一会功夫我就将这些代码抠到项目中。
说说原理吧,原理很简单,我之前也知道过一部分,他是将com.android.systemui名称的进程杀掉,不过这个杀不同,它是每隔一秒杀一回。之前我也试过kill这个进程,但因为每次kill后隔几秒就会重启,可能因为内核保护吧,当时就没再继续。而Hide Bar跑了个循环,隔一秒杀一下,这下内核想保护也没用了。
当然我手上平板众多,也发现一些小问题,比如一秒有点长,有的板子在这一秒间隔重启了com.android.systemui进程,界面显示出加载的画面,但是不一会又被杀了,界面抖了一下又没了那个进程,因为这样显得有点不稳定,我减小了kill的间隔;还有就是因为调用杀进程的命令是killall,在有的板子上却不支持这个命令,于是我又将其他板子上/system/xbin/下的killall和usleep拿了过来,增加了这个代码的适用性。
话不多说了,上代码。
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
287 }
将killall和usleep放到assets文件夹下,执行以下代码即可。
2 Device device = Device.getInstance();
3 device.showSystembar(false);