2016/04/25

Google Developers Summit Tokyo 2016

Android 2016 April 25th

Overview of Android Beta Program

鈴木拓生 @taquo

Nの勉強会をなぜ今するのか?
3月にPreviewをリリースして, Q3にFinalリリースの予定である.
Developerからのフィードバックを欲しい. その目的のためにも今回Summitの機会を用意しました.

Preview3…
初期段階のテストや開発用の環境を提供.
既存アプリの互換性をこのタイミングで確認してGoogleにフィードバックして欲しい.
(これはOS機能として提供して欲しい etc.)
正式版までに対応判断する.

Android Studio 2.0

江川崇 @t_egg

複数のAndroid Studioバージョンの共存

新しいバージョンのAndroidStudioを導入するのが怖いなら,
Macなら*.appファイルの名前を変える(Android Studio Canary.appなど)が有効.

ツールのバージョン追従の考え方

全部隊一斉投入は難しい. dev, canaryを並行して触れておくのが良い.
ツールのVersionを先にあげて, targetSdkVersionは後からゆっくりあげても大丈夫.
gradleは2.4以上(できれば2.8), pluginは2.0系に,
compileSdkVersion, buildToolsVersionは23系(support lib.)に.

Android SDK Install directory

複数のプロジェクト間で共有しても大きな問題はない.
ただし, 実験用のバージョンにひきづられる場合があるので注意.
例えば, N PreviewをインストールしたSDKを共有していると,
プロジェクトを新規作成した場合, レイアウトエディタでRendering Problemsが発生する.
これはレイアウトエディタのPlatform VersionがNになっている.
23に戻せばちゃんと動くので, 細かなテクニックが必要になるところもある.

Instant Run

コードの変更を即座にapk install, 確認できるようになりました(Android Studio2.0以降).
コードの変更から反映確認までは2~3秒ほどにまで縮まりました.

Android Studio 2.1に関すること

Java8の機能のランタイムサポート. lambdaはtoolchainが下位互換をサポート(JDK8必須)

Jack & Jill

Androidの新しいtoolchain. jackはコンパイラ, jillはリンカに相当.
従来は.classを作成していたがJackはこの工程がない(.jackファイルが作成される)
AndroidNはJackでコンパイルされている.
Jackはまだまだ不具合を抱えている. Instant Run絡みや既存ツール互換性など.
http://b.android.comの”Android Studio bug”や”Jack bug report”を選択してフィードバックを頂きたい.
バグか新機能リクエストか迷ったらAndroid Studio bugに起票して,
Android Studio担当に見てもらうことをお勧めする.

DEXに関する処理の改善による高速化.

dexInProcess. 複数, 別々のVMプロセスでDEX buildされていたのを1つのプロセスで
行うようになりました. Android Gradle 2.0からはデフォルトTrue.
依存ライブラリが多くなるとビルドが遅くなっていたのを上記で解消. 約倍速になります.
これに伴いメモリ不足時の対策が変わります.

dexOptions {
javaMaxHeapSize “2g”
}
↓↓↓
gradle.propertiesに “org.gradle.jvmargs=-Xmx4096m”

シュリンク機能

不要なメソッドを削除したい場合. ProGuardはフルDEX化が必要でビルド時間が非常に長くなる.
これを回避するためにシュリンク機能だけ版を設けました(minifyEnable).
これはデバッグモード向けに用意された機能なので, リリース版ではProGuard使いましょう.

ADB depoy

23.1から2sから0.4sに改善.

接続中デバイスに特化したパッケージの生成

AAPTでインストール先のdensityだけを含んだapkを転送する.
将来はcpuアーキテクチャーなどもサポート範囲に含める.

Instant Run

接続デバイスへのapk実行を2回目以降に高速化する.
Instant Runの状態は下記(API Lv.15以上. Cold swapは21以上).

  • hot swap (method change)
  • warm swap (activity re-launch. but process lived)
  • cold swap (method add, field add, signature change)
  • new build/deploy (re-install)

