2012年4月30日月曜日

KeyCharacterMap: No keyboard for id 0

KeyCharacterMap: No keyboard for id 0

エミュレータでは次の趣旨の警告が出る。
W/KeyCharacterMap: No keyboard for id 0
W/KeyCharacterMap: Using default keymap: /system/usr/keychars/qwerty.kcm.bin

実機では次の趣旨の警告が出る。
W/KeyCharacterMap: Can't open keycharmap file
W/KeyCharacterMap: Error loading keycharmap file (省略)
W/KeyCharacterMap: Using default keymap:(省略)

これらの警告を発出させることができるcodeは次のとおりである。
public class MenuActivity extends Activity {
    private static final int Menu_ID = Menu.FIRST;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, Menu_ID, Menu.NONE, R.string.app_name);
        return super.onCreateOptionsMenu(menu);
    }
}

上記プログラムを実行させて、メニューキーを押し下げれば、上記に掲げた警告が出る。

この程度の簡単なプログラムで発出される警告であるから、何も問題は発生していないのであろう。

警告は複数発出されている。警告の前半は、真の意味で警告である。後半は、前半の警告を解除する趣旨の警告である。

むむむ!

2012年4月29日日曜日

webcore: Can't get the viewWidth after the first layout

webcore: Can't get the viewWidth after the first layout

AdMobを使用すると、広告は正常に表示されるにも関わらず、標題の警告がLogCatに出ます。AdMobのSDKは4.3.1及び6.0.0で確認しました。

この警告を発出しているcodeは、android.webkit.WebViewCoreに掲載されているのではないかと思われます。関係する部分は次のとおりです。
2097        // now notify webview
2098        // webViewWidth refers to the width in the view system
2099        int webViewWidth;
2100        // viewportWidth refers to the width in the document system
2101        int viewportWidth = mCurrentViewWidth;
2102        if (viewportWidth == 0) {
2103            // this may happen when WebView just starts. This is not perfect as
2104            // we call WebView method from WebCore thread. But not perfect
2105            // reference is better than no reference.
2106            webViewWidth = mWebView.getViewWidth();
2107            viewportWidth = (int) (webViewWidth / adjust);
2108            if (viewportWidth == 0) {
2109                Log.w(LOGTAG, "Can't get the viewWidth after the first layout");
2110            }
2111        } else {
2112            webViewWidth = Math.round(viewportWidth * mCurrentViewScale);
2113        }

WebViewを別のスレッドで起動させたばっかりなので、必要なデータを取得できない状況です、ということでしょうか。
警告のログを発出しただけであって、処理は継続しているので、事実上問題は無いでしょう。
LogCatに表示されるのは次の趣旨のとおりです。
W/webcore: Can't get the viewWidth after the first layout
I/Ads: Received ad url:(省略)
W/webcore: Can't get the viewWidth after the first layout
I/Ads: onReceiveAd()
webcoreが発出する警告に引き続き、その警告を否定するかのように、Adsが「受け取った」という趣旨の情報を発出しています。
しかし、Adsは情報を発出してはいるものの、webcoreの警告との関連性まで言及していません。
本当に問題が無いのであれば、その旨の情報をどこかに掲載して頂ければ幸いです。

2012年4月27日金曜日

半透明の程度を動的に変更する

半透明の程度を動的に変更する

半透明の程度の値(alpha値)を、何か1個の値で固定したままにするのであれば、その値をxmlファイルに設定すれば良い。
この記事では、利用者の操作等により、alpha値が任意の値に動的に変更・表示できる方法を示す。

この場合、透明のActivityにはconfiguration changeが発生しないという現象があるので注意して頂きたい。

手順概要
1 アプリ(又は任意のActivity)を、完全な透明であるように設定する。
2 任意のタイミングで、任意の半透明の値に設定・表示する。

1 アプリ(又は任意のActivity)を、完全な透明であるように設定する。
処理対象ファイル:AndroidManifest.xml
書き加えるコマンド:android:theme="@android:style/Theme.Translucent"
書き加える場所:アプリ全体を半透明化するのであれば、<application>の属性として書く。任意のActivityだけに施すのであれば、<activity>の属性として書く。
sample code:アプリ全体を半透明化する場合、次のとおりである。
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.Androyer.Transparent"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Translucent"
        >
        <activity
            android:name=".TransparentActivity"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

2 任意のタイミングで、任意の半透明の値に設定・表示する。
Java codeの中で、setBackgroundColorメソッドを使う。
sample codeは次のとおりである。
public class TransparentActivity extends Activity
    implements
    OnClickListener
    {
    Button bu;
    TextView tv;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        bu = (Button)findViewById(R.id.Button);
        bu.setOnClickListener(this);
        
        int i;
        char c = '亜';
        StringBuilder sv;
        
        //適当に文字列を作成・表示する。
        sv = new StringBuilder();
        for(i=0; i<800; i++, c++) sv.append(c);
        tv = (TextView)findViewById(R.id.Text);
        tv.setText(sv);
        //本アプリの後ろの他のアプリが完全に見える状態で表示される。
        //ただし、文字は白色で表示される。
    }
    
    @Override
    public void onClick(View v) {
        if(v==bu){
            //任意の色の背景色にする。ここでは桃色の半透明にする。
            tv.setBackgroundColor(Color.argb(0x66, 0xff, 0, 0xff));
        }
    }
}

