一部の Wear OS アプリは常にユーザーに表示されます。
Android バージョン 5.1 以降が搭載されている Wear OS デバイスでは、電池の消耗を抑えながらアプリをフォアグラウンドで実行し続けることができます。Wear OS アプリは、スマートウォッチが省電力モード(常に画面表示モード)になっている間、スマートウォッチの表示内容を制御できます。常に画面表示モードとインタラクティブ モードの両方で実行される Wear アプリを常時オンアプリと呼びます。
こうしたアプリにより、たとえばジョギング中のユーザーは、スマートウォッチで走行距離や経過時間を一目で確認できます。また、買い物リストを記録して、買い物中にそのリストのアイテムをすばやく確認することもできます。
アプリを常に表示すると電池寿命が短くなるため、そのような機能をアプリに追加する場合は電池寿命への影響について注意深く検討する必要があります。
重要: Android サポート ライブラリのバージョン 27.1.0 では、常に画面表示モードをサポートする新しい方法(WearableActivity
クラスではなく AmbientModeSupport
クラスを使用する方法)を使用できます。常に画面表示モードをサポートする新たな方法(推奨)を使用するか、WearableActivity クラスを拡張するかを選択できます。
注: AmbientMode
は非推奨クラスとなっており、AmbientModeSupport
クラスに置き換えられています。
以下の関連リソースもご覧ください。
プロジェクトを設定する
常に画面表示モードをサポートするには、Android SDK を更新し、開発プロジェクトを設定する必要があります。必要な変更を行う手順は次のとおりです。
- ウェアラブル アプリの作成と実行ページの設定に基づいて、プロジェクトを作成または更新します。
WAKE_LOCK
権限を Android マニフェスト ファイルに追加します。
<uses-permission android:name="android.permission.WAKE_LOCK" />
AmbientModeSupport クラスを使用した常に画面表示モード
常に画面表示モードをサポートするために AmbientModeSupport
クラスを使用すると、以下によるメリットが得られます。
-
FragmentActivity
などの Android サポート ライブラリのActivity
サブクラス(フラグメント機能を使用可能) - ライフサイクルに対応したアーキテクチャ コンポーネント
- Google ログインのサポート強化
AmbientModeSupport
クラスを使用するには、FragmentActivity
サブクラスのいずれかまたは FragmentActivity 自体を拡張し、プロバイダ インターフェースを実装します。このインターフェースを使用すると、常に画面表示モードのアップデートをリッスンできるようになります。
注: AmbientModeSupport.attach(FragmentActivity)
メソッドは、指定の FragmentActivity
クラスまたはサブクラスにヘッドレス フラグメントをアタッチします。その後で FragmentManager.getFragments()
を呼び出すと、このフラグメントへの参照が返されます(この参照をなんらかの方法で使用することを意図したものではありません)。
以下に、AmbientModeSupport
クラスの一般的な使用方法を示します。
-
FragmentActivity
クラスのいずれかのサブクラスを作成します。 -
以下の例のように
AmbientCallbackProvider
インターフェースを実装します。Android システムからの常に画面表示イベントに対応するのに必要なコールバックを提供するようにgetAmbientCallback()
メソッドをオーバーライドします。ステップ 4 では、カスタムのコールバック クラスを作成します。Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { … override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = MyAmbientCallback() … }
Java
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) } ... }
Java
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 } }
Java
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 } }
詳細とおすすめの方法については、AlwaysOn のサンプルをご覧ください。
WearableActivity クラスを使用した常に画面表示モード
新規と既存のどちらのプロジェクトでも、プロジェクトの設定を更新することによって Wear アプリに対する常に画面表示モードのサポートを強化できます。
常に画面表示モードをサポートするアクティビティを作成する
WearableActivity
クラスを使用することで、アクティビティ内で常に画面表示モードを有効にすることができます。
-
WearableActivity
を拡張するアクティビティを作成します。 -
アクティビティの
onCreate()
メソッド内で、setAmbientEnabled()
メソッドを呼び出します。
以下のように、アクティビティ内で常に画面表示モードを有効にします。
Kotlin
class MainActivity : WearableActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ... } }
Java
public class MainActivity extends WearableActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ... }
モードの遷移に対処する
アプリが表示されている間にユーザーがしばらくアプリを操作しなかった場合や、ユーザーが画面を手のひらで覆った場合、システムによってアクティビティが常に画面表示モードに切り替えられます。アプリが常に画面表示モードに切り替わったら、アクティビティの UI をより基本的なレイアウトに変更して消費電力を削減します。黒色の背景を使用し、白色のグラフィックとテキストを最小限に抑えます。インタラクティブ モードから常に画面表示モードに簡単に遷移できるようにするには、画面上のアイテムの配置がほぼ同じになるようにします。常に画面表示モードにおけるコンテンツの表示について詳しくは、Wear OS 向けウォッチフェイスの設計ガイドをご覧ください。
ハードウェア ボタンがないデバイスでアプリを実行している場合、画面を手のひらで覆ってもアプリは常に画面表示モードに切り替わりません。その代わり、アプリが終了してホーム画面が表示されます。この動作は、ユーザーがアプリをスムーズに終了できるようにすることを目的としています。ただし、このようなデバイスでも、画面がタイムアウトしたときには常に画面表示モードに切り替わります。
注: 常に画面表示モードでは、画面上のインタラクティブな要素(ボタンなど)をすべて無効にしてください。常時オンアプリのユーザー操作を設計する方法について詳しくは、Wear OS 向けのアプリ構造の設計ガイドをご覧ください。
アクティビティが常に画面表示モードに切り替わると、システムによって onEnterAmbient()
メソッドがウェアラブル アクティビティ内で呼び出されます。次のコード スニペットは、システムによって常に画面表示モードに切り替えられた後にテキストの色を白に変更し、アンチ エイリアスを無効にする方法を示しています。
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) stateTextView.setTextColor(Color.WHITE) stateTextView.paint.isAntiAlias = false }
Java
@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 }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); stateTextView.setTextColor(Color.GREEN); stateTextView.getPaint().setAntiAlias(true); }
常に画面表示モードでコンテンツを更新する
常に画面表示モードでは、ユーザーの新しい情報で画面を更新できますが、表示の更新と電池寿命のバランスを慎重に取る必要があります。常に画面表示モードでは、画面の更新を 1 分に 1 回にするように
onUpdateAmbient()
メソッドをオーバーライドすることを強くおすすめします。更新頻度を上げる必要がある場合は、電池寿命と更新頻度の間にトレードオフがあることを考慮します。電池の消耗を抑えるためには、更新頻度を 10 秒に 1 回以下にする必要があります。ただし実際には、更新頻度をさらに下げる必要があります。
1 分に 1 回更新する
電池の消耗を抑えるためには、ほとんどの Wear アプリで常に画面表示モードの間、画面の更新頻度を下げる必要があります。このモードでは、画面の更新頻度を 1 分に 1 回にするようにアプリを設計することをおすすめします。システムに用意されているコールバック メソッド onUpdateAmbient()
を使用すると、この推奨頻度で画面を更新できます。
アプリのコンテンツを更新するには、ウェアラブル アクティビティ内で onUpdateAmbient()
メソッドをオーバーライドします。
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
Java
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
更新頻度を上げる
常に画面表示モードでの Wear アプリの更新頻度を 1 分に 1 回より上げることは可能ですが、推奨されません。頻繁に更新する必要があるアプリでは、AlarmManager
オブジェクトを使用してプロセッサを復帰させ、画面を頻繁に更新できます。
常に画面表示モードでコンテンツをより頻繁に更新するアラームを実装する手順を以下に示します。
- アラーム マネージャーを準備します。
- 更新頻度を設定します。
- アクティビティが常に画面表示モードに切り替わったとき、または、アクティビティが常に画面表示モードのときに、次回の更新のスケジュールを設定します。
- アクティビティがインタラクティブ モードに切り替わったとき、または、アクティビティが停止したときに、アラームをキャンセルします。
注: アラーム マネージャーは、アクティビティの新しいインスタンスの作成とトリガーを同時に行うことがあります。このような状況が発生しないようにするには、マニフェストで android:launchMode="singleInstance"
パラメータを使用してアクティビティを宣言します。
以下のセクションで、この手順について詳しく説明します。
アラーム マネージャーを準備する
アラーム マネージャーは、画面を更新して次回のアラームのスケジュールを設定するペンディング インテントを開始します。次の例は、アクティビティの 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() } } ... }
Java
// 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()
でブロードキャスト レシーバの登録と登録解除を行う必要があります。
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) }
Java
@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 } }
Java
// 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() }
Java
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); refreshDisplayAndSetNextUpdate(); } @Override public void onUpdateAmbient() { super.onUpdateAmbient(); refreshDisplayAndSetNextUpdate(); }
注: この例では、画面の更新が必要なときに refreshDisplayAndSetNextUpdate()
メソッドが呼び出されます。このメソッドを呼び出すタイミングの詳細な例については、AlwaysOn のサンプルをご覧ください。
アラームをキャンセルする
デバイスがインタラクティブ モードに切り替わったら、onExitAmbient()
メソッドでアラームをキャンセルします。
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
ユーザーがアクティビティを終了または停止したら、アクティビティの onDestroy()
メソッドでアラームをキャンセルします。
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
Java
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }
下位互換性を維持する
常に画面表示モードをサポートするアクティビティは、Android のバージョンが 5.1(API レベル 22)より前の Wear デバイスでは、自動的に通常のアクティビティに戻されます。これらのバージョンの Android では、デバイスのサポートのために特別なアプリコードは必要ありません。デバイスが常に画面表示モードに切り替わるとホーム画面に戻り、アクティビティが終了します。
Android のバージョンが 5.1 より前のデバイスでアプリのインストールまたは更新を行うことができない場合は、以下を使用してマニフェストを更新します。
<uses-library android:name="com.google.android.wearable" android:required="true" />