tmytのらくがき

個人の日記レベルです

GitHubからAzureにCDするのが一瞬でできて感動したというだけの話

GitHubからASP.NET CoreなアプリケーションをAzure Web Appにデプロイするのにビルドとか面倒だなと思っていたら、Azure Portalから一瞬で設定ができて感動した。

  1. 左のメニューから”デプロイ センター”を選ぶ
  2. 右の画面から”設定”を開く
  3. ソースを ”GitHub”にする
  4. ”承認”みたいなボタンが出るので、押してGitHubでログインする
  5. 組織、リポジトリ、ブランチを順番にたどってデプロイしたいリポジトリを選ぶ
  6. ビルドは各自いい感じにする
  7. ”保存”を押す

f:id:tmyt:20210210054209p:plain

これでおわり。自動でGitHub Actionsの設定がリポジトリにコミットされて、自動でビルドからデプロイまでが実行される。

f:id:tmyt:20210210053845p:plain

一瞬で設定できてすごいね。というだけの話。

Surface PenのボタンでSurface Duoのスクリーンショットを撮る

Surface PenはSurface Duoからはキーボードに見えていて、短押しと長押しでそれぞれ特定のスキャンコードを出力するので、Surface Penに設定されているキーレイアウトをカスタムしてPrintScreen*1に割り当てましょう。という話です。

スキャンコードに対応するキーコードを入れ替える

今回は短推しで出力されるキーコード"291"を"SYSRQ"に入れ替えることを目標にします。

Androidに接続されているキーボードは、設定の物理キーボードのレイアウト設定*2で変更できます。しかも、ここのレイアウトはAPKで後から追加できます。じゃぁ作るしかない。

キーボードレイアウトを追加するAPKは、キーキャラクタマップ(KCM)をはじめとしていくつかのファイルが必要です。といっても大したことはないのでAndroidのソースツリーにあるやつをコピペして使うのでほぼ問題ないです。

具体的には、キャラクタマップ、キーレイアウトXML、BroadcastReceiverと、AndroidManifestです。ほかはローカライズで使ってたりするだけなので不要。しいて言えばアイコンぐらいはいるかもしれない。

キャラクタマップの書き方がわからない

書き方は、SDKドキュメントに書いてます。

書いてますがたいして参考になりません。今回みたいな文字を出力しないキーのことはさっぱりわからないのでこのファイルを解釈しているソースを読みます。

このファイルを読んでいくとパーサーの実装が見つかります。

