blob: fb3818cf9db123d4c8505601f8ccb3e7c87e79bf [file] [log] [blame]
Jason Monk5db8a412015-10-21 15:16:23 -07001/*
Jason Monk62b63a02016-02-02 15:15:31 -05002 * Copyright (C) 2016 The Android Open Source Project
Jason Monk5db8a412015-10-21 15:16:23 -07003 *
Jason Monk62b63a02016-02-02 15:15:31 -05004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
Jason Monk5db8a412015-10-21 15:16:23 -07006 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
Jason Monk62b63a02016-02-02 15:15:31 -05009 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
Jason Monk5db8a412015-10-21 15:16:23 -070013 */
14
15package com.android.systemui.qs.customize;
16
Jason Monk5db8a412015-10-21 15:16:23 -070017import android.content.Context;
Jason Monk62b63a02016-02-02 15:15:31 -050018import android.graphics.Canvas;
19import android.graphics.drawable.ColorDrawable;
20import android.support.v4.view.ViewCompat;
21import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
22import android.support.v7.widget.RecyclerView;
23import android.support.v7.widget.RecyclerView.ItemDecoration;
24import android.support.v7.widget.RecyclerView.State;
25import android.support.v7.widget.RecyclerView.ViewHolder;
26import android.support.v7.widget.helper.ItemTouchHelper;
27import android.support.v7.widget.helper.ItemTouchHelper.Callback;
Jason Monk5db8a412015-10-21 15:16:23 -070028import android.view.LayoutInflater;
29import android.view.View;
Jason Monk5db8a412015-10-21 15:16:23 -070030import android.view.ViewGroup;
Jason Monk62b63a02016-02-02 15:15:31 -050031import android.widget.FrameLayout;
Jason Monk5db8a412015-10-21 15:16:23 -070032import com.android.systemui.R;
Jason Monk62b63a02016-02-02 15:15:31 -050033import com.android.systemui.qs.QSIconView;
34import com.android.systemui.qs.QSTileView;
35import com.android.systemui.qs.customize.TileAdapter.Holder;
36import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
37import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
Jason Monk5db8a412015-10-21 15:16:23 -070038import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monk5db8a412015-10-21 15:16:23 -070039
40import java.util.ArrayList;
Jason Monk5db8a412015-10-21 15:16:23 -070041import java.util.List;
42
Jason Monk62b63a02016-02-02 15:15:31 -050043public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
Jason Monk5db8a412015-10-21 15:16:23 -070044
Jason Monk62b63a02016-02-02 15:15:31 -050045 private static final long DRAG_LENGTH = 100;
46 private static final float DRAG_SCALE = 1.2f;
47 public static final long MOVE_DURATION = 150;
Jason Monk5db8a412015-10-21 15:16:23 -070048
Jason Monk62b63a02016-02-02 15:15:31 -050049 private static final int TYPE_TILE = 0;
50 private static final int TYPE_EDIT = 1;
51
Jason Monk5db8a412015-10-21 15:16:23 -070052 private final Context mContext;
53
Jason Monk62b63a02016-02-02 15:15:31 -050054 private final List<TileInfo> mTiles = new ArrayList<>();
55 private int mDividerIndex;
56 private List<String> mCurrentSpecs;
57 private List<TileInfo> mOtherTiles;
58 private List<TileInfo> mAllTiles;
Jason Monk5db8a412015-10-21 15:16:23 -070059
Jason Monk62b63a02016-02-02 15:15:31 -050060 private Holder mCurrentDrag;
61
62 public TileAdapter(Context context) {
Jason Monk5db8a412015-10-21 15:16:23 -070063 mContext = context;
Jason Monk62b63a02016-02-02 15:15:31 -050064 setHasStableIds(true);
Jason Monk5db8a412015-10-21 15:16:23 -070065 }
66
67 @Override
68 public long getItemId(int position) {
Jason Monk62b63a02016-02-02 15:15:31 -050069 return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
70 }
71
72 public Callback getCallback() {
73 return mCallbacks;
74 }
75
76 public ItemDecoration getItemDecoration() {
77 return mDecoration;
78 }
79
80 public void saveSpecs(QSTileHost host) {
81 List<String> newSpecs = new ArrayList<>();
82 for (int i = 0; mTiles.get(i) != null; i++) {
83 newSpecs.add(mTiles.get(i).spec);
84 }
85 host.changeTiles(mCurrentSpecs, newSpecs);
86 setTileSpecs(newSpecs);
87 }
88
89 public void setTileSpecs(List<String> currentSpecs) {
90 mCurrentSpecs = currentSpecs;
91 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -070092 }
93
94 @Override
Jason Monk62b63a02016-02-02 15:15:31 -050095 public void onTilesChanged(List<TileInfo> tiles) {
96 mAllTiles = tiles;
97 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -070098 }
99
Jason Monk62b63a02016-02-02 15:15:31 -0500100 private void recalcSpecs() {
101 if (mCurrentSpecs == null || mAllTiles == null) {
102 return;
Jason Monk5db8a412015-10-21 15:16:23 -0700103 }
Jason Monk62b63a02016-02-02 15:15:31 -0500104 mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
105 mTiles.clear();
106 for (int i = 0; i < mCurrentSpecs.size(); i++) {
107 mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i)));
Jason Monk5db8a412015-10-21 15:16:23 -0700108 }
Jason Monk62b63a02016-02-02 15:15:31 -0500109 mTiles.add(null);
110 mTiles.addAll(mOtherTiles);
111 mDividerIndex = mTiles.indexOf(null);
112 notifyDataSetChanged();
113 }
Jason Monk5db8a412015-10-21 15:16:23 -0700114
Jason Monk62b63a02016-02-02 15:15:31 -0500115 private TileInfo getAndRemoveOther(String s) {
116 for (int i = 0; i < mOtherTiles.size(); i++) {
117 if (mOtherTiles.get(i).spec.equals(s)) {
118 return mOtherTiles.remove(i);
Jason Monk5db8a412015-10-21 15:16:23 -0700119 }
Jason Monk62b63a02016-02-02 15:15:31 -0500120 }
121 return null;
122 }
123
124 @Override
125 public int getItemViewType(int position) {
126 if (mTiles.get(position) == null) {
127 return TYPE_EDIT;
128 }
129 return TYPE_TILE;
130 }
131
132 @Override
133 public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
134 final Context context = parent.getContext();
135 LayoutInflater inflater = LayoutInflater.from(context);
136 if (viewType == 1) {
137 return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
138 }
139 FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
140 false);
141 frame.addView(new QSTileView(context, new QSIconView(context)));
142 return new Holder(frame);
143 }
144
145 @Override
146 public int getItemCount() {
147 return mTiles.size();
148 }
149
150 @Override
151 public void onBindViewHolder(Holder holder, int position) {
152 if (holder.getItemViewType() == TYPE_EDIT) return;
153
154 TileInfo info = mTiles.get(position);
155 holder.mTileView.onStateChanged(info.state);
156 }
157
158 public SpanSizeLookup getSizeLookup() {
159 return mSizeLookup;
160 }
161
162 public class Holder extends ViewHolder {
163 private QSTileView mTileView;
164
165 public Holder(View itemView) {
166 super(itemView);
167 if (itemView instanceof FrameLayout) {
168 mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
Jason Monk5db8a412015-10-21 15:16:23 -0700169 }
Jason Monk5db8a412015-10-21 15:16:23 -0700170 }
171
Jason Monk62b63a02016-02-02 15:15:31 -0500172 public void startDrag() {
173 itemView.animate()
174 .setDuration(DRAG_LENGTH)
175 .scaleX(DRAG_SCALE)
176 .scaleY(DRAG_SCALE);
177 mTileView.findViewById(R.id.tile_label).animate()
178 .setDuration(DRAG_LENGTH)
179 .alpha(0);
180 }
181
182 public void stopDrag() {
183 itemView.animate()
184 .setDuration(DRAG_LENGTH)
185 .scaleX(1)
186 .scaleY(1);
187 mTileView.findViewById(R.id.tile_label).animate()
188 .setDuration(DRAG_LENGTH)
189 .alpha(1);
Jason Monk5db8a412015-10-21 15:16:23 -0700190 }
191 }
192
Jason Monk62b63a02016-02-02 15:15:31 -0500193 private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
Jason Monk5db8a412015-10-21 15:16:23 -0700194 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500195 public int getSpanSize(int position) {
196 return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
197 }
198 };
199
200 private final ItemDecoration mDecoration = new ItemDecoration() {
201 // TODO: Move this to resource.
202 private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
203
204 @Override
205 public void onDraw(Canvas c, RecyclerView parent, State state) {
206 super.onDraw(c, parent, state);
207
208 final int childCount = parent.getChildCount();
209 final int width = parent.getWidth();
210 final int bottom = parent.getBottom();
211 for (int i = 0; i < childCount; i++) {
212 final View child = parent.getChildAt(i);
213 final ViewHolder holder = parent.getChildViewHolder(child);
214 if (holder.getAdapterPosition() < mDividerIndex) {
Jason Monk5db8a412015-10-21 15:16:23 -0700215 continue;
216 }
Jason Monk62b63a02016-02-02 15:15:31 -0500217
218 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
219 .getLayoutParams();
220 final int top = child.getTop() + params.topMargin +
221 Math.round(ViewCompat.getTranslationY(child));
222 // Draw full width, in case there aren't tiles all the way across.
223 mDrawable.setBounds(0, top, width, bottom);
224 mDrawable.draw(c);
225 break;
Jason Monk5db8a412015-10-21 15:16:23 -0700226 }
Jason Monk62b63a02016-02-02 15:15:31 -0500227 }
228 };
229
230 private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
231
232 @Override
233 public boolean isLongPressDragEnabled() {
234 return true;
Jason Monk5db8a412015-10-21 15:16:23 -0700235 }
236
237 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500238 public boolean isItemViewSwipeEnabled() {
239 return false;
Jason Monk5db8a412015-10-21 15:16:23 -0700240 }
Jason Monk5db8a412015-10-21 15:16:23 -0700241
Jason Monk62b63a02016-02-02 15:15:31 -0500242 @Override
243 public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
244 super.onSelectedChanged(viewHolder, actionState);
245 if (mCurrentDrag != null) {
246 mCurrentDrag.stopDrag();
247 }
248 if (viewHolder != null) {
249 mCurrentDrag = (Holder) viewHolder;
250 mCurrentDrag.startDrag();
251 }
252 }
253
254 @Override
255 public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
256 if (viewHolder.getItemViewType() == TYPE_EDIT) {
257 return makeMovementFlags(0, 0);
258 }
259 int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
260 | ItemTouchHelper.LEFT;
261 return makeMovementFlags(dragFlags, 0);
262 }
263
264 @Override
265 public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
266 int from = viewHolder.getAdapterPosition();
267 int to = target.getAdapterPosition();
268 if (to > mDividerIndex) {
269 if (from < mDividerIndex) {
270 to = mDividerIndex;
271 } else {
272 return false;
273 }
274 }
275 if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
276 to++;
277 }
278 move(from, to, mTiles);
279 mDividerIndex = mTiles.indexOf(null);
280 notifyItemMoved(from, to);
281 return true;
282 }
283
284 private <T> void move(int from, int to, List<T> list) {
285 list.add(from > to ? to : to + 1, list.get(from));
286 list.remove(from > to ? from + 1 : from);
287 }
288
289 @Override
290 public void onSwiped(ViewHolder viewHolder, int direction) {
291 }
292 };
Jason Monk5db8a412015-10-21 15:16:23 -0700293}