Инструкции
Представляем Cahier: новый пример приложения для Android на GitHub, предназначенный для повышения производительности и творчества на больших экранах.
11 минут чтения

API Ink теперь находится в стадии бета-тестирования и готов к интеграции в ваше приложение. Этот этап стал возможен благодаря ценным отзывам разработчиков, что привело к постоянному улучшению производительности, стабильности и визуального качества API.
Приложения Google, такие как Google Docs , Pixel Studio , Google Photos , Chrome PDF , YouTube Effect Maker, а также уникальные функции Android, например Circle to Search , используют новейшие API.
В честь этого знаменательного события мы рады объявить о запуске Cahier — полноценного демонстрационного приложения для ведения заметок, оптимизированного для устройств Android всех размеров, особенно для планшетов и складных телефонов.
Что такое Cahier?
Cahier («блокнот» по-французски) — это пример приложения, демонстрирующий, как можно создать приложение, позволяющее пользователям фиксировать и систематизировать свои мысли, комбинируя текст, рисунки и изображения.
Этот пример может служить отличным справочным пособием для повышения производительности и креативности пользователей на больших экранах. Он демонстрирует лучшие практики создания подобных интерфейсов, ускоряя понимание и внедрение разработчиками соответствующих мощных API и методов. В этой статье мы рассмотрим основные функции Cahier, ключевые API и архитектурные решения, которые делают этот пример отличным справочным материалом для ваших собственных приложений.
Ключевые особенности, продемонстрированные в образце, включают:
- Универсальное создание заметок: демонстрируется, как реализовать гибкую систему создания контента, поддерживающую несколько форматов в рамках одной заметки, включая текст, произвольные рисунки и прикрепленные изображения.
- Инструменты для креативного рисования тушью : Реализует высокопроизводительный процесс рисования с низкой задержкой, используя API Ink . Пример демонстрирует практическую интеграцию различных кистей, палитры цветов, функций отмены/повтора действий и инструмента «ластик».
- Гибкая интеграция контента с помощью перетаскивания : демонстрирует, как обрабатывать входящий и исходящий контент с помощью перетаскивания. Это включает в себя прием изображений, перетаскиваемых из других приложений, и предоставление пользователям возможности перетаскивать контент из вашего приложения для беспрепятственного обмена.
- Организация заметок : отмечайте заметки как избранные для быстрого доступа. Фильтруйте отображение для поддержания порядка.
- Архитектура с приоритетом на автономный режим: Приложение создано с использованием архитектуры Room , ориентированной на автономный режим, что гарантирует локальное сохранение всех данных и полную функциональность приложения без подключения к интернету.
- Мощная поддержка многооконного и многоэкземплярного режима : демонстрирует, как поддерживать многоэкземплярный режим, позволяя запускать приложение в нескольких окнах, чтобы пользователи могли работать над разными заметками одновременно, повышая производительность и креативность на больших экранах.
- Адаптивный пользовательский интерфейс для всех экранов : пользовательский интерфейс плавно адаптируется к различным размерам и ориентациям экрана с помощью ListDetailPaneScaffold и NavigationSuiteScaffold , обеспечивая оптимизированное взаимодействие с пользователем на телефонах, планшетах и складных устройствах.
- Глубокая системная интеграция : В этом руководстве описано, как сделать ваше приложение приложением для создания заметок по умолчанию на Android 14 и выше, реагируя на системные интенты Notes, что позволяет быстро фиксировать контент из различных точек входа в систему.
Создан для повышения производительности и креативности на больших экранах.
На начальном этапе запуска мы сосредоточимся на нескольких ключевых функциях, которые делают Cahier важным учебным ресурсом как для повышения производительности, так и для развития творческих способностей.
Основа адаптивности
Cahier изначально разработан с учетом адаптивности. В примере используется библиотека material3-adaptive, а именно ListDetailPaneScaffold и NavigationSuiteScaffold, для плавной адаптации макета приложения к различным размерам и ориентациям экрана. Это важнейший элемент для современного Android-приложения, и Cahier наглядно демонстрирует, как эффективно его реализовать.