Instant Runはまだ問題が多い…
multiDexEnabled trueかつminSdkVersion20の場合, パフォーマンスが落ちる.
DEXに含まれるメソッド数が増える(仕組み上やむなし).
Jackと共存ができない etc.

Instant Runの中身を知りたい人は下記スライドが参考になります.
Instant Runを実現する仕組み by Atsushi Eno at DroidoKaigi 2016

Emulator

Emulator version 2.0から高速になっています. 実機よりも早い.
従来の機能はそのままに, ウィンドウの拡大縮小やapkをD&Dでインストールなど.
新EmulatorはまだBetaです.

その他

GPU Profiler. 各フレームのデバッグが容易に.
IntelliJ. ver.15がベースになっています.
App Indexing支援機能が追加.

参考情報:

  • What’s New in Android Studio 2.0
  • Android Dev Summit 2015(What’s New in Android Studio)

Android N What’s New + Support Library update

荒木佑一

AndroidN. Preview4まではAPIが変わる可能性があります.
Preview4からAPI Lv.24が出て, 過去の端末にインストールして試せるアプリが作れるようになる予定.

Multi-window.

テレビはpicture in picture modeに対応.
ほとんどのphone/tabletでは2分割形式(split-screen).
OEMの設定によっては自由形式(free form)を選択できるようになる.

画面のリサイズにどう対応するか?
これまで通り. swdpで対応. ライフサイクルも変更なし.
画面サイズ変更時はconfigurationChangeで吸収.
今回, 非活性化状態が顕著になったが, 今までは透明アクティビティが前面に来た場合にはありえた.
UI更新の停止はonPauseではなくonStopですること.
動画アプリなど, 非アクティブ状態でも見たいアプリがある場合はonStopで更新を停止するなど配慮が必要.

TargetSdkVersionがN以上であればMulti-windowサポート済みとして扱われる.
(resizeableActivityがデフォルトtrueなど)
inPictureInPictureはMulti-Windowの一部なので, isMultiWindowModeは必ずtrueである.
split-mode/free formはユーザ操作でのみ可能. アプリからは制御できない.

通知

直接返信はwearの機能をphoneに持ってきたもの.
新規追加されたremote input historyを使えば過去の入力をサジェストして入力支援できる.

Bundle Styleは新規追加. 既存のinbox styleやbig text styleなどを置き換えるものではなく共存するものである.

Java8

build.gradleでjackOptions { enabled true }として使う.
jackを使わないとJava8は使えない.

Lambdaは後方互換あり. ただ, lambdaは内部クラスをnewするコードを生成/展開する.
つまり, ListViewなどのUI周りでlambda使うとnewが頻繁に走る.
lambdaを使うときはnewしていることを忘れないようにしなければならない.

Quick Setting

クイック設定にタイルを追加, 削除できる.
see Tile, TileService.

Scoped Directory

SDカードにアクセスする際に何の情報にアクセスするのかわかりづらかった.
これをユーザにわかるように改善しました.

Doze

ポケットの中に入れて移動中など, 端末がstableでない状態でもdozeに入ります.
ただしnetworkアクセス制限だけ. つまりDozeは2段階になりました.

Project Svelte

メモリ512MB端末でも動くように. 日本の潤沢なデバイスは世界標準ではない.
Connectivity_Action, New_Picture, New_VideoはBroadcastIntentから廃止.
Connectivity_Actionは動的BroadcastReceiverであればまだ受信できる.
Connectivity changeの度に多くのアプリを起動していてはメモリが足らなくなり, 消費電力が上がってしまう.

ScreenZoom

最大でもsw320dp (Nexus4相当). これが保証されていれば問題ないはず.

Android NDK / Game / Vulkan Updates

松田白郎

ゲーム, NDK

N Developer Preview

ゲームに役立つ機能としてはVulkan, OpenGL ES3.2対応.
ES3.2 = ES3.2+android extension packとほぼ同じ.

Security

/system/lib 配下の未公開ライブラリの参照禁止.
libpng, libcryptoなどはNG.
NDKで公開されているものはwhite list化されているのでアクセスできる.

