/*
* 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();
}
}
}
}