Адаптивный пользовательский интерфейс Cahier, созданный с использованием библиотеки Material 3 Adaptive.
Демонстрация ключевых API и интеграций.
Данный пример демонстрирует мощные API-интерфейсы для повышения производительности, которые вы можете использовать в своих приложениях, в том числе:
- API чернил
- Роль примечаний
- Многоэкземплярная , многооконная и оконная работа рабочего стола
- Перетаскивание
Более подробный обзор ключевых API
Давайте подробнее рассмотрим два ключевых API, которые Cahier интегрирует для обеспечения первоклассного опыта ведения заметок.
Создание естественных интерфейсов для рисования с помощью Ink API
Ввод с помощью стилуса превращает устройства с большими экранами в цифровые блокноты и альбомы для эскизов. Чтобы помочь вам создавать плавные и естественные процессы рисования, мы сделали API для рисования чернилами краеугольным камнем этого примера. API для рисования чернилами упрощает создание, отображение и манипулирование красивыми штрихами чернил с лучшей в своем классе низкой задержкой.
API Ink предлагает модульную архитектуру, позволяющую адаптировать его к конкретным потребностям и стеку технологий вашего приложения. Модули API включают в себя:
- Модули для создания макетов ( Compose - views ): Обработка ввода данных при рукописном вводе в реальном времени для создания плавных штрихов с минимальной задержкой, которую может обеспечить устройство.
- В DrawingSurface Cahier использует недавно представленный модуль InProgressStrokes для обработки ввода с помощью стилуса или сенсорного экрана в реальном времени. Этот модуль отвечает за захват событий указателя и отрисовку штрихов чернилами с минимально возможной задержкой.
- Модуль Strokes : представляет собой ввод чернил и его визуальное отображение. Когда пользователь заканчивает рисовать линию, функция обратного вызова onStrokesFinished предоставляет приложению завершенный/сухой объект Stroke . Этот неизменяемый объект, представляющий собой завершенный штрих чернил, затем управляется в DrawingCanvasViewModel .
- Модуль рендеринга: эффективно отображает штрихи чернил, позволяя комбинировать их с Jetpack Compose или представлениями Android .
- Для отображения как существующих, так и новых штрихов Cahier использует CanvasStrokeRenderer в DrawingSurface для активного рисования и в DrawingDetailPanePreview для отображения статического предварительного просмотра ноты. Этот модуль эффективно рисует объекты Stroke на холсте .
- Модули кистей ( Compose - views ): предоставляют декларативный способ определения визуального стиля штрихов. Недавние обновления (с момента выпуска alpha03) включают новую пунктирную кисть , особенно полезную для таких функций, как выделение лассо. DrawingCanvasViewModel хранит состояние текущей кисти. Панель инструментов в DrawingCanvas позволяет пользователям выбирать различные семейства кистей (например, StockBrushes.pressurePen() или StockBrushes.highlighter() ) и изменять цвета. ViewModel обновляет объект Brush , который затем используется компонентом InProgressStrokes для создания новых штрихов.
- Модули геометрии ( Компоновка - Виды ): Поддерживают манипулирование и анализ обводки для таких функций, как стирание и выделение.
- Инструмент «Ластик» на панели инструментов и функциональность DrawingCanvasViewModel основаны на модуле геометрии. Когда ластик активен, он создает MutableParallelogram вокруг траектории жеста пользователя. Затем ластик проверяет наличие пересечений между формой и ограничивающими рамками существующих штрихов, чтобы определить, какие штрихи нужно удалить, что делает работу ластика интуитивно понятной и точной.
- Модуль хранения : обеспечивает эффективную сериализацию и десериализацию данных чернил, что приводит к значительной экономии места на диске и в сети. Для сохранения рисунков Cahier сохраняет объекты Stroke в своей базе данных Room. В Converters пример использует функцию encode модуля хранения для сериализации StrokeInputBatch (исходных данных точек) в ByteArray . Массив байтов вместе со свойствами кисти сохраняется в виде строки JSON. Функция decode используется для восстановления штрихов при загрузке заметки.

Помимо этих основных модулей, недавние обновления расширили возможности API Ink:
- Новые экспериментальные API для пользовательских объектов
BrushFamilyпозволяют разработчикам создавать креативные и уникальные типы кистей, открывая возможности для таких инструментов, как кисти «Карандаш» и «Лазерная указка» .
В Cahier используются специально разработанные кисти, в том числе уникальная музыкальная кисть, представленная ниже, для демонстрации расширенных творческих возможностей.

Радужный лазер, созданный с помощью пользовательских кистей Ink API.

Музыкальная кисть, созданная с помощью пользовательских кистей Ink API.
- Встроенные модули взаимодействия Jetpack Compose упрощают интеграцию функций рукописного ввода непосредственно в пользовательский интерфейс Compose, обеспечивая более идиоматичный и эффективный процесс разработки.
API Ink предлагает ряд преимуществ, которые делают его идеальным выбором для приложений, повышающих производительность и способствующих творчеству, по сравнению с собственной реализацией:
- Простота использования: API Ink абстрагирует сложные графические и геометрические элементы, позволяя вам сосредоточиться на основных функциях Cahier.
- Производительность: Встроенная поддержка низкой задержки и оптимизированный рендеринг обеспечивают плавную и отзывчивую работу с рукописным вводом.
- Гибкость: модульная конструкция позволяет выбирать необходимые компоненты, что обеспечивает бесшовную интеграцию API Ink в архитектуру Cahier.
API Ink уже используется во многих приложениях Google, в том числе для разметки в документах и для функции Circle to Search, а также в партнерских приложениях, таких как Orion Notes и PDF Scanner .
«Ink API был нашим первым выбором для функции Circle-to-Search (CtS). Благодаря обширной документации интеграция Ink API прошла очень легко, что позволило нам создать первый рабочий прототип всего за одну неделю. Поддержка пользовательских текстур кисти и анимации в Ink позволила нам быстро дорабатывать дизайн штрихов». — Джордан Комода, инженер-программист, Google
Стать приложением для заметок по умолчанию при наличии роли «Заметки»
Создание заметок — это ключевая функция, повышающая производительность пользователей на устройствах с большими экранами. Благодаря функции ролей для заметок пользователи могут получать доступ к совместимым приложениям с экрана блокировки или во время работы других приложений. Эта функция определяет и устанавливает системные приложения для создания заметок по умолчанию и предоставляет им разрешение на запуск для сохранения контента.
Реализация в Cahier
Реализация роли «заметки» включает в себя несколько ключевых шагов, все из которых продемонстрированы в примере:
- Объявление в манифесте : Во-первых, приложение должно объявить о своей способности обрабатывать намерения для создания заметок. В файле AndroidManifest.xml Cahier включает
<intent-filter>для действия android.intent.action.CREATE_NOTE . Это сигнализирует системе, что приложение является потенциальным кандидатом на роль приложения для создания заметок. - Проверка статуса роли : SettingsViewModel использует RoleManager Android для определения текущего статуса. SettingsViewModel проверяет, доступна ли роль «Заметки» на устройстве ( isRoleAvailable ) и занимает ли Cahier в данный момент эту роль ( isRoleHeld ). Это состояние передается в пользовательский интерфейс с помощью потоков Kotlin.
- Запрос роли : В файле Settings.kt пользователю отображается кнопка , если роль доступна, но не занята. При нажатии на кнопку вызывается функция
requestNotesRoleв ViewModel. Эта функция создает интент для открытия экрана настроек приложения по умолчанию, где пользователь может выбрать Cahier. Процесс управляется с помощью API rememberLauncherForActivityResult , который отвечает за запуск интента и получение результата. - Обновление пользовательского интерфейса : После того, как пользователь возвращается с экрана настроек, функция обратного вызова ActivityResultLauncher запускает функцию в ViewModel для обновления статуса роли, обеспечивая точное отображение в пользовательском интерфейсе того, является ли приложение теперь приложением по умолчанию.
Узнайте, как интегрировать функцию заметок в ваше приложение, в нашем руководстве по созданию приложения для ведения заметок .

