Skip to content

Most visited

Recently visited

navigation
WatchFace / Wearable / src / com.example.android.wearable.watchface /

DigitalWatchFaceWearableConfigActivity.java

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.watchface;
18
 
19
import android.animation.AnimatorSet;
20
import android.animation.ObjectAnimator;
21
import android.app.Activity;
22
import android.content.Context;
23
import android.graphics.Color;
24
import android.os.Bundle;
25
import android.support.v7.widget.LinearLayoutManager;
26
import android.support.v7.widget.RecyclerView;
27
import android.support.wearable.view.BoxInsetLayout;
28
import android.support.wearable.view.CircledImageView;
29
import android.support.wearable.view.WearableListView;
30
import android.util.Log;
31
import android.view.LayoutInflater;
32
import android.view.View;
33
import android.view.ViewGroup;
34
import android.view.WindowInsets;
35
import android.widget.LinearLayout;
36
import android.widget.TextView;
37
 
38
import com.google.android.gms.common.ConnectionResult;
39
import com.google.android.gms.common.api.GoogleApiClient;
40
import com.google.android.gms.wearable.DataMap;
41
import com.google.android.gms.wearable.Wearable;
42
 
43
/**
44
 * The watch-side config activity for {@link DigitalWatchFaceService}, which allows for setting the
45
 * background color.
46
 */
47
public class DigitalWatchFaceWearableConfigActivity extends Activity implements
48
        WearableListView.ClickListener, WearableListView.OnScrollListener {
49
    private static final String TAG = "DigitalWatchFaceConfig";
50
 
51
    private GoogleApiClient mGoogleApiClient;
52
    private TextView mHeader;
53
 
54
    @Override
55
    protected void onCreate(Bundle savedInstanceState) {
56
        super.onCreate(savedInstanceState);
57
        setContentView(R.layout.activity_digital_config);
58
 
59
        mHeader = (TextView) findViewById(R.id.header);
60
        WearableListView listView = (WearableListView) findViewById(R.id.color_picker);
61
        BoxInsetLayout content = (BoxInsetLayout) findViewById(R.id.content);
62
        // BoxInsetLayout adds padding by default on round devices. Add some on square devices.
63
        content.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
64
            @Override
65
            public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
66
                if (!insets.isRound()) {
67
                    v.setPaddingRelative(
68
                            (int) getResources().getDimensionPixelSize(R.dimen.content_padding_start),
69
                            v.getPaddingTop(),
70
                            v.getPaddingEnd(),
71
                            v.getPaddingBottom());
72
                }
73
                return v.onApplyWindowInsets(insets);
74
            }
75
        });
76
 
77
        listView.setHasFixedSize(true);
78
        listView.setClickListener(this);
79
        listView.addOnScrollListener(this);
80
 
81
        String[] colors = getResources().getStringArray(R.array.color_array);
82
        listView.setAdapter(new ColorListAdapter(colors));
83
 
84
        mGoogleApiClient = new GoogleApiClient.Builder(this)
85
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
86
                    @Override
87
                    public void onConnected(Bundle connectionHint) {
88
                        if (Log.isLoggable(TAG, Log.DEBUG)) {
89
                            Log.d(TAG, "onConnected: " + connectionHint);
90
                        }
91
                    }
92
 
93
                    @Override
94
                    public void onConnectionSuspended(int cause) {
95
                        if (Log.isLoggable(TAG, Log.DEBUG)) {
96
                            Log.d(TAG, "onConnectionSuspended: " + cause);
97
                        }
98
                    }
99
                })
100
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
101
                    @Override
102
                    public void onConnectionFailed(ConnectionResult result) {
103
                        if (Log.isLoggable(TAG, Log.DEBUG)) {
104
                            Log.d(TAG, "onConnectionFailed: " + result);
105
                        }
106
                    }
107
                })
108
                .addApi(Wearable.API)
109
                .build();
110
    }
111
 
112
    @Override
