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