Home | History | Annotate | Download | only in datalayer
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.wearable.datalayer;
     18 
     19 import static com.example.android.wearable.datalayer.DataLayerListenerService.LOGD;
     20 
     21 import android.app.Activity;
     22 import android.app.Fragment;
     23 import android.app.FragmentManager;
     24 import android.graphics.Bitmap;
     25 import android.graphics.BitmapFactory;
     26 import android.net.Uri;
     27 import android.os.AsyncTask;
     28 import android.os.Bundle;
     29 import android.support.wearable.view.DotsPageIndicator;
     30 import android.support.wearable.view.FragmentGridPagerAdapter;
     31 import android.support.wearable.view.GridViewPager;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 import android.view.View;
     35 import android.view.WindowManager;
     36 import android.widget.Toast;
     37 
     38 import com.example.android.wearable.datalayer.fragments.AssetFragment;
     39 import com.example.android.wearable.datalayer.fragments.DataFragment;
     40 import com.example.android.wearable.datalayer.fragments.DiscoveryFragment;
     41 import com.google.android.gms.common.ConnectionResult;
     42 import com.google.android.gms.common.api.GoogleApiClient;
     43 import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
     44 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
     45 import com.google.android.gms.common.api.PendingResult;
     46 import com.google.android.gms.common.api.ResultCallback;
     47 import com.google.android.gms.wearable.Asset;
     48 import com.google.android.gms.wearable.CapabilityApi;
     49 import com.google.android.gms.wearable.CapabilityInfo;
     50 import com.google.android.gms.wearable.DataApi;
     51 import com.google.android.gms.wearable.DataEvent;
     52 import com.google.android.gms.wearable.DataEventBuffer;
     53 import com.google.android.gms.wearable.DataMapItem;
     54 import com.google.android.gms.wearable.MessageApi;
     55 import com.google.android.gms.wearable.MessageEvent;
     56 import com.google.android.gms.wearable.Node;
     57 import com.google.android.gms.wearable.Wearable;
     58 
     59 import java.io.InputStream;
     60 import java.util.ArrayList;
     61 import java.util.HashSet;
     62 import java.util.List;
     63 import java.util.Map;
     64 import java.util.Set;
     65 
     66 /**
     67  * The main activity with a view pager, containing three pages:<p/>
     68  * <ul>
     69  * <li>
     70  * Page 1: shows a list of DataItems received from the phone application
     71  * </li>
     72  * <li>
     73  * Page 2: shows the photo that is sent from the phone application
     74  * </li>
     75  * <li>
     76  * Page 3: includes two buttons to show the connected phone and watch devices
     77  * </li>
     78  * </ul>
     79  */
     80 public class MainActivity extends Activity implements
     81         ConnectionCallbacks,
     82         OnConnectionFailedListener,
     83         DataApi.DataListener,
     84         MessageApi.MessageListener,
     85         CapabilityApi.CapabilityListener {
     86 
     87     private static final String TAG = "MainActivity";
     88     private static final String CAPABILITY_1_NAME = "capability_1";
     89     private static final String CAPABILITY_2_NAME = "capability_2";
     90 
     91     private GoogleApiClient mGoogleApiClient;
     92     private GridViewPager mPager;
     93     private DataFragment mDataFragment;
     94     private AssetFragment mAssetFragment;
     95 
     96     @Override
     97     public void onCreate(Bundle savedInstanceState) {
     98         super.onCreate(savedInstanceState);
     99         setContentView(R.layout.main_activity);
    100         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    101         setupViews();
    102         mGoogleApiClient = new GoogleApiClient.Builder(this)
    103                 .addApi(Wearable.API)
    104                 .addConnectionCallbacks(this)
    105                 .addOnConnectionFailedListener(this)
    106                 .build();
    107     }
    108 
    109     @Override
    110     protected void onResume() {
    111         super.onResume();
    112         mGoogleApiClient.connect();
    113     }
    114 
    115     @Override
    116     protected void onPause() {
    117         if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
    118             Wearable.DataApi.removeListener(mGoogleApiClient, this);
    119             Wearable.MessageApi.removeListener(mGoogleApiClient, this);
    120             Wearable.CapabilityApi.removeListener(mGoogleApiClient, this);
    121             mGoogleApiClient.disconnect();
    122         }
    123 
    124         super.onPause();
    125     }
    126 
    127     @Override
    128     public void onConnected(Bundle connectionHint) {
    129         LOGD(TAG, "onConnected(): Successfully connected to Google API client");
    130         Wearable.DataApi.addListener(mGoogleApiClient, this);
    131         Wearable.MessageApi.addListener(mGoogleApiClient, this);
    132         Wearable.CapabilityApi.addListener(
    133                 mGoogleApiClient, this, Uri.parse("wear://"), CapabilityApi.FILTER_REACHABLE);
    134     }
    135 
    136     @Override
    137     public void onConnectionSuspended(int cause) {
    138         LOGD(TAG, "onConnectionSuspended(): Connection to Google API client was suspended");
    139     }
    140 
    141     @Override
    142     public void onConnectionFailed(ConnectionResult result) {
    143         Log.e(TAG, "onConnectionFailed(): Failed to connect, with result: " + result);
    144     }
    145 
    146     @Override
    147     public void onDataChanged(DataEventBuffer dataEvents) {
    148         LOGD(TAG, "onDataChanged(): " + dataEvents);
    149 
    150         for (DataEvent event : dataEvents) {
    151             if (event.getType() == DataEvent.TYPE_CHANGED) {
    152                 String path = event.getDataItem().getUri().getPath();
    153                 if (DataLayerListenerService.IMAGE_PATH.equals(path)) {
    154                     DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
    155                     Asset photoAsset = dataMapItem.getDataMap()
    156                             .getAsset(DataLayerListenerService.IMAGE_KEY);
    157                     // Loads image on background thread.
    158                     new LoadBitmapAsyncTask().execute(photoAsset);
    159 
    160                 } else if (DataLayerListenerService.COUNT_PATH.equals(path)) {
    161                     LOGD(TAG, "Data Changed for COUNT_PATH");
    162                     mDataFragment.appendItem("DataItem Changed", event.getDataItem().toString());
    163                 } else {
    164                     LOGD(TAG, "Unrecognized path: " + path);
    165                 }
    166 
    167             } else if (event.getType() == DataEvent.TYPE_DELETED) {
    168                 mDataFragment.appendItem("DataItem Deleted", event.getDataItem().toString());
    169             } else {
    170                 mDataFragment.appendItem("Unknown data event type", "Type = " + event.getType());
    171             }
    172         }
    173     }
    174 
    175     public void onClicked(View view) {
    176         switch (view.getId()) {
    177             case R.id.capability_2_btn:
    178                 showNodes(CAPABILITY_2_NAME);
    179                 break;
    180             case R.id.capabilities_1_and_2_btn:
    181                 showNodes(CAPABILITY_1_NAME, CAPABILITY_2_NAME);
    182                 break;
    183             default:
    184                 Log.e(TAG, "Unknown click event registered");
    185         }
    186     }
    187 
    188     /**
    189      * Find the connected nodes that provide at least one of the given capabilities
    190      */
    191     private void showNodes(final String... capabilityNames) {
    192 
    193         PendingResult<CapabilityApi.GetAllCapabilitiesResult> pendingCapabilityResult =
    194                 Wearable.CapabilityApi.getAllCapabilities(
    195                         mGoogleApiClient,
    196                         CapabilityApi.FILTER_REACHABLE);
    197 
    198         pendingCapabilityResult.setResultCallback(
    199                 new ResultCallback<CapabilityApi.GetAllCapabilitiesResult>() {
    200                     @Override
    201                     public void onResult(
    202                             CapabilityApi.GetAllCapabilitiesResult getAllCapabilitiesResult) {
    203 
    204                         if (!getAllCapabilitiesResult.getStatus().isSuccess()) {
    205                             Log.e(TAG, "Failed to get capabilities");
    206                             return;
    207                         }
    208 
    209                         Map<String, CapabilityInfo> capabilitiesMap =
    210                                 getAllCapabilitiesResult.getAllCapabilities();
    211                         Set<Node> nodes = new HashSet<>();
    212 
    213                         if (capabilitiesMap.isEmpty()) {
    214                             showDiscoveredNodes(nodes);
    215                             return;
    216                         }
    217                         for (String capabilityName : capabilityNames) {
    218                             CapabilityInfo capabilityInfo = capabilitiesMap.get(capabilityName);
    219                             if (capabilityInfo != null) {
    220                                 nodes.addAll(capabilityInfo.getNodes());
    221                             }
    222                         }
    223                         showDiscoveredNodes(nodes);
    224                     }
    225 
    226                     private void showDiscoveredNodes(Set<Node> nodes) {
    227                         List<String> nodesList = new ArrayList<>();
    228                         for (Node node : nodes) {
    229                             nodesList.add(node.getDisplayName());
    230                         }
    231                         LOGD(TAG, "Connected Nodes: " + (nodesList.isEmpty()
    232                                 ? "No connected device was found for the given capabilities"
    233                                 : TextUtils.join(",", nodesList)));
    234                         String msg;
    235                         if (!nodesList.isEmpty()) {
    236                             msg = getString(R.string.connected_nodes,
    237                                     TextUtils.join(", ", nodesList));
    238                         } else {
    239                             msg = getString(R.string.no_device);
    240                         }
    241                         Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
    242                     }
    243                 });
    244     }
    245 
    246     @Override
    247     public void onMessageReceived(MessageEvent event) {
    248         LOGD(TAG, "onMessageReceived: " + event);
    249         mDataFragment.appendItem("Message", event.toString());
    250     }
    251 
    252     @Override
    253     public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
    254         LOGD(TAG, "onCapabilityChanged: " + capabilityInfo);
    255         mDataFragment.appendItem("onCapabilityChanged", capabilityInfo.toString());
    256     }
    257 
    258     private void setupViews() {
    259         mPager = (GridViewPager) findViewById(R.id.pager);
    260         mPager.setOffscreenPageCount(2);
    261         DotsPageIndicator dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.page_indicator);
    262         dotsPageIndicator.setDotSpacing((int) getResources().getDimension(R.dimen.dots_spacing));
    263         dotsPageIndicator.setPager(mPager);
    264         mDataFragment = new DataFragment();
    265         mAssetFragment = new AssetFragment();
    266         DiscoveryFragment discoveryFragment = new DiscoveryFragment();
    267         List<Fragment> pages = new ArrayList<>();
    268         pages.add(mDataFragment);
    269         pages.add(mAssetFragment);
    270         pages.add(discoveryFragment);
    271         final MyPagerAdapter adapter = new MyPagerAdapter(getFragmentManager(), pages);
    272         mPager.setAdapter(adapter);
    273     }
    274 
    275     /**
    276      * Switches to the page {@code index}. The first page has index 0.
    277      */
    278     private void moveToPage(int index) {
    279         mPager.setCurrentItem(0, index, true);
    280     }
    281 
    282     private class MyPagerAdapter extends FragmentGridPagerAdapter {
    283 
    284         private List<Fragment> mFragments;
    285 
    286         public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
    287             super(fm);
    288             mFragments = fragments;
    289         }
    290 
    291         @Override
    292         public int getRowCount() {
    293             return 1;
    294         }
    295 
    296         @Override
    297         public int getColumnCount(int row) {
    298             return mFragments == null ? 0 : mFragments.size();
    299         }
    300 
    301         @Override
    302         public Fragment getFragment(int row, int column) {
    303             return mFragments.get(column);
    304         }
    305 
    306     }
    307 
    308     /*
    309      * Extracts {@link android.graphics.Bitmap} data from the
    310      * {@link com.google.android.gms.wearable.Asset}
    311      */
    312     private class LoadBitmapAsyncTask extends AsyncTask<Asset, Void, Bitmap> {
    313 
    314         @Override
    315         protected Bitmap doInBackground(Asset... params) {
    316 
    317             if (params.length > 0) {
    318 
    319                 Asset asset = params[0];
    320 
    321                 InputStream assetInputStream = Wearable.DataApi.getFdForAsset(
    322                         mGoogleApiClient, asset).await().getInputStream();
    323 
    324                 if (assetInputStream == null) {
    325                     Log.w(TAG, "Requested an unknown Asset.");
    326                     return null;
    327                 }
    328                 return BitmapFactory.decodeStream(assetInputStream);
    329 
    330             } else {
    331                 Log.e(TAG, "Asset must be non-null");
    332                 return null;
    333             }
    334         }
    335 
    336         @Override
    337         protected void onPostExecute(Bitmap bitmap) {
    338 
    339             if (bitmap != null) {
    340                 LOGD(TAG, "Setting background image on second page..");
    341                 moveToPage(1);
    342                 mAssetFragment.setBackgroundImage(bitmap);
    343             }
    344         }
    345     }
    346 }