Приложение Cahier запускалось в плавающем окне как приложение для создания заметок по умолчанию на планшете Lenovo.
Значительный шаг вперед: Lenovo включает функцию заметок.
Мы рады объявить о значительном шаге вперед в повышении производительности Android-устройств с большими экранами: Lenovo добавила поддержку функции «Заметки» на планшетах под управлением Android 15 и выше! Благодаря этому обновлению вы можете обновить свои приложения для заметок, чтобы пользователи совместимых устройств Lenovo могли установить их в качестве приложений по умолчанию, обеспечивая беспрепятственный доступ с экрана блокировки и разблокируя функции захвата контента на системном уровне.
Это обязательство ведущего производителя оборудования демонстрирует растущую важность функции заметок для обеспечения по-настоящему интегрированного и продуктивного пользовательского опыта на Android.
Многоэкземплярная, многооконная и оконная работа рабочего стола
Эффективная работа на большом экране – это прежде всего управление информацией и рабочими процессами. Именно поэтому Cahier создан с учетом всех возможностей Android по работе с окнами, предоставляя гибкое рабочее пространство, адаптирующееся к потребностям пользователя. Приложение поддерживает:
- Многооконный режим : фундаментальная возможность запуска приложения параллельно с другим приложением в режиме разделенного экрана или произвольного форматирования. Это необходимо для таких задач, как просмотр веб-страницы во время ведения заметок в Cahier.
- Многозадачность : Вот где проявляется настоящая многозадачность. Cahier позволяет пользователям открывать несколько независимых окон приложения одновременно . Представьте, что вы сравниваете две разные заметки рядом или обращаетесь к текстовой заметке в одном окне, работая над рисунком в другом. Cahier демонстрирует, как управлять этими отдельными экземплярами, каждый из которых имеет собственное состояние, превращая ваше приложение в мощный, многофункциональный инструмент.
- Оконный режим рабочего стола : При подключении к внешнему дисплею режим рабочего стола Android превращает планшет или складной компьютер в рабочую станцию. Благодаря адаптивному пользовательскому интерфейсу и поддержке многоэкземплярной работы, Cahier прекрасно работает в этой среде. Пользователи могут открывать, изменять размер и позиционировать несколько окон Cahier, как на традиционном настольном компьютере, что позволяет выполнять сложные рабочие процессы, ранее недоступные на мобильных устройствах.

