我想用代碼來打開android的消息中心,也叫做statusbar、通知欄。通知欄其實就是一個常駐的服務,至於原理這里就不多說了,簡單說下思路和問題。
思路:API中沒有實現的方法,那么就利用反射機制
問題:4.2系統中的方法變更
解決辦法:分系統實現不同的方法
源碼路徑:……\sdk\sources\android-18\android\app\StatusBarManager
我們先來看android 4.4(API 19)中的方法,android 4.3(API 18),android 4.2.2(API 17)中都是下列方法
/** * Expand the notifications panel. */ public void expandNotificationsPanel() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.expandNotificationsPanel(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } } /** * Collapse the notifications and settings panels. */ public void collapsePanels() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.collapsePanels(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } }
我們再來看android 4.1.2(API 16)中的方法,終於發現了方法名的不同了。
/** * Expand the status bar. */ public void expand() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.expand(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } } /** * Collapse the status bar. */ public void collapse() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.collapse(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } }
最后發現API 16自己包括之前的方法都是叫做expand(),collapse(),之后的方法就改名了。至於改名的原因也很清楚,就是4.2后狀態欄中多了一個設置界面。所以要所寫一個方法,由於expand(展開)這個方法名太籠統,所以就把拉開通知欄的方法叫做了expandNotificationsPanel,把拉開設置界面的方法叫做expandSettingsPanel。
下面是折疊/拉開設置界面的方法:
/** * Collapse the notifications and settings panels. */ public void collapsePanels() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.collapsePanels(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } } /** * Expand the settings panel. */ public void expandSettingsPanel() { try { final IStatusBarService svc = getService(); if (svc != null) { svc.expandSettingsPanel(); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } }
好啦,找到問題后我們就需要用反射機制和判斷系統版本的方式來寫代碼了。
/** * 顯示消息中心 */ public static void openStatusBar(Context mContext){ try { Object service = mContext.getSystemService ("statusbar"); System.out.println("SDK INT= "+VERSION.SDK_INT +" BUILD.VERSION.SDK"+Build.VERSION.SDK_INT); Class <?> statusBarManager = Class.forName("android.app.StatusBarManager"); // 判斷系統版本號 String methodName = (VERSION.SDK_INT<=16)?"expand":"expandNotificationsPanel"; Method expand = statusBarManager.getMethod (methodName); expand.invoke (service); } catch (Exception e) { e.printStackTrace(); } } /** * 關閉消息中心 */ public static void closeStatusBar(Context mContext){ try { Object service = mContext.getSystemService ("statusbar"); Class <?> statusBarManager = Class.forName("android.app.StatusBarManager"); // 判斷系統版本號 String methodName = (VERSION.SDK_INT<=16)?"collapse":"collapsePanels"; Method expand = statusBarManager.getMethod(methodName); expand.invoke(service); } catch (Exception e) { e.printStackTrace(); } }
整理后得到如下代碼,方便大家調用(android 2.2及以上測試正常):
private static void doInStatusBar(Context mContext, String methodName) { try { Object service = mContext.getSystemService("statusbar"); Class<?> statusBarManager = Class.forName("android.app.StatusBarManager"); Method expand = statusBarManager.getMethod(methodName); expand.invoke(service); } catch (Exception e) { e.printStackTrace(); } } /** * 顯示消息中心 */ public static void openStatusBar(Context mContext) { // 判斷系統版本號 String methodName = (VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel"; doInStatusBar(mContext, methodName); } /** * 關閉消息中心 */ public static void closeStatusBar(Context mContext) { // 判斷系統版本號 String methodName = (VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels"; doInStatusBar(mContext, methodName); }
