2010年8月28日土曜日

Android Get color of status bar

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

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




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

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

 これを見ると、


<com.android.server.status.StatusBarView xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/statusbar_background"
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
>
<LinearLayout android:id="@+id/icons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">

<com.android.server.status.IconMerger android:id="@+id/notificationIcons"
android:layout_width="0dip"
...
/>
</LinearLayout>
</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)を保持しています。


public class StatusBarService extends IStatusBar.Stub
{
...

final Context mContext;
final Display mDisplay;
StatusBarView mStatusBarView;

...

/**
* Construct the service, add the status bar view to the window manager
*/
public StatusBarService(Context context) {
mContext = context;
mDisplay = ((WindowManager)context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
makeStatusBarView(context);
mUninstallReceiver = new UninstallReceiver();
}

....

// ================================================================================
// Constructing the view
// ================================================================================
private void makeStatusBarView(Context context) {
Resources res = context.getResources();
mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
mRightIcons = new StatusBarIcon[mRightIconSlots.length];

ExpandedView expanded = (ExpandedView)View.inflate(context,
com.android.internal.R.layout.status_bar_expanded, null);
expanded.mService = this;
StatusBarView sb = (StatusBarView)View.inflate(context,
com.android.internal.R.layout.status_bar, null);
sb.mService = this;

// figure out which pixel-format to use for the status bar.
mPixelFormat = PixelFormat.TRANSLUCENT;
Drawable bg = sb.getBackground();
if (bg != null) {
mPixelFormat = bg.getOpacity();
}

mStatusBarView = sb;

...



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

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

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

 ステータスバーの背景画像を取得する

private Drawable getStatusBarBackground() {

try {
ClassLoader cl = getClassLoader();
Class clazz;
clazz = cl.loadClass("com.android.server.status.StatusBarService");
Constructor constructor = clazz.getConstructor(Context.class);
Object obj = constructor.newInstance(this);
Class c = obj.getClass();
Field field;
//field = c.getDeclaredField("com.android.server.status.StatusBarService.mStatusBarView");
field = c.getDeclaredField("mStatusBarView");

if(!field.isAccessible()) {
field.setAccessible(true);
}
ViewGroup vg = (ViewGroup) field.get(obj);
Drawable d = vg.getBackground();
return d;

} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} catch (SecurityException e) {
e.printStackTrace();
return null;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
} catch (InstantiationException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
} catch (NoSuchFieldException e) {
e.printStackTrace();
return null;
}
}


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


 おまけ:

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

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


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Drawable d = getStatusBarBackground();

if(d != null) {
ImageView iv = ((ImageView)findViewById(R.id.imageview));
iv.setImageDrawable(d);
}
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
ImageView iv = (ImageView)findViewById(R.id.imageview);

iv.setDrawingCacheEnabled(true);
iv.buildDrawingCache();
Bitmap b = iv.getDrawingCache();
if(b != null) {
int x = b.getWidth() / 2;
int y = b.getHeight() / 2;
int c = b.getPixel(x, y);
((TextView)findViewById(R.id.textview)).setText("
"alpha: " + Color.alpha(c) +
" red: " + Color.red(c) +
" green: " + Color.green(c) +
" blue: " + Color.blue(c));
}
else {
((TextView)findViewById(R.id.textview)).setText("no drawing cache");
}
}


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

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

 標準だと灰色なんだけど



 HTC Hero は黒でした。

1 件のコメント:

  1. Did you know that you can shorten your links with Shortest and get $$$ for every click on your shortened links.

    返信削除