Приложение Cahier работает в оконном режиме рабочего стола на планшете Pixel.
Вот как мы реализовали эти функции в Cahier:
Для включения многоэкземплярного режима сначала необходимо было сообщить системе, что приложение поддерживает многократный запуск, добавив свойство PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI в объявление MainActivity в AndroidManifest :
<activity android:name="com.example.cahier.MainActivity" android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.MyApplication" android:showWhenLocked="true" android:turnScreenOn="true" android:resizeableActivity="true" android:launchMode="singleInstancePerTask"> <property android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI" android:value="true"/> ... </activity>
Далее мы реализовали логику запуска нового экземпляра приложения. В файле CahierHomeScreen.kt , когда пользователь решает открыть заметку в новом окне, мы создаём новый Intent со специальными флагами, которые указывают системе, как обрабатывать запуск новой активности. Комбинация флагов FLAG_ACTIVITY_NEW_TASK , FLAG_ACTIVITY_MULTIPLE_TASK и FLAG_ACTIVITY_LAUNCH_ADJACENT гарантирует, что заметка откроется в новом, отдельном окне рядом с существующим.
fun openNewWindow(activity: Activity?, note: Note) {
val intent = Intent(activity, MainActivity::class.java)
intent.putExtra(AppArgs.NOTE_TYPE_KEY, note.type)
intent.putExtra(AppArgs.NOTE_ID_KEY, note.id)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
activity?.startActivity(intent)
} Для поддержки многооконного режима нам необходимо было сообщить системе, что приложение поддерживает изменение размера, указав в манифесте элемент <activity> или <application> .
<activity android:name="com.example.cahier.MainActivity" android:resizeableActivity="true" ...> </activity>
Благодаря использованию адаптивной библиотеки Material 3, пользовательский интерфейс плавно адаптируется к многооконным сценариям, таким как режим разделенного экрана в Android.
Для улучшения пользовательского опыта мы добавили поддержку перетаскивания. Ниже вы можете увидеть, как мы реализовали это в Cahier.
Перетаскивание
По-настоящему продуктивное или творческое приложение не работает изолированно; оно беспрепятственно взаимодействует с остальной экосистемой устройства. Перетаскивание является краеугольным камнем этого взаимодействия, особенно на больших экранах, где пользователи часто работают в нескольких окнах приложений. Cahier полностью учитывает это, внедряя интуитивно понятную функцию перетаскивания как для добавления, так и для обмена контентом.
- Простой импорт : пользователи могут перетаскивать изображения из других приложений — например, веб-браузера, фотогалереи или файлового менеджера — и помещать их непосредственно на холст заметки. Для этого Cahier использует модификатор dragAndDropTarget для определения зоны перетаскивания, проверки на совместимость содержимого (например,
image/*) и обработки входящего URI. - Простой обмен : контент внутри Cahier так же легко передавать, как и контент из других приложений. Пользователи могут долго удерживать изображение внутри текстовой заметки или долго удерживать холст композиции из рисунка и изображения и перетащить его в другое приложение.
Технический анализ: Перенос данных с чертежной доски
Реализация жеста перетаскивания на холсте для рисования представляет собой уникальную задачу. В нашем DrawingSurface компоненты, обрабатывающие ввод данных для рисования в реальном времени ( InProgressStrokes из Ink API), и Box , который распознает длительное нажатие для начала перетаскивания, являются соседними компонентами .
По умолчанию система ввода указателя в Jetpack Compose устроена таким образом, что событие получает только один соседний компонент (первый в порядке объявления, перекрывающий точку касания). В случае Cahier нам нужно, чтобы логика обработки ввода при перетаскивании успела выполниться и, возможно, обработать ввод до того, как компонент InProgressStrokes использует весь необработанный ввод для рисования, а затем обработает его. Если мы не расположим элементы в правильном порядке, наш Box не обнаружит жест длительного нажатия для начала перетаскивания, или InProgressStrokes не получит ввод для рисования.
Для решения этой проблемы мы создали собственный модификатор pointerInputWithSiblingFallthrough и разместили наш Box с этим модификатором перед InProgressStrokes в коде компонуемого объекта. Эта утилита представляет собой тонкую обертку над стандартной системой pointerInput , но с одним важным изменением: она переопределяет функцию sharePointerInputWithSiblings() и возвращает true . Это указывает фреймворку Compose разрешить передачу событий указателя соседним компонуемым объектам, даже после их обработки.
internal fun Modifier.pointerInputWithSiblingFallthrough(
pointerInputEventHandler: PointerInputEventHandler
) = this then PointerInputSiblingFallthroughElement(pointerInputEventHandler)
private class PointerInputSiblingFallthroughModifierNode(
pointerInputEventHandler: PointerInputEventHandler
) : PointerInputModifierNode, DelegatingNode() {
var pointerInputEventHandler: PointerInputEventHandler
get() = delegateNode.pointerInputEventHandler
set(value) {
delegateNode.pointerInputEventHandler = value
}
val delegateNode = delegate(
SuspendingPointerInputModifierNode(pointerInputEventHandler)
)
override fun onPointerEvent(
pointerEvent: PointerEvent,
pass: PointerEventPass,
bounds: IntSize
) {
delegateNode.onPointerEvent(pointerEvent, pass, bounds)
}
override fun onCancelPointerInput() {
delegateNode.onCancelPointerInput()
}
override fun sharePointerInputWithSiblings() = true
}
private data class PointerInputSiblingFallthroughElement(
val pointerInputEventHandler: PointerInputEventHandler
) : ModifierNodeElement<PointerInputSiblingFallthroughModifierNode>() {
override fun create() = PointerInputSiblingFallthroughModifierNode(pointerInputEventHandler)
override fun update(node: PointerInputSiblingFallthroughModifierNode) {
node.pointerInputEventHandler = pointerInputEventHandler
}
override fun InspectorInfo.inspectableProperties() {
name = "pointerInputWithSiblingFallthrough"
properties["pointerInputEventHandler"] = pointerInputEventHandler
}
} Вот как это используется в DrawingSurface :
Box(
modifier = Modifier
.fillMaxSize()
// Our custom modifier enables this gesture to coexist with the drawing input.
.pointerInputWithSiblingFallthrough {
detectDragGesturesAfterLongPress(
onDragStart = { onStartDrag() },
onDrag = { _, _ -> /* consume drag events */ },
onDragEnd = { /* No action needed */ }
)
}
)
// The Ink API's composable for live drawing sits here as a sibling.
InProgressStrokes(...) Благодаря этому система корректно распознает одновременно и движения при рисовании, и жест перетаскивания с длительным нажатием. После начала перетаскивания мы создаем общий URI content:// с помощью FileProvider и передаем этот URI в систему перетаскивания, используя view.startDragAndDrop() . Это решение обеспечивает надежный и интуитивно понятный пользовательский интерфейс, демонстрируя, как преодолевать сложные конфликты жестов в многоуровневых пользовательских интерфейсах.
Построено в соответствии с современными архитектурными принципами.
Помимо конкретных API, Cahier демонстрирует важнейшие архитектурные шаблоны для создания высококачественных адаптивных приложений.
Уровень представления: Jetpack Compose и адаптивность.
Слой представления полностью построен с использованием Jetpack Compose. Как уже упоминалось, Cahier использует библиотеку material3-adaptive для адаптации пользовательского интерфейса. Управление состоянием осуществляется в строгом соответствии с шаблоном однонаправленного потока данных (UDF), при этом экземпляры ViewModel используются в качестве контейнеров данных, содержащих информацию о заметках и состоянии пользовательского интерфейса.
Слой данных: хранилища и комнаты
Для уровня данных Cahier использует интерфейс NoteRepository , чтобы абстрагировать все операции с данными. Такое проектное решение позволяет приложению легко переключаться между локальным источником данных (Room) и потенциальным удаленным бэкэндом в будущем. Поток данных для такого действия, как редактирование заметки, прост:
- Интерфейс Jetpack Compose запускает метод в ViewModel.
- ViewModel получает заметку из NoteRepository , обрабатывает логику и передает обновленную заметку обратно в репозиторий.
- NoteRepository сохраняет обновление в базу данных Room.
Комплексная поддержка ввода
Чтобы стать по-настоящему мощным инструментом повышения производительности, приложение должно безупречно обрабатывать различные методы ввода. Cahier разработано в соответствии с рекомендациями по вводу данных на больших экранах и поддерживает:
- Стилус: интеграция с API Ink, защита от случайного касания ладонью, регистрация роли для заметок, ввод текста с помощью стилуса в текстовые поля и иммерсивный режим.
- Клавиатура: Поддержка большинства распространенных сочетаний клавиш (например, Ctrl+клик, Meta+клик) и наглядная индикация фокуса клавиатуры.
- Мышь и тачпад: поддержка щелчка правой кнопкой мыши и наведения курсора.
Поддержка расширенных возможностей взаимодействия с клавиатурой, мышью и трекпадом является ключевым направлением для дальнейших улучшений.
Начните сегодня!
Мы надеемся, что Cahier послужит стартовой площадкой для вашего следующего замечательного приложения. Мы создали его как всеобъемлющий ресурс с открытым исходным кодом, демонстрирующий, как сочетать адаптивный пользовательский интерфейс, мощные API, такие как Ink и роль заметок, и современную адаптивную архитектуру.
Готовы погрузиться в это с головой?
- Изучите код : перейдите в наш репозиторий на GitHub , чтобы изучить кодовую базу Cahier и увидеть принципы проектирования в действии.
- Создайте свой собственный стиль : используйте Cahier в качестве основы для ведения заметок, разметки документов или творческого применения.
- Внесите свой вклад : Мы приветствуем ваши предложения! Помогите нам сделать Cahier еще лучшим ресурсом для сообщества разработчиков Android.
Ознакомьтесь с официальными руководствами для разработчиков и начните создавать свое приложение нового поколения для повышения производительности и творчества уже сегодня. Мы с нетерпением ждем, что вы создадите!
Продолжить чтение

