Home | History | Annotate | Download | only in com.example.android.wearable.watchface
      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 }
    299