Créer un visage de montre Android

L'une des fonctionnalités qui rend Android si spécial est la possibilité de personnaliser chaque aspect de l'expérience utilisateur. Lors du premier lancement d'Android Wear sur Google I / O 2014, de nombreux développeurs et utilisateurs ont découvert que cela n'était pas tout à fait le cas pour les montres intelligentes, car l'API officielle permettant de créer des faces de montre faisait nettement défaut. Étant donné que les utilisateurs souhaitaient créer des cadrans de montre personnalisés, il n’est donc pas surprenant que les développeurs aient découvert un moyen de créer leurs propres cadrans avec un piratage non documenté dans Android Wear.

Heureusement, Google a rapidement informé tout le monde qu'une API officielle était en route et qu'en décembre 2014, cette API a finalement été diffusée dans la communauté de développement. Dans cet article, vous allez découvrir l'API Watch Faces officielle pour Android Wear et mettre en place un cadran de montre numérique simple que vous pourrez développer pour vos propres besoins. L'implémentation des visages de surveillance peut être un peu prolixe, mais vous pouvez trouver un exemple d'application pour cet article sur GitHub..

1. Configurer votre IDE

La première chose à faire pour créer votre propre cadran de montre est de configurer votre projet dans Android Studio. Lors de la création de votre projet, sélectionnez Téléphone et tablette avec un SDK minimum de l'API 18 sous Android 4.3 est la version la plus basse du système d'exploitation prenant en charge les applications Android Wear fournies. Vous devrez également vérifier le Porter boîte avec un SDK minimum de l'API 21 sélectionné. Vous pouvez voir un exemple de ce que votre Périphériques Android cibles l'écran devrait ressembler.

Quand vous arrivez aux deux Ajouter une activité écrans, sélectionnez Ajouter aucune activité pour les deux écrans.

Une fois que vous cliquez terminer, votre environnement de projet doit construire et avoir un module pour mobile et un autre pour porter.

2. Création du service de surveillance de l'usure

Android Wear implémente les visages de montres grâce à l'utilisation de WatchFaceService. Dans cet article, vous allez créer une extension de la CanvasWatchFaceService classe, qui est une implémentation de WatchFaceService qui fournit également un Toile pour dessiner le cadran de votre montre. Commencez par créer une nouvelle classe Java sous le porter module dans Android Studio qui s'étend CanvasWatchFaceService.

Classe publique WatchFaceService étend CanvasWatchFaceService

Une fois que vous avez votre classe, vous allez avoir besoin de créer une classe interne, WatchFaceEngine dans les fichiers source de cet article, qui s'étend Moteur. C’est le moteur de la face de la montre qui gère les événements système, tels que l’extinction ou le passage de l’écran en mode ambiant..

classe privée WatchFaceEngine étend le moteur

Quand votre code de stub pour WatchFaceEngine est dans, revenir à la classe externe et substituer la onCreateEngine méthode pour retourner votre nouvelle classe interne. Ceci associera votre service de cadran de montre au code qui pilotera l’affichage..

@Override public Engine onCreateEngine () retour new WatchFaceEngine (); 

Une fois que vous avez mis en place le service de base, vous pouvez passer aux tâches d’entretien général consistant à mettre à jour votre AndroidManifest fichiers afin que votre service soit détectable par Android Wear. Gardez à l'esprit que votre code actuel ne fera rien pour le moment. Nous reviendrons dans cette classe et peaufinerons le moteur après avoir fait le ménage du projet..

3. Mise à jour des fichiers AndroidManifest

Ouvrez le AndroidManifest.xml déposer dans le porter module. Près du sommet, vous devriez déjà voir une ligne qui dit:

Au-dessous de cette ligne, nous devons ajouter les deux autorisations requises pour un cadran de surveillance. Ces conditions sont les suivantes:

 

Une fois vos autorisations définies, vous devrez ajouter un nœud pour votre service dans le répertoire. application noeud avec la permission de BIND_WALLPAPER, quelques ensembles de méta-données contenant des images de référence de votre cadran pour l’écran de sélection (dans cet exemple, nous utilisons simplement l’icône du lanceur), et un filtre d'intention faire savoir au système que votre service est destiné à l'affichage d'un cadran de montre.

        

