第1回Android Test Casual Talks でuiautomatorの話をしました #androidtest
12/13(金)に開催された Android Test Casual Talks #1 でLTをしました。以下が発表資料です。
「uiautomatorを使うときのひと工夫」というタイトルで、 拙作のUiautomator Unicode Input Helperの紹介をベースに、 日本語環境でuiautomatorを快適に利用する工夫について発表しました。
勉強会では初めての発表だったということもあり、 かなりドキドキしていたのですが、皆さんに興味を持って聴いていただけたようで、 ほっとしています。
LTの補足
発表の中で、
UiObject.clearTextField()
の実装を日本語ロケール向けにローカライズを行った、
というお話もさせていただきました。
それについて、帰宅後に少し調べてみたところ、
意外と簡単に国際化対応できそうな事に気付きましたので、
このブログで補足させてください。
このような対応が必要となる原因は、
UiObject.clearTextField()
の実装で、
以下のように"Select all"
がハードコーディングされているからでした。
public void clearTextField() throws UiObjectNotFoundException { // (省略) getInteractionController().longTapNoSync(rect.left + 20, rect.centerY()); // check if the edit menu is open UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); if(selectAll.waitForExists(50)) selectAll.click(); // wait for the selection SystemClock.sleep(250); // delete it getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); }
"Select all"
を表すリソースIDは
R.string.selectAll
なので、通常のAndroidアプリであれば"Select all"
を
context.getString(android.R.string.selectAll)
(context
はContext
のインスタンス)
に置き換えれば自然に国際化できるのですが、
uiautomatorのテストコードからはContext
を取得する手段が無いため、
getString()
できないだろうと思い込んでいました。
ところが、その思い込みは間違いで、システムリソース
(android.R.
から始まるリソース)に限り
Resources.getSystem()
を使えば、Context
無しにリソースにアクセスできることが分かりました*1。
恥ずかしながら、このようなAPIが有ることを今まで知りませんでした。
手持ちの以下の2つの端末で確認してみた感じでは、 uiautomatorから上記を呼び出すと、端末の言語設定に応じて、 適切な文字列を返してくれているようです。
ですので、原理的には、以下のように書き換えれば、
端末の言語設定にかかわらず、clearTextField()
が動作するはずです。
AOSPへのバグ報告は別途行いたいと思います。
public void clearTextField() throws UiObjectNotFoundException { // (省略) String selectAllDesc = Resources.getSystem().getString(android.R.string.selectAll); UiObject selectAll = new UiObject(new UiSelector().descriptionContains(selectAllDesc)); // (省略) }
各自で回避する場合の多言語対応版は以下のようになります。
public void myClearTextField(UiObject editText) throws UiObjectNotFoundException { editText.longClickTopLeft(); // "Select all"のリソース文字列を取得 String selectAllDesc = Resources.getSystem().getString(android.R.string.selectAll); UiObject selectAll = new UiObject(new UiSelector().descriptionContains(selectAllDesc)); if (selectAll.waitForExists(50)) selectAll.click(); SystemClock.sleep(250); getUiDevice().pressDelete(); }
さいごに
他の皆さんのLTも、どれも新しい発見があり、とても興味深く聴かせていただきました。 これからも、このような勉強会で引き続き情報交換していきたいです。
今回の勉強会を主催し、LTに誘って下さった@hotchemiさんをはじめとする運営の皆さん、 コメント下さった参加者の皆さん、本当にありがとうございました。
*1:実は、「Contextを取得できない」というのも勘違いの可能性が高いです。Android4.3からはUiAutomatorTestCaseがInstrumentationTestCaseを継承するようになっていました。ということは、getInstrumentation().getContext()が呼び出せるかもしれません。今度調べてみようと思います。