Wear OS는 사용자가 시계를 더 이상 사용하지 않을 때 활성 상태 앱의 저전력 모드 전환을 자동으로 처리합니다. 이를 시스템 대기 모드라고 합니다. 사용자가 특정 시간 내에 시계와 다시 상호작용하면 Wear OS는 사용자가 중단한 앱을 다시 표시합니다.
특정 사용 사례(예: 사용자가 달리기 중에 심박수와 속도를 확인하고자 함)에서는 저전력 대기 모드에서 표시되는 항목을 제어할 수도 있습니다. 대기 모드와 대화형 모드에서 모두 실행되는 Wear OS 앱을 상시 사용 설정 앱이라고 합니다.
앱이 계속 표시되도록 하면 배터리 수명에 영향을 미치므로 앱에 이 기능을 추가할 때는 이러한 영향을 고려하세요.
프로젝트 구성
대기 모드를 지원하려면 다음 단계를 따르세요.
- 웨어러블 앱을 만들고 실행 페이지의 구성을 기준으로 프로젝트를 만들거나 업데이트합니다.
- Android 매니페스트 파일에
WAKE_LOCK
권한을 추가합니다.
<uses-permission android:name="android.permission.WAKE_LOCK" />
AmbientModeSupport 클래스를 사용한 대기 모드
AmbientModeSupport
클래스를 사용하려면 다음 단계를 따르세요.
-
FragmentActivity
의 서브클래스 또는 서브클래스 중 하나를 만듭니다. -
다음 예와 같이
AmbientCallbackProvider
인터페이스를 구현합니다.getAmbientCallback()
메서드를 재정의하여 Android 시스템의 대기 이벤트에 반응하는 데 필요한 콜백을 제공합니다. 이후 단계에서 맞춤 콜백 클래스를 만듭니다.Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { ... override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = MyAmbientCallback() ... }
자바
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { ... @Override public AmbientModeSupport.AmbientCallback getAmbientCallback() { return new MyAmbientCallback(); } ... }
-
onCreate()
메서드에서AmbientModeSupport.attach(FragmentActivity)
를 호출하여 대기 모드를 사용 설정합니다. 이 메서드는AmbientModeSupport.AmbientController
를 반환합니다. 컨트롤러를 사용하면 콜백 외부에서 대기 상태를 확인할 수 있습니다.AmbientModeSupport.AmbientController
객체 참조를 유지하는 것이 좋습니다.Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private lateinit var ambientController: AmbientModeSupport.AmbientController ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ... ambientController = AmbientModeSupport.attach(this) } ... }
자바
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private AmbientModeSupport.AmbientController ambientController; ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... ambientController = AmbientModeSupport.attach(this); } ... }
-
대기 이벤트를 처리하기 위해
AmbientCallback
클래스를 확장하는 내부 클래스를 만듭니다. 이 클래스는 다음 예와 같이 2단계에서 만든 메서드에서 반환된 객체가 됩니다.Kotlin
private class MyAmbientCallback : AmbientModeSupport.AmbientCallback() { override fun onEnterAmbient(ambientDetails: Bundle?) { // Handle entering ambient mode } override fun onExitAmbient() { // Handle exiting ambient mode } override fun onUpdateAmbient() { // Update the content } }
자바
private class MyAmbientCallback extends AmbientModeSupport.AmbientCallback { @Override public void onEnterAmbient(Bundle ambientDetails) { // Handle entering ambient mode } @Override public void onExitAmbient() { // Handle exiting ambient mode } @Override public void onUpdateAmbient() { // Update the content } }
자세한 내용과 권장사항은 GitHub의 AlwaysOnKotlin 샘플을 참고하세요.
WearableActivity 클래스를 사용한 대기 모드
신규 및 기존 프로젝트의 경우, 프로젝트 구성을 업데이트하여 Wear 앱에 대기 모드 지원을 추가할 수 있습니다.
대기 모드를 지원하는 활동 만들기
다음과 같이
WearableActivity
클래스를 사용하여 활동에서 대기 모드를 사용 설정할 수 있습니다.
-
WearableActivity
를 확장하는 활동을 생성합니다. -
활동의
onCreate()
메서드에서setAmbientEnabled()
메서드를 호출합니다.
다음 스니펫은 활동에서 대기 모드를 사용 설정하는 방법을 보여줍니다.
Kotlin
class MainActivity : WearableActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ... } }
자바
public class MainActivity extends WearableActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ... }
모드 간 전환 처리
사용자가 앱이 표시되는 동안 일정 시간 앱과 상호작용하지 않거나, 화면이 가려진 경우 시스템은 활동을 대기 모드로 전환합니다.
앱이 대기 모드로 전환되면, 활동 UI를 보다 기본적인 레이아웃으로 업데이트하여 전력 소비를 줄이세요. 흰색 그래픽과 텍스트가 최소한으로 들어간 검은색 배경을 사용하세요.
대화형 모드에서 대기 모드로 쉽게 전환하려면 화면에서 항목 배치를 유사하게 유지합니다.
참고: 대기 모드에서는 버튼과 같은 화면의 대화형 요소를 중지합니다.
활동이 대기 모드로 전환되면 시스템은 대기 콜백의
onEnterAmbient()
메서드를 호출합니다. 다음 코드 스니펫은 시스템이 대기 모드로 전환된 후 텍스트 색상을 흰색으로 변경하고 앤티앨리어싱을 중지하는 방법을 보여줍니다.
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) stateTextView.setTextColor(Color.WHITE) stateTextView.paint.isAntiAlias = false }
자바
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); stateTextView.setTextColor(Color.WHITE); stateTextView.getPaint().setAntiAlias(false); }
사용자가 화면을 탭하거나 손목을 위로 올리면 활동이 대기 모드에서 대화형 모드로 전환됩니다. 시스템에서
onExitAmbient()
메서드를 호출합니다. 이 메서드를 재정의하여 앱이 대화형 풀 컬러 상태로 표시되도록 UI 레이아웃을 업데이트합니다.
다음 코드 스니펫은 시스템이 대화형 모드로 전환될 때 텍스트 색상을 녹색으로 변경하고 앤티앨리어싱을 사용 설정하는 방법을 보여줍니다.
Kotlin
override fun onExitAmbient() { super.onExitAmbient() stateTextView.setTextColor(Color.GREEN) stateTextView.paint.isAntiAlias = true }
자바
@Override public void onExitAmbient() { super.onExitAmbient(); stateTextView.setTextColor(Color.GREEN); stateTextView.getPaint().setAntiAlias(true); }
대기 모드의 콘텐츠 업데이트
대기 모드에서는 화면을 새로운 사용자 정보로 업데이트할 수 있지만, 화면 업데이트와 배터리 수명 간에 적절한 균형을 유지해야 합니다. 대기 모드에서는 1분 이상의 주기로 화면을 업데이트하는 것이 좋습니다.
앱 콘텐츠를 업데이트하려면 대기 콜백에서
onUpdateAmbient()
메서드를 재정의합니다.
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
자바
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
대기 모드의 Wear OS 앱은 1분에 한 번 이상 업데이트하지 않는 것이 좋습니다. 더 자주 업데이트해야 하는 앱의 경우 AlarmManager
객체를 사용하여 프로세서의 절전 모드를 해제하고 화면을 더 자주 업데이트합니다.
대기 모드에서 콘텐츠를 더 자주 업데이트하는 알람을 구현하려면 다음 단계를 따르세요.
- 알람 관리자를 준비합니다.
- 업데이트 빈도를 설정합니다.
- 기기가 현재 대기 모드에 있는지 확인하고 활동이 대기 모드로 전환될 때 다음 업데이트를 예약합니다.
- 활동이 대화형 모드로 전환되거나 활동이 중지되면 알람을 취소합니다.
참고: 알람 관리자가 트리거되면 활동의 새 인스턴스를 만들 수도 있습니다. 이 동작을 방지하려면 매니페스트에서 android:launchMode="singleInstance"
매개변수를 사용하여 활동을 선언하세요.
다음 섹션에서 각 단계를 자세히 설명합니다.
알람 관리자 준비
알람 관리자는 화면을 업데이트하고 다음 알람을 예약하는 PendingIntent
를 실행합니다. 다음 예에서는 활동의 onCreate()
메서드에서 알람 관리자 및 대기 중인 인텐트를 선언하는 방법을 보여줍니다.
Kotlin
// Action for updating the display in ambient mode, per our custom refresh cycle private const val AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE" ... private lateinit var ambientUpdateAlarmManager: AlarmManager private lateinit var ambientUpdatePendingIntent: PendingIntent private lateinit var ambientUpdateBroadcastReceiver: BroadcastReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ambientUpdateAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager ambientUpdatePendingIntent = Intent(AMBIENT_UPDATE_ACTION).let { ambientUpdateIntent -> PendingIntent.getBroadcast(this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT) } ambientUpdateBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { refreshDisplayAndSetNextUpdate() } } ... }
자바
// Action for updating the display in ambient mode, per our custom refresh cycle private static final String AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE"; private AlarmManager ambientUpdateAlarmManager; private PendingIntent ambientUpdatePendingIntent; private BroadcastReceiver ambientUpdateBroadcastReceiver; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ambientUpdateAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent ambientUpdateIntent = new Intent(AMBIENT_UPDATE_ACTION); ambientUpdatePendingIntent = PendingIntent.getBroadcast( this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT); ambientUpdateBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { refreshDisplayAndSetNextUpdate(); } }; ... }
onResume()
및 onPause()
를 사용하여 broadcast receiver를 등록 및 등록 취소합니다.
Kotlin
override fun onResume() { super.onResume() IntentFilter(AMBIENT_UPDATE_ACTION).also { filter -> registerReceiver(ambientUpdateBroadcastReceiver, filter) } } override fun onPause() { super.onPause() unregisterReceiver(ambientUpdateBroadcastReceiver) ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
자바
@Override public void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(AMBIENT_UPDATE_ACTION); registerReceiver(ambientUpdateBroadcastReceiver, filter); ... } @Override public void onPause() { super.onPause(); unregisterReceiver(ambientUpdateBroadcastReceiver); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); ... }
화면 업데이트 및 데이터 업데이트 일정 예약
이 활동 예에서는 알람 관리자가 대기 모드에서 20초마다 트리거됩니다. 타이머가 소리를 내면 알람이 화면 업데이트 인텐트를 트리거한 후 다음 업데이트에 관한 지연을 설정합니다.
다음 예에서는 화면의 정보를 업데이트하고 다음 업데이트에 관한 알람을 설정하는 방법을 보여줍니다.
Kotlin
// Milliseconds between waking processor/screen for updates private val AMBIENT_INTERVAL_MS: Long = TimeUnit.SECONDS.toMillis(20) ... private fun refreshDisplayAndSetNextUpdate() { if (isAmbient) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } val timeMs: Long = System.currentTimeMillis() // Schedule a new alarm if (isAmbient) { // Calculate the next trigger time val delayMs: Long = AMBIENT_INTERVAL_MS - timeMs % AMBIENT_INTERVAL_MS val triggerTimeMs: Long = timeMs + delayMs ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent) } else { // Calculate the next trigger time for interactive mode } }
자바
// Milliseconds between waking processor/screen for updates private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20); private void refreshDisplayAndSetNextUpdate() { if (isAmbient()) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } long timeMs = System.currentTimeMillis(); // Schedule a new alarm if (isAmbient()) { // Calculate the next trigger time long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS); long triggerTimeMs = timeMs + delayMs; ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent); } else { // Calculate the next trigger time for interactive mode } }
다음 알람 일정 예약
다음 샘플과 같이 onEnterAmbient()
메서드와 onUpdateAmbient()
메서드를 재정의하여 화면을 업데이트하도록 알람 일정을 예약합니다.
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) refreshDisplayAndSetNextUpdate() } override fun onUpdateAmbient() { super.onUpdateAmbient() refreshDisplayAndSetNextUpdate() }
자바
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); refreshDisplayAndSetNextUpdate(); } @Override public void onUpdateAmbient() { super.onUpdateAmbient(); refreshDisplayAndSetNextUpdate(); }
참고: 이 예에서는 화면을 업데이트해야 할 때마다 refreshDisplayAndSetNextUpdate()
메서드가 호출됩니다. 이 메서드를 호출하는 시기에 관한 더 많은 예는 GitHub의
AlwaysOnKotlin 샘플을 참고하세요.
알람 취소
기기가 대화형 모드로 전환되면 onExitAmbient()
메서드에서 알람을 취소합니다.
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
자바
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
사용자가 활동을 종료하거나 중지하면 활동의 onDestroy()
메서드에서 알람을 취소합니다.
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
자바
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }