Chromebook の入力互換性

通常、ノートパソコンで使用される入力デバイスは、スマートフォンとは異なります。

Chromebook 上の Android アプリは、マウス、タッチパッド、キーボードを備えたノートパソコンのウィンドウ内に表示されるという、設計時の想定とは異なる環境で実行されます。Android ではこういったデバイスがサポートされていますが、ほとんどのアプリには適切に実装されていないのが実情です。そのようなアプリを動作させるために、Chromebook には互換モードが用意されています。このモードは、デフォルトですべてのアプリに適用されます。

互換モード

互換モードでは、Android API とは異なる方法でアプリにイベントが渡されます。このモードは、アプリに Chromebook 固有の機能を実装せず、タップ操作前提のまま動作しさえすればよい、という場合に便利です。

互換モードでの動作は次のようになります。

  • 2 本の指を使ったタッチパッドでのスクロールにより、タッチスクリーンでのスクロールをエミュレートできます。
  • マウスホイールでもスクロールできます。
  • すべての測定とイベントは、アプリ ウィンドウが全画面であるかのように動作します。つまり、getRawXgetRawY などのメソッドからは、画面スペースの座標でなく、ウィンドウ スペースの座標が返されます。

アプリのターゲットに設定された API レベルに応じて、互換モードによる互換性維持の動作は多少異なります。

android.hardware.type.pc の使用

アプリを Chromebook での実行用に最適化し、入力デバイスを有効活用するには、アプリ マニフェストで次のように宣言します。

<uses-feature
        android:name="android.hardware.type.pc"
        android:required="false" />
    

この宣言により、基本的にキーボード、マウス、タッチパッドで操作する PC デバイスをターゲットにすることを Android に伝えます。こうすることで、互換モードを無効にし、マウスやタッチパッドのカスタム動作を実装できるようになります。

DecorCaptionView に関する注意事項

フリーフォーム ウィンドウ モードでは、アプリのキャプション バーはビュー階層に含まれており、制御が可能です。通常はこれを意識する必要はありませんが、次の点に注意が必要です。

  • Window.getDecorView() を使用しないでください。最上位のビューを追加する場合は、Activity.setContentView() として設定したビューに追加します。
  • Activity.setContentView() がアプリの (0, 0) にあるとは限りません。(0, 0) にあるのはキャプション バーです。
  • 可能な限り、MotionEvent.getRawX()MotionEvent.getRawY() は使用しないでください。使用する場合は、View.getLocationOnScreen() と併用して座標をビュースペース座標に変換してください。

入力デバイスのサポート

android.hardware.type.pc フラグを使って PC デバイスをターゲットにすると、以下のイベントが発生するようになります。

マウスとタッチパッドのサポート

マウスとタッチパッドのどちらからも、タップイベントと同様に MotionEvents が生成されます。MotionEvent.getSource() を確認することで、SOURCE_MOUSESOURCE_TOUCHSCREEN を区別します。

  • マウスやタッチパッドでの移動操作。 ACTION_HOVER_MOVE イベントが生成されます。これは View.onGenericMotionEvent() で処理されます。
  • マウスやタッチパッドでのボタン操作。 ACTION_BUTTON_PRESS イベントと ACTION_BUTTON_RELEASE イベントが View.onGenericMotionEvent() に送信されます。getButtonState() を使用することにより、マウスイベントやタッチパッド イベントで押されたボタンを確認することもできます。
  • タッチパッドでのスクロール操作。 タッチパッドで 2 本の指を使ってスクロール操作を行うと、タッチスクリーンでのドラッグ イベントと同様に、指の動きに応じた滑らかなスクロールが可能です。タッチスクリーンでのドラッグとタッチパッドでのスクロールを異なる動作にする場合は、getSource() を使用します。
  • マウスホイールでのスクロール操作。 マウスホイールでのスクロール操作は、ACTION_SCROLL イベントとして View.onGenericMotionEvent() に報告されます。
  • マウスやタッチパッドでのクリックしてドラッグする操作。 クリックしてドラッグするイベントは、タッチスクリーンでのドラッグ イベントとよく似ています。getButtonState() を使用して、クリックしてドラッグするイベントとタッチパッドでのスクロール イベントとを区別します。クリックしてドラッグする操作は常にボタン操作を伴いますが、タッチパッドでのスクロールでは伴いません。

右クリックのサポート

右クリック イベント(コンテキスト クリック イベント)の処理は、View.OnContextClickListener をビューに設定するだけで簡単に行えます。

Kotlin

    yourView.setOnContextClickListener {
        //display context click options
        true
    }
    

Java

    yourView.setOnContextClickListener(new View.OnContextClickListener() {
    @Override
      public boolean onContextClick(View view) {
        //display context click options
        return true;
      }
    });
    

このメソッドは API レベル 23 で追加されました。それより古いバージョンの Android を搭載するデバイスに同様の機能を実装するには、上述の一般的なモーション イベントを使用します。