vulkan

動作にはデバイスにvalkan driverが入っていることが必要.
Nexus Player, Nexus9でもHW的にvalkanが使える.

NDK

正式Ver r11c. Clangがデフォルトコンパイラに.
frameworkもClangでコンパイル, gccはdeprecated.
r11cからSDK Managerからダウンロードされるようになります.
NDKの開発は全てAOSP上で行われるようになりました.
NDKのバグ報告はgithub.com/android-ndk/ndkで受付.

r12 BetaでVulkanに対応. vulkan.h / Vulkan.so追加.
Vulkanサポートツール

  • glslc
  • libShaderc
  • Validation layer

各ベンダーからDLできるがNDKにも同じものをforkしている.
正式版ではいものはgithubからDLする. github.com/android-ndk

Google Play, 開発ツール

Gamer ID.
Google Play GamesがGoogle+がなくても使えるように.
Gamer IDの新設. 1度でも認証すれば他のアプリも承認なしで使えるように.
オプトアプト形式.

Video record API
プレイ動画をストリームできるapi. 実況機能も追加予定.

Cardboard SDK.
VRゲーム対応の3DオーディオAPI.
HRTF処理.
モノラル音源 etc…

Android Studio
- LLDBを使った安定デバッグ.
- adb 高速化
- GradleでのC++コンパイル.
- GPUデバッガ(OpenGLのみ対応, Valkunもゆくゆくは対応したい)

Vulkan
次世代高速汎用描画API: Vulkan
CPUのオーバーヘッドを小さくする.
ドライバの仕事を減らしてアプリ側で頑張る.

Vulkan対応の機種を考えると, Open GLとの両対応が必要.
vulkanを使いたい場合はダイナミックロード推奨(vulkan_wrapper.h/cpp)

テクスチャーフォーマット.
Vulkan標準は未定義, androidではvulkan support = OpenGL3.1/AEP = ASTC support.
ということでASTCがほぼほぼ使えるはず.

Vulkan sample.
googlesamples/vulkan-basic-sample

おまけ

FPL Fun propulsion labs. ニアンテックラボと同じような位置づけでインディゲーム
を開発しているチーム. 開発したゲームはパイヌーン, ズーシーなど.

Android N Q&A Session

松田, 荒木, 鈴木

Q. androidでswiftってどうなの?
A. まずないと思う. コアメンバはJavaラブなので.

Q. Kotlinは?
A. いいとは思うけど, 基本Javaだと思う.

Q. Volleyどうなるの?org.apache.http.legacy使わないとなんだけど…
A. 最近メンテされてないし, 今後どうなるかはわからない.

Q. Jack & Jill使う理由は? java toolchainが使えなくなって欠点あるけど
A. aptの件などは内部でも認識していて取り組む試みは見える.
ビルド時間短縮化は大きな課題として認識しており, Jackのビルド時間短縮は大きい.

Q. Bottom naviでたけど, 画面下naviを推奨するの?
A. ユーザやDeveloperについて良いならそう変える.
bottom naviはtabの置き換えではなくnavigation drawerのactionを配置すること.

Q. multi windowのユースケースは?
A. ゲームしながら攻略サイト見るとか

Q. suport lib. 23.3.0 で何が追加されたのか?
A. bug fixがメイン.

Q. Android Playground欲しい
A. 意見くれれば

Q. Bazel採用されるの?
A. AOSPウォッチ.

Q. NはNori?
A. わからない

Q. Streamがバックポートされる予定はあるか
A. おそらくない

Q. Bottom NaviはDesign support lib.に入るか?
A. 現状作ってないが, リクエストが多ければ

Q. InboxのようなFAB+MenuなものがSupport Libに入るか?
A. 入れようとしたが一度諦めた. ニーズがあれば再開.

Q. Jack&Jillになったらoracle sdkいらない?
A. ASなど欲しいと思う

Q. org.apache.http.legacyはいつまでサポートされる?
A. わからない