Инструкции
Сегодня мы рады объявить о появлении новых подтвержденных учетных данных электронной почты, выданных Google, которые разработчики теперь могут получать напрямую через API цифровых учетных данных Credential Manager в Android.
Niharika Arora , Jean-Pierre Pralle • Чтение 3 минуты

Инструкции
Независимо от того, используете ли вы Gemini в Android Studio, Gemini CLI, Antigravity или сторонние агенты, такие как Claude Code или Codex, наша миссия — обеспечить возможность высококачественной разработки под Android повсюду.
Adarsh Fernando , Esteban de la Canal • Чтение 4 минуты

Инструкции
Понимая, что чрезмерный расход заряда батареи является одной из главных проблем для пользователей Android, Google предпринимает значительные шаги, чтобы помочь разработчикам создавать более энергоэффективные приложения.
Alice Yuan • 8 мин чтения
Будьте в курсе событий
Получайте еженедельно самые свежие новости о разработке Android прямо на свою электронную почту.
Инструкции
Представляем Cahier: новый пример приложения для Android на GitHub, предназначенный для повышения производительности и творчества на больших экранах.
11 минут чтения

API Ink теперь находится в стадии бета-тестирования и готов к интеграции в ваше приложение. Этот этап стал возможен благодаря ценным отзывам разработчиков, что привело к постоянному улучшению производительности, стабильности и визуального качества API.
Приложения Google, такие как Google Docs , Pixel Studio , Google Photos , Chrome PDF , YouTube Effect Maker, а также уникальные функции Android, например Circle to Search , используют новейшие API.
В честь этого знаменательного события мы рады объявить о запуске Cahier — полноценного демонстрационного приложения для ведения заметок, оптимизированного для устройств Android всех размеров, особенно для планшетов и складных телефонов.
Что такое Cahier?
Cahier («блокнот» по-французски) — это пример приложения, демонстрирующий, как можно создать приложение, позволяющее пользователям фиксировать и систематизировать свои мысли, комбинируя текст, рисунки и изображения.
Этот пример может служить отличным справочным пособием для повышения производительности и креативности пользователей на больших экранах. Он демонстрирует лучшие практики создания подобных интерфейсов, ускоряя понимание и внедрение разработчиками соответствующих мощных API и методов. В этой статье мы рассмотрим основные функции Cahier, ключевые API и архитектурные решения, которые делают этот пример отличным справочным материалом для ваших собственных приложений.
Ключевые особенности, продемонстрированные в образце, включают:
- Универсальное создание заметок: демонстрируется, как реализовать гибкую систему создания контента, поддерживающую несколько форматов в рамках одной заметки, включая текст, произвольные рисунки и прикрепленные изображения.
- Инструменты для креативного рисования тушью : Реализует высокопроизводительный процесс рисования с низкой задержкой, используя API Ink . Пример демонстрирует практическую интеграцию различных кистей, палитры цветов, функций отмены/повтора действий и инструмента «ластик».
- Гибкая интеграция контента с помощью перетаскивания : демонстрирует, как обрабатывать входящий и исходящий контент с помощью перетаскивания. Это включает в себя прием изображений, перетаскиваемых из других приложений, и предоставление пользователям возможности перетаскивать контент из вашего приложения для беспрепятственного обмена.
- Организация заметок : отмечайте заметки как избранные для быстрого доступа. Фильтруйте отображение для поддержания порядка.
- Архитектура с приоритетом на автономный режим: Приложение создано с использованием архитектуры Room , ориентированной на автономный режим, что гарантирует локальное сохранение всех данных и полную функциональность приложения без подключения к интернету.
- Мощная поддержка многооконного и многоэкземплярного режима : демонстрирует, как поддерживать многоэкземплярный режим, позволяя запускать приложение в нескольких окнах, чтобы пользователи могли работать над разными заметками одновременно, повышая производительность и креативность на больших экранах.
- Адаптивный пользовательский интерфейс для всех экранов : пользовательский интерфейс плавно адаптируется к различным размерам и ориентациям экрана с помощью ListDetailPaneScaffold и NavigationSuiteScaffold , обеспечивая оптимизированное взаимодействие с пользователем на телефонах, планшетах и складных устройствах.
- Глубокая системная интеграция : В этом руководстве описано, как сделать ваше приложение приложением для создания заметок по умолчанию на Android 14 и выше, реагируя на системные интенты Notes, что позволяет быстро фиксировать контент из различных точек входа в систему.
Создан для повышения производительности и креативности на больших экранах.
На начальном этапе запуска мы сосредоточимся на нескольких ключевых функциях, которые делают Cahier важным учебным ресурсом как для повышения производительности, так и для развития творческих способностей.
Основа адаптивности
Cahier изначально разработан с учетом адаптивности. В примере используется библиотека material3-adaptive, а именно ListDetailPaneScaffold и NavigationSuiteScaffold, для плавной адаптации макета приложения к различным размерам и ориентациям экрана. Это важнейший элемент для современного Android-приложения, и Cahier наглядно демонстрирует, как эффективно его реализовать.

