2010年8月28日土曜日

Android Get color of status bar

くごーさんがステータスバーの色を取得したいと言うので
がんばってみました。

 Xperia X10 のステータスバーは濃い青




 ステータスバーのレイアウトを指定している xml がこれです。

 frameworks/base/core/res/res/layout/status_bar.xml

 これを見ると、

  1. <com.android.server.status.StatusBarView xmlns:android="http://schemas.android.com/apk/res/android"   
  2.     android:background="@drawable/statusbar_background"  
  3.     android:orientation="vertical"  
  4.     android:focusable="true"  
  5.     android:descendantFocusability="afterDescendants"  
  6.     >  
  7.     <LinearLayout android:id="@+id/icons"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:orientation="horizontal">  
  11.               
  12.         <com.android.server.status.IconMerger android:id="@+id/notificationIcons"  
  13.             android:layout_width="0dip"  
  14.             ...  
  15.          />  
  16.     </LinearLayout>  
  17. </com.android.server.status.StatusBarView>  


 com.android.server.status.StatusBarView というカスタムビューを
 使っています。
 ここで、背景画像を設定しています。
  android:background="@drawable/statusbar_background" 

 ちなみにこの画像は Android Open Source Project のここ
 で見られます。

 こんなやつ


 com.android.server.status.StatusBarView を生成しているのが、
 com.android.server.status.StatusBarService です。

 こいつ
 frameworks/base/services/java/com/android/server/status/StatusBarService.java

 StatusBarService.java はこことかでみられます。
 StatusBarView.java はこのへんで。


 この StatusBarService は変数として、StatusBarView
 (mStatusBarView)を保持しています。

  1. public class StatusBarService extends IStatusBar.Stub  
  2. {  
  3.     ...  
  4.   
  5.     final Context mContext;  
  6.     final Display mDisplay;  
  7.     StatusBarView mStatusBarView;  
  8.   
  9.     ...  
  10.   
  11.     /** 
  12.      * Construct the service, add the status bar view to the window manager 
  13.      */  
  14.     public StatusBarService(Context context) {  
  15.         mContext = context;  
  16.         mDisplay = ((WindowManager)context.getSystemService(  
  17.                 Context.WINDOW_SERVICE)).getDefaultDisplay();  
  18.         makeStatusBarView(context);  
  19.         mUninstallReceiver = new UninstallReceiver();  
  20.     }  
  21.   
  22.     ....  
  23.   
  24.     // ================================================================================  
  25.     // Constructing the view  
  26.     // ================================================================================  
  27.     private void makeStatusBarView(Context context) {  
  28.         Resources res = context.getResources();  
  29.         mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);  
  30.         mRightIcons = new StatusBarIcon[mRightIconSlots.length];  
  31.   
  32.         ExpandedView expanded = (ExpandedView)View.inflate(context,  
  33.                 com.android.internal.R.layout.status_bar_expanded, null);  
  34.         expanded.mService = this;  
  35.         StatusBarView sb = (StatusBarView)View.inflate(context,  
  36.                 com.android.internal.R.layout.status_bar, null);  
  37.         sb.mService = this;  
  38.   
  39.         // figure out which pixel-format to use for the status bar.  
  40.         mPixelFormat = PixelFormat.TRANSLUCENT;  
  41.         Drawable bg = sb.getBackground();  
  42.         if (bg != null) {  
  43.             mPixelFormat = bg.getOpacity();  
  44.         }  
  45.   
  46.         mStatusBarView = sb;  
  47.   
  48.         ...  


 つまり、この mStatusBarView を取得して getBackground すれば
 背景画像がとれちゃうわけです。

 今回もリフレクションしますw

  *注! この方法は Reflection で内部クラスを使っているので、SDKのアップデートなどで使えなくなる可能性があります。

 ステータスバーの背景画像を取得する
  1. private Drawable getStatusBarBackground() {  
  2.        
  3.     try {  
  4.         ClassLoader cl = getClassLoader();  
  5.         Class<!----> clazz;  
  6.         clazz = cl.loadClass("com.android.server.status.StatusBarService");  
  7.         Constructor<!----> constructor = clazz.getConstructor(Context.class);  
  8.         Object obj = constructor.newInstance(this);  
  9.         Class<!----> c = obj.getClass();  
  10.         Field field;  
  11.         //field = c.getDeclaredField("com.android.server.status.StatusBarService.mStatusBarView");  
  12.         field = c.getDeclaredField("mStatusBarView");  
  13.   
  14.         if(!field.isAccessible()) {  
  15.             field.setAccessible(true);  
  16.         }  
  17.         ViewGroup vg = (ViewGroup) field.get(obj);  
  18.         Drawable d = vg.getBackground();  
  19.         return d;  
  20.   
  21.     } catch (ClassNotFoundException e) {  
  22.         e.printStackTrace();  
  23.         return null;  
  24.     } catch (SecurityException e) {  
  25.         e.printStackTrace();  
  26.         return null;  
  27.     } catch (NoSuchMethodException e) {  
  28.         e.printStackTrace();  
  29.         return null;  
  30.     } catch (IllegalArgumentException e) {  
  31.         e.printStackTrace();  
  32.         return null;  
  33.     } catch (InstantiationException e) {  
  34.         e.printStackTrace();  
  35.         return null;  
  36.     } catch (IllegalAccessException e) {  
  37.         e.printStackTrace();  
  38.         return null;  
  39.     } catch (InvocationTargetException e) {  
  40.         e.printStackTrace();  
  41.         return null;  
  42.     } catch (NoSuchFieldException e) {  
  43.         e.printStackTrace();  
  44.         return null;  
  45.     }  
  46. }  


 注: AndroidManifest.xml に
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
 を入れないと、Homeキーを押したときに落ちます


 おまけ:

  取得した Drawable は BitmapDrawable ではなく、
  NinePatchDrawable です。
  なので、
   "Bitmap, Drawableに変換 - hyoromoの日記"
  の方法では、Bitmap に変換できませんでした。

  そこで一回ImageViewに突っ込んでから、DrawingCache で Bitmap を
  取得しました。

  1. @Override  
  2. public void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.     setContentView(R.layout.main);  
  5.           
  6.     Drawable d = getStatusBarBackground();  
  7.           
  8.     if(d != null) {  
  9.         ImageView iv = ((ImageView)findViewById(R.id.imageview));  
  10.         iv.setImageDrawable(d);  
  11.     }  
  12. }  
  13.       
  14. @Override  
  15. public void onWindowFocusChanged(boolean hasFocus) {  
  16.     super.onWindowFocusChanged(hasFocus);  
  17.     ImageView iv = (ImageView)findViewById(R.id.imageview);  
  18.   
  19.     iv.setDrawingCacheEnabled(true);  
  20.     iv.buildDrawingCache();  
  21.     Bitmap b = iv.getDrawingCache();  
  22.     if(b != null) {  
  23.         int x = b.getWidth() / 2;  
  24.         int y = b.getHeight() / 2;  
  25.         int c = b.getPixel(x, y);  
  26.         ((TextView)findViewById(R.id.textview)).setText("  
  27.             "alpha: " + Color.alpha(c) +   
  28.             "  red: " + Color.red(c) +   
  29.             "  green: " + Color.green(c) +   
  30.             "  blue: " + Color.blue(c));  
  31.     }  
  32.     else {  
  33.         ((TextView)findViewById(R.id.textview)).setText("no drawing cache");         
  34.     }  
  35. }  


  かっとなって、アプリを公開しちゃいました。

  GetStatusBarColor AndroidOnly → http://goo.gl/WT24

 標準だと灰色なんだけど



 HTC Hero は黒でした。

0 件のコメント:

コメントを投稿