# Stories by Julien Salvi on Medium

Stories by Julien Salvi on Medium

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Monitoring Android Vitals with the Play Developer Reporting API

DevFeed: [Monitoring Android Vitals with the Play Developer Reporting API](<https://devfeed.tech/articles/monitoring-android-vitals-with-the-play-developer-reporting-api-25945.md>)

Original publisher: [Read original article](<https://medium.com/google-developer-experts/monitoring-android-vitals-with-the-play-developer-reporting-api-85edabb772a9?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2026-03-19T12:41:51Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [API](<https://devfeed.tech/topics/api.md>), [Google Play](<https://devfeed.tech/topics/google-play.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [CI/CD Pipeline](<https://devfeed.tech/topics/ci-cd-pipeline.md>), [Google Cloud Platform (GCP)](<https://devfeed.tech/topics/google-cloud.md>), [Slack](<https://devfeed.tech/topics/slack.md>)

Tags: [aircall](<https://devfeed.tech/tags/aircall.md>), [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [anr](<https://devfeed.tech/tags/anr.md>), [api](<https://devfeed.tech/tags/api.md>), [ci-cd-pipeline](<https://devfeed.tech/tags/ci-cd-pipeline.md>), [crash](<https://devfeed.tech/tags/crash.md>), [google-play-developer](<https://devfeed.tech/tags/google-play-developer.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [reporting](<https://devfeed.tech/tags/reporting.md>), [slack](<https://devfeed.tech/tags/slack.md>)

### AI overview

This tutorial explains how Aircall uses the Google Play Developer Reporting API in a Gradle task to retrieve Android Vitals, including ANR and crash metrics, and deliver daily health reporting to Slack. It covers metric-set queries, timeline aggregations, service-account authentication, data modeling, and health thresholds.

### Source excerpt

At Aircall, we built an automated reporting tool that fetches our Android Vitals metrics thanks to the Play Developer Reporting API and delivers a daily health dashboard straight to Slack. All of this powered by a simple Gradle task. Discovering the API The Google Play Developer Reporting API gives programmatic access to the same quality metrics you see in the Google Play Console. It covers the core Android Vitals: ANR rate, crash rate, slow start rate, and stuck background wakelocks, the signals Google uses to determine whether your app meets the bad behavior thresholds. The API is organized around metric sets that you query with a timeline specification. Each metric set returns daily, 7-day, and 28-day user-weighted aggregates, giving you the full picture from short-term regressions to long-term trends. The key advantage over scraping the Console UI is that you can automate the entire flow and integrate it into your existing CI/CD pipeline. You will find the complete API reference in the official documentation. Build with Play VitalsSetting up the dependency We chose to implement this as a Gradle task inside our build-logic module. This keeps the reporting logic close to the project without polluting the app code. First, let's add the dependency: # libs.versions.toml googleApiReporting = "v1beta1-rev20230803-2.0.0" buildLogic-plugin-google-play-developer-reporting = { module = "com.google.apis:google-api-services-playdeveloperreporting", version.ref = "googleApiReporting" } Which can then be added to the build.gradle.kts of your build-logic module: dependencies { // API to get Google Play store vitals metrics implementation(libs.buildLogic.plugin.google.play.developer.reporting) }Authenticating with a Service Account To access the API, you need a Google Cloud Service Account with the Play Developer Reporting scope. We pass the credentials as an environment variable to keep secrets out of the repository. The Reporting client initializes the API with these credentia

## Bridging Compose and View: Seamless Interop Communication with CompositionLocal

DevFeed: [Bridging Compose and View: Seamless Interop Communication with CompositionLocal](<https://devfeed.tech/articles/bridging-compose-and-view-seamless-interop-communication-with-compositionlocal-25937.md>)

Original publisher: [Read original article](<https://juliensalvi.medium.com/bridging-compose-and-view-seamless-interop-communication-with-compositionlocal-4b0a273bf15f?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2025-03-05T13:42:13Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Compose](<https://devfeed.tech/topics/compose.md>), [interoperability](<https://devfeed.tech/topics/interoperability.md>), [Dependency injection](<https://devfeed.tech/topics/dependency-injection.md>), [ui](<https://devfeed.tech/topics/ui.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [bridge](<https://devfeed.tech/tags/bridge.md>), [compose](<https://devfeed.tech/tags/compose.md>), [dependency-injection](<https://devfeed.tech/tags/dependency-injection.md>), [interface-implementation](<https://devfeed.tech/tags/interface-implementation.md>), [interoperability](<https://devfeed.tech/tags/interoperability.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [sharedflow](<https://devfeed.tech/tags/sharedflow.md>), [stateflow](<https://devfeed.tech/tags/stateflow.md>), [ui](<https://devfeed.tech/tags/ui.md>), [viewmodel](<https://devfeed.tech/tags/viewmodel.md>)

### AI overview

This tutorial explains how to bridge Jetpack Compose and traditional Android Views using CompositionLocal. It shows how to provide a FeedbackMessageInterop implementation so composables can trigger View-based feedback, and describes the reverse direction through an interface and reactive streams such as StateFlow or SharedFlow.

### Source excerpt

Migrating to Compose exposed the team to several interoperability challenges as we integrated new Composables into our existing codebase. One key hurdle was figuring out how to trigger events from Compose and dispatch them to the main View holder, such as a Fragment or Activity. After some exploration, we found an efficient solution using CompositionLocal. Here's how we made it work! 🚀 What is a CompositionLocal? Think of CompositionLocal as a localized dependency injection system built directly into Compose's composition model. You create a CompositionLocal instance, which acts as a key for a specific type of data. Then, using the CompositionLocalProvider, you define a scope within your UI tree and associate a value with that CompositionLocal key. Any composable within that scope can then access the provided value using the CompositionLocal.current property, without needing to know where the value originated. This not only simplifies code but also makes it more maintainable and reusable. Furthermore, CompositionLocal values can be dynamic, triggering recomposition when they change, and they are thread-safe, making them a powerful tool for managing shared state within your Compose UI. Interop Communication with CompositionLocal In the following code, LocalFeedbackInterop is a staticCompositionLocalOf that will hold an implementation of the FeedbackMessageInterop interface. This interface defines the methods for showing feedback alerts, and the staticCompositionLocalOf ensures that the implementation is unlikely to change as it cannot be re-provided. This allows any composable within the scope to access the FeedbackMessageInterop implementation and trigger feedback messages without explicit dependencies. import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.staticCompositionLocalOf val LocalFeedbackInterop: ProvidableCompositionLocal<FeedbackMessageInterop?> = staticCompositionLocalOf { null } interface FeedbackMessageInterop { fu

## ML Kit Document Scanner in action

DevFeed: [ML Kit Document Scanner in action](<https://devfeed.tech/articles/ml-kit-document-scanner-in-action-25944.md>)

Original publisher: [Read original article](<https://medium.com/google-developer-experts/ml-kit-document-scanner-in-action-1c3a49ef5a33?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2024-04-15T09:53:27Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [ML Kit](<https://devfeed.tech/topics/ml-kit.md>), [Android](<https://devfeed.tech/topics/android.md>), [API](<https://devfeed.tech/topics/api.md>), [pdf](<https://devfeed.tech/topics/pdf.md>), [Google](<https://devfeed.tech/topics/google.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [api](<https://devfeed.tech/tags/api.md>), [code](<https://devfeed.tech/tags/code.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [machine-learning](<https://devfeed.tech/tags/machine-learning.md>), [ml-kit](<https://devfeed.tech/tags/ml-kit.md>), [ml-kit-android](<https://devfeed.tech/tags/ml-kit-android.md>), [pdf](<https://devfeed.tech/tags/pdf.md>), [scanner](<https://devfeed.tech/tags/scanner.md>)

### AI overview

This tutorial explores ML Kit Document Scanner for Android and demonstrates integrating it into a messaging feature. The library digitizes physical documents, supports automatic capture, detection, cropping, rotation, image editing, and optional gallery import, with the scan flow delivered through Play Services.

### Source excerpt

Recently, ML Kit released a new library to digitize physical documents directly from your Android application. ML Kit Document Scanner allows the users to easily scan documents with maximum controls and minimum code integration. During my time at Aircall, I took some time to explore and integrate the library to build an Android-exclusive feature for the messaging scope. Discovering the library ML Document Scanner is the newborn of the ML Kit family. It allows users to convert physical documents into digital formats. The library now brings this feature to any apps with many capabilities like applying filters, cleaning the image, removing shadows and many more. The entire scan flow is delivered by the Play Services so no camera permission is mandatory and the library size (~300KB download size increase) has a low impact in your app (the ML models are also managed by the Play Services). So let's dig into the what the library offers. The ML Kit Document Scanner offers key capabilities like a high-quality user interface that ensures consistency across Android applications. With automatic capture and document detection, the users can effortlessly scan documents, while accurate edge detection ensures optimal cropping results. Additionally, automatic rotation detection ensures that scanned documents are presented upright. For developers seeking customization options, the Document Scanner API offers flexibility. You can set a limit on the number of pages scanned and enable or disable the capability to import from the photo gallery. Moreover, there are 3 editing modes available: basic editing capabilities, editing with image filters or editing with ML-enabled image cleaning capabilities (erase stains, fingers...). You will find a complete overview of the library with the official documentation. ML Kit | Google for Developers Build with Document ScannerCrafting the feature It's now time to craft our new feature with ML Kit Document Scanner. Here, we want to give the ability to t

## UI tests with Jetpack Compose and Appium x UIAutomator

DevFeed: [UI tests with Jetpack Compose and Appium x UIAutomator](<https://devfeed.tech/articles/ui-tests-with-jetpack-compose-and-appium-x-uiautomator-25941.md>)

Original publisher: [Read original article](<https://juliensalvi.medium.com/ui-tests-with-jetpack-compose-and-appium-x-uiautomator-5d276fb655aa?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2022-12-05T13:01:16Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [ui-testing](<https://devfeed.tech/topics/ui-testing.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Android](<https://devfeed.tech/topics/android.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [Instrumentation](<https://devfeed.tech/topics/instrumentation.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [appium](<https://devfeed.tech/tags/appium.md>), [compose](<https://devfeed.tech/tags/compose.md>), [instrumentation](<https://devfeed.tech/tags/instrumentation.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [ui-testing](<https://devfeed.tech/tags/ui-testing.md>), [uiautomator](<https://devfeed.tech/tags/uiautomator.md>)

### AI overview

This tutorial explains how Aircall adapted Android UI automation tests when migrating from View-based components to Jetpack Compose. It describes using Compose semantics and testTag values mapped to resource IDs, then locating the resulting components with UiSelector in Appium and UIAutomator.

### Source excerpt

At Aircall we are pushing a lot around quality thanks to our great QA team. Huge efforts are put on Android developer side with the unit tests and our QA engineers tackle everything around automation & UI tests. Before integrating our brand new design system made with Compose UI in production, we wanted to be sure that the transition to Compose would be painless with our automation framework and tools: Appium and UIAutomator. This article will explain how the Android team validated the move to Compose with our automation framework. Automation tests with View components The Aircall QA team has developed lots of automation tests that cover more than 90% of the use cases in the Android app. And to do so, they rely on Appium with the UI testing framework UIAutomator which is an instrumentation-based API and works with the AndroidJUnitRunner test runner. To locate a View-based component in the application, UIAutomator provides an annotation @AndroidFindBy where you need to specify the resource id of a UI element you want to identify. @AndroidFindBy(id = "myButtonId") protected WebElement myButton; But this method does work properly with Compose UI components. Indeed, when looking for a Composable with its dedicated tag, no elements are found in the screen. Now, let's have a closer look at the changes we had to make in order to smoothly add our new Compose code in the current codebase and not breaking everything on the automation side. UI tests with Compose UI and UIAutomator To unlock the UI testing with UIAutomator and Compose, we will have to take advantage of the semantics Modifier in each Composable we want to locate with the testTag property. In order to ease the migration, we are going to keep the same component IDs we were using with our View-based elements. Modifier.semantics { testTag = "myButtonId" } And at the top level Composable, we should toggle the configuration to map testTags to the resource IDs in the semantics Modifier. This will allow the automation f

## Hands on Jetpack Compose VisualTransformation to create a phone number formatter

DevFeed: [Hands on Jetpack Compose VisualTransformation to create a phone number formatter](<https://devfeed.tech/articles/hands-on-jetpack-compose-visualtransformation-to-create-a-phone-number-formatter-25943.md>)

Original publisher: [Read original article](<https://medium.com/google-developer-experts/hands-on-jetpack-compose-visualtransformation-to-create-a-phone-number-formatter-99b0347fc4f6?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-12-21T15:05:42Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Compose](<https://devfeed.tech/topics/compose.md>), [Design system](<https://devfeed.tech/topics/design-system.md>), [ui](<https://devfeed.tech/topics/ui.md>), [Google](<https://devfeed.tech/topics/google.md>)

Tags: [aircall](<https://devfeed.tech/tags/aircall.md>), [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [component](<https://devfeed.tech/tags/component.md>), [compose](<https://devfeed.tech/tags/compose.md>), [constructor](<https://devfeed.tech/tags/constructor.md>), [design-system](<https://devfeed.tech/tags/design-system.md>), [filter](<https://devfeed.tech/tags/filter.md>), [function](<https://devfeed.tech/tags/function.md>), [google](<https://devfeed.tech/tags/google.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [mapping](<https://devfeed.tech/tags/mapping.md>), [parameter](<https://devfeed.tech/tags/parameter.md>), [transformation](<https://devfeed.tech/tags/transformation.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

This tutorial explains how to use Jetpack Compose's VisualTransformation to format phone-number input for international display. It covers the filter() function, TransformedText, and OffsetMapping for mapping positions between original and transformed text.

### Source excerpt

At Aircall, we are currently rewriting our design system with Jetpack Compose, the new UI framework made by Google. One of our UI component is a text input that formats a phone number to its international format according to its origin country. With the View UI toolkit, we can use a PhoneNumberFormattingTextWatcher, which is available since API 1, to format the input text. But no equivalent has been implemented with Jetpack Compose so far. In this article we are going to cover how we managed to create a reliable alternative for Compose with VisualTransformation. VisualTransformation explained First, let's have a look at the VisualTransformation interface to understand how it works under the hood and how you can use it to format the input text of a TextField as you wish. https://medium.com/media/bb42609ef6212c4b0f63f06f83c0534c/href In order to filter the text, you will need to implement the filter() function which takes the original text to transform as a parameter and returns a TransformedText where all the magic happens! If we take a look at the constructor it takes a text (which will be transformed) and an OffsetMapping which provides a bidirectional mapping between the original text and the new one. Which means that we'll need to implement the transformation from and to the original. Let's have a look at the password transformation that the framework provides to see the OffsetMapping in action: https://medium.com/media/5e50cd5af8fd0d3acd9300d03665735b/href Here, the implementation is pretty straightforward as we just need to transform the input text where every character will be replaced by a mask, so the text will have the same length. The transformed text will contain the mapped text and the offsetMapping will handle the transformation. Here, as we don't have any extra character to be displayed in the returned text, the two functions will return the original offset. The two transformations can become a bit more complex if we need to display additional characte

## Lifecycle-aware delayed actions in Android Views with Kotlin Coroutines

DevFeed: [Lifecycle-aware delayed actions in Android Views with Kotlin Coroutines](<https://devfeed.tech/articles/safe-delay-in-android-views-goodbye-handlers-hello-coroutines-25940.md>)

Original publisher: [Read original article](<https://juliensalvi.medium.com/safe-delay-in-android-views-goodbye-handlers-hello-coroutines-cd47f53f0fbf?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-08-08T13:22:20Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [kotlin-coroutines](<https://devfeed.tech/topics/kotlin-coroutines.md>), [Library](<https://devfeed.tech/topics/library.md>), [ui](<https://devfeed.tech/topics/ui.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [deprecated](<https://devfeed.tech/tags/deprecated.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [lifecycle](<https://devfeed.tech/tags/lifecycle.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

This tutorial explains why delayed actions posted through Android Handlers or Views can run after a view is detached or destroyed. It demonstrates replacing Handler().postDelay() with Kotlin coroutines tied to a view's lifecycle, using the lifecycle owner, a lifecycle coroutine scope, the Main Dispatcher, and delay().

### Source excerpt

Using Handlers, without providing a Looper, has been deprecated in recent versions of Android because they can lead to bugs where operations are silently lost or crashes. According to the documentation, you can use an Executor or access the Handler of a view as a replacement, but they can also crash silently as it's not bound to any lifecycle. Let's see how we can take advantage of the coroutines and lifecycle libraries to replace the Handler().postDelay() method to safely trigger an action after a specified amount of time. Handler: old fashioned way Even if the Handler() constructor is deprecated, you can access the handler of a View by calling getHandler() or you can directly call the method postDelay() on the View. That way, you won't use any deprecated method and you will be able to delay you action with a given amount of time. Let's see how it works under the hood. To push new events, you will get access to an Handler that is associated with the thread running the view. Every time a new action will be posted with postDelay(), a new Runnable will be added to the message queue (remember that the runnable will be running on the UI thread). By doing this, your delayed action may run when the view is detached or destroyed and this can lead to unexpected behaviors or crashes. Kotlin + Coroutine + Lifecycle 💚 Let's see how we can implement a better solution than Handler().postDelay() using Kotlin, Coroutines and the lifecycle library. First, make sure that you have these dependencies in your project: Then, we are ready to implement the function. To achieve a safe delay, we'll need to find the lifecycleOwner of the view thanks to the findViewTreeLifecycleOwner() method provided by the lifecycle library. Then, we can access the coroutine scope of the lifecycle to launch a new coroutine with a given Dispatcher (we'll be using the Main Dispatcher by default as we want to perform actions in the UI thread). To trigger the work in the coroutine in a specified amount of time,

## Lessons learned from Google Assistant and App Actions on Android

DevFeed: [Lessons learned from Google Assistant and App Actions on Android](<https://devfeed.tech/articles/lessons-learned-from-google-assistant-and-app-actions-on-android-25939.md>)

Original publisher: [Read original article](<https://juliensalvi.medium.com/lessons-learned-from-google-assistant-and-app-actions-on-android-c59c2dc60bd5?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-06-08T13:48:11Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Google](<https://devfeed.tech/topics/google.md>), [Android](<https://devfeed.tech/topics/android.md>), [App Indexing](<https://devfeed.tech/topics/app-indexing.md>), [Firebase](<https://devfeed.tech/topics/firebase.md>), [XML](<https://devfeed.tech/topics/xml.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [iOS](<https://devfeed.tech/topics/ios.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [app-indexing](<https://devfeed.tech/tags/app-indexing.md>), [firebase](<https://devfeed.tech/tags/firebase.md>), [google](<https://devfeed.tech/tags/google.md>), [google-assistant](<https://devfeed.tech/tags/google-assistant.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [ios](<https://devfeed.tech/tags/ios.md>), [voice-assistant](<https://devfeed.tech/tags/voice-assistant.md>), [xml](<https://devfeed.tech/tags/xml.md>)

### AI overview

A developer explains how Aircall experimented with Google Assistant voice interactions on Android and implemented App Actions for initiating calls. The article also describes using Android Slices to display a user's to-do list outside the app, including the relevant dependencies, actions.xml configuration, built-in intents, deep links, and manifest setup.

### Source excerpt

Photo by Soundtrap on Unsplash My company, Aircall, recently organized a hackathon to unleash our tech ideas for one and a half day. With the iOS folks, we decided to experiment voice interactions with Siri and Google Assistant in order to call a contact or show a specific data outside the application's scope with Android Slices. In this article, I'll show what we learned from Google Assistant and how we used App Actions to bring voice controls to our app. Identifying the features First, we wanted to identify the features we can bring to our application, thanks to Google Assistant. Our main app is a VoIP phone for businesses, so the first idea was to call someone from your contacts with the voice like "Ok Google, call John Doe on Aircall". Google Assistant offers the App Actions to achieve such goals on Android. Then, we thought about bringing relevant data to our users outside the application using voice actions. To do so, we will use the Android Slices to bring what's on the to-do of a user in Google Assistant with a command like the following: "Ok Google, show my to-do list on Aircall". Let's see how we implemented these two features in the Aircall app. Let's play with App Actions and Slices First, let's add the dependencies to the project. We need to add the Firebase Core and the App Indexing libraries to make the (deep)link between Google Assistant and our app. To display interactive cards on Google Assistant, we are going to use the AndroidX Slice library. Check for the latest updates of the Slice library here. Gradle dependenciesMake a call with App Actions To interact with our application, we need to define some actions in an actions.xml file located in the xml folder of the resources. Each action is associated with a built-in intent (BII) which model some of the common ways that users express tasks. App Actions provides over 60+ BIIs. Once the file is created, we are going to create the dedicated action to call a number or a contact, thanks to the intent ac

## Custom Shape with Jetpack Compose

DevFeed: [Custom Shape with Jetpack Compose](<https://devfeed.tech/articles/custom-shape-with-jetpack-compose-25938.md>)

Original publisher: [Read original article](<https://juliensalvi.medium.com/custom-shape-with-jetpack-compose-1cb48a991d42?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-04-26T14:33:26Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Compose](<https://devfeed.tech/topics/compose.md>), [Canvas](<https://devfeed.tech/topics/canvas.md>), [API](<https://devfeed.tech/topics/api.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [api](<https://devfeed.tech/tags/api.md>), [canvas](<https://devfeed.tech/tags/canvas.md>), [code](<https://devfeed.tech/tags/code.md>), [compose](<https://devfeed.tech/tags/compose.md>), [google-developer-expert](<https://devfeed.tech/tags/google-developer-expert.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>)

### AI overview

This tutorial explains how to create custom shapes for Jetpack Compose composables. It covers built-in shapes, Modifier functions for applying shapes, the Path API, and two approaches for custom outlines: GenericShape or a Shape implementation that overrides createOutline(). It also introduces animated shapes.

### Source excerpt

After exploring the Jetpack Compose Canvas in a previous article, this new post will explain how you can draw and use a custom Shape for your Composables to give them a specific outline. The Jetpack Compose foundation library already provides common shapes but we'll see how to take advantage of the Path API to build custom outlines. We will go even further by adding some animations to our brand new shapes. Introduction to Shape With Jetpack Compose, it is easy to add some rounded or cut corners to your Composable thanks to the foundation library which provides several shapes: RoundedCornerShape(): to have a rounded corner outline with a given radius CutCornerShape(): to have a cut corner outline with a given size GenericShape(): to build custom outlines with a given Path For example, a CutCornerShape with a corner size of 32dp applied to a Text Composable looks like the following image: CutCornerShape Shapes can be applied to your Composable thanks to by using several Modifier functions. Let's have a look at them: background(color, shape): it will define the new outline of the Composable with a given Color or Brush. graphicsLayer{}: set the shape attribute to define the new outline. Do not forget to set clip to true if you want that the shadow elevation matches the outline. border(width, color, shape): for drawing a border around the composable with a given shape, width and color. drawBehind{}: accessing the DrawScope and the Canvas to draw the outline of the composable. We can combine multiple Modifier methods to get the shape you can see above. The order matters when chaining the Modifier functions! For example, be sure to always call background() after graphicsLayer{} to ensure that your Composable will be correctly painted with the right color. Here is the code snippet of the Composable. https://medium.com/media/0d9ccf4b24727e20c1e32cd80016b24d/href Now that we've had a glimpse at the capabilities of shapes and how to use them, let's see how we can build our own

## Exploring Jetpack Compose Canvas: the power of drawing

DevFeed: [Exploring Jetpack Compose Canvas: the power of drawing](<https://devfeed.tech/articles/exploring-jetpack-compose-canvas-the-power-of-drawing-25942.md>)

Original publisher: [Read original article](<https://medium.com/google-developer-experts/exploring-jetpack-compose-canvas-the-power-of-drawing-8cc60815babe?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-03-19T16:38:56Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Canvas](<https://devfeed.tech/topics/canvas.md>), [Android](<https://devfeed.tech/topics/android.md>), [ui](<https://devfeed.tech/topics/ui.md>), [Code](<https://devfeed.tech/topics/code.md>), [Development](<https://devfeed.tech/topics/development.md>), [Google](<https://devfeed.tech/topics/google.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [animation](<https://devfeed.tech/tags/animation.md>), [canvas](<https://devfeed.tech/tags/canvas.md>), [code](<https://devfeed.tech/tags/code.md>), [component](<https://devfeed.tech/tags/component.md>), [compose](<https://devfeed.tech/tags/compose.md>), [function](<https://devfeed.tech/tags/function.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [library](<https://devfeed.tech/tags/library.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

A tutorial on using Canvas with Jetpack Compose to draw and animate shapes and text in Android applications. It explains the Canvas composable, DrawScope, coordinate origin, drawing styles, colors and brushes, and demonstrates a smiley face built from circles, arcs and rectangles. The examples are based on Compose 1.0.0-beta02, whose API methods may change.

### Source excerpt

In this article, I will share my experience of using Canvas with Jetpack Compose, which is the new UI toolkit made by Google. The Android Dev Challenge #2 gave me the opportunity to learn tons of things about Canvas and how to take advantage of it to draw and animate shapes or texts in a very nice way. Most of the code samples are based on the project below: Oleur/TimePack-CountPose Disclaimer: the code samples are based on Compose 1.0.0-beta02. The API methods might change in a near future.First steps with Canvas If you are familiar with the Android View canvas methods you won't be lost with the one from Jetpack Compose. All function names are same and some of them are even more explicit when dealing the Path API for example: relativeQuadraticBezierTo() instead of rQuadto() to curve a segment of the path. If you are not familiar with the native Android Canvas, I highly recommend to take a look at this article by Rebecca Franks to have a great introduction to the Android Canvas. Getting Started with Drawing on the Android Canvas 🖼 With Jetpack Compose, there is a Composable that is part of the UI component library called Canvas to unleash the power of drawing in your application. We are going to draw a smiley face with simple shapes (circle, arc and rectangles) to show its capabilities. https://medium.com/media/4c07f10b71cb6c5a87c46a02a3fa31b0/href The onDraw lambda on the Canvas give us access to the DrawScope. This scope is allowing us to draw everything we want in the Canvas. Remember that the origin (x=0, y=0) of the Canvas is located at the top left. Canvas with x-y axis and origin at top left To draw the head of the smiley face, we are going to draw a circle with a stroke style. If we let the style empty, it will be filled by default. All draw methods accept a Color or a Brush (used for adding gradients with a list of colors). To set the radius, we have access to the dimension of the current drawing environment with size provided by the the DrawScope in order

## Aircall Journey to Android App Bundle

DevFeed: [Aircall Journey to Android App Bundle](<https://devfeed.tech/articles/aircall-journey-to-android-app-bundle-25946.md>)

Original publisher: [Read original article](<https://medium.com/inside-aircall/aircall-journey-to-android-app-bundle-14d0df0d0ea7?source=rss-cbfc736ddcd3------2>)

Author: Julien Salvi

Published: 2021-02-18T15:12:51Z

Content type: tutorial

Language: en

Sources: [Stories by Julien Salvi on Medium](<https://devfeed.tech/sources/stories-by-julien-salvi-on-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [APK](<https://devfeed.tech/topics/apk.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [CircleCI](<https://devfeed.tech/topics/circleci.md>), [feature flags](<https://devfeed.tech/topics/feature-flags.md>), [ci](<https://devfeed.tech/topics/ci.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-bundle](<https://devfeed.tech/tags/android-app-bundle.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [apk](<https://devfeed.tech/tags/apk.md>), [ci](<https://devfeed.tech/tags/ci.md>), [circleci](<https://devfeed.tech/tags/circleci.md>), [continuous-integration](<https://devfeed.tech/tags/continuous-integration.md>), [feature-flags](<https://devfeed.tech/tags/feature-flags.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [play-store](<https://devfeed.tech/tags/play-store.md>)

### AI overview

Aircall describes migrating its Android app from APK distribution to Android App Bundle to deliver optimized APKs. The article covers APK size reduction, language, density, and ABI splits, Gradle configuration, and planned Play Feature Delivery, with CircleCI and fastlane mentioned for release automation.

### Source excerpt

A couple months, we decided to use Android App Bundle (AAB) to distribute Aircall's Android app in Play Store. After analyzing the Aircall Android application package (APK), we found we could deliver optimized APKs to our users -- an overall size reduction of 60%! In this article, we are going to expose our journey to Android App Bundle from our own motivations to the development within the application and the CI with CircleCI and fastlane to release on the Play Store. Why move to App Bundle? Moving to App Bundle had many advantages. The first and main reason was the APK size optimization, to deliver only what the user needs. After looking at our application file, we found that we embedded all native libraries (.so files) of all supported architectures! We could have used the abi split in our main build.gradle but we would have managed 4 APKs with different version code. We also saw we could reduce the resource assets to match the density of the device where the app is installed. Here is what the Aircall universal APK looks like on the inside: APK analysis with Android Studio Optimizing size was not the only advantage we saw. Migrating to AAB will allow us (a little bit) to save the planet! Indeed, with all the MB saved from the downloads and updates, we are using less storage space and consuming fewer energy resources. You can see our MAD Score below. If it hits 1 million downloads we could save 22 TB of data -- really a huge impact. MAD Score data from the Aircall project We were also excited by our future ability to enable Play Feature Delivery to push features to specific users. Since we are already using feature flags inside our applications, this would let us develop features on-the-go for our users. Gradle configuration Moving to AAB was a very smooth process and did not require a lot of configuration code. To replicate this move, on your build.gradle of your application, add the following block to build an AAB file. You will be able to add the language, densit