Адаптивный пользовательский интерфейс Cahier, созданный с использованием библиотеки Material 3 Adaptive.
Демонстрация ключевых API и интеграций.
Данный пример демонстрирует мощные API-интерфейсы для повышения производительности, которые вы можете использовать в своих приложениях, в том числе:
- API чернил
- Роль примечаний
- Многоэкземплярная , многооконная и оконная работа рабочего стола
- Перетаскивание
Более подробный обзор ключевых API
Давайте подробнее рассмотрим два ключевых API, которые Cahier интегрирует для обеспечения первоклассного опыта ведения заметок.
Создание естественных интерфейсов для рисования с помощью Ink API
Ввод с помощью стилуса превращает устройства с большими экранами в цифровые блокноты и альбомы для эскизов. Чтобы помочь вам создавать плавные и естественные процессы рисования, мы сделали API для рисования чернилами краеугольным камнем этого примера. API для рисования чернилами упрощает создание, отображение и манипулирование красивыми штрихами чернил с лучшей в своем классе низкой задержкой.
API Ink предлагает модульную архитектуру, позволяющую адаптировать его к конкретным потребностям и стеку технологий вашего приложения. Модули API включают в себя:
- Модули для создания макетов ( Compose - views ): Обработка ввода данных при рукописном вводе в реальном времени для создания плавных штрихов с минимальной задержкой, которую может обеспечить устройство.
- В DrawingSurface Cahier использует недавно представленный модуль InProgressStrokes для обработки ввода с помощью стилуса или сенсорного экрана в реальном времени. Этот модуль отвечает за захват событий указателя и отрисовку штрихов чернилами с минимально возможной задержкой.
- Модуль Strokes : представляет собой ввод чернил и его визуальное отображение. Когда пользователь заканчивает рисовать линию, функция обратного вызова onStrokesFinished предоставляет приложению завершенный/сухой объект Stroke . Этот неизменяемый объект, представляющий собой завершенный штрих чернил, затем управляется в DrawingCanvasViewModel .
- Модуль рендеринга: эффективно отображает штрихи чернил, позволяя комбинировать их с Jetpack Compose или представлениями Android .
- Для отображения как существующих, так и новых штрихов Cahier использует CanvasStrokeRenderer в DrawingSurface для активного рисования и в DrawingDetailPanePreview для отображения статического предварительного просмотра ноты. Этот модуль эффективно рисует объекты Stroke на холсте .
- Модули кистей ( Compose - views ): предоставляют декларативный способ определения визуального стиля штрихов. Недавние обновления (с момента выпуска alpha03) включают новую пунктирную кисть , особенно полезную для таких функций, как выделение лассо. DrawingCanvasViewModel хранит состояние текущей кисти. Панель инструментов в DrawingCanvas позволяет пользователям выбирать различные семейства кистей (например, StockBrushes.pressurePen() или StockBrushes.highlighter() ) и изменять цвета. ViewModel обновляет объект Brush , который затем используется компонентом InProgressStrokes для создания новых штрихов.
- Модули геометрии ( Компоновка - Виды ): Поддерживают манипулирование и анализ обводки для таких функций, как стирание и выделение.
- Инструмент «Ластик» на панели инструментов и функциональность DrawingCanvasViewModel основаны на модуле геометрии. Когда ластик активен, он создает MutableParallelogram вокруг траектории жеста пользователя. Затем ластик проверяет наличие пересечений между формой и ограничивающими рамками существующих штрихов, чтобы определить, какие штрихи нужно удалить, что делает работу ластика интуитивно понятной и точной.
- Модуль хранения : обеспечивает эффективную сериализацию и десериализацию данных чернил, что приводит к значительной экономии места на диске и в сети. Для сохранения рисунков Cahier сохраняет объекты Stroke в своей базе данных Room. В Converters пример использует функцию encode модуля хранения для сериализации StrokeInputBatch (исходных данных точек) в ByteArray . Массив байтов вместе со свойствами кисти сохраняется в виде строки JSON. Функция decode используется для восстановления штрихов при загрузке заметки.

Помимо этих основных модулей, недавние обновления расширили возможности API Ink:
- Новые экспериментальные API для пользовательских объектов
BrushFamilyпозволяют разработчикам создавать креативные и уникальные типы кистей, открывая возможности для таких инструментов, как кисти «Карандаш» и «Лазерная указка» .
В Cahier используются специально разработанные кисти, в том числе уникальная музыкальная кисть, представленная ниже, для демонстрации расширенных творческих возможностей.

Радужный лазер, созданный с помощью пользовательских кистей Ink API.

Музыкальная кисть, созданная с помощью пользовательских кистей Ink API.
- Встроенные модули взаимодействия Jetpack Compose упрощают интеграцию функций рукописного ввода непосредственно в пользовательский интерфейс Compose, обеспечивая более идиоматичный и эффективный процесс разработки.
API Ink предлагает ряд преимуществ, которые делают его идеальным выбором для приложений, повышающих производительность и способствующих творчеству, по сравнению с собственной реализацией:
- Простота использования: API Ink абстрагирует сложные графические и геометрические элементы, позволяя вам сосредоточиться на основных функциях Cahier.
- Производительность: Встроенная поддержка низкой задержки и оптимизированный рендеринг обеспечивают плавную и отзывчивую работу с рукописным вводом.
- Гибкость: модульная конструкция позволяет выбирать необходимые компоненты, что обеспечивает бесшовную интеграцию API Ink в архитектуру Cahier.
API Ink уже используется во многих приложениях Google, в том числе для разметки в документах и для функции Circle to Search, а также в партнерских приложениях, таких как Orion Notes и PDF Scanner .
«Ink API был нашим первым выбором для функции Circle-to-Search (CtS). Благодаря обширной документации интеграция Ink API прошла очень легко, что позволило нам создать первый рабочий прототип всего за одну неделю. Поддержка пользовательских текстур кисти и анимации в Ink позволила нам быстро дорабатывать дизайн штрихов». — Джордан Комода, инженер-программист, Google
Стать приложением для заметок по умолчанию при наличии роли «Заметки»
Создание заметок — это ключевая функция, повышающая производительность пользователей на устройствах с большими экранами. Благодаря функции ролей для заметок пользователи могут получать доступ к совместимым приложениям с экрана блокировки или во время работы других приложений. Эта функция определяет и устанавливает системные приложения для создания заметок по умолчанию и предоставляет им разрешение на запуск для сохранения контента.
Реализация в Cahier
Реализация роли «заметки» включает в себя несколько ключевых шагов, все из которых продемонстрированы в примере:
- Объявление в манифесте : Во-первых, приложение должно объявить о своей способности обрабатывать намерения для создания заметок. В файле AndroidManifest.xml Cahier включает
<intent-filter>для действия android.intent.action.CREATE_NOTE . Это сигнализирует системе, что приложение является потенциальным кандидатом на роль приложения для создания заметок. - Проверка статуса роли : SettingsViewModel использует RoleManager Android для определения текущего статуса. SettingsViewModel проверяет, доступна ли роль «Заметки» на устройстве ( isRoleAvailable ) и занимает ли Cahier в данный момент эту роль ( isRoleHeld ). Это состояние передается в пользовательский интерфейс с помощью потоков Kotlin.
- Запрос роли : В файле Settings.kt пользователю отображается кнопка , если роль доступна, но не занята. При нажатии на кнопку вызывается функция
requestNotesRoleв ViewModel. Эта функция создает интент для открытия экрана настроек приложения по умолчанию, где пользователь может выбрать Cahier. Процесс управляется с помощью API rememberLauncherForActivityResult , который отвечает за запуск интента и получение результата. - Обновление пользовательского интерфейса : После того, как пользователь возвращается с экрана настроек, функция обратного вызова ActivityResultLauncher запускает функцию в ViewModel для обновления статуса роли, обеспечивая точное отображение в пользовательском интерфейсе того, является ли приложение теперь приложением по умолчанию.
Узнайте, как интегрировать функцию заметок в ваше приложение, в нашем руководстве по созданию приложения для ведения заметок .

