blob: 6c392cab8225d57f74ae8e94c7565321b3d4574c [file] [log] [blame]
Lujiang Xue0daa9192017-12-06 11:48:39 -08001/*
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 */
16package com.android.car.settings.quicksettings;
17
18import android.annotation.Nullable;
19import android.content.Context;
20import android.graphics.drawable.Drawable;
Lujiang Xue73f45732018-04-05 09:42:19 -070021import android.support.v7.widget.GridLayoutManager;
22import android.support.v7.widget.RecyclerView;
Lujiang Xue0daa9192017-12-06 11:48:39 -080023import android.text.TextUtils;
24import android.view.LayoutInflater;
25import android.view.View;
Lujiang Xueeaff6c32018-04-10 08:20:29 -070026import android.view.View.OnClickListener;
Lujiang Xue0daa9192017-12-06 11:48:39 -080027import android.view.ViewGroup;
Lujiang Xue73f45732018-04-05 09:42:19 -070028import android.widget.ImageView;
29import android.widget.SeekBar;
Lujiang Xue0daa9192017-12-06 11:48:39 -080030import android.widget.TextView;
31
32import com.android.car.settings.R;
33
34import java.util.ArrayList;
35import java.util.List;
36
37/**
38 * Controls the content in quick setting grid view.
39 */
Lujiang Xue73f45732018-04-05 09:42:19 -070040public class QuickSettingGridAdapter
41 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StateChangedListener {
42 private static final int COLUMN_COUNT = 4;
Lujiang Xue73f45732018-04-05 09:42:19 -070043 private static final int SEEKBAR_VIEWTYPE = 0;
44 private static final int TILE_VIEWTYPE = 1;
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();
Lujiang Xue0daa9192017-12-06 11:48:39 -080050
51 public QuickSettingGridAdapter(Context context) {
52 mContext = context;
Lujiang Xue73f45732018-04-05 09:42:19 -070053 mInflater = LayoutInflater.from(context);
54 }
55
56 GridLayoutManager getGridLayoutManager() {
57 GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext,
58 mContext.getResources().getInteger(R.integer.quick_setting_column_count));
59 gridLayoutManager.setSpanSizeLookup(mQsSpanSizeLookup);
60 return gridLayoutManager;
Lujiang Xue0daa9192017-12-06 11:48:39 -080061 }
62
63 /**
64 * Represents an UI tile in the quick setting grid.
65 */
66 interface Tile extends View.OnClickListener {
67
68 /**
69 * A state to indicate how we want to render icon, this is independent of what to show
70 * in text.
71 */
72 enum State {OFF, ON}
73
74 /**
75 * Called when activity owning this tile's onStop() gets called.
76 */
77 void stop();
78
79 Drawable getIcon();
80
81 @Nullable
82 String getText();
83
84 State getState();
Lujiang Xueeaff6c32018-04-10 08:20:29 -070085
86 /**
87 * Returns {@code true} if this tile should be displayed.
88 */
89 boolean isAvailable();
90
91 /**
92 * Returns a listener for launching a setting fragment for advanced configuration for this
93 * tile, A.K.A deep dive, if available. {@code null} if deep dive is not available.
94 */
95 @Nullable
96 OnClickListener getDeepDiveListener();
Lujiang Xue0daa9192017-12-06 11:48:39 -080097 }
98
Lujiang Xue73f45732018-04-05 09:42:19 -070099 interface SeekbarTile extends SeekBar.OnSeekBarChangeListener {
100 /**
101 * Called when activity owning this tile's onStop() gets called.
102 */
103 void stop();
104
105 int getMax();
106
107 int getCurrent();
108 }
109
110 QuickSettingGridAdapter addSeekbarTile(SeekbarTile seekbarTile) {
111 mSeekbarTiles.add(seekbarTile);
Lujiang Xue0daa9192017-12-06 11:48:39 -0800112 return this;
113 }
114
Lujiang Xue73f45732018-04-05 09:42:19 -0700115 QuickSettingGridAdapter addTile(Tile tile) {
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700116 if (tile.isAvailable()) {
117 mTiles.add(tile);
118 }
Lujiang Xue73f45732018-04-05 09:42:19 -0700119 return this;
120 }
121
122 void stop() {
123 for (SeekbarTile tile : mSeekbarTiles) {
Lujiang Xue0daa9192017-12-06 11:48:39 -0800124 tile.stop();
125 }
Lujiang Xue73f45732018-04-05 09:42:19 -0700126 for (Tile tile : mTiles) {
127 tile.stop();
128 }
129 mTiles.clear();
130 mSeekbarTiles.clear();
Lujiang Xue0daa9192017-12-06 11:48:39 -0800131 }
132
133 @Override
Lujiang Xue73f45732018-04-05 09:42:19 -0700134 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
135 switch (viewType) {
136 case SEEKBAR_VIEWTYPE:
137 return new BrightnessViewHolder(mInflater.inflate(
138 R.layout.brightness_tile, parent, /* attachToRoot= */ false));
139 case TILE_VIEWTYPE:
140 return new TileViewHolder(mInflater.inflate(
141 R.layout.tile, parent, /* attachToRoot= */ false));
142 default:
143 throw new RuntimeException("unknown viewType: " + viewType);
144 }
Lujiang Xue0daa9192017-12-06 11:48:39 -0800145 }
146
147 @Override
Lujiang Xue73f45732018-04-05 09:42:19 -0700148 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
149 switch (holder.getItemViewType()) {
150 case SEEKBAR_VIEWTYPE:
151 SeekbarTile seekbarTile = mSeekbarTiles.get(position);
152 SeekBar seekbar = ((BrightnessViewHolder) holder).mSeekBar;
153 seekbar.setMax(seekbarTile.getMax());
154 seekbar.setProgress(seekbarTile.getCurrent());
155 seekbar.setOnSeekBarChangeListener(seekbarTile);
Lujiang Xue0daa9192017-12-06 11:48:39 -0800156 break;
Lujiang Xue73f45732018-04-05 09:42:19 -0700157 case TILE_VIEWTYPE:
158 Tile tile = mTiles.get(position - mSeekbarTiles.size());
159 TileViewHolder vh = (TileViewHolder) holder;
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700160 OnClickListener deepDiveListener = tile.getDeepDiveListener();
161 if (deepDiveListener != null) {
162 vh.mDeepDiveIcon.setVisibility(View.VISIBLE);
163 vh.mTextContainer.setOnClickListener(deepDiveListener);
164 vh.mIconContainer.setOnClickListener(tile);
165 vh.itemView.setOnClickListener(null);
166 vh.itemView.setClickable(false);
167 } else {
168 vh.itemView.setOnClickListener(tile);
169 vh.itemView.setClickable(true);
170 vh.mIconContainer.setOnClickListener(null);
171 vh.mIconContainer.setClickable(false);
172 vh.mDeepDiveIcon.setVisibility(View.GONE);
173 vh.mTextContainer.setClickable(false);
174 vh.mTextContainer.setOnClickListener(null);
175 }
Lujiang Xue73f45732018-04-05 09:42:19 -0700176 vh.mIcon.setImageDrawable(tile.getIcon());
177 switch (tile.getState()) {
178 case ON:
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700179 vh.mIcon.setEnabled(true);
180 vh.mIconBackground.setEnabled(true);
Lujiang Xue73f45732018-04-05 09:42:19 -0700181 break;
182 case OFF:
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700183 vh.mIcon.setEnabled(false);
184 vh.mIconBackground.setEnabled(false);
Lujiang Xue73f45732018-04-05 09:42:19 -0700185 break;
186 default:
187 }
188 String textString = tile.getText();
189 if (!TextUtils.isEmpty(textString)) {
190 vh.mText.setText(textString);
191 }
Lujiang Xue0daa9192017-12-06 11:48:39 -0800192 break;
193 default:
Lujiang Xue0daa9192017-12-06 11:48:39 -0800194 }
Lujiang Xue73f45732018-04-05 09:42:19 -0700195 }
196
197 private class BrightnessViewHolder extends RecyclerView.ViewHolder {
198 private final SeekBar mSeekBar;
199
200 BrightnessViewHolder(View view) {
201 super(view);
202 mSeekBar = (SeekBar) view.findViewById(R.id.seekbar);
Lujiang Xue0daa9192017-12-06 11:48:39 -0800203 }
Lujiang Xue73f45732018-04-05 09:42:19 -0700204 }
205
206 private class TileViewHolder extends RecyclerView.ViewHolder {
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700207 private final View mIconContainer;
208 private final View mTextContainer;
209 private final View mIconBackground;
Lujiang Xue73f45732018-04-05 09:42:19 -0700210 private final ImageView mIcon;
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700211 private final ImageView mDeepDiveIcon;
Lujiang Xue73f45732018-04-05 09:42:19 -0700212 private final TextView mText;
213
214 TileViewHolder(View view) {
215 super(view);
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700216 mIconContainer = view.findViewById(R.id.icon_container);
217 mTextContainer = view.findViewById(R.id.text_container);
218 mIconBackground = view.findViewById(R.id.icon_background);
Lujiang Xue73f45732018-04-05 09:42:19 -0700219 mIcon = (ImageView) view.findViewById(R.id.tile_icon);
Lujiang Xueeaff6c32018-04-10 08:20:29 -0700220 mDeepDiveIcon = (ImageView) view.findViewById(R.id.deep_dive_icon);
Lujiang Xue73f45732018-04-05 09:42:19 -0700221 mText = (TextView) view.findViewById(R.id.tile_text);
222 }
223 }
224
225 class QsSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
226
227 /**
228 * Each line item takes a full row, and each tile takes only 1 span.
229 */
230 @Override
231 public int getSpanSize(int position) {
232 return position < mSeekbarTiles.size() ? COLUMN_COUNT : 1;
233 }
234
235 @Override
236 public int getSpanIndex(int position, int spanCount) {
237 return position < mSeekbarTiles.size()
238 ? 1 : (position - mSeekbarTiles.size()) % COLUMN_COUNT;
239 }
240 }
241
242 @Override
243 public int getItemViewType(int position) {
244 return position < mSeekbarTiles.size() ? SEEKBAR_VIEWTYPE : TILE_VIEWTYPE;
245 }
246
247 @Override
248 public int getItemCount() {
249 return mTiles.size() + mSeekbarTiles.size();
Lujiang Xue0daa9192017-12-06 11:48:39 -0800250 }
251
252 @Override
253 public void onStateChanged() {
254 notifyDataSetChanged();
255 }
256}