Une fois votre porter le manifeste est complet, vous devrez ouvrir le AndroidManifest.xml déposer dans le mobile module et ajouter dans les deux autorisations que nous avons utilisées dans le porter module pour PROVIDE_BACKGROUND et VERROUILLAGE DE RÉVEIL, parce que Android Wear exige que les deux porter et mobile Les modules demandent les mêmes autorisations pour l'usure APK à installer sur la montre d'un utilisateur. Une fois les deux fichiers de manifeste remplis, vous pouvez revenir à CustomWatchFaceService.java pour commencer à implémenter le moteur.

4. Démarrer votre moteur

le Moteur L’objet associé à votre service est le moteur de votre montre. Il gère les minuteries, affiche votre interface utilisateur, active et désactive le mode ambiant et permet d'obtenir des informations sur l'affichage de la montre physique. En bref, c'est là que la magie opère.

Étape 1: Définition des valeurs et des variables nécessaires

La première chose que vous allez faire est d'implémenter un ensemble de variables membres dans votre moteur pour garder une trace des états des périphériques, des intervalles de minuterie et des attributs pour votre affichage..

// Variable de membre private Typeface WATCH_TEXT_TYPEFACE = Typeface.create (Typeface.SERIF, Typeface.NORMAL); int statique final final MSG_UPDATE_TIME_ID = 42; private long mUpdateRateMs = 1000; heure privée mDisplayTime; peinture privée mBackgroundColorPaint; peinture privée mTextColorPaint; boolean privé mHasTimeZoneReceiverBeenRegistered = false; boolean privé mIsInMuteMode; boIlean privé mIsLowBitAmbient; flottant privé mXOffset; flotteur privé mYOffset; private int mBackgroundColor = Color.parseColor ("noir"); private int mTextColor = Color.parseColor ("rouge");