キーボード

キーボードは、デスクトップ パソコンやノートパソコンにとって重要な入力方法です。ユーザー補助機能のためにも不可欠です。

入力フォーカスの有効化を適切に行うには、次のようにして、デフォルトの Android API による通常のリソース追加手順を行います。

  • キーボード入力を独自に処理する場合は、KeyEvent.callback のデフォルトの関数を使用します。TextEdit 要素内ではキーボード入力を処理する必要はありません。
  • テキストを独自に編集する場合は、onKeyDownonKeyLongPressonKeyUp を使用します。ただし、onKeyPreIME イベントは、IME の全機能を独自に実装する(非推奨)場合を除いて使用しません。

タッチペン

タッチペンから報告されるイベントは、タッチスクリーンから View.onTouchEvent() を介して報告されるものと似ています。ただし、タッチペン イベントには、さらに次の情報も含まれます。

  • MotionEvent.getToolType()。このツールタイプにより、TOOL_TYPE_FINGER イベントと TOOL_TYPE_STYLUS イベントを区別できます。また、TOOL_TYPE_ERASER で、ペンの消しゴム側(ある場合)の使用を確認することもできます。
  • MotionEvent.getPressure()。タッチペンに加えられた物理的な圧力を表します(サポートされている場合)。
  • MotionEvent.AXIS_TILT/AXIS_ORIENTATIONMotionEvent.getAxisValue() と併用して、タッチペンの物理的な傾きと方向を読み取ることができます(サポートされている場合)。

履歴ポイント

Android では、入力イベントはフレームごとに一括で送信されます。しかし、タッチペンでは、はるかに高い頻度(200 Hz はごく一般的)での報告が可能です。描画アプリを作成する際は、履歴 API から取得したポイントを使用することが重要です。

  • MotionEvent.getHistoricalX()
  • MotionEvent.getHistoricalY()
  • MotionEvent.getHistoricalPressure()
  • MotionEvent.getHistoricalAxisValue()

パーム リジェクション

Chrome OS では、置かれた手のひらが認識され、アプリに報告されないようになっています。ただし、これは常に可能というわけではなく、それが手のひらと認識される前にタップが報告される場合があります。その場合は、ACTION_CANCEL イベントを報告することで、タップをキャンセルできます。

このイベントにより、すべてのタップは無効であり、それに基づく操作はすべて元に戻すべきである旨がアプリに伝わります。たとえば描画アプリの場合、新しいラインが一時的に描画された後、一連のタップが明確に終了してはじめてキャンバスにコミットされます。タップがキャンセルされた場合は、一時的なラインは簡単に削除できます。

メモのインテント

Chrome OS では、org.chromium.arc.intent.action.CREATE_NOTE アクションと Intent.CATEGORY_DEFAULT(すなわち android.intent.category.DEFAULT)カテゴリを含むインテントを処理するよう登録されたアプリのリストが表示されます。アプリの登録は、次のコード スニペットのようにして行います。

  <intent-filter>
        <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
    

これにより、ユーザーはこのアプリを選択できるようになり、その後、メモアプリをリクエストするとこのアプリが起動するようになります。

ユーザーが新しいメモの作成をリクエストすると、前述のアクションとカテゴリのみを含むインテントによってアプリが起動します。アプリでは、タッチペンで記述できるモードで空のメモが作成されるようにします。

ユーザーが画像(スクリーンショットやダウンロードした画像など)に注釈を付けることを要求すると、前述のアクションとカテゴリを含むインテントによりアプリが起動します(content:// URI の項目を含む ClipData を含めて)。アプリでは、最初に添付された画像を背景画像にして、それにタッチペンで描画できるモードでメモが作成されるようにします。

タッチペンなしでのテスト

  1. デベロッパー モードに切り替えてデバイスを書き込み可能にします
  2. Ctrl+Alt+F2(→)キーを押してシェルを開きます。
  3. sudo vi /etc/chrome_dev.conf コマンドを実行します。
  4. ファイルの末尾に新しい行として --ash-enable-palette を追加します。
  5. Ctrl+Alt+F1(←)キーを押して UI に戻ります。
  6. ログアウトして再度ログインします。

次のようにして、タッチペンのエントリ ポイントを確認できます。 - まず、シェルフでタッチペン ボタンをタップして [新しいメモ] を選択します。これにより、アプリで空白の描画メモが開きます。 - スクリーンショットを撮る(シェルフから、タッチペン ボタン > [画面をキャプチャ])か、画像をダウンロードすると、通知内に [画像に注釈を付ける] オプションが表示されます。これにより、その画像に注釈を付けられる状態でアプリが起動します。

ゲームパッド

Chromebook は、ゲームパッドを 4 台までサポートしています。ゲームパッドからの報告は、標準の Android API に準拠しています。残念ながら、Android 用に設計されていないゲームパッドでも正しいボタン マッピングが表示されることがよくあります。