String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "type") {
    mTokenizer->skipDelimiters(WHITESPACE);
    status_t status = parseType();
    if (status) return status;
} else if (keywordToken == "map") {
    mTokenizer->skipDelimiters(WHITESPACE);
    status_t status = parseMap();
    if (status) return status;
} else if (keywordToken == "key") {
    mTokenizer->skipDelimiters(WHITESPACE);
    status_t status = parseKey();
    if (status) return status;
} else {

行頭に現れる値は type, map, key の3種類だそうです。typeの引数は次の6種類があるようです。

  • NUMERIC
  • PREDICTIVE
  • ALPHA
  • FULL
  • SPECIAL_FUNCTION
  • OVERLAY

このtypeOVERLAYにしておくのがいいらしいです。

次に、map。これは次のような構文らしいです。

map key usage {usage code} {key code}
map key {scan code} {key code}

usageが付くパターンは、HIDのUsageを指定するそうですがよくわかりません。ここに

上位の 16 ビットで HID 使用状況ページを、下位の 16 ビットで HID 使用状況 ID を示します。

と書いてあるけれどもそれがどう動くのかはよくわからんやつです。

今回やりたいのはusageが付かない2個目のほう。これを使うと任意のスキャンコードを任意のキーコードに書き換えられます。 たとえばCapslockを左Ctrlに置き換えるとかもこれでできますね。

一番後ろのkey codeはキーコードの名前を指定するとよさそうです。この時指定できる名前は、InputEventLabels.hに定義されてます。

ここを見れば一覧が書いてます。KEYCODE_ってつかないタイプのキーの名前を書けばいい感じですね。

残った、key、これはドキュメントに書いてあるので読んでください。

キャラクタマップを書く

書き方さえわかれば後は簡単。

type OVERLAY
map key 190 SYSRQ

これでおわり。あとはXMLとか用意してAPKにすれば、Surface Penの後ろのボタンでスクリーンショットが取れます。ただ30秒で切断されて反応しなくなるのであんまり役には立たないですね。

今回のソースコードはこちら。

*1:内部的にはSYSRQ

*2:場所は端末によってまちまち、だいたい言語設定の近く

Surface Duoに接続したSurface Penのボタンをイベントで受ける

Surface DuoはいちおうSurfaceと言ってるだけあって、Surface Pen(Slim Pen含む)に対応してます。サイドボタンなどなども一応ちゃんと動くそうです。

さて、このペンがAndroidにどう認識されているのかとても気になるので確認してみます。

$ getevent -p
add device 1: /dev/input/event6
  name:     "sm8150-tavil-snd-card Button Jack"
  events:
    KEY (0001): 0072  0073  00e2  0104  0105  0246
  input props:
    <none>
add device 2: /dev/input/event5
  name:     "sm8150-tavil-snd-card Headset Jack"
  events:
    SW  (0005): 0002  0004  0006  0007  0010  0011  0012  0013
  input props:
    <none>
add device 3: /dev/input/event4
  name:     "surface_touchscreen"
  events:
    KEY (0001): 0141  014b
    ABS (0003): 002f  : value 0, min 0, max 11, fuzz 0, flat 0, resolution 0
                0030  : value 0, min 0, max 21067, fuzz 0, flat 0, resolution 0
                0031  : value 0, min 0, max 21067, fuzz 0, flat 0, resolution 0
                0034  : value 0, min -90, max 90, fuzz 0, flat 0, resolution 0
                0035  : value 0, min 0, max 17709, fuzz 0, flat 0, resolution 0
                0036  : value 0, min 0, max 11411, fuzz 0, flat 0, resolution 0
                0037  : value 0, min 0, max 15, fuzz 0, flat 0, resolution 0
                0039  : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0
                003a  : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0
  input props:
    INPUT_PROP_DIRECT
add device 4: /dev/input/event3
  name:     "surface_tail_button"
  events:
    KEY (0001): 007d  00bc  00bd  00be
  input props:
    <none>
add device 5: /dev/input/event1
  name:     "da7280-haptic"
  events:
    FF  (0015): 0050  0051  0052  005d  0060
  input props:
    <none>
add device 6: /dev/input/event0
  name:     "qpnp_pon"
  events:
    KEY (0001): 0072  0074
  input props:
    <none>
add device 7: /dev/input/event2
  name:     "gpio-keys"
  events:
    KEY (0001): 0073
  input props:
    <none>

"surface_tail_button" なんて気になる名前があります。とりあえずペンで画面をタップします。

/dev/input/event4: 0003 002f 0000000a
/dev/input/event4: 0003 0039 0000ffff
/dev/input/event4: 0003 0035 00002c7f
/dev/input/event4: 0003 0036 000018ae
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0003 0035 00002c82

ペンは /dev/input/event4 なので、 "surface_touchscreen" で処理されていました。ペンの両端とも反応します。後のボタンは反応しません。

後ろボタンの行方

ペンの後ろのボタンは"surface_tail_button" で来ると思った…けれどもどうやら違うようです。ペンの後ろボタンは実はBluetooth接続されています。あのボタンだけ。 ペンを接続するために、後ろのボタンを5秒間長押しします。すると、ペンが接続されて新しいデバイスが出現します。

add device 1: /dev/input/event7
  name:     "Surface Slim Pen"
  events:
    KEY (0001): 0001  0002  0003  0004  0005  0006  0007  0008
                0009  000a  000b  000c  000d  000e  000f  0010
                0011  0012  0013  0014  0015  0016  0017  0018
                0019  001a  001b  001c  001d  001e  001f  0020
                0021  0022  0023  0024  0025  0026  0027  0028
                0029  002a  002b  002c  002d  002e  002f  0030
                0031  0032  0033  0034  0035  0036  0037  0038
                0039  003a  003b  003c  003d  003e  003f  0040
                0041  0042  0043  0044  0045  0046  0047  0048
                0049  004a  004b  004c  004d  004e  004f  0050
                0051  0052  0053  0056  0057  0058  0060  0061
                0062  0063  0064  0066  0067  0068  0069  006a
                006b  006c  006d  006e  006f  0074  0075  0077
                007d  007e  007f  00b7  00b8  00b9  00ba  00bb
                00bc  00bd  00be
    ABS (0003): 0028  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0029  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002a  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002b  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002c  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002d  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002e  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                002f  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0030  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0031  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0032  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0033  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0034  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0035  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0036  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0037  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0038  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                0039  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003a  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003b  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003c  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003d  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003e  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                003f  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
    MSC (0004): 0004
  input props:
    <none>

これが後ろのペンに反応する入力デバイスだそうです。これはキーボードに見えていて、ボタンを押すとキーコードを出力します。

操作 キーコード
短押し 291
長押し 289

しかも、ACTION_UPだけきます。

…と、ここまではつながってさえいればアプリに新機能組み込んだりいろいろできそうだね!で終わるのですがちゃんとオチを用意しました。

このボタン、30秒無操作でBluetoothが切断します。30秒以内にボタンを押せば一応延長されます。でも無操作30秒で切断されます。再接続は5秒長押しです。というわけであんまり役に立ちません…

ところで

"surface_tail_button" は何だったんだろう…古いSurface Penだとあそこが反応する…?いやそんなまさかね…

Android 10以降で表示されるバッテリ残り時間を取得する

たぶんAndroid 10から追加されたバッテリーの残り時間をアプリで取得できたのでメモ。

Settings.Globalに格納されていて、ContentResolverでアクセスできる。キーはandroid.provider.Settingsに定義があったけれど、@hideされていたのでコピペして使った。

private val BATTERY_ESTIMATES_LAST_UPDATE_TIME = "battery_estimates_last_update_time"
private val TIME_REMAINING_ESTIMATE_MILLIS = "time_remaining_estimate_millis"
private val TIME_REMAINING_ESTIMATE_BASED_ON_USAGE = "time_remaining_estimate_based_on_usage"
private val AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge"

private val AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1
private val ESTIMATE_MILLIS_UNKNOWN = -1

data class Estimate(
    val lastUpdateTime: Long,
    val estimateMillis: Long,
    val isEstimateBasedOnUsage: Boolean,
    val timeToDischarge: Long,
)
fun getEstimate() = Estimate(
    Settings.Global.getLong(
        contentResolver,
        BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1
    ),
    Settings.Global.getLong(
        contentResolver,
        TIME_REMAINING_ESTIMATE_MILLIS,
        ESTIMATE_MILLIS_UNKNOWN.toLong()
    ),
    Settings.Global.getInt(
        contentResolver,
        TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, 0
    ) == 1,
    Settings.Global.getLong(
        contentResolver,
        AVERAGE_TIME_TO_DISCHARGE,
        AVERAGE_TIME_TO_DISCHARGE_UNKNOWN.toLong()
    )
)

Surface Duo向けアプリ2個をPlayストアに公開しておきました

Surface Duo向けのアプリ2個をPlayストアに公開しておきました。

Duo BrowserHelper

ひとつめ。G8X BrowserHelperのSurface Duo版。

Chrome Custom Tabs互換のブラウザアプリのふりをしてインテントを受け取って、常に別画面でブラウザを開くためのもの。Surface Duoの画面を折りたたんで、半画面で使っているときはCustom Tabsを起動するような仕組みになっています。

アイコンまでコピペなのでそのうちなんとかします。

play.google.com

スクショカッター

ふたつめ。Surface Duoのスクショを片画面分のサイズで切り抜くだけのもの。

Surface Duoは画面がどんな状態になっていても2枚つながったスクショを保存するので、半画面で使ってると空白のディスプレイ部分もくっついてくる。これを、スクショ通知の共有ボタンからこのアプリで開くことで簡単に半分サイズのスクショに編集できるというやつです。

名前がダサい?僕もそう思います。

play.google.com

startActivityの挙動

Surface DuoでのstartActivityの挙動をメモしたものです。基本的にはドキュメントに書いてある内容です。

定義

  • それぞれの画面はペインと呼びます。
  • ホーム画面が表示されているペインは空き状態と呼びます。
  • なにかアプリが起動しているペインは占有状態と呼びます。

挙動

  • ペインに表示されいてるアプリがstartActivityを呼ぶと、同じペインにアクティビティが表示されます
    • ただし、Intent.FLAG_ACTIVITY_NEW_TASKが設定されているかつ、もう一方のペインが空き状態の場合は空きペインに表示されます
      • ただし、もう一方のペインが空き状態でない場合は、呼び出したアクティビティと同じペインに表示されます

表にしておきます。

左側ペインにアプリAを起動して、異なるパッケージに属するアクティビティをstartActivityしたことを想定。

Flags 右側ペインの状態 起動場所
なし 空き
なし 占有
FLAG_ACTIVITY_NEW_TASK 空き
FLAG_ACTIVITY_NEW_TASK 占有

同じパッケージに属するアクティビティをstartActivityする場合はIntent.FLAG_ACTIVITY_MULTIPLE_TASKを付けないと、常に同じペインで表示されます。

Surface Duoを買いました

使い始めてもう2週間くらいになるのだけれども、Surface Duoを買いました。

工事設計認証も通っているのですぐに日本ででるだろう。と思って待っていたのだけれども、一向にアメリカ以外の展開が発表されないので意を決して輸入に至りました*1

受け取り&開封

受け取り

本当はFedExのひとがうちまで配達に来てくれる…予定だったのだけども、せっかくなので関西空港での受け取りに挑戦。 FedExの営業所へ電話をして空港で受け取れないか?と尋ねたところ、ちょうど通関の許可が出たころでギリギリ間に合ったみたいでした。

用意ができたとの連絡を受けいざ空港へ…国際貨物と書かれたレーンを間違えないように進みます。

f:id:tmyt:20201019042751p:plain

一般人が使うのは一時立ち入りレーンなので一番右側の車線。

f:id:tmyt:20201019042903p:plain

しばらく行くと検問があって、右側2レーンぐらいが一時立ち入り向け。左側レーンは許可車両なので間違えないように進む。

f:id:tmyt:20201019043016p:plain

関係者以外立ち入り禁止とか書かれていてちょっとドキドキする。

f:id:tmyt:20201019043128p:plain

順番が回ってくると、検問のおじさんに、何しに来たの。と聞かれるので「FedExに荷物を取りに来た」と伝えると、一時立ち入りに必要な書類の記入をしてね。と紙を渡されるので書く。 一緒に、免許証を身分証として提出。退出予定時刻を伝えると、立ち入り許可証を受け取ってついに制限エリアの中へ!

FedExへ行くには国際郵便局前の信号を右折。僕は間違えて制限エリアの中をさまよいました。

国際郵便局前の信号を右折したらひたすら直進。突き当りを右折するとFedExの入り口と駐車場があるので、車をとめて荷物を受け取ります。 荷物受け取りに来たよ、と伝えると内線でここにかけて。といわれるので、内線で電話をしてトラッキング番号を伝えると奥から持ってきてくれます。

最後に、立ち入り許可証にハンコを押してもらって逆のルートで帰ればおしまい。

開封

BigAppleBuddy という、BestBuyとかで代わりに買ってきてくれるサービスを使ったのでそこのお手紙付き。

f:id:tmyt:20201019044140p:plain

本体、バンパー、ドキュメント類、充電器とケーブルが入ってました。SIMピンはドキュメント類の中に入ってました。

f:id:tmyt:20201019044745p:plain

Powered by Android

f:id:tmyt:20201019044322p:plain

楽天MobileのSIMを入れていたからか、言語設定の選択肢に日本語が出てきたのが印象的でした。

f:id:tmyt:20201019044426p:plain

セットアップ中も完全に日本語。

f:id:tmyt:20201019044455p:plain

早く日本でも普通に買えるようになってほしいね…

ちなみに、ちゃんと技適表示あります。

f:id:tmyt:20201019045157p:plain

設定その他

楽天MobileのAPNは自動設定されないので手動で設定。rakuten.jp と書いてあとは適当に設定。普通につながりました。 VoLTEはIMSを設定しても有効にならないみたい。4G LTE拡張モードのチェックが表示されないので使えなさそう。

そのほかの設定はあんまりやることもなくいつも通り普通のAndroidでした。

うちに届く2日前にミヤビックスからSurface Duo向けのOverlayほにゃららがタイミングよく販売スタートしたので、注文しておきました。 液晶はOverlay 9H Brilliant、背面はOverlay 9H Plusを貼っています。外側さらさらでとてもよい…

感想

サイズ感

2、3日使ってみたタイミングで折りたたんだ状態での手に持ったサイズ感が昔持ったことある気がする……ということになり、記憶をたどったところ2013年に発売された、Xperia Z Ultraとサイズ感が同じだ…ということに気付きました。

f:id:tmyt:20201019050433p:plain

Surface Duoのほうが少し幅広。縦は短い。数値で比較するとこう。

機種 サイズ
Surface Duo 145.2mm (H) x 93.3mm (W) x 9.9mm (T)
Xperia Z Ultra 179mm (H) × 92mm (W) x 6.5mm (T)

おんなじやんけ…案外サイズ感って覚えてるもんなんやな…と思った瞬間でした。Xperia Z Ultraの後継機が長年発売されないことに悲しんでいたところでのこれは個人的にうれしいポイントでした。

重さ

データ上は250gって書いてました。それがいいかどうかはさておき。

見開き状態で片手で持ってると微妙に重いかもしれない?いやそうでもないかも?そもそも昨今の情勢で電車に乗らなくなってしまったのであまり立って使うこともなく…… ただ、閉じた状態で片手で持っているとちょっと重いかな。という気持ちになります。たぶん気持ちの問題です。キー入力するときは両手で持つのであまり気になりません。

そんなぐらいの重さ感。

画面

スペックシートにはAMOLEDと書いてます。ちなみにLGのパネルだそうです。Kernelソース*2にそう書いてました。たぶんあってると思います。 まぁまぁ高いだけあって左右の色味もわりとちゃんと調整されているような雰囲気。あまり詳しいことはわかりません。

片面だと3:4、両面だと3:2ということになっているので35mm版の写真がぴったりやんけ!!壁紙設定したろ!!って設定したら微妙に合わないんです。 なぜかというと、片面だと1800x1350、両面だと2700x1800というサイズの画面ということになってるので、両面だと3:2ということになってます。だいたいどこのメディアとかもそう書いてます。スペックにもそう書いてるのであってます。

ただこれは、正確ではなく内部的にはヒンジ部分を非表示の84px幅の画面として扱ってます。いわゆる縦長のノッチです。なので、壁紙に必要なサイズは 2784x1800 です。これは3.09:2になるので微妙に3:2より横長なんですよね。豆知識です。

電子書籍

もっともおすすめの使い方は電子書籍リーダーです。コミックを読むために存在していると思っています。SurfaceブランドにはSurface Bookという製品がありますが、Surface DuoのほうがさらにBookだな思いました*3

f:id:tmyt:20201019063210p:plain

試したアプリが偏っていますが結果を書き残しておきます。リクエストあったら何かの方法で伝えてください。

  • Kindle: 見開きで読めるすばらしい。ただし文字の本はヒンジで文字が隠れるのでダメ。
  • サイコミ: 見開きにならない。2画面にするとデバイスとしては横向きになってしまう。
  • ジャンププラス: 表紙とかの片面ページが中央揃えになってヒンジと被る。見開きOK。

そのほか

  • カメラはとりあえず写ります。最近の複数レンズ構成の高級スマートフォンと比べると大してきれいではないと思います。結局iPhoneがカメラとしては優秀だと思います。たぶん。
  • 背面に移るときのダブルタップはわりと時々失敗します。2回目やるとだいたい成功するのでそんなに気にしてません。
  • 折りたたんで片側モードの時にスクショを撮影するとなにもない反対側までを含めた大きい画像が保存されます。ちょっとおもしろい。微妙に不便なのでアプリ作りました f:id:tmyt:20201019052441p:plain
  • 空きディスプレイ(ホーム画面が表示されている状態を空いていると定義する)は自動で積極的に利用される。
    • 新しいタスク*4を起動すると空きディスプレイは積極的に埋められます。
  • プリインストールのMicrosoft Launcher以外の利用は考えない方がよさそう
    • Surface Duoの内部APIまでしっかり組み込まれているのがこれしかない
  • プリインストールのMicrosoft SwiftKey keybaord以外の利用は考えない方がよさそう
    • Launcherにおなじ。Gboardとかはキーボードを使ってない側のアクティビティもキーボードが開いているみたいなサイズになるので怪しい。
  • 見開き状態で懐中電灯を誤ってONにしてしまうと、強力な目つぶしを受けてしまうので十分注意すること。
  • バッテリーはけっこうもちます*5
  • 当初Facebook Messengerの挙動があやしかったのは10月のアップデートで修正されました。
  • いちおう3年はアップデートの面倒を見てくれるそうです。

あと気づいたら書き足します。

おしまい

18万といわれるといやーさすがにたけーわ…となるのはわかります。正直僕も高いと思います。さすがにありえんと思います。ただ、買ってよかったか。というと、これは買ってよかったなぁ。という電話になりました。

*1:ちなみに日本円で約18万円だそうです。恐ろしい…

*2:厳密にはGPLで公開されているKernelコードに含まれているdevice tree

*3:ちなみに表示されているのは。ふらいんぐうぃっち(1)です。 https://www.amazon.co.jp/dp/B00HUIL6M6/

*4:Intent.FLAG_NEW_TASK

*5:使用頻度にもよるけど1.5日ぐらい持つかもしれない