blob: 876f41798521bd18ea17f7e83f8da34c9174b783 [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;
Jason Monk5db8a412015-10-21 15:16:23 -070027import android.view.LayoutInflater;
Jason Monkb53b6c52016-02-24 17:25:49 -050028import android.view.MotionEvent;
Jason Monk5db8a412015-10-21 15:16:23 -070029import android.view.View;
Jason Monkb53b6c52016-02-24 17:25:49 -050030import android.view.View.OnTouchListener;
Jason Monk5db8a412015-10-21 15:16:23 -070031import android.view.ViewGroup;
Jason Monk62b63a02016-02-02 15:15:31 -050032import android.widget.FrameLayout;
Jason Monk5db8a412015-10-21 15:16:23 -070033import com.android.systemui.R;
Jason Monk62b63a02016-02-02 15:15:31 -050034import com.android.systemui.qs.QSIconView;
35import com.android.systemui.qs.QSTileView;
36import com.android.systemui.qs.customize.TileAdapter.Holder;
37import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
38import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
Jason Monk5db8a412015-10-21 15:16:23 -070039import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monk5db8a412015-10-21 15:16:23 -070040
41import java.util.ArrayList;
Jason Monk5db8a412015-10-21 15:16:23 -070042import java.util.List;
43
Jason Monk62b63a02016-02-02 15:15:31 -050044public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
Jason Monk5db8a412015-10-21 15:16:23 -070045
Jason Monk62b63a02016-02-02 15:15:31 -050046 private static final long DRAG_LENGTH = 100;
47 private static final float DRAG_SCALE = 1.2f;
48 public static final long MOVE_DURATION = 150;
Jason Monk5db8a412015-10-21 15:16:23 -070049
Jason Monk62b63a02016-02-02 15:15:31 -050050 private static final int TYPE_TILE = 0;
51 private static final int TYPE_EDIT = 1;
52
Jason Monk5db8a412015-10-21 15:16:23 -070053 private final Context mContext;
54
Jason Monk62b63a02016-02-02 15:15:31 -050055 private final List<TileInfo> mTiles = new ArrayList<>();
Jason Monkb53b6c52016-02-24 17:25:49 -050056 private final ItemTouchHelper mItemTouchHelper;
Jason Monk62b63a02016-02-02 15:15:31 -050057 private int mDividerIndex;
58 private List<String> mCurrentSpecs;
59 private List<TileInfo> mOtherTiles;
60 private List<TileInfo> mAllTiles;
Jason Monk5db8a412015-10-21 15:16:23 -070061
Jason Monk62b63a02016-02-02 15:15:31 -050062 private Holder mCurrentDrag;
63
64 public TileAdapter(Context context) {
Jason Monk5db8a412015-10-21 15:16:23 -070065 mContext = context;
Jason Monkb53b6c52016-02-24 17:25:49 -050066 mItemTouchHelper = new ItemTouchHelper(mCallbacks);
Jason Monk62b63a02016-02-02 15:15:31 -050067 setHasStableIds(true);
Jason Monk5db8a412015-10-21 15:16:23 -070068 }
69
70 @Override
71 public long getItemId(int position) {
Jason Monk62b63a02016-02-02 15:15:31 -050072 return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
73 }
74
Jason Monkb53b6c52016-02-24 17:25:49 -050075 public ItemTouchHelper getItemTouchHelper() {
76 return mItemTouchHelper;
Jason Monk62b63a02016-02-02 15:15:31 -050077 }
78
79 public ItemDecoration getItemDecoration() {
80 return mDecoration;
81 }
82
83 public void saveSpecs(QSTileHost host) {
84 List<String> newSpecs = new ArrayList<>();
85 for (int i = 0; mTiles.get(i) != null; i++) {
86 newSpecs.add(mTiles.get(i).spec);
87 }
88 host.changeTiles(mCurrentSpecs, newSpecs);
89 setTileSpecs(newSpecs);
90 }
91
92 public void setTileSpecs(List<String> currentSpecs) {
93 mCurrentSpecs = currentSpecs;
94 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -070095 }
96
97 @Override
Jason Monk62b63a02016-02-02 15:15:31 -050098 public void onTilesChanged(List<TileInfo> tiles) {
99 mAllTiles = tiles;
100 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -0700101 }
102
Jason Monk62b63a02016-02-02 15:15:31 -0500103 private void recalcSpecs() {
104 if (mCurrentSpecs == null || mAllTiles == null) {
105 return;
Jason Monk5db8a412015-10-21 15:16:23 -0700106 }
Jason Monk62b63a02016-02-02 15:15:31 -0500107 mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
108 mTiles.clear();
109 for (int i = 0; i < mCurrentSpecs.size(); i++) {
110 mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i)));
Jason Monk5db8a412015-10-21 15:16:23 -0700111 }
Jason Monk62b63a02016-02-02 15:15:31 -0500112 mTiles.add(null);
113 mTiles.addAll(mOtherTiles);
114 mDividerIndex = mTiles.indexOf(null);
115 notifyDataSetChanged();
116 }
Jason Monk5db8a412015-10-21 15:16:23 -0700117
Jason Monk62b63a02016-02-02 15:15:31 -0500118 private TileInfo getAndRemoveOther(String s) {
119 for (int i = 0; i < mOtherTiles.size(); i++) {
120 if (mOtherTiles.get(i).spec.equals(s)) {
121 return mOtherTiles.remove(i);
Jason Monk5db8a412015-10-21 15:16:23 -0700122 }
Jason Monk62b63a02016-02-02 15:15:31 -0500123 }
124 return null;
125 }
126
127 @Override
128 public int getItemViewType(int position) {
129 if (mTiles.get(position) == null) {
130 return TYPE_EDIT;
131 }
132 return TYPE_TILE;
133 }
134
135 @Override
136 public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
137 final Context context = parent.getContext();
138 LayoutInflater inflater = LayoutInflater.from(context);
139 if (viewType == 1) {
140 return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
141 }
142 FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
143 false);
144 frame.addView(new QSTileView(context, new QSIconView(context)));
145 return new Holder(frame);
146 }
147
148 @Override
149 public int getItemCount() {
150 return mTiles.size();
151 }
152
153 @Override
Jason Monkb53b6c52016-02-24 17:25:49 -0500154 public void onBindViewHolder(final Holder holder, int position) {
Jason Monk62b63a02016-02-02 15:15:31 -0500155 if (holder.getItemViewType() == TYPE_EDIT) return;
156
157 TileInfo info = mTiles.get(position);
158 holder.mTileView.onStateChanged(info.state);
Jason Monkb53b6c52016-02-24 17:25:49 -0500159 holder.mTileView.setOnTouchListener(new OnTouchListener() {
160 @Override
161 public boolean onTouch(View v, MotionEvent event) {
162 mItemTouchHelper.startDrag(holder);
163 return true;
164 }
165 });
Jason Monk62b63a02016-02-02 15:15:31 -0500166 }
167
168 public SpanSizeLookup getSizeLookup() {
169 return mSizeLookup;
170 }
171
172 public class Holder extends ViewHolder {
173 private QSTileView mTileView;
174
175 public Holder(View itemView) {
176 super(itemView);
177 if (itemView instanceof FrameLayout) {
178 mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
Jason Monk5db8a412015-10-21 15:16:23 -0700179 }
Jason Monk5db8a412015-10-21 15:16:23 -0700180 }
181
Jason Monk62b63a02016-02-02 15:15:31 -0500182 public void startDrag() {
183 itemView.animate()
184 .setDuration(DRAG_LENGTH)
185 .scaleX(DRAG_SCALE)
186 .scaleY(DRAG_SCALE);
187 mTileView.findViewById(R.id.tile_label).animate()
188 .setDuration(DRAG_LENGTH)
189 .alpha(0);
190 }
191
192 public void stopDrag() {
193 itemView.animate()
194 .setDuration(DRAG_LENGTH)
195 .scaleX(1)
196 .scaleY(1);
197 mTileView.findViewById(R.id.tile_label).animate()
198 .setDuration(DRAG_LENGTH)
199 .alpha(1);
Jason Monk5db8a412015-10-21 15:16:23 -0700200 }
201 }
202
Jason Monk62b63a02016-02-02 15:15:31 -0500203 private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
Jason Monk5db8a412015-10-21 15:16:23 -0700204 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500205 public int getSpanSize(int position) {
206 return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
207 }
208 };
209
210 private final ItemDecoration mDecoration = new ItemDecoration() {
211 // TODO: Move this to resource.
212 private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
213
214 @Override
215 public void onDraw(Canvas c, RecyclerView parent, State state) {
216 super.onDraw(c, parent, state);
217
218 final int childCount = parent.getChildCount();
219 final int width = parent.getWidth();
220 final int bottom = parent.getBottom();
221 for (int i = 0; i < childCount; i++) {
222 final View child = parent.getChildAt(i);
223 final ViewHolder holder = parent.getChildViewHolder(child);
224 if (holder.getAdapterPosition() < mDividerIndex) {
Jason Monk5db8a412015-10-21 15:16:23 -0700225 continue;
226 }
Jason Monk62b63a02016-02-02 15:15:31 -0500227
228 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
229 .getLayoutParams();
230 final int top = child.getTop() + params.topMargin +
231 Math.round(ViewCompat.getTranslationY(child));
232 // Draw full width, in case there aren't tiles all the way across.
233 mDrawable.setBounds(0, top, width, bottom);
234 mDrawable.draw(c);
235 break;
Jason Monk5db8a412015-10-21 15:16:23 -0700236 }
Jason Monk62b63a02016-02-02 15:15:31 -0500237 }
238 };
239
240 private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
241
242 @Override
243 public boolean isLongPressDragEnabled() {
244 return true;
Jason Monk5db8a412015-10-21 15:16:23 -0700245 }
246
247 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500248 public boolean isItemViewSwipeEnabled() {
249 return false;
Jason Monk5db8a412015-10-21 15:16:23 -0700250 }
Jason Monk5db8a412015-10-21 15:16:23 -0700251
Jason Monk62b63a02016-02-02 15:15:31 -0500252 @Override
253 public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
254 super.onSelectedChanged(viewHolder, actionState);
255 if (mCurrentDrag != null) {
256 mCurrentDrag.stopDrag();
257 }
258 if (viewHolder != null) {
259 mCurrentDrag = (Holder) viewHolder;
260 mCurrentDrag.startDrag();
261 }
262 }
263
264 @Override
265 public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
266 if (viewHolder.getItemViewType() == TYPE_EDIT) {
267 return makeMovementFlags(0, 0);
268 }
269 int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
270 | ItemTouchHelper.LEFT;
271 return makeMovementFlags(dragFlags, 0);
272 }
273
274 @Override
275 public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
276 int from = viewHolder.getAdapterPosition();
277 int to = target.getAdapterPosition();
278 if (to > mDividerIndex) {
Jason Monkb53b6c52016-02-24 17:25:49 -0500279 if (from >= mDividerIndex) {
Jason Monk62b63a02016-02-02 15:15:31 -0500280 return false;
281 }
282 }
283 if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
284 to++;
285 }
286 move(from, to, mTiles);
287 mDividerIndex = mTiles.indexOf(null);
288 notifyItemMoved(from, to);
289 return true;
290 }
291
292 private <T> void move(int from, int to, List<T> list) {
293 list.add(from > to ? to : to + 1, list.get(from));
294 list.remove(from > to ? from + 1 : from);
295 }
296
297 @Override
298 public void onSwiped(ViewHolder viewHolder, int direction) {
299 }
300 };
Jason Monk5db8a412015-10-21 15:16:23 -0700301}