参考:上記sample codeで使用したレイアウト用のxml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    >
    <Button
        android:id="@+id/Button"
        android:text="@string/Button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </Button>
    <TextView
        android:id="@+id/Text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </TextView>
</LinearLayout>

2012年4月10日火曜日

Error generating final archive: Debug Certificate expired

Error generating final archive: Debug Certificate expired

副題:Your project contains error(s), please fix them before running your application.

このエラーが発生する根拠は、Signing Your ApplicationsのExpiry of the Debug Certificateに書かれています。

The self-signed certificate used to sign your application in debug mode (the default on Eclipse/ADT and Ant builds) will have an expiration date of 365 days from its creation date.
デバッグモードにおける署名証明書は、その作成日から365日の有効期限があります

解決方法もそこに書かれています。

To fix this problem, simply delete the debug.keystore file. The default storage location for AVDs is in ~/.android/ on OS X and Linux, in C:\Documents and Settings\<user>\.android\ on Windows XP, and in C:\Users\<user>\.android\ on Windows Vista and Windows 7.
The next time you build, the build tools will regenerate a new keystore and debug key.
この問題を解決するには、単にdebug.keystoreファイルを削除すれば良いです。 このファイルの保存場所は開発環境毎に異なります。次のとおりです。
OS XおよびLinuxの場合: ~/.android/
Windows XPの場合: C:\Documents and Settings\<user>\.android\
Windows Vista and Windows 7の場合: C:\Users\<user>\.android\

このファイルを削除した後、「Clean...」を実行し、更に「Debug」を実行すると、debug.keystoreファイルが自動的に生成され、エラーが発生しなくなります。
Eclipseの再起動の必要はありません。

上記措置を講じて、デバッグを実行しようとすると次のエラーが出るかもしれません。

Re-installation failed due to different application signatures.
You must perform a full uninstall of the application. WARNING: This will remove the application data!
Please execute 'adb uninstall jp.Androyer.JPV' in a shell.
Launch canceled!
このエラーに対処するため、デバッグを実行する前に、開発用端末上の、又はエミュレータ上の、開発中のアプリをアンインストールしておく必要があります。


毎年1回、上記の作業を行うことになります。
この記事をお読みになった皆様、1年後に、また、この記事でお会いしましょう。

2012年4月8日日曜日

オプションメニューの作成と変更

オプションメニューの作成と変更

副題:複雑な形状のオプションメニューを作成し、必要に応じ、メニューの一部を削除する。

形状が複雑なオプションメニューはJavaのcodeで書くよりも、xmlで書いた方が視認性が高まる。
sampleは次のとおりである。
resフォルダーの直下にmenuという名前のフォルダーを作成し、menuフォルダーの直下に、このxmlファイルを配置する。このsampleでは、このxmlファイル名は、menu_inputactivity.xmlである。
<?xml version="1.0" encoding="utf-8"?>

<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:id="@+id/Menu_Setting"
        android:title="@string/Menu_Setting"
        >
    </item>
    <item
        android:id="@+id/Menu_Display"
        android:title="@string/Menu_Display"
        >
        <menu>
            <item
                android:id="@+id/Menu_ShowButtons"
                android:title="@string/Menu_ShowButtons"
                >
            </item>
            <item
                android:id="@+id/Menu_HeightSize"
                android:title="@string/Menu_HeightSize"
                >
            </item>
        </menu>
    </item>
    <item
        android:id="@+id/Menu_Quit"
        android:title="@string/Menu_Quit"
        >
    </item>
</menu>

このメニューを任意のActivityに作成するsample codeは次のとおりである。必要に応じ、任意のメニューを削除する。
    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        MenuInflater inf;
        
        inf = getMenuInflater();
        inf.inflate(R.menu.menu_inputactivity, menu);
        if(p!=null && p.iInputMethod==1){//必要に応じ
            MenuItem mi;
            mi = menu.findItem(R.id.Menu_Display);
            if(mi!=null){//サブメニューのメニューを削除する。
                SubMenu sub;
                sub = mi.getSubMenu();
                sub.removeItem(R.id.Menu_ShowButtons);
            }
        }
        return super.onCreateOptionsMenu(menu);
    }

onCreateOptionsMenuメソッドは、Activityの起動時に1回しか呼ばれない。そういう意味で、上記のJava codeだと、「静的に」メニューを作成したことになる。
動的にメニューを変更するのであれば、下記のようにonPrepareOptionsMenuメソッドを組み合わせて使うことになる。
    @Override

    public boolean onCreateOptionsMenu(Menu menu){
        MenuInflater inf;
        inf = getMenuInflater();
        inf.inflate(R.menu.menu_inputactivity, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if(p==null) return super.onPrepareOptionsMenu(menu);
        MenuItem mi;
        SubMenu sub;
        mi = menu.findItem(R.id.Menu_Display);
        sub = mi.getSubMenu();
        mi = sub.findItem(R.id.Menu_ShowButtons);
        if(p.iInputMethod==1){//必要に応じ
            if(mi!=null) sub.removeItem(R.id.Menu_ShowButtons);
        }
        else{
            if(mi==null){
                sub.add(Menu.NONE, R.id.Menu_ShowButtons,
                    Menu.NONE, R.string.Menu_ShowButtons);
            }
        }
        return super.onPrepareOptionsMenu(menu);
    }