Tạo ứng dụng ghi chú

Ghi chú là một chức năng cốt lõi của Android giúp tăng năng suất của người dùng trên các thiết bị có màn hình lớn. Với ứng dụng ghi chú, người dùng có thể viết và phác thảo trong một cửa sổ nổi hoặc trên toàn màn hình, ghi lại và chú thích nội dung trên màn hình, cũng như lưu ghi chú để xem lại và sửa đổi sau.

Người dùng có thể truy cập vào ứng dụng ghi chú từ màn hình khoá hoặc khi đang chạy các ứng dụng khác.

Tính năng hỗ trợ ghi chú bằng bút cảm ứng mang lại trải nghiệm ấn tượng cho người dùng.

Vai trò ghi chú

Vai trò RoleManager.ROLE_NOTES xác định các ứng dụng ghi chú và cấp quyền LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE cho chúng.

Để lấy vai trò ghi chú cho ứng dụng, hãy làm như sau:

  1. Gọi lệnh isRoleAvailable() để kiểm tra trạng thái của vai trò.
  2. Nếu có vai trò ghi chú, hãy gọi lệnh createRequestRoleIntent() để lấy ý định dành riêng cho ghi chú.
  3. Gọi lệnh startActivityForResult() với ý định ghi chú để nhắc người dùng cấp vai trò ghi chú cho ứng dụng của bạn.

Chỉ một ứng dụng có thể sở hữu vai trò ghi chú.

Ứng dụng sẽ mở ra để phản hồi thao tác theo ý định ACTION_CREATE_NOTE ngầm ẩn. Nếu được gọi từ màn hình khoá của thiết bị, ứng dụng sẽ mở ở chế độ toàn màn hình. Nếu được gọi trong khi màn hình ở chế độ mở khoá, ứng dụng sẽ mở trong một cửa sổ nổi.

Tệp kê khai ứng dụng

Để đủ điều kiện sử dụng vai trò ghi chú, ứng dụng của bạn phải đưa nội dung khai báo sau vào tệp kê khai ứng dụng:

<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>

Phần khai báo cho phép người dùng chỉ định vai trò ghi chú cho ứng dụng của bạn, đặt ứng dụng đó làm ứng dụng ghi chú mặc định:

  • ACTION_CREATE_NOTE đặt thao tác theo ý định mà ứng dụng của bạn phản hồi

  • showWhenLocked giúp người dùng truy cập vào ứng dụng của bạn từ màn hình khoá của thiết bị

  • turnScreenOn cho phép ứng dụng của bạn bật màn hình thiết bị khi ứng dụng đó chạy

Tính năng của ứng dụng

Một ứng dụng ghi chú khác biệt trên màn hình lớn bổ sung đầy đủ các chức năng ghi chú.

Hỗ trợ bút cảm ứng

Nếu được gọi khi ý định bổ sung EXTRA_USE_STYLUS_MODE được đặt thành true, ứng dụng của bạn sẽ mở một ghi chú chấp nhận phương thức nhập bằng bút cảm ứng (hoặc chạm bằng ngón tay).

Nếu ý định bổ sung được đặt thành false, ứng dụng đó sẽ mở một ghi chú chấp nhận phương thức nhập bằng bàn phím.

Truy cập vào màn hình khoá

Ứng dụng của bạn phải cung cấp một hoạt động ở chế độ toàn màn hình. Hoạt động này sẽ chạy khi ứng dụng đó được mở từ màn hình khoá của thiết bị.

Ứng dụng của bạn chỉ nên hiện các ghi chú trước đây nếu người dùng đã đồng ý (ở trạng thái thiết bị đã mở khoá) với điều đó. Nếu không, khi mở từ màn hình khoá, ứng dụng đó sẽ luôn tạo một ghi chú mới.

Bạn có thể dùng lệnh KeyguardManager#isKeyguardLocked() để kiểm tra xem ứng dụng của mình có được chạy từ màn hình khoá hay không. Để yêu cầu người dùng xác thực và mở khoá thiết bị, hãy gọi lệnh 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.
  }
});

Cửa sổ nổi

Đối với ghi chú theo ngữ cảnh, ứng dụng của bạn phải cung cấp một hoạt động. Hoạt động này sẽ mở trong cửa sổ nổi khi một ứng dụng khác đang chạy.

Ứng dụng của bạn phải hỗ trợ chế độ multi-instance để người dùng có thể tạo nhiều ghi chú trong nhiều cửa sổ nổi ngay cả khi chạy ứng dụng ghi chú ở chế độ toàn màn hình hoặc ở chế độ chia đôi màn hình.

Ghi lại nội dung

Ghi lại nội dung là một chức năng chính của ứng dụng ghi chú. Với chức năng này, người dùng có thể chụp ảnh màn hình phía sau cửa sổ nổi của ứng dụng ghi chú. Người dùng có thể ghi lại toàn bộ hoặc một phần màn hình, dán nội dung vào ghi chú và chú thích hoặc đánh dấu nội dung đã ghi.

Ứng dụng ghi chú của bạn phải cung cấp một thuộc tính tương tác trên giao diện người dùng giúp chạy ActivityResultLauncher do registerForActivityResult() tạo. Thao tác theo ý định ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE được cung cấp cho trình chạy một cách trực tiếp hoặc thông qua ActivityResultContract.

Một hoạt động của hệ thống sẽ ghi lại nội dung, lưu nội dung này trên thiết bị và trả về URI nội dung cho ứng dụng của bạn trong đối số gọi lại của registerForActivityResult().

Ví dụ sau đây sử dụng một hợp đồng StartActivityForResult chung:

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));
        });
}

Ứng dụng của bạn phải xử lý tất cả các mã kết quả:

Khi hệ thống ghi xong nội dung, hãy dán hình ảnh đã chụp vào ghi chú, ví dụ:

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.
        }
    });

Tính năng ghi lại nội dung chỉ nên hiển thị thông qua một thuộc tính tương tác trên giao diện người dùng khi ứng dụng ghi chú của bạn đang chạy trong một cửa sổ nổi, chứ không phải khi chạy ở chế độ toàn màn hình, được chạy từ màn hình khoá của thiết bị. (Người dùng có thể chụp ảnh màn hình của chính ứng dụng ghi chú bằng chức năng chụp ảnh màn hình trên thiết bị.)

Để xác định xem ứng dụng của bạn có đang ở cửa sổ nổi (hoặc bong bóng trò chuyện) hay không, hãy gọi các phương thức sau:

  • isLaunchedFromBubble() để kiểm tra nhằm đảm bảo rằng ứng dụng ghi chú của bạn không được chạy ở chế độ toàn màn hình từ màn hình khoá của thiết bị
  • isRoleHeld(RoleManager.ROLE_NOTES) để xác minh rằng ứng dụng của bạn là ứng dụng ghi chú mặc định (ứng dụng đó có thể chạy trong một cuộc trò chuyện hoặc loại bong bóng trò chuyện khác nếu không có vai trò ghi chú)

Tài nguyên khác