Cómo crear una app para tomar notas

La toma de notas es una función principal de Android que mejora la productividad del usuario en dispositivos con pantalla grande. Las apps para tomar notas permiten a los usuarios escribir y dibujar en una ventana flotante o en pantalla completa, capturar y anotar el contenido de la pantalla, y guardar notas para revisarlas y revisarlas más tarde.

Los usuarios pueden acceder a las apps para tomar notas desde la pantalla de bloqueo o mientras ejecutan otras apps.

La compatibilidad con la pluma stylus para tomar notas proporciona una experiencia del usuario excepcional.

Rol de notas

El rol RoleManager.ROLE_NOTES identifica a las apps para tomar notas y les otorga el permiso LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE.

Para adquirir el rol de notas para tu app, haz lo siguiente:

  1. Llama a isRoleAvailable() para verificar el estado del rol.
  2. Si el rol de notas está disponible, llama a createRequestRoleIntent() para obtener un intent específico de notas.
  3. Llama a startActivityForResult() con el intent de notas para solicitarle al usuario que otorgue el rol de notas a tu app.

Solo una app puede tener la función de notas.

La app se abre en respuesta a una acción de intent ACTION_CREATE_NOTE implícita. Si se invoca desde la pantalla de bloqueo del dispositivo, la app abre la pantalla completa; si se invoca mientras la pantalla está desbloqueada, en una ventana flotante.

Manifiesto de la app

A fin de cumplir con los requisitos para la función de notas, tu app debe incluir la siguiente declaración en el manifiesto de la app:

<activity
    android:name="YourActivityName"
    android:exported="true"
    android:showWhenLocked="true"
    android:turnScreenOn="true">
    <intent-filter>
        <action android:name="android.intent.action.CREATE_NOTE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

La declaración permite que los usuarios asignen el rol de notas a tu app, lo que la convierte en la aplicación predeterminada para tomar notas:

  • ACTION_CREATE_NOTE establece la acción de intent a la que responde la app.

  • showWhenLocked permite que se pueda acceder a tu app desde la pantalla de bloqueo del dispositivo

  • turnScreenOn permite que tu app encienda la pantalla del dispositivo cuando se ejecuta.

Funciones de la app

Una app diferenciada para tomar notas en pantalla grande ofrece un complemento completo de las capacidades de toma de notas.

Compatibilidad con pluma stylus

Cuando se invoca tu app con el intent adicional EXTRA_USE_STYLUS_MODE configurado en true, la app debe abrir una nota que acepte la entrada de la pluma stylus (o la función táctil).

Si el intent adicional se establece en false, tu app debe abrir una nota que acepte la entrada del teclado.

Acceso a la pantalla de bloqueo

Tu app debe proporcionar una actividad de pantalla completa que se ejecute cuando se abra desde la pantalla de bloqueo del dispositivo.

Tu app solo debe mostrar notas históricas si el usuario dio su consentimiento (en el estado del dispositivo desbloqueado) para mostrar notas anteriores. De lo contrario, cuando se abra desde la pantalla de bloqueo, la app siempre deberá crear una nota nueva.

Puedes verificar si tu app se inició desde la pantalla de bloqueo con KeyguardManager#isKeyguardLocked(). Para pedirle al usuario que se autentique y desbloquee el dispositivo, llama a KeyguardManager#requestDismissKeyguard():

Kotlin

val keyguardManager = getSystemService(KEYGUARD_SERVICE) as KeyguardManager

keyguardManager.requestDismissKeyguard(
    this,
    object : KeyguardDismissCallback() {

    override fun onDismissError() {
        // Unlock failed. Dismissing keyguard is not feasible.
    }

    override fun onDismissSucceeded() {
        // Unlock succeeded. Device is now unlocked.
    }

    override fun onDismissCancelled() {
        // Unlock failed. User cancelled operation or request otherwise cancelled.
    }
})

Java

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);

boolean isLocked = keyguardManager.isKeyguardLocked();

