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

What's New in Android - I/O Extended Yangon 2018

What's New in Android - I/O Extended Yangon 2018

Talk from I/O Extended Yangon 2018.

Aung Kyaw Paing

July 08, 2018
Tweet

More Decks by Aung Kyaw Paing

Other Decks in Technology

Transcript

  1. What’s new in Android?
    Photo Ⓒ Rami Al-zayat

    View Slide

  2. What’s new in Android P?
    Photo Ⓒ Lauren Robert

    View Slide

  3. Notch Support
    Photo Ⓒ Google

    View Slide

  4. Notch Support
    - DisplayCount class
    - getDisplayCutout() method
    - New window attribute, layoutInDisplayCutoutMode
    - LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
    - LAYOUT_IN_DISPLAY_CUTOUT_SHORT EDGES
    - LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

    View Slide

  5. LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
    - The notch has to be contained in System Bar
    - If not, the window won’t overlap it

    View Slide

  6. LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
    - Can extends into notch
    - Developer has to handle drawing

    View Slide

  7. LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
    - Will never overlaps

    View Slide

  8. Notch Support
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    val windowAttributes = window.attributes
    windowAttributes.layoutInDisplayCutoutMode =
    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
    }

    View Slide

  9. Notification
    - Person API
    - Can now display Image
    - Reply drafts
    - Group conversations support
    - Semantic Action (Reply, Mark as
    read, thumbs up… etc.)
    - Smart Reply
    Photo Ⓒ Google

    View Slide

  10. Notification
    // create new Person
    val sender = Person()
    .setName(name)
    .setUri(uri)
    .setIcon(null)
    .build()
    // create image message
    val message = Message("Picture", time, sender)
    .setData("image/";, imageUri)
    val style = Notification.MessagingStyle(getUser())
    .addMessage("Check this out!", 0, sender)
    .addMessage(message)

    View Slide

  11. Notification Channel
    - Can block entire “groups” of channel
    - Can check if blocked via isBlocked
    - New policies

    View Slide

  12. TextView
    Photo Ⓒ Best practices for text on Android ( Google IO / 18 )

    View Slide

  13. Photo Ⓒ Best practices for text on Android ( Google IO / 18 )

    View Slide

  14. PreComputed Text
    // UI thread
    val params: PrecomputedText.Params = textView.getTextMetricsParams()
    val ref = WeakReference(textView)
    executor.execute {
    // background thread
    val text = PrecomputedText.create("Hello", params)
    val textView = ref.get()
    textView?.post {
    // UI thread
    val textViewRef = ref.get()
    textViewRef?.text = text
    }
    }

    View Slide

  15. Magnifier

    View Slide

  16. Magnifier
    fun onTouchEvent(event: MotionEvent): Boolean {
    when (event.actionMasked) {
    MotionEvent.ACTION_DOWN ->
    magnifier.show(event.x, event.y)
    MotionEvent.ACTION_MOVE ->
    magnifier.show(event.x, event.y)
    MotionEvent.ACTION_UP ->
    magnifier.dismiss()
    }
    }

    View Slide

  17. Smart Linkify

    View Slide

  18. Smart Linkify
    // UI thread
    val text: Spannable = ...
    val request = TextLinks.Request.Builder(text)
    val ref = WeakReference(textView)
    executor.execute {
    // background thread
    TextClassifier.generateLinks(request).apply(text)
    val textView = ref.get()
    textView?.post {
    // UI thread
    val textViewRef = ref.get()
    textViewRef?.text = text
    }
    }

    View Slide

  19. Fingerprint Auth

    View Slide

  20. And….
    - Indoor positioning
    - Multi-camera support
    - ImageDecoder
    - AnimatedImageDrawable
    - Client side encryptions for backups
    - New accessibility features
    - Autofill improvements
    - And Many more!

    View Slide

  21. What’s new in Android Support Library?
    Photo Ⓒ Leo Fosdal

    View Slide

  22. Major Refactor
    android.support.v4.*
    android.support.v7.*
    android.support.v9.*
    android.support.v14.*

    View Slide

  23. Major Refactor
    android.support.*
    androidx.*

    View Slide

  24. Major Refactor
    Available in Android Studio Canary Channel

    View Slide

  25. Major Refactor
    https://developer.android.com/topic/libraries/support-library/refactor

    View Slide

  26. Android KTX
    https://github.com/android/android-ktx

    View Slide

  27. Android KTX
    sharedPreferences.edit {
    putBoolean("key", value)
    putLong("key2", value2)
    }
    val args = bundleOf {
    "key" to 1,
    "key2" to true
    }

    View Slide

  28. Android JetPack
    https://developer.android.com/jetpack/

    View Slide

  29. Slices
    - UI templates with interactive contents
    - Used in Google Search, Google Assistant

    View Slide

  30. Slices
    fun createSliceWithGridRow(sliceUri: Uri): Slice {
    // Create the parent builder.
    return list(context, sliceUri, ListBuilder.INFINITY) {
    header {
    setTitle("Famous restaurants")
    setPrimaryAction(SliceAction(pendingIntent, icon, "Famous restaurants"))
    }
    gridRow {
    cell {
    addImage(image1, LARGE_IMAGE)
    addTitleText("Top Restaurant")
    addText("0.3 mil")
    setContentIntent(intent1)
    }
    cell {
    addImage(image2, LARGE_IMAGE)
    addTitleText("Fast and Casual")
    addText("0.5 mil")
    setContentIntent(intent2)
    }
    }
    }
    }

    View Slide

  31. Actions
    - Can recommend actions to users
    - Increases discoverability

    View Slide

  32. RecyclerView ListAdapter
    - Uses DiffUtils
    - Automatic Animation

    View Slide

  33. class MovieRecyclerViewAdapter :
    ListAdapter() {
    }
    RecyclerView ListAdapter

    View Slide

  34. RecyclerView ListAdapter
    companion object {
    private val MOVIE_DIFF_CALLBACK = object : DiffUtil.ItemCallback() {
    override fun areItemsTheSame(item1: Movie, item2: Movie): Boolean {
    return item1.id == item2.id
    }
    override fun areContentsTheSame(item1: Movie, item2: Movie): Boolean {
    return item1 == item2
    }
    }
    }

    View Slide

  35. class MovieRecyclerViewAdapter :
    ListAdapter(MOVIE_DIFF_CALLBACK) {
    companion object {
    private val MOVIE_DIFF_CALLBACK = object : DiffUtil.ItemCallback() {
    override fun areItemsTheSame(item1: Movie, item2: Movie): Boolean {
    return item1.id == item2.id
    }
    override fun areContentsTheSame(item1: Movie, item2: Movie): Boolean {
    return item1 == item2
    }
    }
    }
    }
    RecyclerView ListAdapter

    View Slide

  36. movieListLiveData.observe(this, Observer {itemList ->
    movieRecyclerViewAdapter.submitList(itemList)
    })
    RecyclerView ListAdapter

    View Slide

  37. RecyclerView Selection
    - Allow select/deselect multiple items in list
    SelectionTracker tracker = new SelectionTracker.Builder<>(
    "my-selection-id",
    recyclerView,
    new StableIdKeyProvider(recyclerView),
    new MyDetailsLookup(recyclerView),
    StorageStrategy.createLongStorage())
    .build();

    View Slide

  38. Material Components
    https://material.io/

    View Slide

  39. BottomAppBar

    View Slide

  40. BottomAppBar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    android:id="@+id/bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    app:navigationIcon="@drawable/ic_menu_24"/>
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_anchor="@id/bar"/>

    View Slide

  41. MaterialButton

    View Slide

  42. MaterialButton
    android:id="@+id/material_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/button_label_enabled"/>

    View Slide

  43. MaterialCardView

    View Slide

  44. MaterialCardView
    style="@style/Widget.MaterialComponents.CardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="@dimen/mtrl_card_spacing"
    android:layout_marginTop="@dimen/mtrl_card_spacing"
    android:layout_marginRight="@dimen/mtrl_card_spacing"
    android:minHeight="200dp">


    View Slide

  45. Chips

    View Slide

  46. Chips
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:chipText="@string/hello_world"/>
    style="@style/Widget.MaterialComponents.Chip.Entry"
    style="@style/Widget.MaterialComponents.Chip.Filter"
    style="@style/Widget.MaterialComponents.Chip.Choice"

    View Slide

  47. Chips
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    View Slide

  48. Android Arch Components
    - Paging Library
    - WorkManager
    - Navigation

    View Slide

  49. - Use for enqueuing background works
    - JobScheduler for API 23+
    - Firebase JobDispatcher (or) custom AlarmManager + Broadcast
    Receiver for backport
    WorkManager

    View Slide

  50. val workManager = WorkManager.getInstance()
    val workRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java).build()
    workManager.enqueue(workRequest)
    WorkManager

    View Slide

  51. val workManager = WorkManager.getInstance()
    val workConstraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.METERED)
    .setRequiresCharging(true)
    .setRequiresStorageNotLow(false)
    .build()
    val workRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java)
    .setConstraints(workConstraints)
    .build()
    workManager.enqueue(workRequest)
    WorkManager

    View Slide

  52. val workManager = WorkManager.getInstance()
    val workRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java).build()
    workManager.enqueue(workRequest)
    WorkManager

    View Slide

  53. val workManager = WorkManager.getInstance()
    val workRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java).build()
    workManager.enqueue(workRequest)
    val workStatusLiveData = workManager.getStatusById(workRequest.id)
    workStatusLiveData.observe(this, Observer { workStatus ->
    when (workStatus?.state) {
    State.ENQUEUED -> TODO()
    State.RUNNING -> TODO()
    State.SUCCEEDED -> TODO()
    State.FAILED -> TODO()
    State.BLOCKED -> TODO()
    State.CANCELLED -> TODO()
    }
    })
    WorkManager

    View Slide

  54. val workManager = WorkManager.getInstance()
    val workRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java).build()
    workManager.enqueue(workRequest)
    workManager.cancelWorkById(workRequest.id)
    WorkManager

    View Slide

  55. WorkManager
    val workManager = WorkManager.getInstance()
    val request1 = OneTimeWorkRequest.Builder(FooWorker::class.java).build()
    val request2 = OneTimeWorkRequest.Builder(BarWorker::class.java).build()
    val request3 = OneTimeWorkRequest.Builder(BazWorker::class.java).build()
    workManager.beginWith(request1, request2).then(request3).enqueue()

    View Slide

  56. Navigation Arch Component
    - Single Activity, Multiple Fragment
    - Uses “Stack”, last-in first out structure
    - Deep Link has same stack

    View Slide

  57. Navigation Arch Component

    View Slide

  58. Navigation Arch Component

    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination=“@id/blankFragment">
    android:id="@+id/blankFragment"
    android:name="com.example.cashdog.cashdog.BlankFragment"
    android:label="fragment_blank"
    tools:layout="@layout/fragment_blank" />
    android:id="@+id/blankFragment2"
    android:name="com.example.cashdog.cashdog.BlankFragment2"
    android:label="Blank2"
    tools:layout="@layout/fragment_blank_fragment2" />

    View Slide

  59. Navigation Arch Component

    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination=“@id/blankFragment">
    android:id="@+id/blankFragment"
    android:name="com.example.cashdog.cashdog.BlankFragment"
    android:label="fragment_blank"
    tools:layout="@layout/fragment_blank" >
    android:id="@+id/action_blankFragment_to_blankFragment2"
    app:destination="@id/blankFragment2" />

    android:id="@+id/blankFragment2"
    android:name="com.example.cashdog.cashdog.BlankFragment2"
    android:label="fragment_blank_fragment2"
    tools:layout="@layout/fragment_blank_fragment2" />

    View Slide

  60. Navigation Arch Component
    ?xml version="1.0" encoding="utf-8"?>
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/my_nav_host_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:navGraph="@navigation/nav_graph"
    app:defaultNavHost="true"
    />

    View Slide

  61. Navigation Arch Component
    override fun onSupportNavigateUp()
    = findNavController(R.id.nav_host_fragment).navigateUp()

    View Slide

  62. Navigation Arch Component
    button.setOnClickListener(
    Navigation.createNavigateOnClickListener(R.id.next_fragment, null)
    )

    View Slide

  63. android:label="@string/details"
    android:name="com.example.android.myapp.DetailsFragment" />
    Navigation Arch Component -
    NavigationView(Drawer)

    View Slide

  64. android:label="@string/details"
    android:name="com.example.android.myapp.DetailsFragment" />
    android:id="@id/details_page_fragment"
    android:icon="@drawable/ic_details"
    android:title="@string/details" />
    Navigation Arch Component -
    NavigationView(Drawer)

    View Slide

  65. android:label="@string/details"
    android:name="com.example.android.myapp.DetailsFragment" />
    android:id="@id/details_page_fragment"
    android:icon="@drawable/ic_details"
    android:title="@string/details" />
    val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
    val navigationView = findViewById(R.id.nav_view)
    navigationView.setupWithNavController(navController)
    Navigation Arch Component -
    NavigationView(Drawer)

    View Slide

  66. Navigation Arch Component - Arguments
    android:id="@+id/confirmationFragment"
    android:name="com.example.cashdog.cashdog.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">

    View Slide

  67. Navigation Arch Component - Arguments
    android:id="@+id/confirmationFragment"
    android:name="com.example.cashdog.cashdog.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">

    var bundle = bundleOf("amount" to amount)
    view.findNavController().navigate(R.id.confirmationAction, bundle)

    View Slide

  68. Navigation Arch Component - Arguments
    android:id="@+id/confirmationFragment"
    android:name="com.example.cashdog.cashdog.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">

    var bundle = bundleOf("amount" to amount)
    view.findNavController().navigate(R.id.confirmationAction, bundle)
    val tv = view.findViewById(R.id.textViewAmount)
    tv.text = arguments.getString("amount")

    View Slide

  69. Navigation Arch Component - Safe Args
    apply plugin: 'com.android.application'
    apply plugin: 'androidx.navigation.safeargs'
    android {
    //...
    }

    View Slide

  70. Navigation Arch Component - Safe Args
    android:id="@+id/confirmationFragment"
    android:name="com.example.buybuddy.buybuddy.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">


    View Slide

  71. Navigation Arch Component - Safe Args
    android:id="@+id/specifyAmountFragment"
    android:name="com.example.buybuddy.buybuddy.SpecifyAmountFragment"
    android:label="fragment_specify_amount"
    tools:layout="@layout/fragment_blank" >
    android:id="@+id/action_specify_to_confirm"
    app:destination="@id/confirmationFragment" />

    android:id="@+id/confirmationFragment"
    android:name="com.example.buybuddy.buybuddy.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">
    >

    View Slide

  72. Navigation Arch Component - Safe Args
    override fun onClick(v: View?) {
    val amount = 100
    val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
    v.findNavController().navigate(action)
    }

    View Slide

  73. Navigation Arch Component - Safe Args
    override fun onClick(v: View?) {
    val amount = 100
    val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
    v.findNavController().navigate(action)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val tv: TextView = view.findViewById(R.id.textViewAmount)
    val amount = ConfirmationFragmentArgs.fromBundle(arguments).amount
    tv.text = amount.toString()
    }

    View Slide

  74. https://github.com/googlesamples/android-sunflower

    View Slide

  75. ConstraintLayout 1.1
    - Barrier
    - Group
    - Circular constraints
    - Chains
    - Constraint set

    View Slide

  76. ConstraintLayout 2.0
    - ConstraintProperties
    - MotionLayout
    - Better Optimizers

    View Slide

  77. - Kotlin Support
    - New APIs
    Testing

    View Slide

  78. - Kotlin Support
    - New APIs
    assertEquals(view.visibility, View.VISIBLE)
    Testing

    View Slide

  79. - Kotlin Support
    - New APIs
    assertEquals(view.visibility, View.VISIBLE)
    “Failed Expected 0 but was 16”
    Testing

    View Slide

  80. - Kotlin Support
    - New APIs
    assertEquals(view.visibility, View.VISIBLE)
    Testing

    View Slide

  81. - Kotlin Support
    - New APIs
    assertThat(view).isVisible()
    Testing

    View Slide

  82. - Kotlin Support
    - New APIs
    assertThat(view).isVisible()
    “Failed, view was not visible”
    Testing

    View Slide

  83. Testing
    - Roboelectric to be packaged inside androidx.test
    - Roboelectric semantics will be same as Espresso
    http://robolectric.org/blog/2018/05/09/robolectric-4-0-alpha/

    View Slide

  84. Testing
    - Roboelectric to be packaged inside androidx.test
    - Roboelectric semantics will be same as Espresso
    - Will be able to run UI test in local JVM
    http://robolectric.org/blog/2018/05/09/robolectric-4-0-alpha/

    View Slide

  85. Project Nitrogen

    View Slide

  86. What’s new in Android Development Tools?
    Photo Ⓒ Fleur Treurniet

    View Slide

  87. App Bundle
    - A new publishing format, instead of APK
    - Minimized APK depends on user’s device
    - Deliver downloadable “dynamic feature”

    View Slide

  88. D8
    - New dex-ing tool
    - Default already on Android Studio 3.1
    - Manually turn on by adding android.enableD8=true in
    gradle.properties

    View Slide

  89. R8
    - Better Proguard
    - Can include proguard rules in java library module by placing
    inside “META-INF/proguard”

    View Slide

  90. Emulator
    - Saving states (Cold boot / Hot boot)
    - AMD CPU support
    - Notch emulation
    - Sceneform emulation

    View Slide

  91. Android Studio Canary
    - Navigation Arch Component Support
    - MotionLayout Support
    - Better Profiler
    - WebP support

    View Slide

  92. Android Studio on ChromeOS

    View Slide

  93. Play Store
    - Digital Rights Management(DRM) metadata
    - App now have to be complaint with GDPR
    - Algorithm changes
    - Must have minimum API level 26 by end of August 2018

    View Slide

  94. Q & A

    View Slide