Skip to content

Most visited

Recently visited

navigation
XYZTouristAttractions / Wearable / src / com.example.android.xyztouristattractions / ui /

AttractionsGridPagerAdapter.java

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.content.Intent;
22
import android.graphics.Rect;
23
import android.graphics.drawable.BitmapDrawable;
24
import android.graphics.drawable.ColorDrawable;
25
import android.graphics.drawable.Drawable;
26
import android.os.Handler;
27
import android.support.wearable.activity.ConfirmationActivity;
28
import android.support.wearable.view.ActionPage;
29
import android.support.wearable.view.CardFrame;
30
import android.support.wearable.view.CardScrollView;
31
import android.support.wearable.view.GridPagerAdapter;
32
import android.support.wearable.view.GridViewPager;
33
import android.text.TextUtils;
34
import android.view.Gravity;
35
import android.view.LayoutInflater;
36
import android.view.View;
37
import android.view.ViewGroup;
38
import android.widget.FrameLayout;
39
import android.widget.ImageView;
40
import android.widget.TextView;
41
 
42
import com.example.android.xyztouristattractions.R;
43
import com.example.android.xyztouristattractions.common.Attraction;
44
import com.example.android.xyztouristattractions.common.Constants;
45
import com.example.android.xyztouristattractions.service.UtilityService;
46
 
47
import java.util.ArrayList;
48
 
49
/**
50
 * This adapter backs the main GridViewPager component found in
51
 * {@link com.example.android.xyztouristattractions.ui.AttractionsActivity}.
52
 */