Comme vous pouvez le voir, nous définissons le TypeFace que nous utiliserons pour le texte de notre montre numérique, ainsi que pour la couleur de fond et la couleur du texte du visage de la montre. le Temps l'objet est utilisé pour, vous l'aurez deviné, en gardant une trace de l'heure actuelle de l'appareil. mUpdateRateMs est utilisé pour contrôler une minuterie que nous devrons mettre en œuvre pour mettre à jour notre cadran de surveillance toutes les secondes (d'où la valeur de 1000 millisecondes pour mUpdateRateMs), parce que la norme WatchFaceService garde seulement la trace du temps par incréments d'une minute. mXOffset et MyOffset sont définis une fois que le moteur connaît la forme physique de la montre afin que le cadran de notre montre puisse être dessiné sans être trop proche du haut ou de la gauche de l’écran, ni coupé par un coin arrondi. Les trois valeurs booléennes permettent de suivre différents états de périphériques et d'applications..

Le prochain objet à définir est un récepteur de diffusion qui gère la situation dans laquelle un utilisateur peut se déplacer et changer de fuseau horaire. Ce récepteur efface simplement le fuseau horaire enregistré et réinitialise l'heure d'affichage.

BroadcastReceiver final mTimeZoneBroadcastReceiver = new BroadcastReceiver () @Override public void onReceive (contexte de contexte, intention de l’intention) mDisplayTime.clear (intent.getStringExtra ("zone horaire")); mDisplayTime.setToNow (); ;

Une fois votre récepteur défini, l’objet final que vous devrez créer en haut de votre moteur est un Gestionnaire to met à jour votre cadran de montre chaque seconde. Cela est nécessaire en raison des limites de WatchFaceService discuté ci-dessus. Si votre propre cadran ne doit être mis à jour que toutes les minutes, vous pouvez ignorer cette section en toute sécurité..

gestionnaire final privé mTimeHandler = nouveau gestionnaire () @Override public void handleMessage (Message msg) switch (msg.what) case MSG_UPDATE_TIME_ID: invalidate (); if (isVisible () &&! isInAmbientMode ()) long currentTimeMillis = System.currentTimeMillis (); long delay = mUpdateRateMs - (currentTimeMillis% mUpdateRateMs); mTimeHandler.sendEmptyMessageDelayed (MSG_UPDATE_TIME_ID, délai);  Pause; ;

La mise en œuvre de la Gestionnaire est assez simple. Il vérifie d'abord l'ID du message. Si correspond MSG_UPDATE_TIME_ID, il continue d'invalider la vue en cours pour le rafraîchir. Une fois la vue invalidée, le Gestionnaire vérifie si l'écran est visible et non en mode ambiant. S'il est visible, il envoie une demande de répétition une seconde plus tard. La raison pour laquelle nous ne faisons que répéter l'action dans le Gestionnaire Lorsque le cadran de la montre est visible et qu’il n’est pas en mode ambiant, la mise à jour à la seconde peut s’avérer lourde. Si l'utilisateur ne regarde pas l'écran, nous retombons simplement sur l'écran. WatchFaceService mise en œuvre qui met à jour chaque minute.

Étape 2: initialisation du moteur

Maintenant que vos variables et objets sont déclarés, il est temps d'initialiser le cadran. Moteur a un onCreate méthode qui devrait être utilisée pour créer des objets et d’autres tâches qui peuvent prendre beaucoup de temps et de batterie. Vous voudrez également définir quelques drapeaux pour la WatchFaceStyle ici pour contrôler la manière dont le système interagit avec l'utilisateur lorsque le cadran de la montre est actif.

@Override public void onCreate (titulaire SurfaceHolder) super.onCreate (titulaire); setWatchFaceStyle (nouvelle version de WatchFaceStyle.Builder (CustomWatchFaceService.this) .setBackgroundVisibility (WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE) mDisplayTime = new Time (); initBackground (); initDisplayText (); 

Pour l'exemple d'application, vous utiliserez setWatchFaceStyle pour définir l’arrière-plan de vos cartes de notification de manière à indiquer brièvement si le type de carte est défini comme interruptif. Vous définissez également le mode Peek afin que les cartes de notification occupent tout l'espace nécessaire..

Enfin, vous voudrez dire au système de ne pas afficher l'heure par défaut puisque vous l'afficherez vous-même. Bien que ce ne soient que quelques-unes des options disponibles, vous pouvez trouver encore plus d’informations dans la documentation officielle de la WatchFaceStyle.Builder objet.

Après votre WatchFaceStyle a été défini, vous pouvez initialiser mDisplayTime comme une nouvelle Temps objet.

initBackground et initDisplayText allouer les deux Peindre les objets que vous avez définis en haut du moteur. L'arrière-plan et le texte ont alors leur couleur définie et le texte a son type et sa taille de police, tout en activant l'anti-aliasing.

private void initBackground () mBackgroundColorPaint = new Paint (); mBackgroundColorPaint.setColor (mBackgroundColor);  void privé initDisplayText () mTextColorPaint = new Paint (); mTextColorPaint.setColor (mTextColor); mTextColorPaint.setTypeface (WATCH_TEXT_TYPEFACE); mTextColorPaint.setAntiAlias ​​(true); mTextColorPaint.setTextSize (getResources (). getDimension (R.dimen.text_size)); 

Étape 3: Gestion de l'état du périphérique

Ensuite, vous devez implémenter diverses méthodes à partir du Moteur classe qui sont déclenchés par des modifications de l'état du périphérique. Nous allons commencer par passer en revue les onVisibilityChanged méthode, qui est appelée lorsque l'utilisateur masque ou affiche le visage de la montre.

@Override public void onVisibilityChanged (booléen visible) super.onVisibilityChanged (visible); if (visible) if (! mHasTimeZoneReceiverBeenRegistered) IntentFilter filter = new IntentFilter (Intent.ACTION_TIMEZONE_CHANGED); CustomWatchFaceService.this.registerReceiver (mTimeZoneBroadcastReceiver, filtre); mHasTimeZoneReceiverBeenRegistered = true;  mDisplayTime.clear (TimeZone.getDefault (). getID ()); mDisplayTime.setToNow ();  else if (mHasTimeZoneReceiverBeenRegistered) CustomWatchFaceService.this.unregisterReceiver (mTimeZoneBroadcastReceiver); mHasTimeZoneReceiverBeenRegistered = false;  updateTimer (); 

Lorsque cette méthode est appelée, elle vérifie si le cadran de la montre est visible ou non. Si le cadran de la montre est visible, il semblerait que le BroadcastReceiver que vous avez défini en haut de la Moteur est enregistré. Si ce n’est pas le cas, la méthode crée un IntentionFilter pour le ACTION_TIMEZONE_CHANGED action et enregistre le BroadcastReceiver écouter.

Si le cadran de la montre n’est pas visible, cette méthode vérifiera si le BroadcastReceiver peut être non enregistré. Une fois la BroadcastReceiver a été manipulé, updateTimer est appelé à déclencher l'invalidation du cadran et redessiner le cadran. updateTimer arrête tout Gestionnaire les actions en attente et vérifie si une autre doit être envoyée.

void privé updateTimer () mTimeHandler.removeMessages (MSG_UPDATE_TIME_ID); if (isVisible () &&! isInAmbientMode ()) mTimeHandler.sendEmptyMessage (MSG_UPDATE_TIME_ID); 

Étape 4: Coopération avec le matériel portable

Lorsque votre service est associé à Android Wear, onApplyWindowInsets est appelé. Ceci est utilisé pour déterminer si le périphérique sur lequel tourne le cadran de votre montre est arrondi ou carré. Cela vous permet de changer le cadran de votre montre pour correspondre au matériel.

Lorsque cette méthode est appelée dans l'exemple d'application, cette méthode vérifie simplement la forme du périphérique et modifie le décalage x utilisé pour tracer le cadran de la montre afin de vous assurer que celui-ci est visible sur le périphérique..

@Override public void onApplyWindowInsets (WindowInsets insets) super.onApplyWindowInsets (insets); mYOffset = getResources (). getDimension (R.dimen.y_offset); if (insets.isRound ()) mXOffset = getResources (). getDimension (R.dimen.x_offset_round);  else mXOffset = getResources (). getDimension (R.dimen.x_offset_square); 

La prochaine méthode que vous devrez remplacer est onPropertiesChanged. Cette méthode est appelée lorsque les propriétés matérielles du périphérique Wear sont déterminées, par exemple si le périphérique prend en charge la protection de rodage ou le mode ambiant à faible débit..

Dans cette méthode, vous vérifiez si ces attributs s’appliquent au périphérique exécutant votre regard et les enregistrez dans une variable membre définie en haut de votre écran. Moteur.

@Override public void onPropertiesChanged (propriétés de l'ensemble) super.onPropertiesChanged (propriétés); if (properties.getBoolean (PROPERTY_BURN_IN_PROTECTION, false)) mIsLowBitAmbient = properties.getBoolean (PROPERTY_LOW_BIT_AMBIENT, false); 

Étape 5: Conservation de la batterie en modes ambiant et en sourdine

Après avoir traité les états initiaux du périphérique, vous souhaiterez implémenter onAmbientModeChanged et onInterruptionFilterChanged. Comme le nom l'indique, onAmbientModeChanged est appelé lorsque l'appareil entre ou sort du mode ambiant.

Si l'appareil est en mode ambiant, vous souhaiterez changer la couleur du cadran de votre montre en noir et blanc afin de prendre en compte la batterie de l'utilisateur. Lorsque l'appareil revient du mode ambiant, vous pouvez réinitialiser les couleurs de votre cadran. Vous voudrez également être attentif à l'anti-aliasing pour les périphériques qui demandent une prise en charge ambiante faible bit. Une fois que toutes les variables d'indicateur sont définies, vous pouvez provoquer l'invalidation et le redessinage du cadran de surveillance, puis vérifier si le minuteur d'une seconde doit démarrer..

@Override public void onAmbientModeChanged (booléen inAmbientMode) super.onAmbientModeChanged (inAmbientMode); if (inAmbientMode) mTextColorPaint.setColor (Color.parseColor ("blanc"));  else mTextColorPaint.setColor (Color.parseColor ("rouge"));  if (mIsLowBitAmbient) mTextColorPaint.setAntiAlias ​​(! inAmbientMode);  invalidate (); updateTimer (); 


onInterruptionFilterChanged est appelée lorsque l'utilisateur modifie manuellement les paramètres d'interruption de son portable. Dans ce cas, vous devrez vérifier si le périphérique est en mode sourdine, puis modifier l'interface utilisateur en conséquence. Dans ce cas, vous allez modifier la transparence du cadran de votre montre, régler votre Gestionnaire mettre à jour uniquement toutes les minutes si le périphérique est en mode sourdine, puis redessinez le cadran de votre montre.

@Override public null onInterruptionFilterChanged (int interruptionFilter) super.onInterruptionFilterChanged (interruptionFilter); boolean isDeviceMuted = (interruptionFilter == android.support.wearable.watchface.WatchFaceService.INTERRUPTION_FILTER_NONE); if (isDeviceMuted) mUpdateRateMs = TimeUnit.MINUTES.toMillis (1);  else mUpdateRateMs = DEFAULT_UPDATE_RATE_MS;  if (mIsInMuteMode! = isDeviceMuted) mIsInMuteMode = isDeviceMuted; int alpha = (isDeviceMuted)? 100: 255; mTextColorPaint.setAlpha (alpha); invalider(); updateTimer (); 

Lorsque votre appareil est en mode ambiant, le Gestionnaire la minuterie sera désactivée. Le cadran de votre montre peut toujours être mis à jour avec l’heure actuelle toutes les minutes à l’aide de la fonction intégrée. onTimeTick méthode pour invalider le Toile.

@Override public void onTimeTick () super.onTimeTick (); invalider(); 

Étape 6: Dessin du cadran

Une fois que toutes vos éventualités sont couvertes, il est temps de dessiner enfin le cadran de votre montre. CanvasWatchFaceService utilise une norme Toile objet, vous aurez donc besoin d'ajouter onDraw à ton Moteur et dessinez manuellement le cadran de votre montre.

Dans ce tutoriel, nous allons simplement dessiner une représentation textuelle de l’heure, bien que vous puissiez changer votre onDraw soutenir facilement un cadran de montre analogique. Dans cette méthode, vous voudrez vérifier que vous affichez l’heure correcte en mettant à jour votre Temps objet et ensuite vous pouvez commencer à appliquer votre cadran.

@Override public void onDraw (toile Canvas, limites Rect) super.onDraw (toile, limites); mDisplayTime.setToNow (); drawBackground (toile, limites); drawTimeText (canvas); 

dessiner applique une couleur unie à l'arrière-plan du dispositif d'usure.

private void drawBackground (toile Canvas, limites Rect) canvas.drawRect (0, 0, bounds.width (), bounds.height (), mBackgroundColorPaint); 

drawTimeText, cependant, crée le texte temporel qui sera affiché à l’aide de plusieurs méthodes d’aide, puis l’appliquera à la grille, aux points de décalage x et y que vous avez définis dans onApplyWindowInsets.

private void drawTimeText (Canevas) String timeText = getHourString () + ":" + String.format ("% 02d", mDisplayTime.minute); if (isInAmbientMode () || mIsInMuteMode) timeText + = (mDisplayTime.hour < 12 ) ? "AM" : "PM";  else  timeText += String.format( ":%02d", mDisplayTime.second);  canvas.drawText( timeText, mXOffset, mYOffset, mTextColorPaint );  private String getHourString()  if( mDisplayTime.hour % 12 == 0 ) return "12"; else if( mDisplayTime.hour <= 12 ) return String.valueOf( mDisplayTime.hour ); else return String.valueOf( mDisplayTime.hour - 12 ); 

Conclusion

Une fois que vous avez mis en œuvre les méthodes de dessin du cadran de votre montre, vous devez disposer des connaissances de base nécessaires pour créer et créer vos propres cadrans. La bonne chose à propos des visages de montres Android Wear est que c'est juste gratter la surface de ce qui est possible.

Vous pouvez ajouter des activités de configuration compagnon sur la montre ou sur le téléphone, remplacer le Toile montre basé sur une implémentation OpenGL, ou dérivez votre propre classe de WatchFaceService pour répondre à vos besoins.

Ajoutez à cela que vous pouvez accéder à d'autres API ou informations du téléphone de l'utilisateur et les possibilités semblent infinies. Faites preuve de créativité avec vos visages et profitez-en.