/* * Copyright (C) 2014 The Android Open Source Project * * 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.wearable.watchface; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.wearable.view.BoxInsetLayout; import android.support.wearable.view.CircledImageView; import android.support.wearable.view.WearableListView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.widget.LinearLayout; import android.widget.TextView; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.wearable.DataMap; import com.google.android.gms.wearable.Wearable; /** * The watch-side config activity for {@link DigitalWatchFaceService}, which allows for setting the * background color. */ public class DigitalWatchFaceWearableConfigActivity extends Activity implements WearableListView.ClickListener, WearableListView.OnScrollListener { private static final String TAG = "DigitalWatchFaceConfig"; private GoogleApiClient mGoogleApiClient; private TextView mHeader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_digital_config); mHeader = (TextView) findViewById(R.id.header); WearableListView listView = (WearableListView) findViewById(R.id.color_picker); BoxInsetLayout content = (BoxInsetLayout) findViewById(R.id.content); // BoxInsetLayout adds padding by default on round devices. Add some on square devices. content.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { if (!insets.isRound()) { v.setPaddingRelative( (int) getResources().getDimensionPixelSize(R.dimen.content_padding_start), v.getPaddingTop(), v.getPaddingEnd(), v.getPaddingBottom()); } return v.onApplyWindowInsets(insets); } }); listView.setHasFixedSize(true); listView.setClickListener(this); listView.addOnScrollListener(this); String[] colors = getResources().getStringArray(R.array.color_array); listView.setAdapter(new ColorListAdapter(colors)); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle connectionHint) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onConnected: " + connectionHint); } } @Override public void onConnectionSuspended(int cause) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onConnectionSuspended: " + cause); } } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult result) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onConnectionFailed: " + result); } } }) .addApi(Wearable.API) .build(); } @Override protected void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override protected void onStop() { if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } super.onStop(); } @Override // WearableListView.ClickListener public void onClick(WearableListView.ViewHolder viewHolder) { ColorItemViewHolder colorItemViewHolder = (ColorItemViewHolder) viewHolder; updateConfigDataItem(colorItemViewHolder.mColorItem.getColor()); finish(); } @Override // WearableListView.ClickListener public void onTopEmptyRegionClick() {} @Override // WearableListView.OnScrollListener public void onScroll(int scroll) {} @Override // WearableListView.OnScrollListener public void onAbsoluteScrollChange(int scroll) { float newTranslation = Math.min(-scroll, 0); mHeader.setTranslationY(newTranslation); } @Override // WearableListView.OnScrollListener public void onScrollStateChanged(int scrollState) {} @Override // WearableListView.OnScrollListener public void onCentralPositionChanged(int centralPosition) {} private void updateConfigDataItem(final int backgroundColor) { DataMap configKeysToOverwrite = new DataMap(); configKeysToOverwrite.putInt(DigitalWatchFaceUtil.KEY_BACKGROUND_COLOR, backgroundColor); DigitalWatchFaceUtil.overwriteKeysInConfigDataMap(mGoogleApiClient, configKeysToOverwrite); } private class ColorListAdapter extends WearableListView.Adapter { private final String[] mColors; public ColorListAdapter(String[] colors) { mColors = colors; } @Override public ColorItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ColorItemViewHolder(new ColorItem(parent.getContext())); } @Override public void onBindViewHolder(WearableListView.ViewHolder holder, int position) { ColorItemViewHolder colorItemViewHolder = (ColorItemViewHolder) holder; String colorName = mColors[position]; colorItemViewHolder.mColorItem.setColor(colorName); RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); int colorPickerItemMargin = (int) getResources() .getDimension(R.dimen.digital_config_color_picker_item_margin); // Add margins to first and last item to make it possible for user to tap on them. if (position == 0) { layoutParams.setMargins(0, colorPickerItemMargin, 0, 0); } else if (position == mColors.length - 1) { layoutParams.setMargins(0, 0, 0, colorPickerItemMargin); } else { layoutParams.setMargins(0, 0, 0, 0); } colorItemViewHolder.itemView.setLayoutParams(layoutParams); } @Override public int getItemCount() { return mColors.length; } } /** The layout of a color item including image and label. */ private static class ColorItem extends LinearLayout implements WearableListView.OnCenterProximityListener { /** The duration of the expand/shrink animation. */ private static final int ANIMATION_DURATION_MS = 150; /** The ratio for the size of a circle in shrink state. */ private static final float SHRINK_CIRCLE_RATIO = .75f; private static final float SHRINK_LABEL_ALPHA = .5f; private static final float EXPAND_LABEL_ALPHA = 1f; private final TextView mLabel; private final CircledImageView mColor; private final float mExpandCircleRadius; private final float mShrinkCircleRadius; private final ObjectAnimator mExpandCircleAnimator; private final ObjectAnimator mExpandLabelAnimator; private final AnimatorSet mExpandAnimator; private final ObjectAnimator mShrinkCircleAnimator; private final ObjectAnimator mShrinkLabelAnimator; private final AnimatorSet mShrinkAnimator; public ColorItem(Context context) { super(context); View.inflate(context, R.layout.color_picker_item, this); mLabel = (TextView) findViewById(R.id.label); mColor = (CircledImageView) findViewById(R.id.color); mExpandCircleRadius = mColor.getCircleRadius(); mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO; mShrinkCircleAnimator = ObjectAnimator.ofFloat(mColor, "circleRadius", mExpandCircleRadius, mShrinkCircleRadius); mShrinkLabelAnimator = ObjectAnimator.ofFloat(mLabel, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA); mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS); mShrinkAnimator.playTogether(mShrinkCircleAnimator, mShrinkLabelAnimator); mExpandCircleAnimator = ObjectAnimator.ofFloat(mColor, "circleRadius", mShrinkCircleRadius, mExpandCircleRadius); mExpandLabelAnimator = ObjectAnimator.ofFloat(mLabel, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA); mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS); mExpandAnimator.playTogether(mExpandCircleAnimator, mExpandLabelAnimator); } @Override public void onCenterPosition(boolean animate) { if (animate) { mShrinkAnimator.cancel(); if (!mExpandAnimator.isRunning()) { mExpandCircleAnimator.setFloatValues(mColor.getCircleRadius(), mExpandCircleRadius); mExpandLabelAnimator.setFloatValues(mLabel.getAlpha(), EXPAND_LABEL_ALPHA); mExpandAnimator.start(); } } else { mExpandAnimator.cancel(); mColor.setCircleRadius(mExpandCircleRadius); mLabel.setAlpha(EXPAND_LABEL_ALPHA); } } @Override public void onNonCenterPosition(boolean animate) { if (animate) { mExpandAnimator.cancel(); if (!mShrinkAnimator.isRunning()) { mShrinkCircleAnimator.setFloatValues(mColor.getCircleRadius(), mShrinkCircleRadius); mShrinkLabelAnimator.setFloatValues(mLabel.getAlpha(), SHRINK_LABEL_ALPHA); mShrinkAnimator.start(); } } else { mShrinkAnimator.cancel(); mColor.setCircleRadius(mShrinkCircleRadius); mLabel.setAlpha(SHRINK_LABEL_ALPHA); } } private void setColor(String colorName) { mLabel.setText(colorName); mColor.setCircleColor(Color.parseColor(colorName)); } private int getColor() { return mColor.getDefaultCircleColor(); } } private static class ColorItemViewHolder extends WearableListView.ViewHolder { private final ColorItem mColorItem; public ColorItemViewHolder(ColorItem colorItem) { super(colorItem); mColorItem = colorItem; } } }