クマは森で用を足しますか?

アウトプットは重要です。

GET INKEY コマンドをサポートしてひとまず完成

しばらくぶりの Java Card プログラミングで結局のところ何を作っていたかと言いますと、GET INPUT コマンドを非同期的に SIM カードから端末に送信する SIM ツールキット用アプレットで、そのコマンドのパラメータをある程度コンフィギュレーションできるようにしたものです。GET INPUT コマンドを非同期的に SIM カードから送信させる仕組みについては、前回(下記参照)までの実装で実現できていました。今回、その GET INPUT コマンドに載せるパラメータをコンフィギュレーションできる仕組みを実装します。

cheerio-the-bear.hatenablog.com

同じことを DISPLAY TEXT コマンドや SELECT ITEM コマンドなどでもやりたいんですけど、それらはまた別の機会に。EF_SUME のコンテンツも自在に更新できるようになるといいですね。

GET INPUT コマンドのコンフィギュレーション

SELECT ITEM コマンドを使って作った第二階層のリストの一番上に、"Settings" 項目を設けていました。ユーザーにその項目が選択され、SELECT ITEM コマンドに対する TERMINAL RESPONSE としてそれがカードに伝えられれば、GET INPUT コマンドのコンフィギュレーションのためのコマンドシーケンスを開始します。

f:id:cheerio-the-bear:20190221001959p:plain
二階層目のメニュー項目 (SELECT ITEM コマンド)

1.「数字のみ」もしくは「英数字」

上述の "Settings" 項目を選択した後、端末のスクリーン上には、まず下記の画面が表示されることになります。

f:id:cheerio-the-bear:20190303193731p:plain
数字のみモード?

この画面では、Command Qualifier のビット 1 の値をユーザーに選択させます。"Yes" が選択されれば「数字(と記号)のみ」モードが、"No" が選択されれば「英数字」モードが適用されます。

bit 1: 0 = digit (0 to 9, *, # and +) only;
       1 = alphabet set.

2. 入力された文字を画面上に表示するか否か

前項の選択を終えると、下のスクリーンショットの画面が次に表示されます。

f:id:cheerio-the-bear:20190303194129p:plain
入力された文字は隠しますか?

この画面では、Command Qualifier のビット 3 の値をユーザーに選択させます。ユーザーに入力された文字が直ちにアスタリスク等に置き換えられて表示される等の配慮があるモードを適用したい場合には "Yes" を、入力された文字がそのまま画面上に表示されて構わない場合には "No" を選択します。

bit 3: 0 = terminal may echo user input on the display;
       1 = user input shall not be revealed in any way (see note).

3. 入力可能文字数の制限

その次に、Response length オブジェクトに設定する Minimum length of response フィールドと Maximum length of response フィールドの値を指定させる画面を表示させます。アプレットの実装を簡単にするため、今回は 1 から 9 までの数値を指定できる程度に留めています。

f:id:cheerio-the-bear:20190303194303p:plain
最小入力文字数は?

f:id:cheerio-the-bear:20190303194344p:plain
最大入力文字数は?

4. 表示するメッセージ

最後に、Text string オブジェクトの Text string フィールドに載せる文字列を入力させます。DCS の選択は今回はさせないことにして、GSM default alphabet 8 bits に固定しています。

f:id:cheerio-the-bear:20190303194502p:plain
表示するメッセージは

GET INKEY コマンドのサポート

Command Qualifier の各ビットの値を "Yes" もしくは "No" で選択させる画面の表示には、ETSI TS 102 223 6.4.2 にて説明されている GET INKEY コマンドの下記の機能を利用しています。

If the UICC requests a "Yes/No" response, the terminal shall allow the user to enter either a positive or a negative decision using MMI means left to terminal manufacturer's choice (keypad, touch screen, softkey, etc.).

ProactiveHandler クラスに用意されている GET INKEY コマンド送信用ヘルパーメソッドも、その他のコマンド用のものと同様に Command Qualifier とテキストを指定するだけの仕様になっています。Duration や Icon Identifier を指定したいような場合には、それぞれ必要な TLV オブジェクトを追加する必要があります。API 仕様の詳細については、GSM 03.19 v2.0.0 Annex A をご参照ください。

public void initGetInkey(byte qualifier,
                         byte dcs,
                         byte[] buffer,
                         short offset,
                         short length)
                  throws java.lang.NullPointerException,
                         java.lang.ArrayIndexOutOfBoundsException,
                         ToolkitException

はて、その "Yes" や "No" を TERMINAL RESPONSE でどのように表現するんだろうと思ったら、やっつけ感のある仕様になっていることに気付きました。本来は文字コードを入れる Text string オブジェクトに "Yes" なら数値 0x01 を、"No" なら数値 0x00 を指定させるようです。

When the terminal issues a successful TERMINAL RESPONSE ("0X" result value - refer to clause 8.12) for a GET INKEY ("Yes/No") command with command qualifier set to "Yes/No", it shall supply the value "01" when the answer is "positive" and the value '00' when the answer is "negative" in the text string data object.

念のために Google/AOSP の GetInkeyInputResponseData クラスの実装も確認しましたが、確かに 0x01 か 0x00 を詰めるようになっていました。美しくないですね。

class GetInkeyInputResponseData extends ResponseData {
...
    // GetInKey Yes/No response characters constants.
    protected static final byte GET_INKEY_YES = 0x01;
    protected static final byte GET_INKEY_NO = 0x00;
...
    @Override
    public void format(ByteArrayOutputStream buf) {
...
        if (mIsYesNo) {
            data = new byte[1];
            data[0] = mYesNoResponse ? GET_INKEY_YES : GET_INKEY_NO;

今回のコミット

ということで、上述の件で作成・追加したコミットはこちらです。今回のアプレットについてはこれでひとまずの完成を迎えたということにして、また別のことに取り掛かってみようと思います。

github.com