Q. multi dexは4.0以降だけど4.0未満は切り捨て?
A. GBのことも忘れないで

Q. support lib.から削除されることは今後もあるのか
A. ない

Q. DataSaverはデフォルトon? White listに追加するapiはある?
A. offです. wlに追加するapiはない.

Q. emulator controlをコードから変更できる?
A. CIサーバ側でavd作成が必要かと. test codeからavdを変更する仕組みはない.

Q. CardBoardSDKのVulkan対応は?
A. あると思う.

Q. emulator 実機どっちのテストが推奨?
A. gameは実機一択.

Q. aapt offに出来るか? ScreenZoom変えてもdrawableの選択がおかしい
A. わからない. drawableの件はバグと思われる.

Q. 下位バージョンのサポート終了アナウンスの予定は?
A. support lib.はもしかしたら今年中に動きがあるかも

Q. build.gradle DSLリファレンスある?
A. ない

以上.

2016/04/16

Android: ScreenZoomを試す際の注意点

Screen Zoom

Android N Developer Previewで搭載されたユーザ補助機能Screen Zoom.
低視力者はこの機能を使うことで表示を拡大した状態で使うことができます.
(あるいは表示を縮小して情報量を増やすことも可能です)

このScreenZoom機能はDensityDPIを変更することで表示の拡大・縮小を実現しています.
DensityDPI値を大きくしても画面の物理サイズ(px)は変わりませんので結果的に拡大表示されているように見せることができる仕組みです.
デフォルトがxxhdpiなNexus5Xも, ScreenZoomの設定でxhdpi, xxxhdpiに変更できます.
開発者はAndroidN以降で端末のDensityDPIが変更される可能性を考慮する必要があります.

drawable-xxx

ScreenZoomでDensityが変わりますので, drawable-xhdpi, drawable-xxhdpiなど設定によって適切なdpi設定修飾子のリソースが選択されるようになります.
ただ, 動作確認でハマったポイントがありました.

AndroidStudio2.1で動作確認したところ, たとえ各DPI毎のdrawableリソースを持っていたとしても, ScreenZoomの設定を変えてもそれらが適切に反映されませんでした.

例): ScreenZoom値を変えても参照されるdwarableリソースが変わらない…

ドロイド君アイコンに格納したDPIの値を記載しています. 上記はdrawalbe-xxhdpiに格納された画像が表示されている状態です.

原因はAndroidStudioがインストール先のデバイスを決定してから作成するapkにありました.
実際に作成されているapkを確認すると, インストール対象デバイスのデフォルトDensityDPI以外のリソースを削除している様子でした.
動作確認をするためには./gradlew :app:assembleDebugで全DensityDPI向けのdrawableを含めたapkを作成し, インストールする必要がありました.

例): ScreenZoom値を変えると参照されるdwarableリソースが変わる

以上です.

2016/04/07

Android: 現在時刻を固定するテストとTestRule

Fixed current time.

時間に依存したAPIの振る舞いをテストする場合, 現在時刻を固定すればテストをRepeatableに保てます.
現在時刻を固定する次の2通りの方法を実装しました.

  1. java.timeを使った方法(Java8以降)
  2. java.utilを使った方法(Java7以前)

テストの際に現在時刻を固定化する下準備として, 現在時刻を返すAPIをラップしたメソッドを用意します.

public static long now() {
    return <現在時刻を返すAPI>
}

テストの際には固定時刻を返すように振る舞いを変更してやれば, このAPIに依存しているモジュールからするとあたかも現在時刻が固定化されているように見えます.

目的達成のためには, now()メソッドが常にダミーのepoch timeを返すように振る舞いを差し替える仕組みを用意する必要があります.
今回はJava7以前で使えるアプローチと, Java8以降で使えるアプローチを実装しました.

Java8

Java8からはjava.timeパッケージが追加され, 日付関係のユーティリティが強化されました(JSR-310).
現在時刻のepoch timeを取得するためにSystem.currentTimeMillis()を使用する代わりにclock.millis()が使えます.

  • Clockクラスを使用します.

