Home | History | Annotate | Download | only in quicksettings
      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 package com.android.car.settings.quicksettings;
     17 
     18 import android.annotation.Nullable;
     19 import android.content.Context;
     20 import android.graphics.drawable.Drawable;
     21 import android.support.v7.widget.GridLayoutManager;
     22 import android.support.v7.widget.RecyclerView;
     23 import android.text.TextUtils;
     24 import android.view.LayoutInflater;
     25 import android.view.View;
     26 import android.view.View.OnClickListener;
     27 import android.view.ViewGroup;
     28 import android.widget.ImageView;
     29 import android.widget.SeekBar;
     30 import android.widget.TextView;
     31 
     32 import com.android.car.settings.R;
     33 
     34 import java.util.ArrayList;
     35 import java.util.List;
     36 
     37 /**
     38  * Controls the content in quick setting grid view.
     39  */
     40 public class QuickSettingGridAdapter
     41         extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StateChangedListener {
     42     private static final int SEEKBAR_VIEWTYPE = 0;
     43     private static final int TILE_VIEWTYPE = 1;
     44     private final int mColumnCount;
     45     private final Context mContext;
     46     private final LayoutInflater mInflater;
     47     private final List<Tile> mTiles = new ArrayList<>();
     48     private final List<SeekbarTile> mSeekbarTiles = new ArrayList<>();
     49     private final QsSpanSizeLookup mQsSpanSizeLookup = new QsSpanSizeLookup();
     50 
     51     public QuickSettingGridAdapter(Context context) {
     52         mContext = context;
     53         mInflater = LayoutInflater.from(context);
     54         mColumnCount = mContext.getResources().getInteger(R.integer.quick_setting_column_count);
     55     }
     56 
     57     GridLayoutManager getGridLayoutManager() {
     58         GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext,
     59                 mContext.getResources().getInteger(R.integer.quick_setting_column_count));
     60         gridLayoutManager.setSpanSizeLookup(mQsSpanSizeLookup);
     61         return gridLayoutManager;
     62     }
     63 
     64     /**
     65      * Represents an UI tile in the quick setting grid.
     66      */
     67     interface Tile extends View.OnClickListener {
     68 
     69         /**
     70          * A state to indicate how we want to render icon, this is independent of what to show
     71          * in text.
     72          */
     73         enum State {OFF, ON}
     74 
     75         /**
     76          * Called when activity owning this tile's onStop() gets called.
     77          */
     78         void stop();
     79 
     80         Drawable getIcon();
     81 
     82         @Nullable
     83         String getText();
     84 
     85         State getState();
     86 
     87         /**
     88          * Returns {@code true} if this tile should be displayed.
     89          */
     90         boolean isAvailable();
     91 
     92         /**
     93          * Returns a listener for launching a setting fragment for advanced configuration for this
     94          * tile, A.K.A deep dive, if available. {@code null} if deep dive is not available.
     95          */
     96         @Nullable
     97         OnClickListener getDeepDiveListener();
     98     }
     99 
    100     interface SeekbarTile extends SeekBar.OnSeekBarChangeListener {
    101         /**
    102          * Called when activity owning this tile's onStop() gets called.
    103          */
    104         void stop();
    105 
    106         int getMax();
    107 
    108         int getCurrent();
    109     }
    110 
    111     QuickSettingGridAdapter addSeekbarTile(SeekbarTile seekbarTile) {
    112         mSeekbarTiles.add(seekbarTile);
    113         return this;
    114     }
    115 
    116     QuickSettingGridAdapter addTile(Tile tile) {
    117         if (tile.isAvailable()) {
    118             mTiles.add(tile);
    119         }
    120         return this;
    121     }
    122 
    123     void stop() {
    124         for (SeekbarTile tile : mSeekbarTiles) {
    125             tile.stop();
    126         }
    127         for (Tile tile : mTiles) {
    128             tile.stop();
    129         }
    130         mTiles.clear();
    131         mSeekbarTiles.clear();
    132     }
    133 
    134     @Override
    135     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    136         switch (viewType) {
    137             case SEEKBAR_VIEWTYPE:
    138                 return new BrightnessViewHolder(mInflater.inflate(
    139                         R.layout.brightness_tile, parent, /* attachToRoot= */ false));
    140             case TILE_VIEWTYPE:
    141                 return new TileViewHolder(mInflater.inflate(
    142                         R.layout.tile, parent, /* attachToRoot= */ false));
    143             default:
    144                 throw new RuntimeException("unknown viewType: " + viewType);
    145         }
    146     }
    147 
    148     @Override
    149     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    150         switch (holder.getItemViewType()) {
    151             case SEEKBAR_VIEWTYPE:
    152                 SeekbarTile seekbarTile = mSeekbarTiles.get(position);
    153                 SeekBar seekbar = ((BrightnessViewHolder) holder).mSeekBar;
    154                 seekbar.setMax(seekbarTile.getMax());
    155                 seekbar.setProgress(seekbarTile.getCurrent());
    156                 seekbar.setOnSeekBarChangeListener(seekbarTile);
    157                 break;
    158             case TILE_VIEWTYPE:
    159                 Tile tile = mTiles.get(position - mSeekbarTiles.size());
    160                 TileViewHolder vh = (TileViewHolder) holder;
    161                 OnClickListener deepDiveListener = tile.getDeepDiveListener();
    162                 vh.itemView.setOnClickListener(tile);
    163                 if (deepDiveListener != null) {
    164                     vh.mDeepDiveIcon.setVisibility(View.VISIBLE);
    165                     vh.mTextContainer.setOnClickListener(deepDiveListener);
    166                 } else {
    167                     vh.mDeepDiveIcon.setVisibility(View.GONE);
    168                     vh.mTextContainer.setClickable(false);
    169                     vh.mTextContainer.setOnClickListener(null);
    170                 }
    171                 vh.mIcon.setImageDrawable(tile.getIcon());
    172                 switch (tile.getState()) {
    173                     case ON:
    174                         vh.mIcon.setEnabled(true);
    175                         vh.mIconBackground.setEnabled(true);
    176                         break;
    177                     case OFF:
    178                         vh.mIcon.setEnabled(false);
    179                         vh.mIconBackground.setEnabled(false);
    180                         break;
    181                     default:
    182                 }
    183                 String textString = tile.getText();
    184                 if (!TextUtils.isEmpty(textString)) {
    185                     vh.mText.setText(textString);
    186                 }
    187                 break;
    188             default:
    189         }
    190     }
    191 
    192     private class BrightnessViewHolder extends RecyclerView.ViewHolder {
    193         private final SeekBar mSeekBar;
    194 
    195         BrightnessViewHolder(View view) {
    196             super(view);
    197             mSeekBar = (SeekBar) view.findViewById(R.id.seekbar);
    198         }
    199     }
    200 
    201     private class TileViewHolder extends RecyclerView.ViewHolder {
    202         private final View mIconContainer;
    203         private final View mTextContainer;
    204         private final View mIconBackground;
    205         private final ImageView mIcon;
    206         private final ImageView mDeepDiveIcon;
    207         private final TextView mText;
    208 
    209         TileViewHolder(View view) {
    210             super(view);
    211             mIconContainer = view.findViewById(R.id.icon_container);
    212             mTextContainer = view.findViewById(R.id.text_container);
    213             mIconBackground = view.findViewById(R.id.icon_background);
    214             mIcon = (ImageView) view.findViewById(R.id.tile_icon);
    215             mDeepDiveIcon = (ImageView) view.findViewById(R.id.deep_dive_icon);
    216             mText = (TextView) view.findViewById(R.id.tile_text);
    217         }
    218     }
    219 
    220     class QsSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
    221 
    222         /**
    223          * Each line item takes a full row, and each tile takes only 1 span.
    224          */
    225         @Override
    226         public int getSpanSize(int position) {
    227             return position < mSeekbarTiles.size() ? mColumnCount : 1;
    228         }
    229 
    230         @Override
    231         public int getSpanIndex(int position, int spanCount) {
    232             return position < mSeekbarTiles.size()
    233                     ? 1 : (position - mSeekbarTiles.size()) % mColumnCount;
    234         }
    235     }
    236 
    237     @Override
    238     public int getItemViewType(int position) {
    239         return position < mSeekbarTiles.size() ? SEEKBAR_VIEWTYPE : TILE_VIEWTYPE;
    240     }
    241 
    242     @Override
    243     public int getItemCount() {
    244         return mTiles.size() + mSeekbarTiles.size();
    245     }
    246 
    247     @Override
    248     public void onStateChanged() {
    249         notifyDataSetChanged();
    250     }
    251 }
    252