53
public class AttractionsGridPagerAdapter extends GridPagerAdapter
54
        implements GridViewPager.OnPageChangeListener {
55
 
56
    public static final int FADE_IN_TIME_MS = 250;
57
    public static final int FADE_OUT_TIME_MS = 500;
58
    private static final int GRID_COLUMN_COUNT = 5;
59
    private static final int FADE_OUT_DELAY_MS = 1500;
60
    private static final int PAGER_PRIMARY_IMAGE_COLUMN = 0;
61
    private static final int PAGER_SECONDARY_IMAGE_COLUMN = 1;
62
    private static final int PAGER_DESCRIPTION_COLUMN = 2;
63
    private static final int PAGER_NAVIGATE_ACTION_COLUMN = 3;
64
    private static final int PAGER_OPEN_ACTION_COLUMN = 4;
65
 
66
    private Context mContext;
67
    private LayoutInflater mLayoutInflater;
68
    private ArrayList<Attraction> mAttractions;
69
    private Rect mInsets = new Rect();
70
    private DelayedHide mDelayedHide = new DelayedHide();
71
    private OnChromeFadeListener mOnChromeFadeListener;
72
 
73
    public AttractionsGridPagerAdapter(
74
            Context context, ArrayList<Attraction> attractions) {
75
        super();
76
        mContext = context;
77
        mLayoutInflater = LayoutInflater.from(context);
78
        mAttractions = attractions;
79
    }
80
 
81
    public void setData(ArrayList<Attraction> attractions) {
82
        mAttractions = attractions;
83
    }
84
 
85
    public void setInsets(Rect insets) {
86
        mInsets = insets;
87
    }
88
 
89
    @Override
90
    public int getRowCount() {
91
        return (mAttractions != null && mAttractions.size() > 0) ? mAttractions.size() : 1;
92
    }
93
 
94
    @Override
95
    public int getColumnCount(int i) {
96
        return GRID_COLUMN_COUNT;
97
    }
98
 
99
    @Override
100
    public Object instantiateItem(ViewGroup container, int row, final int column) {
101
        if (mAttractions != null && mAttractions.size() > 0) {
102
            final Attraction attraction = mAttractions.get(row);
103
            switch (column) {
104
                case PAGER_PRIMARY_IMAGE_COLUMN:
105
                case PAGER_SECONDARY_IMAGE_COLUMN:
106
                    // Two pages of full screen images, one with the attraction name
107
                    // and one with the distance to the attraction
108
                    final View view = mLayoutInflater.inflate(
109
                            R.layout.gridpager_fullscreen_image, container, false);
110
                    ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
111
                    TextView textView = (TextView) view.findViewById(R.id.textView);
112
                    FrameLayout overlayTextLayout =
113
                            (FrameLayout) view.findViewById(R.id.overlaytext);
114
 
115
                    mDelayedHide.add(overlayTextLayout);
116
                    view.setOnClickListener(mDelayedHide);
117
 
118
                    FrameLayout.LayoutParams params =
119
                            (FrameLayout.LayoutParams) textView.getLayoutParams();
120
                    params.bottomMargin = params.bottomMargin + mInsets.bottom;
121
                    params.leftMargin = mInsets.left;
122
                    params.rightMargin = mInsets.right;
123
                    textView.setLayoutParams(params);
124
 
125
                    if (column == PAGER_PRIMARY_IMAGE_COLUMN) {
126
                        imageView.setImageBitmap(attraction.image);
127
                        textView.setText(attraction.name);
128
                    } else {
129
                        imageView.setImageBitmap(attraction.secondaryImage);
130
                        if (TextUtils.isEmpty(attraction.distance)) {
131
                            overlayTextLayout.setVisibility(View.GONE);
132
                        } else {
133
                            textView.setText(mContext.getString(
134
                                    R.string.map_caption, attraction.distance));
135
                        }
136
                    }
137
                    container.addView(view);
138
                    return view;
139
                case PAGER_DESCRIPTION_COLUMN:
140
                    // The description card page
141
                    CardScrollView cardScrollView = (CardScrollView) mLayoutInflater.inflate(
142
                            R.layout.gridpager_card, container, false);
143
                    TextView descTextView = (TextView) cardScrollView.findViewById(R.id.textView);
144
                    descTextView.setText(attraction.description);
145
                    cardScrollView.setCardGravity(Gravity.BOTTOM);
146
                    cardScrollView.setExpansionEnabled(true);
147
                    cardScrollView.setExpansionDirection(CardFrame.EXPAND_DOWN);
148
                    cardScrollView.setExpansionFactor(10);
149
                    container.addView(cardScrollView);
150
                    return cardScrollView;
151
                case PAGER_NAVIGATE_ACTION_COLUMN:
152
                    // The navigate action
153
                    final ActionPage navActionPage = (ActionPage) mLayoutInflater.inflate(
154
                            R.layout.gridpager_action, container, false);
155
 
156
                    navActionPage.setOnClickListener(getStartActionClickListener(
157
                            attraction, Constants.START_NAVIGATION_PATH,
158
                            ConfirmationActivity.SUCCESS_ANIMATION));
159
                    navActionPage.setImageResource(R.drawable.ic_full_directions_walking);
160
                    navActionPage.setText(mContext.getString(R.string.action_navigate));
161
 
162
                    container.addView(navActionPage);
163
                    return navActionPage;
164
                case PAGER_OPEN_ACTION_COLUMN:
165
                    // The "open on device" action
166
                    final ActionPage openActionPage = (ActionPage) mLayoutInflater.inflate(
167
                            R.layout.gridpager_action, container, false);
168
 
169
                    openActionPage.setOnClickListener(getStartActionClickListener(
170
                            attraction, Constants.START_ATTRACTION_PATH,
171
                            ConfirmationActivity.OPEN_ON_PHONE_ANIMATION));
172
                    openActionPage.setImageResource(R.drawable.ic_full_openonphone);
173
                    openActionPage.setText(mContext.getString(R.string.action_open));
174
 
175
                    container.addView(openActionPage);
176
                    return openActionPage;
177
            }
178
        }
179
        return new View(mContext);
180
    }
181
 
182
    @Override
183
    public Drawable getBackgroundForPage(int row, int column) {
184
        if (column == 0) {
185
            return new ColorDrawable(0); // Empty black drawable
186
        }
187
        if (mAttractions.size() > 0 && mAttractions.get(row).image != null) {
188
            return new BitmapDrawable(mContext.getResources(), mAttractions.get(row).image);
189
        }
190
        return super.getBackgroundForPage(row, column);
191
    }
192
 
193
    @Override
194
    public void destroyItem(ViewGroup viewGroup, int row, int column, Object object) {
195
        mDelayedHide.remove((View) object);
196
        viewGroup.removeView((View)object);
197
    }
198
 
199
    @Override
200
    public boolean isViewFromObject(View view, Object object) {
201
        return view == object;
202
    }
203
 
204
    @Override
205
    public void onPageScrolled(int posX, int posY, float posOffsetX, float posOffsetY,
206
                               int posOffsetPixelsX, int posOffsetPixelsY) {}
207
 
208
    @Override
209
    public void onPageSelected(int row, int col) {}
210
 
211
    @Override
212
    public void onPageScrollStateChanged(int state) {
213
        mDelayedHide.show();
214
    }
215
 
216
    /**
217
     * Use the Wear Message API to execute an action. Clears local and remote notifications and
218
     * also runs a confirmation animation before finishing the Wear activity.
219
     *
220
     * @param attraction The attraction to start the action on
221
     * @param pathName The Wear Message API pathname
222
     * @param confirmAnimationType The confirmation animation type from ConfirmationActivity
223
     */
224
    private void startAction(Attraction attraction, String pathName, int confirmAnimationType) {
225
        Intent intent = new Intent(mContext, ConfirmationActivity.class);
226
        intent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, confirmAnimationType);
227
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
228
        mContext.startActivity(intent);
229
 
230
        UtilityService.clearNotification(mContext);
231
        UtilityService.clearRemoteNotifications(mContext);
232
        UtilityService.startDeviceActivity(mContext, pathName, attraction.name, attraction.city);
233
 
234
        ((Activity)mContext).finish();
235
    }
