package com.tutosandroidfrance.wearsample; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.wearable.view.DotsPageIndicator; import android.support.wearable.view.GridViewPager; import android.util.Log; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.wearable.Asset; import com.google.android.gms.wearable.DataApi; import com.google.android.gms.wearable.DataEvent; import com.google.android.gms.wearable.DataEventBuffer; import com.google.android.gms.wearable.DataMap; import com.google.android.gms.wearable.DataMapItem; import com.google.android.gms.wearable.MessageApi; import com.google.android.gms.wearable.MessageEvent; import com.google.android.gms.wearable.Node; import com.google.android.gms.wearable.NodeApi; import com.google.android.gms.wearable.PutDataRequest; import com.google.android.gms.wearable.Wearable; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, MessageApi.MessageListener, DataApi.DataListener { private final static String TAG = MainActivity.class.getCanonicalName(); private GridViewPager pager; private DotsPageIndicator dotsPageIndicator; //la liste des éléments à afficher private List<Element> elementList; protected GoogleApiClient mApiClient; protected DrawableCache mDrawableCache; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pager = (GridViewPager) findViewById(R.id.pager); dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.page_indicator); dotsPageIndicator.setPager(pager); //elementList = creerListElements(); //pager.setAdapter(new ElementGridPagerAdapter(elementList,getFragmentManager())); } /** * Créé une liste d'éléments pour l'affichage */ private List<Element> creerListElements() { List<Element> list = new ArrayList<>(); list.add(new Element("Element 1", "Description 1", Color.parseColor("#F44336"))); list.add(new Element("Element 2", "Description 2", Color.parseColor("#E91E63"))); list.add(new Element("Element 3", "Description 3", Color.parseColor("#9C27B0"))); list.add(new Element("Element 4", "Description 4", Color.parseColor("#673AB7"))); list.add(new Element("Element 5", "Description 5", Color.parseColor("#3F51B5"))); list.add(new Element("Element 6", "Description 6", Color.parseColor("#2196F3"))); return list; } /** * A l'ouverture, connecte la montre au Google API Client / donc au smartphone */ @Override protected void onStart() { super.onStart(); mApiClient = new GoogleApiClient.Builder(this) .addApi(Wearable.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); mApiClient.connect(); } /** * Si nous avons une connection aux Google API, donc au smartphone * Nous autorisons l'envoie de messages */ @Override public void onConnected(Bundle bundle) { Wearable.MessageApi.addListener(mApiClient, this); Wearable.DataApi.addListener(mApiClient, this); //envoie le premier message sendMessage("bonjour", "smartphone"); } /** * A la fermeture de l'application, desactive le GoogleApiClient * Et ferme l'envoie de message */ @Override protected void onStop() { if (null != mApiClient && mApiClient.isConnected()) { Wearable.MessageApi.removeListener(mApiClient, this); Wearable.DataApi.removeListener(mApiClient, this); mApiClient.disconnect(); } super.onStop(); } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } /** * Appellé à la réception d'un message envoyé depuis le smartphone * * @param messageEvent message reçu */ @Override public void onMessageReceived(MessageEvent messageEvent) { //traite le message reçu final String path = messageEvent.getPath(); //récupère le contenu du message final String message = new String(messageEvent.getData()); if (path.equals("bonjour")) { elementList = new ArrayList<>(); elementList.add(new Element("Message reçu", message, Color.parseColor("#F44336"))); startMainScreen(); } } public void startMainScreen() { //penser à effectuer les actions graphiques dans le UIThread runOnUiThread(new Runnable() { @Override public void run() { //nous affichons ici dans notre viewpager if (pager != null && pager.getAdapter() == null) pager.setAdapter(new ElementGridPagerAdapter(elementList, getFragmentManager())); } }); } /** * Envoie un message à au smartphone * * @param path identifiant du message * @param message message à transmettre */ protected void sendMessage(final String path, final String message) { //effectué dans un trhead afin de ne pas être bloquant new Thread(new Runnable() { @Override public void run() { //envoie le message à tous les noeuds/montres connectées final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mApiClient).await(); for (Node node : nodes.getNodes()) { Wearable.MessageApi.sendMessage(mApiClient, node.getId(), path, message.getBytes()).await(); } } }).start(); } @Override public void onDataChanged(DataEventBuffer dataEvents) { //appellé lorsqu'une donnée à été mise à jour, nous utiliserons une autre méthode for (DataEvent event : dataEvents) { //on attend les "elements" if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().startsWith("/elements/")) { DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem()); List<DataMap> elementsDataMap = dataMapItem.getDataMap().getDataMapArrayList("/list/"); if (elementList == null || elementList.isEmpty()) { elementList = new ArrayList<>(); for (DataMap dataMap : elementsDataMap) { elementList.add(getElement(dataMap)); } //charge les images puis affiche le main screen preloadImages(elementList.size()); } } //on attend ici des assets dont le path commence par /image/ if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().startsWith("/image/")) { DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem()); Asset profileAsset = dataMapItem.getDataMap().getAsset("image"); Bitmap bitmap = loadBitmapFromAsset(profileAsset); // On peux maintenant utiliser notre bitmap } } } /** * Récupère une URI de donnée en fonction d'un path * via l'identifiant nodeId du smartphone */ protected Uri getUriForDataItem(String path) { try { //recupère le nodeId du smartphone final String nodeId = Wearable.NodeApi.getConnectedNodes(mApiClient).await().getNodes().get(0).getId(); //construit l'uri pointant vers notre path Uri uri = new Uri.Builder().scheme(PutDataRequest.WEAR_URI_SCHEME).authority(nodeId).path(path).build(); return uri; } catch (Exception e) { Log.e(TAG, e.getMessage(), e); return null; } } /** * Récupère un element depuis sa position */ public Element getElement(DataMap elementDataMap) { return new Element( elementDataMap.getString("titre"), elementDataMap.getString("description"), elementDataMap.getString("url")); } /** * Récupère une bitmap depuis un asset de DataApi */ public Bitmap loadBitmapFromAsset(Asset asset) { final ConnectionResult result = mApiClient.blockingConnect(3000, TimeUnit.MILLISECONDS); if (!result.isSuccess()) { return null; } // convert asset into a file descriptor and block until it's ready final InputStream assetInputStream = Wearable.DataApi.getFdForAsset(mApiClient, asset).await().getInputStream(); if (assetInputStream == null) { return null; } // decode the stream into a bitmap return BitmapFactory.decodeStream(assetInputStream); } /** * Récupère une bitmap partagée avec le smartphone depuis une position */ public Bitmap getBitmap(int position) { final Uri uri = getUriForDataItem("/image/" + position); if (uri != null) { final DataApi.DataItemResult result = Wearable.DataApi.getDataItem(mApiClient, uri).await(); if (result != null && result.getDataItem() != null) { final DataMapItem dataMapItem = DataMapItem.fromDataItem(result.getDataItem()); final Asset firstAsset = dataMapItem.getDataMap().getAsset("image"); if (firstAsset != null) { return loadBitmapFromAsset(firstAsset); } } } return null; } /** * Précharge les images dans un cache Lru (en mémoire, pas sur le disque) * Afin d'être accessibles depuis l'adapter * Puis affiche le viewpager une fois terminé * * @param size nombre d'images à charger */ public void preloadImages(final int size) { //initialise le cache DrawableCache.init(size); //dans le UIThread pour avoir accès aux toasts runOnUiThread(new Runnable() { @Override public void run() { new AsyncTask<Void, Void, Void>() { @Override protected void onPreExecute() { super.onPreExecute(); Toast.makeText(MainActivity.this, "Chargement des images", Toast.LENGTH_LONG).show(); } @Override protected Void doInBackground(Void... params) { //charge les images 1 par 1 et les place dans un LruCache for (int i = 0; i < size; ++i) { Bitmap bitmap = getBitmap(i); Drawable drawable = null; if (bitmap != null) drawable = new BitmapDrawable(MainActivity.this.getResources(), bitmap); else drawable = new ColorDrawable(Color.BLUE); DrawableCache.getInstance().put(i, drawable); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); //affiche le viewpager startMainScreen(); } }.execute(); } }); } }