Clockが指す時刻はClock.fixedClock.offsetを使って自由に変更できます.

現在時刻を取得するAPIにClockを使うことで, 現在時刻を固定化することも可能です.

下記はClockを使った現在時刻のepoch timeを返すメソッドと, それを固定化するメソッドです.

// 現在時刻のepoch timeを返す
public static long now() {
    return clock.millis();
}

// 現在時刻を固定する
@VisibleForTesting
protected static void fixedCurrentTime(@NonNull Clock clock) {
    clock = clock;
}

// 現在時刻の固定を解除する
@VisibleForTesting
protected static void tickCurrentTime() {
    clock = Clock.systemUTC();
}

固定したい日時を設定したClockfixedCurrentTime()に渡せば, now()が返す値が固定されます.
固定化を解除したい場合はtickCurrentTimeを呼びます.

Java7

ClockはJava8で導入されたjava.timeパッケージが提供するAPIです.
そのため, Java7以前の環境では別の方法をとるか, JSR-310のバックポートライブラリを使う必要があります.

バックポートライブラリには下記が使えます.

今回はこれらを使用せず別の方法をとりました.
Java7以前でもライブラリの追加無しでとれる方法です.

まず, Clockに代わる現在時刻のepoch timeを返すインタフェースNowProviderを用意します.
現在時刻を返すにはSystem.currentTimeMillis()を呼び出します.

interface NowProvider {
    long now();
}

private static NowProvider systemCurrentTimeProvider = System::currentTimeMillis;

// nowで返すepoch timeを決定するプロバイダ
private static NowProvider nowProvider = systemCurrentTimeProvider;

// 現在時刻のepoch timeを返す
public static long now() {
    return nowProvider.now();
}

次に現在時刻を返すNowProviderを差し替える仕組みを用意します.

// 現在時刻を固定する
@VisibleForTesting
protected static void fixedCurrentTime(NowProvider provider) {
    nowProvider = provider;
}

// 現在時刻の固定を解除する
@VisibleForTesting
protected static void tickCurrentTime() {
    nowProvider = systemCurrentTimeProvider;
}

固定したい日時を設定したNowProviderfixedCurrentTime()に渡せば, now()が返す値が固定されます.
固定化を解除したい場合はtickCurrentTimeを呼びます.

TestRule

現在時刻を固定するには固定と固定解除のメソッドを対で呼び出す必要があります.
固定解除のコードが実行されないと他のテストケースに意図しない影響を及ぼします.

テストケースごとにtry-finallyで時刻固定-解除のロジックを書くのも骨が折れます.
そこでJUnitTest Ruleを使って簡便化します.

// Java8 or after
public class Jsr310TimeTest {

    @Rule
    public Jsr310TimeRule jsr310TimeRule = new Jsr310TimeRule();

    @Test
    @Now("2000-01-01T00:00:00Z")
    public void テスト() throws Exception {
        assertThat(Jsr310Time.now()).isEqualTo(
                Jsr310Time.parseIso8601Z("2000-01-01T00:00:00Z"));
    }
}

// Java7 or before
public class LegacyTimeTest {

    @Rule
    public LegacyTimeRule legacyTimeRule = new LegacyTimeRule();

    @Test
    @Now("2000-01-01T00:00:00Z")
    public void テスト() throws Exception {
        assertThat(LegacyTime.now()).isEqualTo(
                LegacyTime.parseIso8601Z("2000-01-01T00:00:00Z"));
    }
}

Jsr310TimeRule/LegacyTimeRuleはテストメソッドがNowでアノテートされているとテスト開始時に現在時刻を固定し, テスト終了時に解除します.
@Nowを宣言するだけで現在時刻が固定化されて便利です.

蛇足

テストクラスに含まれる全てのテストで現在時刻を固定したいのであれば, NowアノテーションでElementType.Typeをサポートし, テストランナーを@ClassRuleで宣言すれば実現できます.
ただ, テストケースで現在時刻が固定されていることに気付き辛くなるため実装しませんでした.