236
 
237
    /**
238
     * Helper method to generate the OnClickListener for the attraction actions.
239
     */
240
    private View.OnClickListener getStartActionClickListener(final Attraction attraction,
241
            final String pathName, final int confirmAnimationType) {
242
        View.OnClickListener clickListener = new View.OnClickListener() {
243
            @Override
244
            public void onClick(View v) {
245
                startAction(attraction, pathName, confirmAnimationType);
246
            }
247
        };
248
        return clickListener;
249
    }
250
 
251
    public void setOnChromeFadeListener(OnChromeFadeListener listener) {
252
        mOnChromeFadeListener = listener;
253
    }
254
 
255
    public interface OnChromeFadeListener {
256
        void onChromeFadeIn();
257
        void onChromeFadeOut();
258
    }
259
 
260
    /**
261
     * Helper class to fade out views based on a delay and fade them back in if needed as well.
262
     */
263
    private class DelayedHide implements View.OnClickListener {
264
 
265
        ArrayList<View> hideViews = new ArrayList<View>(GRID_COLUMN_COUNT);
266
        Handler mHideHandler = new Handler();
267
        boolean mIsHidden = false;
268
 
269
        Runnable mHideRunnable = new Runnable() {
270
            @Override
271
            public void run() {
272
                hide();
273
            }
274
        };
275
 
276
        void add(View newView) {
277
            hideViews.add(newView);
278
            delayedHide();
279
        }
280
 
281
        void remove(View removeView) {
282
            hideViews.remove(removeView);
283
        }
284
 
285
        void show() {
286
            mIsHidden = false;
287
            if (mOnChromeFadeListener != null) {
288
                mOnChromeFadeListener.onChromeFadeIn();
289
            }
290
            for (View view : hideViews) {
291
                if (view != null) {
292
                    view.animate().alpha(1).setDuration(FADE_IN_TIME_MS).start();
293
                }
294
            }
295
            delayedHide();
296
        }
297
 
298
        void hide() {
299
            mIsHidden = true;
300
            mHideHandler.removeCallbacks(mHideRunnable);
301
            if (mOnChromeFadeListener != null) {
302
                mOnChromeFadeListener.onChromeFadeOut();
303
            }
304
            for (int i=0; i<hideViews.size(); i++) {
305
                if (hideViews.get(i) != null) {
306
                    hideViews.get(i).animate().alpha(0).setDuration(FADE_OUT_TIME_MS).start();
307
                }
308
            }
309
        }
310
 
311
        void delayedHide() {
312
            mHideHandler.removeCallbacks(mHideRunnable);
313
            mHideHandler.postDelayed(mHideRunnable, FADE_OUT_DELAY_MS);
314