2010年12月30日木曜日

Resource is not public

システムが持つリソース・ファイル (各種 XML ファイルや PNG ファイルなど) は参照できるものと参照できないものがあるようです。

参照できない場合、Eclipse のコンソールに以下のようなエラーが出力されます。

[2010-12-30 11:15:19 - XXXXXXX Proj] C:\android\workspace\XXXXXXX Proj\res\values\styles.xml:77: error: Error: Resource is not public. (at 'android:background' with value '@android:drawable/btn_circle').

@android:drawable/btn_circle を指定して、
<android SDK導入ディレクトリ>\platforms\android-X\data\res\drawable\btn_circle.xml (android-X の X は API レベル) を参照しようとしているのですが、"public じゃないよ" と叱られています。

public かどうかは、その名の通り public.xml で確認できます。
(android 2.2 の場合)
<android SDK導入ディレクトリ>\platforms\android-8\data\res\values\public.xml

ちなみに、public でなくとも、@*android:drawable/btn_circle のように、@ の後ろに * (アスタリスク) を入れると参照できるようになります。

但し、以下のメーリング・リストのやりとりを見ると、public でないものは、頻繁に変更が入るみたいなので、基本的には使用しないほうが無難なようです。
what star (*) means in "@*android:drawable/"?
https://groups.google.com/group/android-developers/browse_thread/thread/d1e06ce82e1f745b?fwc=1&hl=ja

2010年12月24日金曜日

java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor

png などの画像上に drawText() で文字を書こうとして、
以下のような処理を記述すると、4行目の drawText() で、タイトルの例外メッセージが発生します。

Resources r = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(r, R.drawable.icon);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(...);

bitmap が immutable (変えられない) ことが原因です。
mutable か immutable かは、bitmap.isMutable() で true か false かで確認できます。

じゃあ、どうやって mutable にするかというと、
bitmap.copy(Bitmap.Config config, boolean isMutable) を使って、
mutable な Bitmap を新規に作成します。

青字部分が修正内容)
Resources r = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(r, R.drawable.icon);
Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(copy);
canvas.drawText(...);

こうすると、うまく処理できます。


ちなみに、、

bitmap.copy(Bitmap.Config config, boolean isMutable) の第1引数ですが、
ALPHA_8、ARGB_4444、ARGB_8888、RGB_565 のいずれかを選択できます。

ARGB_4444 や RGB_565 を使えば、画像のバイト数を節約できそうです。
画質優先の場合には、ARGB_8888 を使う、というところでしょうか。
ALPHA_8 は、よく分かりません。。

項目 1 ピクセルあたりのバイト数 コピー内容(多分。確証はありません。)
ALPHA_8 1 バイト アルファ値のみ 8 ビット。
ARGB_4444  2 バイト  ARGB それぞれ 4 ビットずつ。
ARGB_8888 4 バイト ARGB それぞれ 8 ビットずつ。
RGB_565 2 バイト RGB が 5/6/5 ビット。


以下は、比較用に作成したサンプルです。


上から、以下の画像を表示させています。
  1. オリジナル画像
  2. ALPHA_8 (表示されていませんが。。)
  3. ARGB_4444
  4. ARGB_8888
  5. RGB_565

以下は、ソースです。

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
<ImageView
  android:id="@+id/imageview1"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  />
<ImageView
  android:id="@+id/imageview2"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  />
<ImageView
  android:id="@+id/imageview3"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  />
<ImageView
  android:id="@+id/imageview4"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  />
<ImageView
  android:id="@+id/imageview5"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  />
</LinearLayout>

BitmapCopyActivity.java
package jp.sample.rtaki;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;

