Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright 2015 Google Inc. All rights reserved.
      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.xyztouristattractions.ui;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.graphics.Rect;
     22 import android.net.Uri;
     23 import android.os.AsyncTask;
     24 import android.os.Bundle;
     25 import android.support.v4.view.GestureDetectorCompat;
     26 import android.support.wearable.view.DismissOverlayView;
     27 import android.support.wearable.view.DotsPageIndicator;
     28 import android.support.wearable.view.GridViewPager;
     29 import android.util.Log;
     30 import android.view.GestureDetector;
     31 import android.view.MotionEvent;
     32 import android.view.View;
     33 import android.view.WindowInsets;
     34 import android.widget.FrameLayout;
     35 import android.widget.ProgressBar;
     36 
     37 import com.example.android.xyztouristattractions.R;
     38 import com.example.android.xyztouristattractions.common.Attraction;
     39 import com.example.android.xyztouristattractions.common.Constants;
     40 import com.example.android.xyztouristattractions.common.Utils;
     41 import com.example.android.xyztouristattractions.service.UtilityService;
     42 import com.google.android.gms.common.ConnectionResult;
     43 import com.google.android.gms.common.api.GoogleApiClient;
     44 import com.google.android.gms.maps.model.LatLng;
     45 import com.google.android.gms.wearable.DataApi;
     46 import com.google.android.gms.wearable.DataMap;
     47 import com.google.android.gms.wearable.DataMapItem;
     48 import com.google.android.gms.wearable.Wearable;
     49 
     50 import java.util.ArrayList;
     51 import java.util.Iterator;
     52 import java.util.List;
     53 import java.util.concurrent.TimeUnit;
     54 
     55 /**
     56  * The main Wear activity that displays nearby attractions in a
     57  * {@link android.support.wearable.view.GridViewPager}. Each row shows
     58  * one attraction and each column shows information or actions for that
     59  * particular attraction.
     60  */
     61 public class AttractionsActivity extends Activity
     62         implements AttractionsGridPagerAdapter.OnChromeFadeListener {
     63     private static final String TAG = AttractionsActivity.class.getSimpleName();
     64 
     65     private GestureDetectorCompat mGestureDetector;
     66     private DismissOverlayView mDismissOverlayView;
     67     private GridViewPager mGridViewPager;
     68     private AttractionsGridPagerAdapter mAdapter;
     69     private DotsPageIndicator mDotsPageIndicator;
     70     private ProgressBar mProgressBar;
     71     private Rect mInsets = new Rect(0, 0, 0, 0);
     72 
     73     private ArrayList<Attraction> mAttractions = new ArrayList<Attraction>();
     74 
     75     @Override
     76     protected void onCreate(Bundle savedInstanceState) {
     77         super.onCreate(savedInstanceState);
     78 
     79         setContentView(R.layout.activity_main);
     80         final FrameLayout topFrameLayout = (FrameLayout) findViewById(R.id.topFrameLayout);
     81         mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
     82         mGridViewPager = (GridViewPager) findViewById(R.id.gridViewPager);
     83         mDotsPageIndicator = (DotsPageIndicator) findViewById(R.id.dotsPageIndicator);
     84         mAdapter = new AttractionsGridPagerAdapter(this, mAttractions);
     85         mAdapter.setOnChromeFadeListener(this);
     86         mGridViewPager.setAdapter(mAdapter);
     87         mDotsPageIndicator.setPager(mGridViewPager);
     88         mDotsPageIndicator.setOnPageChangeListener(mAdapter);
     89 
     90         topFrameLayout.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
     91             @Override
     92             public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
     93                 // Call through to super implementation
     94                 insets = topFrameLayout.onApplyWindowInsets(insets);
     95 
     96                 boolean round = insets.isRound();
     97 
     98                 // Store system window insets regardless of screen shape
     99                 mInsets.set(insets.getSystemWindowInsetLeft(),
    100                         insets.getSystemWindowInsetTop(),
    101                         insets.getSystemWindowInsetRight(),
    102                         insets.getSystemWindowInsetBottom());
    103 
    104                 if (round) {
    105                     // On a round screen calculate the square inset to use.
    106                     // Alternatively could use BoxInsetLayout, although calculating
    107                     // the inset ourselves lets us position views outside the center
    108                     // box. For example, slightly lower on the round screen (by giving
    109                     // up some horizontal space).
    110                     mInsets = Utils.calculateBottomInsetsOnRoundDevice(
    111                             getWindowManager().getDefaultDisplay(), mInsets);
    112 
    113                     // Boost the dots indicator up by the bottom inset
    114                     FrameLayout.LayoutParams params =
    115                             (FrameLayout.LayoutParams) mDotsPageIndicator.getLayoutParams();
    116                     params.bottomMargin = mInsets.bottom;
    117                     mDotsPageIndicator.setLayoutParams(params);
    118                 }
    119 
    120                 mAdapter.setInsets(mInsets);
    121                 return insets;
    122             }
    123         });
    124 
    125         // Set up the DismissOverlayView
    126         mDismissOverlayView = (DismissOverlayView) findViewById(R.id.dismiss_overlay);
    127         mDismissOverlayView.setIntroText(getString(R.string.exit_intro_text));
    128         mDismissOverlayView.showIntroIfNecessary();
    129         mGestureDetector = new GestureDetectorCompat(this, new LongPressListener());
    130 
    131         Uri attractionsUri = getIntent().getParcelableExtra(Constants.EXTRA_ATTRACTIONS_URI);
    132         if (attractionsUri != null) {
    133             new FetchDataAsyncTask(this).execute(attractionsUri);
    134             UtilityService.clearNotification(this);
    135             UtilityService.clearRemoteNotifications(this);
    136         } else {
    137             finish();
    138         }
    139     }
    140 
    141     @Override
    142     public boolean dispatchTouchEvent(MotionEvent event) {
    143         return mGestureDetector.onTouchEvent(event) || super.dispatchTouchEvent(event);
    144     }
    145 
    146     @Override
    147     public boolean onTouchEvent(MotionEvent event) {
    148         return mGestureDetector.onTouchEvent(event) || super.onTouchEvent(event);
    149     }
    150 
    151     @Override
    152     public void onChromeFadeIn() {
    153         // As the custom UI chrome fades in, also fade the DotsPageIndicator in
    154         mDotsPageIndicator.animate().alpha(1).setDuration(
    155                 AttractionsGridPagerAdapter.FADE_IN_TIME_MS).start();
    156     }
    157 
    158     @Override
    159     public void onChromeFadeOut() {
    160         // As the custom UI chrome fades out, also fade the DotsPageIndicator out
    161         mDotsPageIndicator.animate().alpha(0).setDuration(
    162                 AttractionsGridPagerAdapter.FADE_OUT_TIME_MS).start();
    163     }
    164 
    165     private class LongPressListener extends GestureDetector.SimpleOnGestureListener {
    166         @Override
    167         public void onLongPress(MotionEvent event) {
    168             mDismissOverlayView.show();
    169         }
    170     }
    171 
    172     /**
    173      * A background task to load the attraction data via the Wear DataApi.
    174      * This can take a second or two sometimes as several images need to
    175      * be loaded.
    176      */
    177     private class FetchDataAsyncTask extends
    178             AsyncTask<Uri, Void, ArrayList<Attraction>> {
    179 
    180         private Context mContext;
    181 
    182         public FetchDataAsyncTask(Context context) {
    183             mContext = context;
    184         }
    185 
    186         @Override
    187         protected ArrayList<Attraction> doInBackground(Uri... params) {
    188             mAttractions.clear();
    189 
    190             // Connect to Play Services and the Wearable API
    191             GoogleApiClient googleApiClient = new GoogleApiClient.Builder(mContext)
    192                     .addApi(Wearable.API)
    193                     .build();
    194 
    195             ConnectionResult connectionResult = googleApiClient.blockingConnect(
    196                     Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS);
    197 
    198             if (!connectionResult.isSuccess() || !googleApiClient.isConnected()) {
    199                 Log.e(TAG, String.format(Constants.GOOGLE_API_CLIENT_ERROR_MSG,
    200                         connectionResult.getErrorCode()));
    201                 return null;
    202             }
    203 
    204             Uri attractionsUri = params[0];
    205             DataApi.DataItemResult dataItemResult =
    206                     Wearable.DataApi.getDataItem(googleApiClient, attractionsUri).await();
    207 
    208             if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
    209                 DataMapItem dataMapItem = DataMapItem.fromDataItem(dataItemResult.getDataItem());
    210                 List<DataMap> attractionsData =
    211                         dataMapItem.getDataMap().getDataMapArrayList(Constants.EXTRA_ATTRACTIONS);
    212 
    213                 // Loop through each attraction, adding them to the list
    214                 Iterator<DataMap> itr = attractionsData.iterator();
    215                 while (itr.hasNext()) {
    216                     DataMap attractionData = itr.next();
    217 
    218                     Attraction attraction = new Attraction();
    219                     attraction.name = attractionData.getString(Constants.EXTRA_TITLE);
    220                     attraction.description =
    221                             attractionData.getString(Constants.EXTRA_DESCRIPTION);
    222                     attraction.city = attractionData.get(Constants.EXTRA_CITY);
    223                     attraction.distance =
    224                             attractionData.getString(Constants.EXTRA_DISTANCE);
    225                     attraction.location = new LatLng(
    226                             attractionData.getDouble(Constants.EXTRA_LOCATION_LAT),
    227                             attractionData.getDouble(Constants.EXTRA_LOCATION_LNG));
    228                     attraction.image = Utils.loadBitmapFromAsset(googleApiClient,
    229                             attractionData.getAsset(Constants.EXTRA_IMAGE));
    230                     attraction.secondaryImage = Utils.loadBitmapFromAsset(googleApiClient,
    231                             attractionData.getAsset(Constants.EXTRA_IMAGE_SECONDARY));
    232 
    233                     mAttractions.add(attraction);
    234                 }
    235             }
    236 
    237             googleApiClient.disconnect();
    238 
    239             return mAttractions;
    240         }
    241 
    242         @Override
    243         protected void onPostExecute(ArrayList<Attraction> result) {
    244             if (result != null && result.size() > 0) {
    245                 // Update UI based on the result of the background processing
    246                 mAdapter.setData(result);
    247                 mAdapter.notifyDataSetChanged();
    248                 mProgressBar.setVisibility(View.GONE);
    249                 mDotsPageIndicator.setVisibility(View.VISIBLE);
    250                 mGridViewPager.setVisibility(View.VISIBLE);
    251             } else {
    252                 finish();
    253             }
    254         }
    255     }
    256 }
    257