keyguardManager.requestDismissKeyguard(
    this,
    new KeyguardManager.KeyguardDismissCallback() {

  @Override
  public void onDismissError() {
      // Unlock failed. Dismissing keyguard is not feasible.
  }

  @Override
  public void onDismissSucceeded() {
      // Unlock succeeded. Device is now unlocked.
  }

  @Override
  public void onDismissCancelled() {
      // Unlock failed. User cancelled operation or request otherwise cancelled.
  }
});

Ventanas flotantes

Para tomar notas contextuales, tu app debe proporcionar una actividad que se abra en una ventana flotante cuando se esté ejecutando otra aplicación.

Tu app debería admitir el modo multi-instance para que los usuarios puedan crear varias notas en múltiples ventanas flotantes, incluso cuando tu app para tomar notas se inicie en pantalla completa o en modo de pantalla dividida.

Captura de contenido

La captura de contenido es una función clave de las apps para tomar notas. Con la captura de contenido, los usuarios pueden tomar capturas de pantalla de la pantalla detrás de la ventana flotante de la app para tomar notas. Los usuarios pueden capturar toda la pantalla o parte de ella, pegar el contenido en su nota y agregar anotaciones o destacar el contenido capturado.

Tu app para tomar notas debe proporcionar una indicación de IU que inicie un objeto ActivityResultLauncher creado por registerForActivityResult(). La acción de intent ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE se proporciona al selector directamente o a través de un ActivityResultContract.

Una actividad del sistema captura el contenido, lo guarda en el dispositivo y muestra el URI de contenido a tu app en el argumento de devolución de llamada de registerForActivityResult().

En el siguiente ejemplo, se usa un contrato StartActivityForResult genérico:

Kotlin

private val startForResult = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()) {
        result: ActivityResult ->
            if (result.resultCode == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
                val uri = result.data?.data
                // Use the URI to paste the captured content into the note.
            }
    }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        NotesTheme {
            Surface(color = MaterialTheme.colorScheme.background) {
                CaptureButton(
                    onClick = {
                        Log.i("ContentCapture", "Launching intent...")
                        startForResult.launch(Intent(ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE))
                    })
            }
        }
    }
}

@Composable
fun CaptureButton(onClick: () -> Unit) {
    Button(onClick = onClick)
    {Text("Capture Content")}
}

Java

private final ActivityResultLauncher<Intent> startForResult = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
            Uri uri = result.getData() != null ? result.getData().getData() : null;
            // Use the URI to paste the captured content into the note.
        }
    });

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button captureButton = findViewById(R.id.capture_button);

    captureButton.setOnClickListener(
        view -> {
            Log.i("ContentCapture", "Launching intent...");
            startForResult.launch(new Intent(ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE));
        });
}

Tu app debe controlar todos los códigos de resultado:

Cuando la captura de contenido se realice correctamente, pega la imagen capturada en la nota, por ejemplo:

Kotlin

registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
    result: ActivityResult ->
        if (result.resultCode == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
            val uri = result.data?data
            // Use the URI to paste the captured content into the note.
        }
}

Java

registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
            Uri uri = result.getData() != null ? result.getData().getData() : null;
            // Use the URI to paste the captured content into the note.
        }
    });

La función de captura de contenido debe exponerse a través de una indicación de IU solo cuando tu app para tomar notas se ejecuta en una ventana flotante, no cuando se ejecuta en pantalla completa desde la pantalla de bloqueo del dispositivo. (Los usuarios pueden tomar capturas de pantalla de la app para tomar notas con las funciones de captura de pantalla del dispositivo).

Para determinar si tu app está en una ventana flotante (o una burbuja), llama a los siguientes métodos:

  • isLaunchedFromBubble() para verificar que tu app para tomar notas no se haya iniciado en pantalla completa desde la pantalla de bloqueo del dispositivo
  • isRoleHeld(RoleManager.ROLE_NOTES) para verificar que tu app es la predeterminada para tomar notas (se puede ejecutar en una conversación o en otro tipo de burbuja si no tiene la función de notas)

Recursos adicionales