Приложение Cahier запускалось в плавающем окне как приложение для создания заметок по умолчанию на планшете Lenovo.
Значительный шаг вперед: Lenovo включает функцию заметок.
We're thrilled to announce a major step forward for large screen Android productivity: Lenovo has enabled support for Notes Role on tablets running Android 15 and higher! With this update, you can now update your note-taking apps to allow users with compatible Lenovo devices to set them as default, granting seamless access from the lock screen and unlocking system level content capture features.
This commitment from a leading OEM demonstrates the growing importance of the notes role in delivering a truly integrated and productive user experience on Android.
Multi-instance, multi-windowing, and desktop windowing
Productivity on a large screen is all about managing information and workflows efficiently. That's why Cahier is built to fully embrace Android's advanced windowing capabilities, providing a flexible workspace that adapts to user needs. The app supports:
- Multi-windowing : The fundamental ability to run alongside another app in split-screen or free-form mode. This is essential for tasks like referencing a web page while taking notes in Cahier.
- Multi-instance : This is where true multitasking shines. Cahier allows users to open multiple, independent windows of the app simultaneously . Imagine comparing two different notes side by side or referencing a text note in one window while working on a drawing in another. Cahier demonstrates how to manage these separate instances, each with its own state, turning your app into a powerful, multifaceted tool.
- Desktop windowing : When connected to an external display, Android desktop mode transforms a tablet or foldable into a workstation. Because Cahier is built with an adaptive UI and supports multi-instance, the app performs beautifully in this environment. Users can open, resize, and position multiple Cahier windows just like on a traditional desktop, enabling complex workflows that were previously out of reach on mobile devices.