113
    protected void onStart() {
114
        super.onStart();
115
        mGoogleApiClient.connect();
116
    }
117
 
118
    @Override
119
    protected void onStop() {
120
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
121
            mGoogleApiClient.disconnect();
122
        }
123
        super.onStop();
124
    }
125
 
126
    @Override // WearableListView.ClickListener
127
    public void onClick(WearableListView.ViewHolder viewHolder) {
128
        ColorItemViewHolder colorItemViewHolder = (ColorItemViewHolder) viewHolder;
129
        updateConfigDataItem(colorItemViewHolder.mColorItem.getColor());
130
        finish();
131
    }
132
 
133
    @Override // WearableListView.ClickListener
134
    public void onTopEmptyRegionClick() {}
135
 
136
    @Override // WearableListView.OnScrollListener
137
    public void onScroll(int scroll) {}
138
 
139
    @Override // WearableListView.OnScrollListener
140
    public void onAbsoluteScrollChange(int scroll) {
141
        float newTranslation = Math.min(-scroll, 0);
142
        mHeader.setTranslationY(newTranslation);
143
    }
144
 
145
    @Override // WearableListView.OnScrollListener
146
    public void onScrollStateChanged(int scrollState) {}
147
 
148
    @Override // WearableListView.OnScrollListener
149
    public void onCentralPositionChanged(int centralPosition) {}
150
 
151
    private void updateConfigDataItem(final int backgroundColor) {
152
        DataMap configKeysToOverwrite = new DataMap();
153
        configKeysToOverwrite.putInt(DigitalWatchFaceUtil.KEY_BACKGROUND_COLOR,
154
                backgroundColor);
155
        DigitalWatchFaceUtil.overwriteKeysInConfigDataMap(mGoogleApiClient, configKeysToOverwrite);
156
    }
157
 
158
    private class ColorListAdapter extends WearableListView.Adapter {
159
        private final String[] mColors;
160
 
161
        public ColorListAdapter(String[] colors) {
162
            mColors = colors;
163
        }
164
 
165
        @Override
166
        public ColorItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
167
            return new ColorItemViewHolder(new ColorItem(parent.getContext()));
168
        }
169
 
170
        @Override
171
        public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
172
            ColorItemViewHolder colorItemViewHolder = (ColorItemViewHolder) holder;
173
            String colorName = mColors[position];
174
            colorItemViewHolder.mColorItem.setColor(colorName);
175
 
176
            RecyclerView.LayoutParams layoutParams =
177
                    new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
178
                            ViewGroup.LayoutParams.WRAP_CONTENT);
179
            int colorPickerItemMargin = (int) getResources()
180
                    .getDimension(R.dimen.digital_config_color_picker_item_margin);
181
            // Add margins to first and last item to make it possible for user to tap on them.
182
            if (position == 0) {
183
                layoutParams.setMargins(0, colorPickerItemMargin, 0, 0);
184
            } else if (position == mColors.length - 1) {
185
                layoutParams.setMargins(0, 0, 0, colorPickerItemMargin);
186
            } else {
187
                layoutParams.setMargins(0, 0, 0, 0);
188
            }
189
            colorItemViewHolder.itemView.setLayoutParams(layoutParams);
190
        }
191
 
192
        @Override
193
        public int getItemCount() {
194
            return mColors.length;
195
        }
196
    }
197
 
198
    /** The layout of a color item including image and label. */
199
    private static class ColorItem extends LinearLayout implements
