/* * Copyright 2015 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.xyztouristattractions.ui; import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.view.GestureDetectorCompat; import android.support.wearable.view.DismissOverlayView; import android.support.wearable.view.DotsPageIndicator; import android.support.wearable.view.GridViewPager; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.WindowInsets; import android.widget.FrameLayout; import android.widget.ProgressBar; import com.example.android.xyztouristattractions.R; import com.example.android.xyztouristattractions.common.Attraction; import com.example.android.xyztouristattractions.common.Constants; import com.example.android.xyztouristattractions.common.Utils; import com.example.android.xyztouristattractions.service.UtilityService; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.wearable.DataApi; import com.google.android.gms.wearable.DataMap; import com.google.android.gms.wearable.DataMapItem; import com.google.android.gms.wearable.Wearable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; /** * The main Wear activity that displays nearby attractions in a * {@link android.support.wearable.view.GridViewPager}. Each row shows * one attraction and each column shows information or actions for that * particular attraction. */ public class AttractionsActivity extends Activity implements AttractionsGridPagerAdapter.OnChromeFadeListener { private static final String TAG = AttractionsActivity.class.getSimpleName(); private GestureDetectorCompat mGestureDetector; private DismissOverlayView mDismissOverlayView; private GridViewPager mGridViewPager; private AttractionsGridPagerAdapter mAdapter; private DotsPageIndicator mDotsPageIndicator; private ProgressBar mProgressBar; private Rect mInsets = new Rect(0, 0, 0, 0); private ArrayList<Attraction> mAttractions = new ArrayList<Attraction>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final FrameLayout topFrameLayout = (FrameLayout) findViewById(R.id.topFrameLayout); mProgressBar = (ProgressBar) findViewById(R.id.progressBar); mGridViewPager = (GridViewPager) findViewById(R.id.gridViewPager); mDotsPageIndicator = (DotsPageIndicator) findViewById(R.id.dotsPageIndicator); mAdapter = new AttractionsGridPagerAdapter(this, mAttractions); mAdapter.setOnChromeFadeListener(this); mGridViewPager.setAdapter(mAdapter); mDotsPageIndicator.setPager(mGridViewPager); mDotsPageIndicator.setOnPageChangeListener(mAdapter); topFrameLayout.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { // Call through to super implementation insets = topFrameLayout.onApplyWindowInsets(insets); boolean round = insets.isRound(); // Store system window insets regardless of screen shape mInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); if (round) { // On a round screen calculate the square inset to use. // Alternatively could use BoxInsetLayout, although calculating // the inset ourselves lets us position views outside the center // box. For example, slightly lower on the round screen (by giving // up some horizontal space). mInsets = Utils.calculateBottomInsetsOnRoundDevice( getWindowManager().getDefaultDisplay(), mInsets); // Boost the dots indicator up by the bottom inset FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mDotsPageIndicator.getLayoutParams(); params.bottomMargin = mInsets.bottom; mDotsPageIndicator.setLayoutParams(params); } mAdapter.setInsets(mInsets); return insets; } }); // Set up the DismissOverlayView mDismissOverlayView = (DismissOverlayView) findViewById(R.id.dismiss_overlay); mDismissOverlayView.setIntroText(getString(R.string.exit_intro_text)); mDismissOverlayView.showIntroIfNecessary(); mGestureDetector = new GestureDetectorCompat(this, new LongPressListener()); Uri attractionsUri = getIntent().getParcelableExtra(Constants.EXTRA_ATTRACTIONS_URI); if (attractionsUri != null) { new FetchDataAsyncTask(this).execute(attractionsUri); UtilityService.clearNotification(this); UtilityService.clearRemoteNotifications(this); } else { finish(); } } @Override public boolean dispatchTouchEvent(MotionEvent event) { return mGestureDetector.onTouchEvent(event) || super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return mGestureDetector.onTouchEvent(event) || super.onTouchEvent(event); } @Override public void onChromeFadeIn() { // As the custom UI chrome fades in, also fade the DotsPageIndicator in mDotsPageIndicator.animate().alpha(1).setDuration( AttractionsGridPagerAdapter.FADE_IN_TIME_MS).start(); } @Override public void onChromeFadeOut() { // As the custom UI chrome fades out, also fade the DotsPageIndicator out mDotsPageIndicator.animate().alpha(0).setDuration( AttractionsGridPagerAdapter.FADE_OUT_TIME_MS).start(); } private class LongPressListener extends GestureDetector.SimpleOnGestureListener { @Override public void onLongPress(MotionEvent event) { mDismissOverlayView.show(); } } /** * A background task to load the attraction data via the Wear DataApi. * This can take a second or two sometimes as several images need to * be loaded. */ private class FetchDataAsyncTask extends AsyncTask<Uri, Void, ArrayList<Attraction>> { private Context mContext; public FetchDataAsyncTask(Context context) { mContext = context; } @Override protected ArrayList<Attraction> doInBackground(Uri... params) { mAttractions.clear(); // Connect to Play Services and the Wearable API GoogleApiClient googleApiClient = new GoogleApiClient.Builder(mContext) .addApi(Wearable.API) .build(); ConnectionResult connectionResult = googleApiClient.blockingConnect( Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS); if (!connectionResult.isSuccess() || !googleApiClient.isConnected()) { Log.e(TAG, String.format(Constants.GOOGLE_API_CLIENT_ERROR_MSG, connectionResult.getErrorCode())); return null; } Uri attractionsUri = params[0]; DataApi.DataItemResult dataItemResult = Wearable.DataApi.getDataItem(googleApiClient, attractionsUri).await(); if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) { DataMapItem dataMapItem = DataMapItem.fromDataItem(dataItemResult.getDataItem()); List<DataMap> attractionsData = dataMapItem.getDataMap().getDataMapArrayList(Constants.EXTRA_ATTRACTIONS); // Loop through each attraction, adding them to the list Iterator<DataMap> itr = attractionsData.iterator(); while (itr.hasNext()) { DataMap attractionData = itr.next(); Attraction attraction = new Attraction(); attraction.name = attractionData.getString(Constants.EXTRA_TITLE); attraction.description = attractionData.getString(Constants.EXTRA_DESCRIPTION); attraction.city = attractionData.get(Constants.EXTRA_CITY); attraction.distance = attractionData.getString(Constants.EXTRA_DISTANCE); attraction.location = new LatLng( attractionData.getDouble(Constants.EXTRA_LOCATION_LAT), attractionData.getDouble(Constants.EXTRA_LOCATION_LNG)); attraction.image = Utils.loadBitmapFromAsset(googleApiClient, attractionData.getAsset(Constants.EXTRA_IMAGE)); attraction.secondaryImage = Utils.loadBitmapFromAsset(googleApiClient, attractionData.getAsset(Constants.EXTRA_IMAGE_SECONDARY)); mAttractions.add(attraction); } } googleApiClient.disconnect(); return mAttractions; } @Override protected void onPostExecute(ArrayList<Attraction> result) { if (result != null && result.size() > 0) { // Update UI based on the result of the background processing mAdapter.setData(result); mAdapter.notifyDataSetChanged(); mProgressBar.setVisibility(View.GONE); mDotsPageIndicator.setVisibility(View.VISIBLE); mGridViewPager.setVisibility(View.VISIBLE); } else { finish(); } } } }