Conserver la visibilité de votre application sur Wear

Wear OS gère automatiquement le passage en mode économie d'énergie pour une application active lorsqu'un utilisateur n'utilise plus sa montre. Il s'agit du mode Veille du système. Si l'utilisateur interagit de nouveau avec la montre dans un certain délai, Wear OS lui permet de revenir à l'application qu'il a quittée.

Dans des cas d'utilisation spécifiques, par exemple lorsqu'un utilisateur souhaite consulter sa fréquence cardiaque et son allure pendant une course, vous pouvez également contrôler le contenu affiché en mode économie d'énergie (mode Veille). Les applications Wear OS qui s'exécutent en mode Veille et en mode interactif sont les applications toujours activées.

Rendre une application constamment visible a un impact sur l'autonomie de la batterie. Par conséquent, tenez-en compte lorsque vous ajoutez cette fonctionnalité à votre application.

Configurer votre projet

Pour prendre en charge le mode Veille, procédez comme suit :

  1. Créez ou mettez à jour votre projet en fonction des configurations de la page Créer et exécuter une appli connectée.
  2. Ajoutez l'autorisation WAKE_LOCK au fichier manifeste Android :
<uses-permission android:name="android.permission.WAKE_LOCK" />

Mode Veille avec la classe "AmbientModeSupport"

Pour utiliser la classe AmbientModeSupport, procédez comme suit :

  1. Créez une sous-classe d' FragmentActivity ou l'une de ses sous-classes.
  2. Implémentez l'interface AmbientCallbackProvider, comme dans l'exemple suivant. Ignorez la méthode getAmbientCallback() pour fournir les rappels nécessaires permettant de réagir aux événements de veille du système Android. Vous créerez la classe de rappel personnalisée ultérieurement.

    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();
        }
        ...
    }
    
  3. Dans la méthode onCreate(), activez le mode Veille en appelant AmbientModeSupport.attach(FragmentActivity). Cette méthode renvoie un AmbientModeSupport.AmbientController. Le contrôleur vous permet de vérifier l'état de veille en dehors des rappels. Vous pouvez conserver une référence à l'objet 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);
        }
        ...
    }
    
  4. Créez une classe interne qui étend la classe AmbientCallback afin d'agir sur les événements de veille. Cette classe deviendra l'objet renvoyé par la méthode que vous avez créée à l'étape 2, comme illustré dans l'exemple suivant :

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

Consultez l'exemple AlwaysOnKotlin sur GitHub pour en savoir plus et découvrir les bonnes pratiques.

Mode Veille avec la classe "WearableActivity"

Pour les nouveaux projets et les projets existants, vous pouvez ajouter une prise en charge du mode Veille à votre application Wear en mettant à jour la configuration de votre projet.

Créer une activité compatible avec le mode Veille

Vous pouvez activer le mode Veille dans votre activité à l'aide de la classe WearableActivity comme suit :

  1. Créez une activité qui étend WearableActivity.
  2. Dans la méthode onCreate() de votre activité, appelez la méthode setAmbientEnabled().

L'extrait de code suivant montre comment activer le mode Veille dans une activité :

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

Gérer les transitions entre les modes

Si l'utilisateur n'interagit pas avec votre application pendant un certain temps, alors que celle-ci est affichée, ou si l'écran est recouvert, le système fait passer l'activité en mode Veille.

Une fois que l'application passe en mode Veille, mettez à jour l'interface utilisateur des activités avec une mise en page plus basique afin de réduire la consommation d'énergie. Utilisez un arrière-plan noir avec un minimum d'éléments graphiques et de textes blancs.

Pour faciliter la transition du mode interactif au mode Veille, essayez de conserver une disposition similaire des éléments à l'écran.

Remarque : En mode Veille, désactivez tous les éléments interactifs à l'écran, tels que les boutons.

Lorsque l'activité passe en mode Veille, le système appelle la méthode onEnterAmbient() de votre rappel de veille. L'extrait de code suivant indique comment changer la couleur du texte en blanc et désactiver l'anticrénelage après le passage du système en mode Veille :

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

