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

Your app name

Your app name

DroidKaigi 2017

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
 ࢀߟϦϯΫू