200
            WearableListView.OnCenterProximityListener {
201
        /** The duration of the expand/shrink animation. */
202
        private static final int ANIMATION_DURATION_MS = 150;
203
        /** The ratio for the size of a circle in shrink state. */
204
        private static final float SHRINK_CIRCLE_RATIO = .75f;
205
 
206
        private static final float SHRINK_LABEL_ALPHA = .5f;
207
        private static final float EXPAND_LABEL_ALPHA = 1f;
208
 
209
        private final TextView mLabel;
210
        private final CircledImageView mColor;
211
 
212
        private final float mExpandCircleRadius;
213
        private final float mShrinkCircleRadius;
214
 
215
        private final ObjectAnimator mExpandCircleAnimator;
216
        private final ObjectAnimator mExpandLabelAnimator;
217
        private final AnimatorSet mExpandAnimator;
218
 
219
        private final ObjectAnimator mShrinkCircleAnimator;
220
        private final ObjectAnimator mShrinkLabelAnimator;
221
        private final AnimatorSet mShrinkAnimator;
222
 
223
        public ColorItem(Context context) {
224
            super(context);
225
            View.inflate(context, R.layout.color_picker_item, this);
226
 
227
            mLabel = (TextView) findViewById(R.id.label);
228
            mColor = (CircledImageView) findViewById(R.id.color);
229
 
230
            mExpandCircleRadius = mColor.getCircleRadius();
231
            mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO;
232
 
233
            mShrinkCircleAnimator = ObjectAnimator.ofFloat(mColor, "circleRadius",
234
                    mExpandCircleRadius, mShrinkCircleRadius);
235
            mShrinkLabelAnimator = ObjectAnimator.ofFloat(mLabel, "alpha",
236
                    EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
237
            mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
238
            mShrinkAnimator.playTogether(mShrinkCircleAnimator, mShrinkLabelAnimator);
239
 
240
            mExpandCircleAnimator = ObjectAnimator.ofFloat(mColor, "circleRadius",
241
                    mShrinkCircleRadius, mExpandCircleRadius);
242
            mExpandLabelAnimator = ObjectAnimator.ofFloat(mLabel, "alpha",
243
                    SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
244
            mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
245
            mExpandAnimator.playTogether(mExpandCircleAnimator, mExpandLabelAnimator);
246
        }
247
 
248
        @Override
249
        public void onCenterPosition(boolean animate) {
250
            if (animate) {
251
                mShrinkAnimator.cancel();
252
                if (!mExpandAnimator.isRunning()) {
253
                    mExpandCircleAnimator.setFloatValues(mColor.getCircleRadius(), mExpandCircleRadius);
254
                    mExpandLabelAnimator.setFloatValues(mLabel.getAlpha(), EXPAND_LABEL_ALPHA);
255
                    mExpandAnimator.start();
256
                }
257
            } else {
258
                mExpandAnimator.cancel();
259
                mColor.setCircleRadius(mExpandCircleRadius);
260
                mLabel.setAlpha(EXPAND_LABEL_ALPHA);
261
            }
262
        }
263
 
264
        @Override
265
        public void onNonCenterPosition(boolean animate) {
266
            if (animate) {
267
                mExpandAnimator.cancel();
268
                if (!mShrinkAnimator.isRunning()) {
269
                    mShrinkCircleAnimator.setFloatValues(mColor.getCircleRadius(), mShrinkCircleRadius);
270
                    mShrinkLabelAnimator.setFloatValues(mLabel.getAlpha(), SHRINK_LABEL_ALPHA);
271
                    mShrinkAnimator.start();
272
                }
273
            } else {
274
                mShrinkAnimator.cancel();
275
                mColor.setCircleRadius(mShrinkCircleRadius);
276
                mLabel.setAlpha(SHRINK_LABEL_ALPHA);
277
            }
278
        }
279
 
280
        private void setColor(String colorName) {
281
            mLabel.setText(colorName);
282
            mColor.setCircleColor(Color.parseColor(colorName));
283
        }
284
 
285
        private int getColor() {
286
            return mColor.getDefaultCircleColor();
287
        }
288
    }
289
 
290
    private static class ColorItemViewHolder extends WearableListView.ViewHolder {
291
        private final ColorItem mColorItem;
292
 
293
        public ColorItemViewHolder(ColorItem colorItem) {
294
            super(colorItem);
295
            mColorItem = colorItem;
296
        }
297
    }
298
}