Cahier running in desktop window mode on Pixel Tablet
Here's how we implemented these features in Cahier:
To enable multi-instance, we first needed to signal to the system that the app supports being launched multiple times by adding the PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI property to MainActivity 's declaration in AndroidManifest :
<activity android:name="com.example.cahier.MainActivity" android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.MyApplication" android:showWhenLocked="true" android:turnScreenOn="true" android:resizeableActivity="true" android:launchMode="singleInstancePerTask"> <property android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI" android:value="true"/> ... </activity>
Next, we implemented the logic to launch a new instance of the app. In CahierHomeScreen.kt , when a user opts to open a note in a new window, we create a new Intent with specific flags that instruct the system on how to handle the new activity launch. The combination of FLAG_ACTIVITY_NEW_TASK , FLAG_ACTIVITY_MULTIPLE_TASK , and FLAG_ACTIVITY_LAUNCH_ADJACENT ensures the note opens in a new, separate window alongside the existing one.
fun openNewWindow(activity: Activity?, note: Note) {
val intent = Intent(activity, MainActivity::class.java)
intent.putExtra(AppArgs.NOTE_TYPE_KEY, note.type)
intent.putExtra(AppArgs.NOTE_ID_KEY, note.id)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
activity?.startActivity(intent)
} To support multi-window mode, we needed to signal to the system that the app supports resizability by setting the Manifest's <activity> or <application> element.
<activity android:name="com.example.cahier.MainActivity" android:resizeableActivity="true" ...> </activity>
The UI itself being built with the Material 3 adaptive library enables it to adapt seamlessly in multi-window scenarios like Android's split screen mode.
To enhance user experience, we added support for drag and drop. See below how we implemented this in Cahier.
Перетаскивание
A truly productive or creative app doesn't function in isolation; it interacts seamlessly with the rest of the device's ecosystem. Drag and drop is a cornerstone of this interaction, especially on large screens where users are often working across multiple app windows. Cahier fully embraces this by implementing intuitive drag and drop functionality for both adding and sharing content.
- Effortless Importing : Users can drag images from other applications—like a web browser, photo gallery, or file manager—and drop them directly onto a note canvas. For this, Cahier uses the dragAndDropTarget modifier to define a drop zone, check for compatible content (like
image/*), and process the incoming URI. - Simple sharing : Content inside Cahier is just as easy to share as content from other apps. Users can long-press an image within a text note, or long-press the entire canvas of a drawing note and image composite, and drag it out to another application.
Technical deep dive: Dragging from the drawing canvas
Implementing the drag gesture on the drawing canvas presents a unique challenge. In our DrawingSurface , the composables that handle live drawing input (the Ink API's InProgressStrokes ) and the Box that detects the long-press gesture to initiate a drag are sibling composables .
By default, the Jetpack Compose pointer input system is designed so that just one sibling composable —the first one in declaration order that overlaps the touch location—receives the event. In Cahier's case, we want our drag-and-drop input handling logic to have a chance to run and potentially consume inputs before the InProgressStrokes composable uses all unconsumed input for drawing and then consumes that input. If we don't arrange things in the right order, our Box won't detect the long-press gesture to start a drag, or InProgressStrokes won't receive the input to draw.
To solve this, we created a custom pointerInputWithSiblingFallthrough modifier, and we put our Box using that modifier before InProgressStrokes in the composable code. This utility is a thin wrapper around the standard pointerInput system but with one critical change: it overrides the sharePointerInputWithSiblings() function to return true . This tells the Compose framework to allow pointer events to pass through to sibling composables, even after being consumed.
internal fun Modifier.pointerInputWithSiblingFallthrough(
pointerInputEventHandler: PointerInputEventHandler
) = this then PointerInputSiblingFallthroughElement(pointerInputEventHandler)
private class PointerInputSiblingFallthroughModifierNode(
pointerInputEventHandler: PointerInputEventHandler
) : PointerInputModifierNode, DelegatingNode() {
var pointerInputEventHandler: PointerInputEventHandler
get() = delegateNode.pointerInputEventHandler
set(value) {
delegateNode.pointerInputEventHandler = value
}
val delegateNode = delegate(
SuspendingPointerInputModifierNode(pointerInputEventHandler)
)
override fun onPointerEvent(
pointerEvent: PointerEvent,
pass: PointerEventPass,
bounds: IntSize
) {
delegateNode.onPointerEvent(pointerEvent, pass, bounds)
}
override fun onCancelPointerInput() {
delegateNode.onCancelPointerInput()
}
override fun sharePointerInputWithSiblings() = true
}
private data class PointerInputSiblingFallthroughElement(
val pointerInputEventHandler: PointerInputEventHandler
) : ModifierNodeElement<PointerInputSiblingFallthroughModifierNode>() {
override fun create() = PointerInputSiblingFallthroughModifierNode(pointerInputEventHandler)
override fun update(node: PointerInputSiblingFallthroughModifierNode) {
node.pointerInputEventHandler = pointerInputEventHandler
}
override fun InspectorInfo.inspectableProperties() {
name = "pointerInputWithSiblingFallthrough"
properties["pointerInputEventHandler"] = pointerInputEventHandler
}
} Here's how it's used in DrawingSurface :
Box(
modifier = Modifier
.fillMaxSize()
// Our custom modifier enables this gesture to coexist with the drawing input.
.pointerInputWithSiblingFallthrough {
detectDragGesturesAfterLongPress(
onDragStart = { onStartDrag() },
onDrag = { _, _ -> /* consume drag events */ },
onDragEnd = { /* No action needed */ }
)
}
)
// The Ink API's composable for live drawing sits here as a sibling.
InProgressStrokes(...) With this in place, the system correctly detects both the drawing strokes and the long-press drag gesture simultaneously. Once the drag is initiated, we create a shareable content:// URI with FileProvider and pass the URI to the system's drag and drop framework using view.startDragAndDrop() . This solution ensures a robust and intuitive user experience, showcasing how to overcome complex gesture conflicts in layered UIs.
Built with modern architecture
Beyond specific APIs, Cahier demonstrates crucial architectural patterns for building high-quality, adaptive applications.
The presentation layer: Jetpack Compose and adaptability
The presentation layer is built entirely with Jetpack Compose. As mentioned, Cahier adopts the material3-adaptive library for UI adaptability. State management follows a strict Unidirectional Data Flow (UDF) pattern, with ViewModel instances used as data containers that hold note information and UI state.
The data layer: Repositories and Room
For the data layer, Cahier uses a NoteRepository interface to abstract all data operations. This design choice cleanly allows the app to swap between a local data source (Room) and a potential future remote backend. The data flow for an action like editing a note is straightforward:
- The Jetpack Compose UI triggers a method in the ViewModel.
- The ViewModel fetches the note from NoteRepository , handles the logic, and passes the updated note back to the repository.
- NoteRepository saves the update to a Room database.
Comprehensive input support
To be a true productivity powerhouse, an app must handle a variety of input methods flawlessly. Cahier is built to be compliant with large screen input guidelines and supports:
- Stylus: Integration with the Ink API, palm rejection, registration for the notes role, stylus input in text fields, and immersive mode.
- Keyboard: Support for most common keyboard shortcuts and combinations (like ctrl+click, meta+click) and clear indication for keyboard focus.
- Mouse and trackpad: Support for right-click and hover states.
Support for advanced keyboard, mouse, and trackpad interactions is a key focus for further improvements.
Начните сегодня!
We hope Cahier serves as a launchpad for your next great app. We built it to be a comprehensive, open source resource that demonstrates how to combine an adaptive UI, powerful APIs like Ink and notes role, and a modern, adaptive architecture.
Ready to dive in?
- Explore the code : Head over to our GitHub repository to explore the Cahier codebase and see the design principles in action.
- Build your own : Use Cahier as a foundation for your own note-taking, document markup, or creative application.
- Contribute : We welcome your contributions! Help us make Cahier an even better resource for the Android developer community.
Check out the official developer guides and start building your next generation productivity and creativity app today. We can't wait to see what you create!
Продолжить чтение

Инструкции
Сегодня мы рады объявить о появлении новых подтвержденных учетных данных электронной почты, выданных Google, которые разработчики теперь могут получать напрямую через API цифровых учетных данных Credential Manager в Android.
Niharika Arora , Jean-Pierre Pralle • Чтение 3 минуты

Инструкции
Независимо от того, используете ли вы Gemini в Android Studio, Gemini CLI, Antigravity или сторонние агенты, такие как Claude Code или Codex, наша миссия — обеспечить возможность высококачественной разработки под Android повсюду.
Adarsh Fernando , Esteban de la Canal • Чтение 4 минуты

Инструкции
Понимая, что чрезмерный расход заряда батареи является одной из главных проблем для пользователей Android, Google предпринимает значительные шаги, чтобы помочь разработчикам создавать более энергоэффективные приложения.
Alice Yuan • 8 мин чтения
Будьте в курсе событий
Получайте еженедельно самые свежие новости о разработке Android прямо на свою электронную почту.






