連載ストックリスト:Android版「見開きPDFビューア」開発記録
この記事は、ChatGPTと壁打ちしながら、Android Studio内のGeminiの会話履歴、ChatGPTの会話履歴、Gitの変更履歴・ソースコード、保存した成果物を調べて作成しました。
Android版「見開きPDFビューア」開発記録の第7回です。10月27〜28日、Android版「見開きPDFユーティリティ」の使い方を伝えるため、Geminiに操作動画の撮影を依頼しました。ここでは、動画ができても必要な操作が映らず、撮影をやり直した経緯を振り返ります。
「見開きPDFユーティリティ」のAndroid版のクローズドテスト中にフィードバックがありました。
没太看懂怎么用,UI按钮也乱了
(日本語訳) 使い方がよく分かりませんし、UIのボタンの配置も崩れています。
ボタンの配置については、テスト開始時のビルドでボタンを3列に並べ、右寄せにしていたことが指摘につながったと考え、UIを大幅に見直しました。
もう一つ気になったのが、「使い方がよく分かりません」という指摘です。初めてアプリを開いたとき、ボタンの配置が整っていても、どこから操作を始めればよいかは分かりにくいかもしれません。
ヘルプの説明を増やす方法も、起動時にチュートリアルを表示する方法もあります。ショート動画なら、どこを押すと画面がどう変わるのかを、操作の順に見られます。
ヘルプか、ショート動画か(生成AIで作成した生徒……架空のやり取り)
そこで、実際の操作を短い動画で見せることにし、Android StudioのGeminiに撮影と編集を依頼しました。
本稿では、撮影結果を見ながら重ねた指示と、最後まで残った問題を整理します。
当時は(他の作業もしながら)GeminiとWorkモードを行き来していたため、使っている生成AIの名前を取り違えたりしていました。ここでは、チャットとファイルで確認できた経緯に沿って書きます。Workモードの実行担当は、Gemini側の会話ではCodexと呼ばれています。
まずGeminiに依頼し、撮影を試した
10月27日、撮影を自動化する前に、Android StudioのGeminiに動画の制作方法を相談しました。
筆者のプロンプト(全文)
表示するショート動画の制作方法を計画してください。
Geminiは5シーンの制作計画を作り、続く「進めてください。」への回答では英語の字幕・ナレーション原稿も提示しました。
その後、エミュレータでの自動収録を依頼しました。既存の撮影スクリプトを読み、実際のComposeコードからUI要素を特定するよう求めた箇所が、次の抜粋です。
筆者のプロンプト(抜粋)
現在のプロジェクト(
~/src/MihirakiPDFUtility_Android/)のレイアウト・Composeコードを参照し、各シーンで操作するボタンやビューの実際のID、testTag、またはContentDescriptionを特定してください。
ここからは、Geminiでの指示と結果を六つの論点に分けて振り返ります。試行の途中では、同じ問題への対応を行き来しています。引用は当時の入力と回答に基づき、全文・抜粋を明記しています。コードの説明は、Geminiでの試行を最後に保存したコミットcf4dd55を中心に確認しました。すべての回答時点のコードが個別に残っているわけではないため、当時の指摘と、最後まで残った実装上の問題は区別します。
図1〜3・図5〜7は、当時の指摘と最後に残ったコードをもとに、各段階の問題を示した模式図です。図4には保存動画から抜き出した実画面を使い、図7では依頼した方式と保存コードの構成を比較します。
1.実アプリに合わせる指示と、撮影開始前の準備
Geminiから撮影結果が返ってきたので動画を確認すると、1本目は起動後のライセンス表示で止まっていました。
筆者のプロンプト(全文)
動画の内容は失敗しています。アプリの起動後に、CC BY 4.0表示ダイアログが表示されて、必要な操作がブロックされています。対策を考えてください。
ライセンス表示への対策後に撮り直すと、今度はチュートリアル画面で止まりました。Geminiはライセンスを確認し、チュートリアルを閉じる処理を追加したと回答しました。最後に保存されたテストコード(cf4dd55)にも、vm.confirmCcByDialog() と vm.dismissTutorial() が残っています。目的の操作に入るには、撮影前にこうした画面を閉じ、開始状態を整える必要がありました。
初期の撮影依頼には、言語設定や見開きプレビューでのページ送りなど、ビューア向けの操作も混ざっていました。そこで、今回撮るのはPDF編集ツールであり、PDFを開くとサムネイル一覧が出ることを伝え、実在するUIだけを使うよう依頼し直しました。見開き表示への切替ができなかったときは、操作経路も具体的に伝えました。
筆者のプロンプト(抜粋)
画面右上の3点リーダをタップしてからメニューをスクロールして、表示切替をタップする必要があります。
Geminiはこの経路を実装したと回答しました。ただし、最後のScene 1のテストには、メニュー操作で例外が出た場合にvm.toggleMihirakiView()を直接呼ぶ分岐がありました。内部の表示モードが変われば後続のassertTrueは通りますが、利用者が行うメニュー操作が映ったかまでは確認できません。図1では、撮影前の準備と実アプリに合わせた操作の問題・対策を並べ、最後のテストに残った課題を下段に示します。
図1:撮影前の準備と、実アプリに合わせた操作の問題・対策
2.操作の間隔とタップ表示を指示しても、見せ方は保証されなかった
一部の操作は進みましたが、操作が連続しているのでわかりにくいと感じました。そこで、私は操作を見分けられるように指示しました。
筆者のプロンプト(抜粋)
Scene 3の撮影結果ですが、操作は正しいようですが、回転と白紙挿入がほぼ同時に操作されているため、区別がつきません。次の操作まで2秒以上あけてください。
Geminiは操作間の待機時間を増やしました。最後のコードには回転後のThread.sleep(5000)があり、10月28日14時06分のログにも回転から白紙挿入まで約5秒の間隔が記録されています。「待ち時間を追加しなかった」とは説明できません。
一方、確認しているのは内部の回転値やページ数が中心でした。回転結果だけが描画されたフレームを確保し、その後に白紙追加へ進んだかを検査する条件はありません。内部処理の時刻、描画された時刻、完成動画の時刻を結び付けなければ、待機を増やしても映像上の区切りは確認できませんでした。
どこを押したか分からない問題には、Androidのタップ表示を求め、後には編集で波紋を付けるよう依頼しました。しかし、内部メソッドの呼び出しは利用者のタップそのものではありません。add_tap_effects.pyの波紋も、実測した操作ログではなく、固定の時刻と座標の一覧で描かれていました。波紋が見えることを、そこで実際にタップした証拠にはできません(図2)。
図2:待機時間や波紋を追加しても、映像上の操作を証明できなかった
3.「確認ボタンまで押して」と頼んでも、削除のUIが完了していなかった
動画を確認すると、削除の操作が確認ダイアログで止まっていました。そこで、私は次のように指示しています。
筆者のプロンプト(全文)
実際の編集操作で表示されるダイアログは、表示した上でOKなどをタップして進めてください。
Geminiは、確認ボタンをタップしてダイアログを閉じるよう修正したと回答しました。ところが、その後も私は「削除ダイアログが最後まで残っています」と指摘しています。最後のShortsRecordingTest.ktに残っていた処理は、要点を抜き出すと次の構造でした。
clickAction(R.string.action_delete)
// ダイアログの存在は確認する
main { vm.deleteSelected() }
waitForReady()
assertEquals(8, vm.uiState.value.pages.size)
これは構造を示す抜粋で、コメントは説明のために加えています。確認ボタンのタップを省き、内部の削除処理だけを呼んでいます。アプリ本来のMainScreen.ktでは、確認ボタンが次の両方を実行します。
viewModel.deleteSelected()
showDeleteConfirmation = false
削除ダイアログの表示状態は画面側が持っていました。テストが内部処理だけを呼べば、ページ数は減っても、その画面側の変数は閉じる状態になりません。ページ数が8に戻るという検査と、ダイアログを閉じて結果を見せるという成功条件が食い違っていたのです。削除処理とダイアログを閉じる処理の違いを図3に示します。ダイアログが残った動画は図4です。
図3:内部データの削除と、確認ダイアログを閉じるUI操作の違い
図4:Gemini版の動画終盤にも削除確認が残っていた
図4は、後の試行で保存されたGemini版Scene 3の12.0秒と19.7秒です。この節の指摘直後の動画とは特定できませんが、保存動画でも同じ問題が残っていた例として示します。右側では「Final Result」という字幕が表示されていますが、削除確認が開いたままです。少なくともこの動画では、確認を終えて削除結果を見せるところまで収まっていません。
保存にも同じ注意点がありました。保存ボタンを押して保存先画面を開く経路がある一方、テストにはその後の保存先操作がありません。waitForReady()は読み込み中でなくページが存在することなどを見る処理で、出力PDFが保存されたという確認ではありませんでした。
4.先頭のカットと固定字幕では、撮影のずれを直せなかった
録画した後の編集もGeminiに任せたいので、一括処理にするよう依頼しました。しかし完成版にはホーム画面、ファイル選択、起動途中の画面が入り、操作と説明が合いません。私が動画の先頭約7秒の不要な画面を指摘すると、Geminiは次のように回答しました。
Geminiの回答(抜粋)
画面録画開始時のエミュレータ起動画面、ホーム画面、ファイル選択やダイアログ表示にかかっていた先頭約 6.5 秒間を FFmpeg(
-ss 6.5)で完全にカットしました。
しかし、次の試行でもScene 2の開始画面やメニュー操作、Scene 3の回転・白紙追加・削除の時刻が合いませんでした。最後のbuild_shorts_videos.pyも、操作結果の時刻から区間を決めるのではなく、先頭を6.5秒カットし、Scene 3の字幕を0〜5秒、5〜11秒、11〜25秒へ固定する構成です。起動や描画にかかった時間の違いを、この方法だけでは吸収できません。
末尾にはFFmpegの-shortestもあり、必要な操作結果まで残すことを編集条件にしていませんでした。ただし、映像の食い違いをすべてこのオプションだけのせいにはできません。先に述べたUI操作の未完了と、編集時刻の不一致を別々に直す必要がありました。
途中には、QuickTime Playerで音声が聞こえないというやり取りもあります。その後、私が「完成版動画出力先 が変わっていたことに気がつきませんでした。」と伝えており、確認対象のファイルも混乱していました。したがって、この指摘をすべて音声コーデックの不具合だったとは扱いません。どの実行の、どの出力を見ているかも揃える必要がありました。固定の編集時刻と実際の操作時刻のずれは図5に示します。
図5:固定カット・固定字幕と、実際の操作時刻が対応しない問題
5.動画から上流へ調べたが、静止画の内容を合否判定していなかった
更新日時だけが変わり、内容は同じに見えたので、生素材の確認、ログの追加、別の再生ソフト、別名のファイル、完成動画からの静止画、編集前の生録画からの静止画へと、確認対象を上流へ広げました。私は最後にはRunning Devicesを開き、エミュレータの動きも見ています。
筆者のプロンプト(全文)
エミュレータ上の操作が途中で失敗しているのに合わせるように、静止画を確認するとエミュレータ上の操作が失敗するまでは新しい画像が反映し、それ以降は古い映像のままになっていました。
この指摘に対し、Geminiは「厳密なフレーム検証スクリプト」を追加したと回答しました。しかしverify_scene_frames.pyが確認していたのは、主に画像を読み込めるか、極端に暗くないかです。暗い画像や存在しないフォルダは警告だけで通過する分岐もあり、最後には「Frame verification passed」と表示します。
回転と白紙追加が独立して見えるか、削除確認が閉じたか、今回撮った内容かを判定する処理ではありませんでした。最後の実行ログにもこの成功文が残っていますが、要求した映像の正しさを確認したという意味にはなりません。
古いフレームの残留については、最後に抽出先のJPGを削除してから生成する処理が追加されています。この改善は確認できますが、それだけで実操作の失敗は直りません。プレーヤーのキャッシュ、古い画像の残留、録画中の操作失敗は、それぞれ切り分けて考える必要がありました。図6では、私が確認したことと、Geminiの検証で判定できなかったことを並べています。
図6:筆者が確認した操作と、Geminiのフレーム検証で見落としたこと
6.直接ADB方式への全面変更を頼んだが、保存コードはテスト方式のままだった
最後は、操作が反映されない原因を調べ、別の操作方法を求めました。Geminiが直接ADB制御方式を提案したため、私はその方法への切替を依頼しています。
筆者のプロンプト(全文)
直接ADB制御方式へスクリプトを全面的に書き換えて、Scene 3の撮影・ビルドを再実行してください。
この全面変更の依頼の後にも、Geminiは次の正常通過報告を返しました。
Geminiの回答(抜粋):
すべてのUI状態アサーション(ページ選択、回転、白紙追加、削除ダイアログ表示、削除実行)およびフレーム検証スクリプトがエラーなく正常に通過しました。
筆者のプロンプト(全文)
エミュレータで確認したところ、チュートリアル画面から進まないまま終了したように見えました。スクリプトがアプリの最新仕様に対応しているか、確認してください。
ところが、最後に保存されたrecord_shorts_scenes.shは、依然としてam instrumentでShortsRecordingTestを実行する構造です。通常の録画制御などにADBは使っていますが、主要操作をadb shell input tapなどで行う方式への全面変更は確認できません。図7に、依頼した操作方式と、保存コードに残っていた録画・操作の経路を示します。
図7:依頼した直接ADB方式と、保存コードに残ったテスト方式
Geminiは、テスト側と前面画面の状態の違いを原因に挙げましたが、保存コードとログからは根本原因を特定できませんでした。
最終的には、Geminiで撮影する方法をあきらめました。そこで、次のように依頼しています。
筆者のプロンプト(全文)
コミットしてください。動画撮影はまだ成功していません。
この段階の変更は、10月28日14時08分のコミットcf4dd55に残っています。
待機時間の調整やフレーム検証などの改善はありましたが、テストの通過だけでは、必要な操作や結果が動画に映ったことを確認できませんでした。10月28日14時36分頃、撮影をWorkモードに引き継ぎました。第8回では、動画5本を完成・公開し、その実装を次の撮影に使う教材にまとめるまでを紹介します。
図版の出典と引用の扱い
図4は、Gemini版Scene 3の保存動画から実フレームを抽出し、フレームの縦横比を保ったまま、周囲の余白を詰めて並べたものです。
図1〜3・図5〜7は、当時の指摘と保存コードcf4dd55をもとに、指示・残った処理・不足していた確認を整理した模式図です。実画面や各試行の動画を再現した図ではありません。図5の時間軸も実測値の再現ではなく、固定編集と操作時刻の関係を示しています。
画面内の作品はThe Try-It Club / Episode 1、作者はKomairo Hiyoriです。©2026 Komairo Hiyori。CC BY 4.0に基づき表示し、図ではフレーム抽出・縮小・比較配置を行いました。
引用は、当時のユーザー入力と表示された回答に基づきます。
関連する記事
関連:第5回補足「スクリーンショットを撮って、ストアに届けるまで」