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. 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
  2. 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 }
  3. 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
  4. 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)
  5. Notification Channel - Can block entire “groups” of channel -

    Can check if blocked via isBlocked - New policies
  6. 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 } }
  7. 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() } }
  8. 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 } }
  9. And…. - Indoor positioning - Multi-camera support - ImageDecoder -

    AnimatedImageDrawable - Client side encryptions for backups - New accessibility features - Autofill improvements - And Many more!
  10. 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) } } } }
  11. RecyclerView ListAdapter companion object { private val MOVIE_DIFF_CALLBACK = object

    : DiffUtil.ItemCallback<Movie>() { override fun areItemsTheSame(item1: Movie, item2: Movie): Boolean { return item1.id == item2.id } override fun areContentsTheSame(item1: Movie, item2: Movie): Boolean { return item1 == item2 } } }
  12. class MovieRecyclerViewAdapter : ListAdapter<Movie, MovieViewHolder>(MOVIE_DIFF_CALLBACK) { companion object { private

    val MOVIE_DIFF_CALLBACK = object : DiffUtil.ItemCallback<Movie>() { 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
  13. 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();
  14. BottomAppBar <android.support.design.widget.CoordinatorLayout 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"> <!-- Other components and

    views --> <com.google.android.material.bottomappbar.BottomAppBar android:id="@+id/bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:navigationIcon="@drawable/ic_menu_24"/> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_anchor="@id/bar"/> </android.support.design.widget.CoordinatorLayout>
  15. - Use for enqueuing background works - JobScheduler for API

    23+ - Firebase JobDispatcher (or) custom AlarmManager + Broadcast Receiver for backport WorkManager
  16. 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
  17. 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
  18. 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()
  19. Navigation Arch Component - Single Activity, Multiple Fragment - Uses

    “Stack”, last-in first out structure - Deep Link has same stack
  20. Navigation Arch Component <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"

    app:startDestination=“@id/blankFragment"> <fragment android:id="@+id/blankFragment" android:name="com.example.cashdog.cashdog.BlankFragment" android:label="fragment_blank" tools:layout="@layout/fragment_blank" /> <fragment android:id="@+id/blankFragment2" android:name="com.example.cashdog.cashdog.BlankFragment2" android:label="Blank2" tools:layout="@layout/fragment_blank_fragment2" /> </navigation>
  21. Navigation Arch Component <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"

    app:startDestination=“@id/blankFragment"> <fragment android:id="@+id/blankFragment" android:name="com.example.cashdog.cashdog.BlankFragment" android:label="fragment_blank" tools:layout="@layout/fragment_blank" > <action android:id="@+id/action_blankFragment_to_blankFragment2" app:destination="@id/blankFragment2" /> </fragment> <fragment android:id="@+id/blankFragment2" android:name="com.example.cashdog.cashdog.BlankFragment2" android:label="fragment_blank_fragment2" tools:layout="@layout/fragment_blank_fragment2" /> </navigation>
  22. Navigation Arch Component ?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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"> <fragment 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" /> </android.support.constraint.ConstraintLayout>
  23. <fragment android:id="@+id/details_page_fragment" android:label="@string/details" android:name="com.example.android.myapp.DetailsFragment" /> <item 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<NavigationView>(R.id.nav_view) navigationView.setupWithNavController(navController) Navigation Arch Component - NavigationView(Drawer)
  24. Navigation Arch Component - Arguments <fragment android:id="@+id/confirmationFragment" android:name="com.example.cashdog.cashdog.ConfirmationFragment" android:label="fragment_confirmation" tools:layout="@layout/fragment_confirmation">

    <argument android:name="amount" android:defaultValue=”0” /> var bundle = bundleOf("amount" to amount) view.findNavController().navigate(R.id.confirmationAction, bundle)
  25. Navigation Arch Component - Arguments <fragment android:id="@+id/confirmationFragment" android:name="com.example.cashdog.cashdog.ConfirmationFragment" android:label="fragment_confirmation" tools:layout="@layout/fragment_confirmation">

    <argument android:name="amount" android:defaultValue=”0” /> 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")
  26. Navigation Arch Component - Safe Args apply plugin: 'com.android.application' apply

    plugin: 'androidx.navigation.safeargs' android { //... }
  27. Navigation Arch Component - Safe Args <fragment android:id="@+id/confirmationFragment" android:name="com.example.buybuddy.buybuddy.ConfirmationFragment" android:label="fragment_confirmation"

    tools:layout="@layout/fragment_confirmation"> <argument android:name="amount" android:defaultValue="1" app:type="integer"/> </fragment>
  28. Navigation Arch Component - Safe Args <fragment android:id="@+id/specifyAmountFragment" android:name="com.example.buybuddy.buybuddy.SpecifyAmountFragment" android:label="fragment_specify_amount"

    tools:layout="@layout/fragment_blank" > <action android:id="@+id/action_specify_to_confirm" app:destination="@id/confirmationFragment" /> </fragment> <fragment android:id="@+id/confirmationFragment" android:name="com.example.buybuddy.buybuddy.ConfirmationFragment" android:label="fragment_confirmation" tools:layout="@layout/fragment_confirmation"> <argument android:name="amount" android:defaultValue="1" app:type="integer"/ > </fragment>
  29. Navigation Arch Component - Safe Args override fun onClick(v: View?)

    { val amount = 100 val action = SpecifyAmountFragmentDirections.confirmationAction(amount) v.findNavController().navigate(action) }
  30. 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() }
  31. 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/
  32. 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/
  33. App Bundle - A new publishing format, instead of APK

    - Minimized APK depends on user’s device - Deliver downloadable “dynamic feature”
  34. D8 - New dex-ing tool - Default already on Android

    Studio 3.1 - Manually turn on by adding android.enableD8=true in gradle.properties
  35. R8 - Better Proguard - Can include proguard rules in

    java library module by placing inside “META-INF/proguard”
  36. Emulator - Saving states (Cold boot / Hot boot) -

    AMD CPU support - Notch emulation - Sceneform emulation
  37. 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