blob: 2ba40449707a417589cf0d29b3c62100ea0ce90a [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 Monk39c98e62016-03-16 09:18:35 -040017import android.app.AlertDialog;
18import android.app.AlertDialog.Builder;
Jason Monk96defbe2016-03-29 16:51:03 -040019import android.content.ComponentName;
Jason Monk5db8a412015-10-21 15:16:23 -070020import android.content.Context;
Jason Monk39c98e62016-03-16 09:18:35 -040021import android.content.DialogInterface;
Jason Monk62b63a02016-02-02 15:15:31 -050022import android.graphics.Canvas;
23import android.graphics.drawable.ColorDrawable;
Jason Monk1c2fea82016-03-11 11:33:36 -050024import android.os.Handler;
Jason Monk62b63a02016-02-02 15:15:31 -050025import android.support.v4.view.ViewCompat;
26import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
27import android.support.v7.widget.RecyclerView;
28import android.support.v7.widget.RecyclerView.ItemDecoration;
29import android.support.v7.widget.RecyclerView.State;
30import android.support.v7.widget.RecyclerView.ViewHolder;
31import android.support.v7.widget.helper.ItemTouchHelper;
Jason Monk5db8a412015-10-21 15:16:23 -070032import android.view.LayoutInflater;
33import android.view.View;
Jason Monk39c98e62016-03-16 09:18:35 -040034import android.view.View.OnClickListener;
35import android.view.View.OnLayoutChangeListener;
Jason Monk5db8a412015-10-21 15:16:23 -070036import android.view.ViewGroup;
Jason Monk39c98e62016-03-16 09:18:35 -040037import android.view.accessibility.AccessibilityManager;
Jason Monk62b63a02016-02-02 15:15:31 -050038import android.widget.FrameLayout;
Jason Monk24dbd512016-03-16 14:56:42 -040039import android.widget.TextView;
Jason Monk96defbe2016-03-29 16:51:03 -040040import com.android.internal.logging.MetricsLogger;
41import com.android.internal.logging.MetricsProto;
Jason Monk5db8a412015-10-21 15:16:23 -070042import com.android.systemui.R;
Jason Monk62b63a02016-02-02 15:15:31 -050043import com.android.systemui.qs.QSIconView;
Jason Monk62b63a02016-02-02 15:15:31 -050044import com.android.systemui.qs.customize.TileAdapter.Holder;
45import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
46import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
Jason Monk96defbe2016-03-29 16:51:03 -040047import com.android.systemui.qs.external.CustomTile;
Jason Monk5db8a412015-10-21 15:16:23 -070048import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monk39c98e62016-03-16 09:18:35 -040049import com.android.systemui.statusbar.phone.SystemUIDialog;
Jason Monk5db8a412015-10-21 15:16:23 -070050
51import java.util.ArrayList;
Jason Monk5db8a412015-10-21 15:16:23 -070052import java.util.List;
53
Jason Monk62b63a02016-02-02 15:15:31 -050054public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
Jason Monk5db8a412015-10-21 15:16:23 -070055
Jason Monk62b63a02016-02-02 15:15:31 -050056 private static final long DRAG_LENGTH = 100;
57 private static final float DRAG_SCALE = 1.2f;
58 public static final long MOVE_DURATION = 150;
Jason Monk5db8a412015-10-21 15:16:23 -070059
Jason Monk62b63a02016-02-02 15:15:31 -050060 private static final int TYPE_TILE = 0;
61 private static final int TYPE_EDIT = 1;
Jason Monk39c98e62016-03-16 09:18:35 -040062 private static final int TYPE_ACCESSIBLE_DROP = 2;
Jason Monk0b349ad2016-04-04 11:18:03 -040063 private static final int TYPE_DIVIDER = 4;
64
65 private static final long EDIT_ID = 10000;
66 private static final long DIVIDER_ID = 20000;
Jason Monk62b63a02016-02-02 15:15:31 -050067
Jason Monk5db8a412015-10-21 15:16:23 -070068 private final Context mContext;
69
Jason Monk1c2fea82016-03-11 11:33:36 -050070 private final Handler mHandler = new Handler();
Jason Monk62b63a02016-02-02 15:15:31 -050071 private final List<TileInfo> mTiles = new ArrayList<>();
Jason Monkb53b6c52016-02-24 17:25:49 -050072 private final ItemTouchHelper mItemTouchHelper;
Jason Monk39c98e62016-03-16 09:18:35 -040073 private final AccessibilityManager mAccessibilityManager;
Jason Monk0b349ad2016-04-04 11:18:03 -040074 private int mEditIndex;
75 private int mTileDividerIndex;
Jason Monk39c98e62016-03-16 09:18:35 -040076 private boolean mNeedsFocus;
Jason Monk62b63a02016-02-02 15:15:31 -050077 private List<String> mCurrentSpecs;
78 private List<TileInfo> mOtherTiles;
79 private List<TileInfo> mAllTiles;
Jason Monk5db8a412015-10-21 15:16:23 -070080
Jason Monk62b63a02016-02-02 15:15:31 -050081 private Holder mCurrentDrag;
Jason Monk39c98e62016-03-16 09:18:35 -040082 private boolean mAccessibilityMoving;
83 private int mAccessibilityFromIndex;
Jason Monk62b63a02016-02-02 15:15:31 -050084
85 public TileAdapter(Context context) {
Jason Monk5db8a412015-10-21 15:16:23 -070086 mContext = context;
Jason Monk39c98e62016-03-16 09:18:35 -040087 mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
Jason Monkb53b6c52016-02-24 17:25:49 -050088 mItemTouchHelper = new ItemTouchHelper(mCallbacks);
Jason Monk62b63a02016-02-02 15:15:31 -050089 setHasStableIds(true);
Jason Monk5db8a412015-10-21 15:16:23 -070090 }
91
92 @Override
93 public long getItemId(int position) {
Jason Monk0b349ad2016-04-04 11:18:03 -040094 return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
95 : position == mEditIndex ? EDIT_ID : DIVIDER_ID;
Jason Monk62b63a02016-02-02 15:15:31 -050096 }
97
Jason Monkb53b6c52016-02-24 17:25:49 -050098 public ItemTouchHelper getItemTouchHelper() {
99 return mItemTouchHelper;
Jason Monk62b63a02016-02-02 15:15:31 -0500100 }
101
102 public ItemDecoration getItemDecoration() {
103 return mDecoration;
104 }
105
106 public void saveSpecs(QSTileHost host) {
107 List<String> newSpecs = new ArrayList<>();
108 for (int i = 0; mTiles.get(i) != null; i++) {
109 newSpecs.add(mTiles.get(i).spec);
110 }
111 host.changeTiles(mCurrentSpecs, newSpecs);
112 setTileSpecs(newSpecs);
113 }
114
115 public void setTileSpecs(List<String> currentSpecs) {
116 mCurrentSpecs = currentSpecs;
117 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -0700118 }
119
120 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500121 public void onTilesChanged(List<TileInfo> tiles) {
122 mAllTiles = tiles;
123 recalcSpecs();
Jason Monk5db8a412015-10-21 15:16:23 -0700124 }
125
Jason Monk62b63a02016-02-02 15:15:31 -0500126 private void recalcSpecs() {
127 if (mCurrentSpecs == null || mAllTiles == null) {
128 return;
Jason Monk5db8a412015-10-21 15:16:23 -0700129 }
Jason Monk62b63a02016-02-02 15:15:31 -0500130 mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
131 mTiles.clear();
132 for (int i = 0; i < mCurrentSpecs.size(); i++) {
Jason Monkcb654cb2016-02-25 15:43:07 -0500133 final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
134 if (tile != null) {
135 mTiles.add(tile);
136 }
Jason Monk5db8a412015-10-21 15:16:23 -0700137 }
Jason Monk62b63a02016-02-02 15:15:31 -0500138 mTiles.add(null);
Jason Monk0b349ad2016-04-04 11:18:03 -0400139 for (int i = 0; i < mOtherTiles.size(); i++) {
140 final TileInfo tile = mOtherTiles.get(i);
141 if (tile.isSystem) {
142 mOtherTiles.remove(i--);
143 mTiles.add(tile);
144 }
145 }
146 if (mOtherTiles.size() != 0) {
147 mTileDividerIndex = mTiles.size();
148 mTiles.add(null);
149 }
Jason Monk62b63a02016-02-02 15:15:31 -0500150 mTiles.addAll(mOtherTiles);
Jason Monk0b349ad2016-04-04 11:18:03 -0400151 mEditIndex = mTiles.indexOf(null);
Jason Monk62b63a02016-02-02 15:15:31 -0500152 notifyDataSetChanged();
153 }
Jason Monk5db8a412015-10-21 15:16:23 -0700154
Jason Monk62b63a02016-02-02 15:15:31 -0500155 private TileInfo getAndRemoveOther(String s) {
156 for (int i = 0; i < mOtherTiles.size(); i++) {
157 if (mOtherTiles.get(i).spec.equals(s)) {
158 return mOtherTiles.remove(i);
Jason Monk5db8a412015-10-21 15:16:23 -0700159 }
Jason Monk62b63a02016-02-02 15:15:31 -0500160 }
161 return null;
162 }
163
164 @Override
165 public int getItemViewType(int position) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400166 if (mAccessibilityMoving && position == mEditIndex - 1) {
Jason Monk39c98e62016-03-16 09:18:35 -0400167 return TYPE_ACCESSIBLE_DROP;
168 }
Jason Monk0b349ad2016-04-04 11:18:03 -0400169 if (position == mTileDividerIndex) {
170 return TYPE_DIVIDER;
171 }
Jason Monk62b63a02016-02-02 15:15:31 -0500172 if (mTiles.get(position) == null) {
173 return TYPE_EDIT;
174 }
175 return TYPE_TILE;
176 }
177
178 @Override
179 public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
180 final Context context = parent.getContext();
181 LayoutInflater inflater = LayoutInflater.from(context);
Jason Monk0b349ad2016-04-04 11:18:03 -0400182 if (viewType == TYPE_DIVIDER) {
183 return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
184 }
Jason Monk39c98e62016-03-16 09:18:35 -0400185 if (viewType == TYPE_EDIT) {
Jason Monk62b63a02016-02-02 15:15:31 -0500186 return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
187 }
188 FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
189 false);
Jason Monk0b349ad2016-04-04 11:18:03 -0400190 frame.addView(new CustomizeTileView(context, new QSIconView(context)));
Jason Monk62b63a02016-02-02 15:15:31 -0500191 return new Holder(frame);
192 }
193
194 @Override
195 public int getItemCount() {
196 return mTiles.size();
197 }
198
199 @Override
Jason Monk39c98e62016-03-16 09:18:35 -0400200 public void onBindViewHolder(final Holder holder, final int position) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400201 if (holder.getItemViewType() == TYPE_DIVIDER) {
202 return;
203 }
Jason Monk24dbd512016-03-16 14:56:42 -0400204 if (holder.getItemViewType() == TYPE_EDIT) {
205 ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
206 mCurrentDrag != null ? R.string.drag_to_remove_tiles
207 : R.string.drag_to_add_tiles);
208 return;
209 }
Jason Monk39c98e62016-03-16 09:18:35 -0400210 if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
211 holder.mTileView.setClickable(true);
212 holder.mTileView.setFocusable(true);
213 holder.mTileView.setFocusableInTouchMode(true);
214 holder.mTileView.setVisibility(View.VISIBLE);
215 holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
216 holder.mTileView.setContentDescription(mContext.getString(
217 R.string.accessibility_qs_edit_position_label, position + 1));
218 holder.mTileView.setOnClickListener(new OnClickListener() {
219 @Override
220 public void onClick(View v) {
221 selectPosition(position, v);
222 }
223 });
224 if (mNeedsFocus) {
225 // Wait for this to get laid out then set its focus.
226 holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
227 @Override
228 public void onLayoutChange(View v, int left, int top, int right, int bottom,
229 int oldLeft, int oldTop, int oldRight, int oldBottom) {
230 holder.mTileView.removeOnLayoutChangeListener(this);
231 holder.mTileView.requestFocus();
232 }
233 });
234 mNeedsFocus = false;
235 }
236 return;
237 }
Jason Monk62b63a02016-02-02 15:15:31 -0500238
239 TileInfo info = mTiles.get(position);
Jason Monk39c98e62016-03-16 09:18:35 -0400240
Jason Monk0b349ad2016-04-04 11:18:03 -0400241 if (position > mEditIndex) {
Jason Monk39c98e62016-03-16 09:18:35 -0400242 info.state.contentDescription = mContext.getString(
243 R.string.accessibility_qs_edit_add_tile_label, info.state.label);
244 } else if (mAccessibilityMoving) {
245 info.state.contentDescription = mContext.getString(
246 R.string.accessibility_qs_edit_position_label, position + 1);
247 } else {
248 info.state.contentDescription = mContext.getString(
249 R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
250 }
Jason Monk62b63a02016-02-02 15:15:31 -0500251 holder.mTileView.onStateChanged(info.state);
Jason Monk0b349ad2016-04-04 11:18:03 -0400252 holder.mTileView.setAppLabel(info.appLabel);
253 holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
Jason Monk39c98e62016-03-16 09:18:35 -0400254
255 if (mAccessibilityManager.isTouchExplorationEnabled()) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400256 final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
Jason Monk39c98e62016-03-16 09:18:35 -0400257 holder.mTileView.setClickable(selectable);
258 holder.mTileView.setFocusable(selectable);
259 holder.mTileView.setImportantForAccessibility(selectable
260 ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
261 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
262 if (selectable) {
263 holder.mTileView.setOnClickListener(new OnClickListener() {
264 @Override
265 public void onClick(View v) {
266 if (mAccessibilityMoving) {
267 selectPosition(position, v);
268 } else {
Jason Monk0b349ad2016-04-04 11:18:03 -0400269 if (position < mEditIndex) {
Jason Monk39c98e62016-03-16 09:18:35 -0400270 showAccessibilityDialog(position, v);
271 } else {
272 startAccessibleDrag(position);
273 }
274 }
275 }
276 });
277 }
278 }
279 }
280
281 private void selectPosition(int position, View v) {
282 // Remove the placeholder.
Jason Monk0b349ad2016-04-04 11:18:03 -0400283 mTiles.remove(mEditIndex--);
Jason Monk39c98e62016-03-16 09:18:35 -0400284 mAccessibilityMoving = false;
285 move(mAccessibilityFromIndex, position, v);
286 notifyDataSetChanged();
287 }
288
289 private void showAccessibilityDialog(final int position, final View v) {
290 TileInfo info = mTiles.get(position);
291 CharSequence[] options = new CharSequence[] {
292 mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
293 mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
294 };
295 AlertDialog dialog = new Builder(mContext)
296 .setItems(options, new DialogInterface.OnClickListener() {
297 @Override
298 public void onClick(DialogInterface dialog, int which) {
299 if (which == 0) {
300 startAccessibleDrag(position);
301 } else {
Jason Monk0b349ad2016-04-04 11:18:03 -0400302 move(position, mEditIndex, v);
Jason Monk39c98e62016-03-16 09:18:35 -0400303 }
304 }
305 }).setNegativeButton(android.R.string.cancel, null)
306 .create();
307 SystemUIDialog.setShowForAllUsers(dialog, true);
308 SystemUIDialog.applyFlags(dialog);
309 dialog.show();
310 }
311
312 private void startAccessibleDrag(int position) {
313 mAccessibilityMoving = true;
314 mNeedsFocus = true;
315 mAccessibilityFromIndex = position;
316 // Add placeholder for last slot.
Jason Monk0b349ad2016-04-04 11:18:03 -0400317 mTiles.add(mEditIndex++, null);
Jason Monk39c98e62016-03-16 09:18:35 -0400318 notifyDataSetChanged();
Jason Monk62b63a02016-02-02 15:15:31 -0500319 }
320
321 public SpanSizeLookup getSizeLookup() {
322 return mSizeLookup;
323 }
324
Jason Monk39c98e62016-03-16 09:18:35 -0400325 private boolean move(int from, int to, View v) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400326 if (to >= mEditIndex) {
327 if (from >= mEditIndex) {
Jason Monk39c98e62016-03-16 09:18:35 -0400328 return false;
329 }
Jason Monk0b349ad2016-04-04 11:18:03 -0400330 // Sort tiles into system/non-system groups.
331 TileInfo tile = mTiles.get(from);
332 if (tile.isSystem) {
333 if (to > mTileDividerIndex) {
334 to = mTileDividerIndex;
335 }
336 } else {
337 if (mTileDividerIndex == mTiles.size()) {
338 mTiles.add(null);
339 }
340 if (to <= mTileDividerIndex) {
341 to = mTileDividerIndex;
342 }
343 }
Jason Monk39c98e62016-03-16 09:18:35 -0400344 }
345 CharSequence fromLabel = mTiles.get(from).state.label;
346 move(from, to, mTiles);
Jason Monk0b349ad2016-04-04 11:18:03 -0400347 notifyDataSetChanged();
348 updateDividerLocations();
Jason Monk39c98e62016-03-16 09:18:35 -0400349 CharSequence announcement;
Jason Monk0b349ad2016-04-04 11:18:03 -0400350 if (to >= mEditIndex) {
Jason Monk96defbe2016-03-29 16:51:03 -0400351 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
352 strip(mTiles.get(to)));
353 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
354 from);
Jason Monk39c98e62016-03-16 09:18:35 -0400355 announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
356 fromLabel);
Jason Monk0b349ad2016-04-04 11:18:03 -0400357 } else if (from >= mEditIndex) {
Jason Monk96defbe2016-03-29 16:51:03 -0400358 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
359 strip(mTiles.get(to)));
360 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
361 to);
Jason Monk39c98e62016-03-16 09:18:35 -0400362 announcement = mContext.getString(R.string.accessibility_qs_edit_tile_added,
363 fromLabel, (to + 1));
364 } else {
Jason Monk96defbe2016-03-29 16:51:03 -0400365 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC,
366 strip(mTiles.get(to)));
367 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE,
368 to);
Jason Monk39c98e62016-03-16 09:18:35 -0400369 announcement = mContext.getString(R.string.accessibility_qs_edit_tile_moved,
370 fromLabel, (to + 1));
371 }
372 v.announceForAccessibility(announcement);
373 return true;
374 }
375
Jason Monk0b349ad2016-04-04 11:18:03 -0400376 private void updateDividerLocations() {
377 // The first null is the edit tiles label, the second null is the tile divider.
378 // If there is no second null, then there are no non-system tiles.
379 mEditIndex = -1;
380 mTileDividerIndex = mTiles.size();
381 for (int i = 0; i < mTiles.size(); i++) {
382 if (mTiles.get(i) == null) {
383 if (mEditIndex == -1) {
384 mEditIndex = i;
385 } else {
386 mTileDividerIndex = i;
387 }
388 }
389 }
390 if (mTiles.get(mTiles.size() - 1) == null) {
391 mTiles.remove(mTiles.size() - 1);
392 }
393 }
394
Jason Monk96defbe2016-03-29 16:51:03 -0400395 private String strip(TileInfo tileInfo) {
396 String spec = tileInfo.spec;
397 if (spec.startsWith(CustomTile.PREFIX)) {
398 ComponentName component = CustomTile.getComponentFromSpec(spec);
399 return component.getPackageName();
400 }
401 return spec;
402 }
403
Jason Monk39c98e62016-03-16 09:18:35 -0400404 private <T> void move(int from, int to, List<T> list) {
405 list.add(from > to ? to : to + 1, list.get(from));
406 list.remove(from > to ? from + 1 : from);
407 }
408
Jason Monk62b63a02016-02-02 15:15:31 -0500409 public class Holder extends ViewHolder {
Jason Monk0b349ad2016-04-04 11:18:03 -0400410 private CustomizeTileView mTileView;
Jason Monk62b63a02016-02-02 15:15:31 -0500411
412 public Holder(View itemView) {
413 super(itemView);
414 if (itemView instanceof FrameLayout) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400415 mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
Jason Monk04fd2492016-02-29 14:29:26 -0500416 mTileView.setBackground(null);
Jason Monk1aec93f2016-03-01 09:39:30 -0500417 mTileView.getIcon().disableAnimation();
Jason Monk5db8a412015-10-21 15:16:23 -0700418 }
Jason Monk5db8a412015-10-21 15:16:23 -0700419 }
420
Jason Monk62b63a02016-02-02 15:15:31 -0500421 public void startDrag() {
422 itemView.animate()
423 .setDuration(DRAG_LENGTH)
424 .scaleX(DRAG_SCALE)
425 .scaleY(DRAG_SCALE);
426 mTileView.findViewById(R.id.tile_label).animate()
427 .setDuration(DRAG_LENGTH)
428 .alpha(0);
Jason Monk0b349ad2016-04-04 11:18:03 -0400429 mTileView.getAppLabel().animate()
430 .setDuration(DRAG_LENGTH)
431 .alpha(0);
Jason Monk62b63a02016-02-02 15:15:31 -0500432 }
433
434 public void stopDrag() {
435 itemView.animate()
436 .setDuration(DRAG_LENGTH)
437 .scaleX(1)
438 .scaleY(1);
439 mTileView.findViewById(R.id.tile_label).animate()
440 .setDuration(DRAG_LENGTH)
441 .alpha(1);
Jason Monk0b349ad2016-04-04 11:18:03 -0400442 mTileView.getAppLabel().animate()
443 .setDuration(DRAG_LENGTH)
444 .alpha(.6f);
Jason Monk5db8a412015-10-21 15:16:23 -0700445 }
446 }
447
Jason Monk62b63a02016-02-02 15:15:31 -0500448 private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
Jason Monk5db8a412015-10-21 15:16:23 -0700449 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500450 public int getSpanSize(int position) {
Jason Monk0b349ad2016-04-04 11:18:03 -0400451 final int type = getItemViewType(position);
452 return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
Jason Monk62b63a02016-02-02 15:15:31 -0500453 }
454 };
455
456 private final ItemDecoration mDecoration = new ItemDecoration() {
457 // TODO: Move this to resource.
458 private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
459
460 @Override
461 public void onDraw(Canvas c, RecyclerView parent, State state) {
462 super.onDraw(c, parent, state);
463
464 final int childCount = parent.getChildCount();
465 final int width = parent.getWidth();
466 final int bottom = parent.getBottom();
467 for (int i = 0; i < childCount; i++) {
468 final View child = parent.getChildAt(i);
469 final ViewHolder holder = parent.getChildViewHolder(child);
Jason Monk0b349ad2016-04-04 11:18:03 -0400470 if (holder.getAdapterPosition() < mEditIndex) {
Jason Monk5db8a412015-10-21 15:16:23 -0700471 continue;
472 }
Jason Monk62b63a02016-02-02 15:15:31 -0500473
474 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
475 .getLayoutParams();
476 final int top = child.getTop() + params.topMargin +
477 Math.round(ViewCompat.getTranslationY(child));
478 // Draw full width, in case there aren't tiles all the way across.
479 mDrawable.setBounds(0, top, width, bottom);
480 mDrawable.draw(c);
481 break;
Jason Monk5db8a412015-10-21 15:16:23 -0700482 }
Jason Monk62b63a02016-02-02 15:15:31 -0500483 }
484 };
485
486 private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
487
488 @Override
489 public boolean isLongPressDragEnabled() {
490 return true;
Jason Monk5db8a412015-10-21 15:16:23 -0700491 }
492
493 @Override
Jason Monk62b63a02016-02-02 15:15:31 -0500494 public boolean isItemViewSwipeEnabled() {
495 return false;
Jason Monk5db8a412015-10-21 15:16:23 -0700496 }
Jason Monk5db8a412015-10-21 15:16:23 -0700497
Jason Monk62b63a02016-02-02 15:15:31 -0500498 @Override
499 public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
500 super.onSelectedChanged(viewHolder, actionState);
501 if (mCurrentDrag != null) {
502 mCurrentDrag.stopDrag();
Jason Monk24dbd512016-03-16 14:56:42 -0400503 mCurrentDrag = null;
Jason Monk62b63a02016-02-02 15:15:31 -0500504 }
505 if (viewHolder != null) {
506 mCurrentDrag = (Holder) viewHolder;
507 mCurrentDrag.startDrag();
508 }
Jason Monk1c2fea82016-03-11 11:33:36 -0500509 mHandler.post(new Runnable() {
510 @Override
511 public void run() {
Jason Monk0b349ad2016-04-04 11:18:03 -0400512 notifyItemChanged(mEditIndex);
Jason Monk1c2fea82016-03-11 11:33:36 -0500513 }
514 });
Jason Monk62b63a02016-02-02 15:15:31 -0500515 }
516
517 @Override
518 public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
519 if (viewHolder.getItemViewType() == TYPE_EDIT) {
520 return makeMovementFlags(0, 0);
521 }
522 int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
523 | ItemTouchHelper.LEFT;
524 return makeMovementFlags(dragFlags, 0);
525 }
526
527 @Override
528 public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
529 int from = viewHolder.getAdapterPosition();
530 int to = target.getAdapterPosition();
Jason Monk39c98e62016-03-16 09:18:35 -0400531 return move(from, to, target.itemView);
Jason Monk62b63a02016-02-02 15:15:31 -0500532 }
533
534 @Override
535 public void onSwiped(ViewHolder viewHolder, int direction) {
536 }
537 };
Jason Monk5db8a412015-10-21 15:16:23 -0700538}