public class BitmapCopyActivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Paint paint = new Paint();
    paint.setColor(Color.BLUE);
    //paint.setAlpha(200);
    paint.setTextSize(12);

    ImageView v1= (ImageView) findViewById(R.id.imageview1);
    Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.flag);
    v1.setImageBitmap(image);

    ImageView v2 = (ImageView) findViewById(R.id.imageview2);
    Bitmap copy1 = image.copy(Bitmap.Config.ALPHA_8, true);
    Canvas c2 = new Canvas(copy1);
    c2.drawText("ALPHA_8 - " + copy1.getRowBytes()/copy1.getWidth()*1.0, 25, 33, paint);
    v2.setImageBitmap(copy1);

    ImageView v3 = (ImageView) findViewById(R.id.imageview3);
    Bitmap copy2 = image.copy(Bitmap.Config.ARGB_4444, true);
    Canvas c3 = new Canvas(copy2);
    c3.drawText("ARGB_4444 - " + copy2.getRowBytes()/copy2.getWidth()*1.0, 25, 33, paint);
    v3.setImageBitmap(copy2);

    ImageView v4 = (ImageView) findViewById(R.id.imageview4);
    Bitmap copy3 = image.copy(Bitmap.Config.ARGB_8888, true);
    Canvas c4 = new Canvas(copy3);
    c4.drawText("ARGB_8888 - " + copy3.getRowBytes()/copy3.getWidth()*1.0, 25, 33, paint);
    v4.setImageBitmap(copy3);

    ImageView v5 = (ImageView) findViewById(R.id.imageview5);
    Bitmap copy4 = image.copy(Bitmap.Config.RGB_565, true);
    Canvas c5 = new Canvas(copy4);
    c5.drawText("RGB_565 - " + copy4.getRowBytes()/copy4.getWidth()*1.0, 25, 33, paint);
    v5.setImageBitmap(copy4);

  }

}

2010年12月17日金曜日

電波改善計画の電話がきた

android とは、ちっとも関係ありませんが、、

本日、ソフトバンクのコールセンター?の おば じゃなくて、おねえさんから、
電話改善計画のアンケートなる電話がありました。

電話番号は 0120-669-600 だったんですが、
ググると結構ヒットしたので、既に多くの人に電話しているようです。

お小遣い的都合で、android への機種変更ができず、
iPhone 3GS を使い続けているのですが、以下のようなことを質問されました。

  • 自宅では、iPhone を Wi-Fi で使っているか?

  • 自宅のインターネット環境は光か、それともADSLか?

  • プロバイダはどこか?

  • Wi-Fi ルータのメーカーは何か?家電量販店で買ったものか?

  • iPhone でインターネット接続をよくする時間帯はいつか?

  • 自宅で Wi-Fi 使用をどのように確認しているか?
    ちゃんと画面上部のアイコンが 3G から 扇型 になることを確認しているか?

こっちは仕事中なのに、いきなり電話を掛けてきて、
何を聞くんだ?と、ちょっとイラっとしましたが、
この おば じゃなくて、おねえさんに、そんなことを言っても仕方がないので、
いつもの事なかれ主義で、淡々と質問に答えました。

いきなり電話して、こんな質問しようもんなら、相手は100%嫌がると思います。

そう考えると、むしろ、おねえさんが不憫です。。
派遣の自給はいくらですか。。自分より給料よかったりして。

最後に、電話が切られそうになったところで、
「質問の主旨は何ですか?」と訊いてみると、以下のような回答でした。

電話改善運動の一貫で、ご自宅での iPhone の使用状況を確認し、
Wi-Fi を使っていないユーザー様については、FON ルータを配布している。


ということは、正直に「Wi-Fi使っています」と答えなければ、
FON ルータを無料で貸し出せてもらえたのかもしれません。。

そう思うと、ちょっと失敗したかな・・・


しかし、よくよく考えて見ると、
この手の電話は、パケットの通信量が多い人を優先もしくは限定しているじゃないでしょうか。

う~ん、最近は、あんまし使ってないんだけどな~

夏頃は、確かにパケット代が 100 万超えてけど。。(もちろん実際は払った金額は定額料金のみですが)

2010年12月8日水曜日

ブログのタイトル、ちょっと変えました

google で検索すると、rtaki さんが既にいらっしゃるようだったので、rtaki0329 にしました。

あんまし、まぎらわしさが解消されていない気もするんですが、
まあ気にする人もいないだろうということで、ヨシとしておきます。