메모 앱 만들기

메모는 대형 화면 기기에서 사용자 생산성을 향상시키는 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): 앱이 기본 메모 작성 앱인지 확인합니다. 앱이 메모 역할을 하지 않는 경우 대화 또는 다른 유형의 대화창에서 앱을 실행할 수 있습니다.

추가 리소스