Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Your app name

Your app name

DroidKaigi 2017

Avatar for Masaki Ogata

Masaki Ogata

March 09, 2017
Tweet

More Decks by Masaki Ogata

Other Decks in Programming

Transcript

  1. Android TVͱ͸ Google͕ࣾఏڙ͢ΔTV޲͚ϓϥοτϑΥʔϜ • Android 5.0 (Lollipop) ʙ 7.1.1 (Nougat)

    • Google Play StoreʹTV޲͚ΞϓϦΛެ։Մೳ
 (ॳճͷΈ৹ࠪ͋Γ) • ੡଄ϝʔΧʔଟ਺
  2. Android TV - ओͳ౥ࡌσόΠε Nexus Player ʢGoogleʗASUSʣ BRAVIA ʢSONYʣ AQOUS

    ίίϩϏδϣϯ ʢSHARPઐ༻ʣ Life Stick ʢϨΦύϨεઐ༻ʣ Air Stick ʢCCCʣ 2015೥2݄ 2015೥10݄ʙ 2016೥6݄ 2016೥7݄ 2016೥12݄ OS: 7.1.1 Quad-core 1GB RAM 8GB Storage OS: 5.1.1 Dual-core *1
 1.5GB RAM *1
 8GB Storage *1 OS: 5.1 Dual-core *1 2.5GB RAM 16GB Storage - OS: 6.0
 Quad-core 1GB RAM 8GB Storage 13,824ԁ 100,000ԁ ʙ 13,380ԁ - 9,800ԁ *1: ະެදͷͨΊਪଌ
  3. Fire TVͱ͸ Amazon͕ࣾఏڙ͢ΔTV޲͚ϓϥοτϑΥʔϜ • Fire OS 5 (Based on Android

    5.1 - API 22) • Amazon App StoreʹTV޲͚ΞϓϦΛެ։Մೳ
 (Appleࣾͱಉ͘͡ϦϦʔε͝ͱʹ৹ࠪ͋Γ) • ࣗࣾσόΠεͷΈ
  4. Fire TV - ओͳ౥ࡌσόΠε Fire TV Stick - Gen. 1

    ʢAMAZONʣ Fire TV - Gen. 2 ʢAMAZONʣ Fire TV Stick - Gen. 2 ʢAMAZONʣ 2014೥11݄ 2015೥12݄ 2017೥4݄ Fire OS 5 Dual-core 1GB RAM *1 8GB Storage Fire OS 5 Quad-core 2GB RAM 8GB Storage Fire OS 5
 Quad-core 1GB RAM 8GB Storage 4,980ԁʗ6,480ԁ 11,980ԁ 4,980ԁ *1: 512MB system, 512MB video New
  5. σβΠϯͱUXΨΠυϥΠϯ • Designing for Android TV
 https://goo.gl/VWrKs7 • Android TV

    Design Guidelines
 https://goo.gl/Z7tSTj • Design and User Experience Guidelines
 for Fire TV
 https://goo.gl/ZYgf7D
  6. جຊ - ։ൃπʔϧͱSDK Android Studio + Android Emulator • SDK

    tools: 24.0.0 or higher • Minimum SDK: API 21 (Lollipop) or higher
  7. جຊ - ։ൃπʔϧͱSDK ADB over Wi-Fi <—> TVσόΠεʢ࣮ػʣ adb connect

    <Android TV device IP address>:5555 • Using Android Debug Bridge for Android TV
 https://goo.gl/BpSmm0 • Connecting to Fire TV Through ADB
 https://goo.gl/tEsypE
  8. جຊ - ϓϩδΣΫτઃఆ • 320 x 180 px (xhdpi) •

    ΞϓϦ໊Λόφʔը૾಺ʹؚΊΔඞཁ͕͋Δ TVΞϓϦ༻ͷόφʔը૾
  9. جຊ - ϓϩδΣΫτઃఆ <uses-feature> <manifest> <uses-feature android:name="android.software.leanback" android:required="false" /><!-- or

    true (TV devices only) --> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> ... </manifest> • Handle Unsupported Hardware Features
 https://goo.gl/u1UU4D
  10. جຊ - ϓϩδΣΫτઃఆ ͕ɺɺFire TV͸Mobileͱಉ͡ɻ… <activity android:name="com.example.amazon.TvActivity" ...> <intent-filter> <action

    android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
  11. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Mobile

    TV app Google Play Store Amazon App Store app app
  12. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Bad

    :( • ͭͶʹશϓϥοτϑΥʔϜ͕ߋ৽ର৅ͱͳΔ • Manifest΍Ϧιʔεͷ؅ཧ͕ΧΦε • APKαΠζ͸΍΂ʙ੎͍Ͱ͛͢ʔ૿͑Δ⾭
  13. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Mobile

    TV app Google Play Store Amazon App Store app app app
  14. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Good

    :) • σόΠε͝ͱʹΞϓϦΛߋ৽Ͱ͖Δ • Manifest΍Ϧιʔεͷ؅ཧ͸ָνϯ • APKαΠζ͸σόΠε͝ͱʹ࠷దԽ
  15. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Bad

    :( • APKΞοϓϩʔυ࣌ʹΦϖϛεͷةݥ͋Γ • ར༻Ͱ͖Δόʔδϣϯίʔυͷܻ͕ݮΔ
  16. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK •

    Multiple APK Support
 https://goo.gl/WuXcvN Mobile: v1.0.0(1) -> v1.0.1(2) -> v1.1.0(3) -> …
 TV : v1.0.0(1000001) -> v1.0.1(1000002) -> … όʔδϣϯίʔυͷྫʣ
  17. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Mobile

    TV app Google Play Store Amazon App Store app2 app app2 app2
  18. جຊ - ϓϩδΣΫτઃఆ Single APK Multiple APK Other APK Bad

    :( • ϨϏϡʔ΍μ΢ϯϩʔυ਺ͳͲ͕ڞ༗͞Εͳ͍ • ύοέʔδΛ෼͚ͨ͜ͱʹΑΔ৭ʑͳฐ֐
 ʢΞϓϦ಺՝ۚͳͲʣ
  19. جຊ - Focusͷ੍ޚ ॳճදࣔͷFocusҐஔʹ͸requestFocusΛઃఆ <LinearLayout ...> <Button ... android:focusable="true"/> <Button

    ... android:focusable="true"> <requestFocus/> </Button> <Button ... android:focusable="true"/> </LinearLayout>
  20. جຊ - Focusͷ੍ޚ (RecyclerViewͷ৔߹) public View focusSearch(View focused, int direction)

    { View result = mLayout.onInterceptFocusSearch(...); if (result != null) { return result; } final FocusFinder ff = FocusFinder.getInstance(); result = ff.findNextFocus(this, focused, direction); if (...) { eatRequestLayout(); result = mLayout.onFocusSearchFailed(...); resumeRequestLayout(false); } return result != null ? result : super.focusSearch(...); }
  21. جຊ - Focusͷ੍ޚ (RecyclerView + CustomLayoutManagerͷ৔߹) public View focusSearch(View focused,

    int direction) { View result = mLayout.onInterceptFocusSearch(...); if (result != null) { return result; } final FocusFinder ff = FocusFinder.getInstance(); result = ff.findNextFocus(this, focused, direction); if (...) { eatRequestLayout(); result = mLayout.onFocusSearchFailed(...); resumeRequestLayout(false); } return result != null ? result : super.focusSearch(...); }
  22. جຊ - Input Eventͷ੍ޚ onTouchEventͱಉ͘͡ɺbool஋Λฦ͢ @Override public boolean onKeyDown(int keyCode,

    KeyEvent event) { boolean handled = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_UP: ... handled = true; break; default: // no-op } return handled || super.onKeyDown(keyCode, event); }
  23. جຊ - Input Eventͷ੍ޚ Button KeyEvent Voice Search - Select

    KEYCODE_DPAD_CENTER Left KEYCODE_DPAD_LEFT Up KEYCODE_DPAD_UP Right KEYCODE_DPAD_RIGHT Down KEYCODE_DPAD_DOWN Back KEYCODE_BACK Menu KEYCODE_MENU Home - Play/Pause KEYCODE_MEDIA_PLAY_PAUSE Rewind KEYCODE_MEDIA_REWIND Fast Forward KEYCODE_MEDIA_FAST_FORWARD
  24. Leanback Support Libraryͱ͸ Google͕ࣾެࣜʹఏڙ͢ΔϥΠϒϥϦͷ̍ͭͰɺ TVΞϓϦ޲͚ʹ࠷దͳUI΢ΟδΣοτͳͲΛఏڙ dependencies { ... compile "com.android.support:leanback-v17:25.2.0"

    } <style name="AppTheme" parent="@style/Theme.Leanback"> <item name="android:colorPrimary">...</item> <item name="android:colorPrimaryDark">...</item> <item name="android:colorAccent">...</item> </style>
  25. Leanback Support Libraryͷֶͼํ • googlesamples/leanback-showcase
 https://goo.gl/99nI2m • googlesamples/androidtv-Leanback
 https://goo.gl/3foS5q •

    android/platform_frameworks_support
 https://goo.gl/K90lXi GitHub্ͷެࣜαϯϓϧΞϓϦΛίϯύΠϧ͠ ͯಈ͔ͯ͠ΈΔͷ͕Ұ൪ͷۙಓ
  26. VerticalGridView / HorizontalGridView
 ͱRecyclerView͸Կ͕ҧ͏ͷʁ VerticalGridView gv = ...; gv.setNumColumns(1); gv.addItemDecoration(new

    ItemDecoration()); gv.setAdapter(new Adapter()); RecyclerView rv = ...; rv.setLayoutManager(new GridLayoutManager(this, 1)); rv.addItemDecoration(new ItemDecoration()); rv.setAdapter(new Adapter()); Leanback Support Library - Tips
  27. Leanback Support Library - Tips PresenterʁͳʹͦΕʁඒຯ͍͠ͷʁ A Presenter is used

    to generate Views and bind Objects to them on demand. It is closely related to the concept of an RecyclerView.Adapter, but is not position-based. (from API Reference) View Presenter Object
 (Model)
  28. Leanback Support Library - Tips PresenterʁͳʹͦΕʁඒຯ͍͠ͷʁ A Presenter is used

    to generate Views and bind Objects to them on demand. It is closely related to the concept of an RecyclerView.Adapter, but is not position-based. (from API Reference) View Presenter Object
 (Model) Model-View-Presenter (MVP)
  29. Leanback Support Library - Tips PresenterʁͳʹͦΕʁඒຯ͍͠ͷʁ A Presenter is used

    to generate Views and bind Objects to them on demand. It is closely related to the concept of an RecyclerView.Adapter, but is not position-based. (from API Reference) View Presenter Object
 (Model) Model-View-Presenter (MVP)
 RecyclerView with multiple view types
 ΛAdapter͔Β෼཭࣮ͯ͠ݱ͢Δ࢓૊Έ
  30. e.g. RecyclerView with multiple view types { "ranking_items":[ { "rank":1,

    "title":"foo", "image":"http://..." }, { "rank":2, "title":"bar", "image":"http://..." }, ... ] } Rank1 XXXXXXXXXXXXX XXXXXXXXXXX… XXXXXXX… Rank2
  31. public class RankingListAdapter extends RecyclerView.Adapter<ViewHolder> { @Override public int getItemViewType(int

    position) { RankingItem item = ...; return (item.rank == 1) ? LARGE : NORMAL; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return (viewType == LARGE) ? LargeViewHolder.create(parent) : NormalViewHolder.create(parent); } ... e.g. RecyclerView with multiple view types
  32. Presenter LargeRankingItemPresenter NormalRankingItemPresenter public class NormalRankingItemPresenter extends Presenter { @Override

    public ViewHolder onCreateViewHolder(ViewGroup parent) { return NormalViewHolder.create(parent); } @Override public void onBindViewHolder(ViewHolder vh, Object item) { RankingItem rankingItem = (RankingItem) item; NormalViewHolder viewHolder = NormalViewHolder.of(vh); ... } @Override public void onUnbindViewHolder(ViewHolder vh) {} static class NormalViewHolder extends Presenter.ViewHolder
  33. PresenterSelector public class RankingPresenterSelector extends PresenterSelector { final LargeRankingItemPresenter largePresenter

    = ...; final NormalRankingItemPresenter normalPresenter = ...; final Presenter[] presenters = ...; @Override public Presenter getPresenter(Object item) { RankingItem rankingItem = (RankingItem) item; return (rankingItem.rank == 1) ? largeRankingItemPresenter : normalRankingItemPresenter; } @Override public Presenter[] getPresenters() { return presenters; } }
  34. ObjectAdapter (ArrayObjectAdapter) public class RankingFragment extends VerticalGridFragment { // Setup

    VerticalGridPresenter (Column: 1) private ArrayObjectAdapter adapter; @Override protected onViewCreated(...) { ... PresenterSelector ps = new RankingPresenterSelector(); adapter = new ArrayObjectAdapter(ps); setAdapter(adapter); // Load data. } private onLoaded(List<RankingItem> rankingItems) { adapter.addAll(0, rankingItems); } ...
  35. ObjectAdapter (ArrayObjectAdapter) public class RankingFragment extends VerticalGridFragment { // Setup

    VerticalGridPresenter (Column: 1) private ArrayObjectAdapter adapter; @Override protected onViewCreated(...) { ... PresenterSelector ps = new RankingPresenterSelector(); adapter = new ArrayObjectAdapter(ps); setAdapter(adapter); // Load data. } private onLoaded(List<RankingItem> rankingItems) { adapter.addAll(0, rankingItems); } ... RecyclerView with multiple view types
 ΛAdapter͔Β෼཭࣮ͯ͠ݱ͢Δ࢓૊Έ
  36. Leanback Support Library - Pros & Cons • ϝσΟΞ࠶ੜίϯτϩʔϧը໘ͳͲࣗલͰ࡞ Δඞཁ͕ͳ͍

    • FocusͷϑΟʔυόοΫʢεέʔϦϯά΍ίϯ τϥετͳͲʣ͕UI΢ΟδΣοτʹ૊Έࠐ· Ε͍ͯΔͷͰɺྑ͠ͳʹ΍ͬͯ͘ΕΔ Good :)
  37. Leanback Support Library - Pros & Cons Bad :( •

    େ఍ͷσβΠφʔ͞Μ͸LeanbackͷUIͦͷ· ·ͰΑ͍ͱ͸ܾͯ͠ݴͬͯ͘Εͳ͍ • @HideɺPackage Privateɺfinalએݴ͕ඇৗʹ ଟ͘ɺΧελϚΠζͷ೉қ౓ߴΊ
  38. Leanback Support Library - Pros & Cons Bad :( •

    େ఍ͷσβΠφʔ͞Μ͸LeanbackͷUIͦͷ· ·ͰΑ͍ͱ͸ܾͯ͠ݴͬͯ͘Εͳ͍ • @HideɺPackage Privateɺfinalએݴ͕ඇৗʹ ଟ͘ɺΧελϚΠζͷ೉қ౓ߴΊ 㱺RowsFragmentΛϕʔε͢Δͷ͕͓͢͢Ί
  39. FireTVͰߟྀ͢Δ΂͖͜ͱ • How Fire TV Development Differs from Android TV

    Development
 https://goo.gl/kvjiaR • Can you use Firebase on Amazon Android devices?
 https://goo.gl/Y3n4Al • Identifying Amazon Fire TV Devices
 https://goo.gl/fkhp4a
  40. Fire TV޲͚ʹΞϓϦΛ഑෍ Amazon App Store΁ͷਃ੥ʹඞཁͳ΋ͷ • TV޲͚ΨΠυϥΠϯʹద߹ͨ͠ΞϓϦ(.apk) • TV༻ͷը૾Ξηοτ(for Gen.

    2) • εΫϦʔϯγϣοτʢ3ຕҎ্ʣ • όφʔը૾ʢ1280 x 720 pxʣ • όοΫάϥ΢ϯυը૾ʢ1920 x 1080 pxʣ
  41. Fire TV޲͚ʹΞϓϦΛ഑෍ Amazon App Store΁ͷਃ੥ʹඞཁͳ΋ͷ • TV޲͚ΨΠυϥΠϯʹద߹ͨ͠ΞϓϦ(.apk) • TV༻ͷը૾Ξηοτ(for Gen.

    2) • εΫϦʔϯγϣοτʢ3ຕҎ্ʣ • όφʔը૾ʢ1280 x 720 pxʣ • όοΫάϥ΢ϯυը૾ʢ1920 x 1080 pxʣ
  42. Fire TV޲͚ʹΞϓϦΛ഑෍ Amazon App Store΁ͷਃ੥ʹඞཁͳ΋ͷ • TV޲͚ΨΠυϥΠϯʹద߹ͨ͠ΞϓϦ(.apk) • TV༻ͷը૾Ξηοτ(for Gen.

    2) • εΫϦʔϯγϣοτʢ3ຕҎ্ʣ • όφʔը૾ʢ1280 x 720 pxʣ • όοΫάϥ΢ϯυը૾ʢ1920 x 1080 pxʣ
  43. • Distribute to Android TV
 https://goo.gl/kViUiV
 
 TV App Quality


    https://goo.gl/bGdFOi • Submitting Your Fire TV App to the Amazon Appstore
 https://goo.gl/hDuuDH
 ࢀߟϦϯΫू