Lorsque l'utilisateur appuie sur l'écran ou lève son poignet, l'activité repasse du mode Veille au mode interactif. Le système appelle la méthode onExitAmbient(). Ignorez cette méthode pour actualiser la mise en page de l'interface utilisateur afin que votre application s'affiche en couleur et passe en mode interactif.

L'extrait de code suivant indique comment changer la couleur du texte en vert et activer l'anticrénelage après le passage du système en mode interactif :

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

Actualiser le contenu en mode Veille

Le mode Veille vous permet d'actualiser l'écran avec de nouvelles informations pour l'utilisateur, mais vous devez trouver le juste équilibre entre l'actualisation de l'affichage et l'autonomie de la batterie. En mode Veille, actualisez l'écran une fois par minute maximum.

Pour actualiser le contenu de l'application, ignorez la méthode onUpdateAmbient() dans le rappel de veille :

Kotlin

override fun onUpdateAmbient() {
    super.onUpdateAmbient()
    // Update the content
}

Java

@Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();
    // Update the content
}

Il est déconseillé d'actualiser une application Wear OS en mode Veille plus d'une fois par minute. Pour les applications qui nécessitent des actualisations plus fréquentes, utilisez un objet AlarmManager afin d'activer le processeur et d'actualiser l'écran plus fréquemment.

Pour implémenter une alarme qui actualise le contenu plus fréquemment en mode Veille, procédez comme suit :

  1. Préparez le gestionnaire d'alarmes.
  2. Définissez la fréquence des actualisations.
  3. Vérifiez si l'appareil est actuellement en mode Veille et programmez la prochaine actualisation lorsque l'activité passera en mode Veille.
  4. Annulez l'alarme lorsque l'activité passe en mode interactif ou lorsque l'activité est arrêtée.

Remarque : Le gestionnaire d'alarmes peut créer des instances de votre activité à mesure qu'elles sont déclenchées. Pour éviter ce comportement, déclarez votre activité à l'aide du paramètre android:launchMode="singleInstance" dans le fichier manifeste.

Les sections suivantes décrivent ces étapes en détail.

Préparer le gestionnaire d'alarmes

Le gestionnaire d'alarmes lance un PendingIntent qui actualise l'écran et planifie l'alarme suivante. L'exemple suivant montre comment déclarer le gestionnaire d'alarmes et l'intent en attente dans la méthode onCreate() de votre activité :

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

Enregistrez et annulez l'enregistrement du broadcast receiver à l'aide de onResume() et de 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);
    ...
}
Actualiser l'écran et planifier des mises à jour de données

Dans cet exemple d'activité, le gestionnaire d'alarmes se déclenche toutes les 20 secondes en mode Veille. Lorsque le minuteur se déclenche, l'alarme déclenche l'intent pour actualiser l'écran, puis définit le délai pour la prochaine actualisation.

L'exemple suivant montre comment actualiser les informations à l'écran et définir l'alarme pour la prochaine actualisation :

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
    }
}
Planifier la prochaine alarme

Planifiez l'alarme pour actualiser l'écran en ignorant les méthodes onEnterAmbient() et onUpdateAmbient(), comme illustré dans l'exemple suivant :

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

Remarque : Dans cet exemple, la méthode refreshDisplayAndSetNextUpdate() est appelée chaque fois que l'écran doit être actualisé. Pour d'autres exemples indiquant quand appeler cette méthode, consultez l'exemple AlwaysOnKotlin sur GitHub.

Annuler l'alarme

Lorsque l'appareil passe en mode interactif, annulez l'alarme dans la méthode onExitAmbient() :

Kotlin

override fun onExitAmbient() {
    super.onExitAmbient()

    ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent)
}

Java

@Override
public void onExitAmbient() {
    super.onExitAmbient();
    ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent);
}

Lorsque l'utilisateur quitte ou arrête votre activité, annulez l'alarme dans la méthode onDestroy()de votre activité :

Kotlin

override fun onDestroy() {
    ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent)
    super.onDestroy()
}

Java

@Override
public void onDestroy() {
    ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent);
    super.onDestroy();
}