메모 앱 만들기

메모는 대형 화면 기기에서 사용자 생산성을 향상시키는 Android의 핵심 기능입니다. 메모 작성 앱을 사용하면 사용자가 플로팅 창이나 전체 화면에서 글을 쓰고 스케치할 수 있으며, 화면 콘텐츠를 캡처하여 주석을 달 수 있으며, 나중에 검토 및 수정할 수 있도록 메모를 저장할 수 있습니다.

사용자는 잠금 화면에서 또는 다른 앱을 실행하는 동안 메모 앱에 액세스할 수 있습니다.

메모 작성에 스타일러스를 지원함으로써 탁월한 사용자 환경을 제공합니다.

메모 역할

RoleManager.ROLE_NOTES 역할은 메모 앱을 식별하고 앱에 LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE 권한을 부여합니다.

앱이 메모 역할을 획득하려면 다음 단계를 따르세요.

  1. isRoleAvailable()를 호출하여 역할의 상태를 확인합니다.
  2. 메모 역할을 사용할 수 있는 경우 createRequestRoleIntent()를 호출하여 메모 관련 인텐트를 가져옵니다.
  3. 사용자에게 앱에 메모 역할을 부여하라는 메시지를 표시하는 메모 인텐트로 startActivityForResult()를 호출합니다.

하나의 앱만 메모 역할을 받을 수 있습니다.

암시적 ACTION_CREATE_NOTE 인텐트 작업에 대한 응답으로 앱이 열립니다. 기기 잠금 화면에서 호출하면 앱이 전체 화면으로 열리고 화면이 잠금 해제된 상태에서 호출하면 플로팅 창에서 실행됩니다.

앱 매니페스트

메모 역할을 사용하려면 앱의 앱 매니페스트에 다음 선언이 포함되어야 합니다.

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

선언을 통해 사용자는 앱에 메모 역할을 할당하여 앱을 기본 메모 작성 애플리케이션으로 만들 수 있습니다.

  • ACTION_CREATE_NOTE는 앱이 응답하는 인텐트 작업을 설정합니다.

  • showWhenLocked를 사용하면 기기 잠금 화면에서 앱에 액세스할 수 있습니다.

  • turnScreenOn를 사용하면 앱이 실행될 때 앱에서 기기 화면을 켤 수 있습니다.

앱 기능

대형 화면 차별화 메모 작성 앱은 모든 메모 작성 기능을 제공합니다.

스타일러스 지원

앱이 true로 설정된 추가 EXTRA_USE_STYLUS_MODE 인텐트로 호출되면 스타일러스 (또는 손가락 터치) 입력을 허용하는 메모를 열어야 합니다.

추가 인텐트가 false로 설정된 경우 앱은 키보드 입력을 허용하는 메모를 열어야 합니다.

잠금 화면 액세스

앱은 기기 잠금 화면에서 열릴 때 실행되는 전체 화면 활동을 제공해야 합니다.

앱은 사용자가 이전 메모를 표시하는 데 동의한 경우 (잠금 해제된 기기 상태에서) 이전 메모만 표시해야 합니다. 그러지 않으면 잠금 화면에서 앱을 열 때 항상 새 메모를 만들어야 합니다.

KeyguardManager#isKeyguardLocked()를 사용하여 잠금 화면에서 앱이 실행되었는지 확인할 수 있습니다. 사용자에게 기기를 인증하고 잠금 해제하도록 요청하려면 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.
  }
});

플로팅 창

상황에 따라 메모 작성을 위해 앱은 다른 애플리케이션이 실행 중일 때 플로팅 창에서 열리는 활동을 제공해야 합니다.

메모 앱이 전체 화면 또는 화면 분할 모드로 실행되더라도 사용자가 여러 개의 플로팅 창에서 여러 개의 메모를 만들 수 있도록 앱에서 multi-instance 모드를 지원해야 합니다.

콘텐츠 캡처

콘텐츠 캡처는 메모 앱의 핵심 기능입니다. 사용자는 콘텐츠 캡처를 사용하여 메모 앱의 플로팅 창 뒤에 있는 디스플레이의 스크린샷을 찍을 수 있습니다. 사용자는 디스플레이의 전체 또는 일부를 캡처하여 메모에 붙여넣고 캡처된 콘텐츠에 주석을 달거나 강조표시할 수 있습니다.

메모 작성 앱은 registerForActivityResult()에서 만든 ActivityResultLauncher를 실행하는 UI 어포던스를 제공해야 합니다. ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE 인텐트 작업은 직접 또는 ActivityResultContract를 통해 런처에 제공됩니다.

시스템 활동이 콘텐츠를 캡처하여 기기에 저장하고 registerForActivityResult()의 콜백 인수에서 콘텐츠 URI를 앱에 반환합니다.

다음 예에서는 일반 StartActivityForResult 계약을 사용합니다.

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

앱은 모든 결과 코드를 처리해야 합니다.

콘텐츠 캡처에 성공하면 캡처된 이미지를 메모에 붙여넣습니다. 예를 들면 다음과 같습니다.

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

콘텐츠 캡처 기능은 메모 앱이 플로팅 창에서 실행 중일 때만(기기 잠금 화면에서 실행된 전체 화면을 실행할 때가 아님) UI 어포던스를 통해 노출되어야 합니다. (사용자는 기기 스크린샷 기능을 사용하여 메모 앱 자체의 스크린샷을 찍을 수 있습니다.)

앱이 플로팅 창 (또는 도움말 풍선)에 있는지 확인하려면 다음 메서드를 호출합니다.

  • isLaunchedFromBubble(): 메모 앱이 기기 잠금 화면에서 전체 화면으로 실행되지 않았는지 확인
  • isRoleHeld(RoleManager.ROLE_NOTES): 앱이 기본 메모 작성 앱인지 확인 (앱에 메모 역할이 없는 경우 대화 또는 다른 유형의 대화창에서 앱이 실행될 수 있음)

추가 리소스