15db8a4142e35d62073d81806ff7317e840e30ebcJason Monk/*
262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * Copyright (C) 2016 The Android Open Source Project
35db8a4142e35d62073d81806ff7317e840e30ebcJason Monk *
462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * except in compliance with the License. You may obtain a copy of the License at
65db8a4142e35d62073d81806ff7317e840e30ebcJason Monk *
75db8a4142e35d62073d81806ff7317e840e30ebcJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
85db8a4142e35d62073d81806ff7317e840e30ebcJason Monk *
962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
1062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * KIND, either express or implied. See the License for the specific language governing
1262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk * permissions and limitations under the License.
135db8a4142e35d62073d81806ff7317e840e30ebcJason Monk */
145db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
155db8a4142e35d62073d81806ff7317e840e30ebcJason Monkpackage com.android.systemui.qs.customize;
165db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
1739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.app.AlertDialog;
1839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.app.AlertDialog.Builder;
1996defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monkimport android.content.ComponentName;
205db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport android.content.Context;
2139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.content.DialogInterface;
2262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.graphics.Canvas;
2362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.graphics.drawable.ColorDrawable;
241c2fea8df7054d1bc23945c38460a123ce453c4aJason Monkimport android.os.Handler;
2562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v4.view.ViewCompat;
2662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
2762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.RecyclerView;
2862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.RecyclerView.ItemDecoration;
2962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.RecyclerView.State;
3062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.RecyclerView.ViewHolder;
3162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.support.v7.widget.helper.ItemTouchHelper;
325db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport android.view.LayoutInflater;
335db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport android.view.View;
3439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.view.View.OnClickListener;
3539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.view.View.OnLayoutChangeListener;
365db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport android.view.ViewGroup;
3739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport android.view.accessibility.AccessibilityManager;
3862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport android.widget.FrameLayout;
3924dbd51bdaee076f5b3076bb652686be68aa090aJason Monkimport android.widget.TextView;
400c0df7943ce2cf463917fa5a72d08ebf6a5336b4Jason Monk
4196defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monkimport com.android.internal.logging.MetricsLogger;
4296defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monkimport com.android.internal.logging.MetricsProto;
435db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport com.android.systemui.R;
4462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport com.android.systemui.qs.QSIconView;
4562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport com.android.systemui.qs.customize.TileAdapter.Holder;
4662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
4762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkimport com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
4896defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monkimport com.android.systemui.qs.external.CustomTile;
495db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport com.android.systemui.statusbar.phone.QSTileHost;
5039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monkimport com.android.systemui.statusbar.phone.SystemUIDialog;
515db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
525db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport java.util.ArrayList;
535db8a4142e35d62073d81806ff7317e840e30ebcJason Monkimport java.util.List;
545db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
5562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monkpublic class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
5662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
5762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private static final long DRAG_LENGTH = 100;
5862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private static final float DRAG_SCALE = 1.2f;
5962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public static final long MOVE_DURATION = 150;
605db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
6162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private static final int TYPE_TILE = 0;
6262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private static final int TYPE_EDIT = 1;
6339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private static final int TYPE_ACCESSIBLE_DROP = 2;
640b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private static final int TYPE_DIVIDER = 4;
650b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk
660b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private static final long EDIT_ID = 10000;
670b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private static final long DIVIDER_ID = 20000;
685db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
695db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    private final Context mContext;
705db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
711c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk    private final Handler mHandler = new Handler();
7262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private final List<TileInfo> mTiles = new ArrayList<>();
73b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk    private final ItemTouchHelper mItemTouchHelper;
7439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private final AccessibilityManager mAccessibilityManager;
750b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private int mEditIndex;
760b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private int mTileDividerIndex;
7739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private boolean mNeedsFocus;
7862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private List<String> mCurrentSpecs;
7962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private List<TileInfo> mOtherTiles;
8062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private List<TileInfo> mAllTiles;
8162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
8262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private Holder mCurrentDrag;
8339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private boolean mAccessibilityMoving;
8439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private int mAccessibilityFromIndex;
8563554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk    private QSTileHost mHost;
865db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
8762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public TileAdapter(Context context) {
885db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        mContext = context;
8939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
90b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk        mItemTouchHelper = new ItemTouchHelper(mCallbacks);
915db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
925db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
9363554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk    public void setHost(QSTileHost host) {
9463554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk        mHost = host;
9563554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk    }
9663554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk
97b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk    public ItemTouchHelper getItemTouchHelper() {
98b53b6c566f8e4754406cd1c3fddfa16a27515a7eJason Monk        return mItemTouchHelper;
9962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
10062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
10162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public ItemDecoration getItemDecoration() {
10262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return mDecoration;
10362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
10462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
10562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public void saveSpecs(QSTileHost host) {
10662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        List<String> newSpecs = new ArrayList<>();
10789e6f010e2d16fab144336bc2b3501ed6134a02eJason Monk        for (int i = 0; i < mTiles.size() && mTiles.get(i) != null; i++) {
10862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            newSpecs.add(mTiles.get(i).spec);
10962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
11062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        host.changeTiles(mCurrentSpecs, newSpecs);
11163554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk        mCurrentSpecs = newSpecs;
11262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
11362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
11462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public void setTileSpecs(List<String> currentSpecs) {
115b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        if (currentSpecs.equals(mCurrentSpecs)) {
116b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            return;
117b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        }
11862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mCurrentSpecs = currentSpecs;
11962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        recalcSpecs();
12062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
12162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
12262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    @Override
12362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public void onTilesChanged(List<TileInfo> tiles) {
12462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mAllTiles = tiles;
12562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        recalcSpecs();
12662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
12762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
12862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private void recalcSpecs() {
12962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        if (mCurrentSpecs == null || mAllTiles == null) {
13062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return;
1315db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
13262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
13362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mTiles.clear();
13462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        for (int i = 0; i < mCurrentSpecs.size(); i++) {
135cb654cb1722d72062461eaa604d077e0368ddb23Jason Monk            final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
136cb654cb1722d72062461eaa604d077e0368ddb23Jason Monk            if (tile != null) {
137cb654cb1722d72062461eaa604d077e0368ddb23Jason Monk                mTiles.add(tile);
138cb654cb1722d72062461eaa604d077e0368ddb23Jason Monk            }
13962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
14062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mTiles.add(null);
1410b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        for (int i = 0; i < mOtherTiles.size(); i++) {
1420b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            final TileInfo tile = mOtherTiles.get(i);
1430b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            if (tile.isSystem) {
1440b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                mOtherTiles.remove(i--);
1450b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                mTiles.add(tile);
1460b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            }
1470b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
14817d0399858306ab0a838b382c77a30217bac1d59Jason Monk        mTileDividerIndex = mTiles.size();
149dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk        mTiles.add(null);
15062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        mTiles.addAll(mOtherTiles);
151dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk        updateDividerLocations();
15262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        notifyDataSetChanged();
1535db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
1545db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
15562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private TileInfo getAndRemoveOther(String s) {
15662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        for (int i = 0; i < mOtherTiles.size(); i++) {
15762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            if (mOtherTiles.get(i).spec.equals(s)) {
15862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                return mOtherTiles.remove(i);
15962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            }
16062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
16162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return null;
1625db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
1635db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
1645db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    @Override
16562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public int getItemViewType(int position) {
1660b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (mAccessibilityMoving && position == mEditIndex - 1) {
16739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            return TYPE_ACCESSIBLE_DROP;
16839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
1690b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (position == mTileDividerIndex) {
1700b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            return TYPE_DIVIDER;
1710b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
17262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        if (mTiles.get(position) == null) {
17362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return TYPE_EDIT;
17462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
17562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return TYPE_TILE;
1765db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
1775db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
1785db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    @Override
17962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
18062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        final Context context = parent.getContext();
18162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        LayoutInflater inflater = LayoutInflater.from(context);
1820b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (viewType == TYPE_DIVIDER) {
1830b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
1840b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
18539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        if (viewType == TYPE_EDIT) {
18662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
18762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
18862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
18962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                false);
1900b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        frame.addView(new CustomizeTileView(context, new QSIconView(context)));
19162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return new Holder(frame);
1925db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
1935db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
1945db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    @Override
19562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public int getItemCount() {
19662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return mTiles.size();
1975db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
1985db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
1995db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    @Override
20017d0399858306ab0a838b382c77a30217bac1d59Jason Monk    public boolean onFailedToRecycleView(Holder holder) {
20117d0399858306ab0a838b382c77a30217bac1d59Jason Monk        holder.clearDrag();
20217d0399858306ab0a838b382c77a30217bac1d59Jason Monk        return true;
20317d0399858306ab0a838b382c77a30217bac1d59Jason Monk    }
20417d0399858306ab0a838b382c77a30217bac1d59Jason Monk
20517d0399858306ab0a838b382c77a30217bac1d59Jason Monk    @Override
20617d0399858306ab0a838b382c77a30217bac1d59Jason Monk    public void onBindViewHolder(final Holder holder, int position) {
2070b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (holder.getItemViewType() == TYPE_DIVIDER) {
208dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk            holder.itemView.setVisibility(mTileDividerIndex < mTiles.size() - 1 ? View.VISIBLE
209dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk                    : View.INVISIBLE);
2100b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            return;
2110b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
21224dbd51bdaee076f5b3076bb652686be68aa090aJason Monk        if (holder.getItemViewType() == TYPE_EDIT) {
21324dbd51bdaee076f5b3076bb652686be68aa090aJason Monk            ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
21424dbd51bdaee076f5b3076bb652686be68aa090aJason Monk                    mCurrentDrag != null ? R.string.drag_to_remove_tiles
21524dbd51bdaee076f5b3076bb652686be68aa090aJason Monk                    : R.string.drag_to_add_tiles);
21624dbd51bdaee076f5b3076bb652686be68aa090aJason Monk            return;
21724dbd51bdaee076f5b3076bb652686be68aa090aJason Monk        }
21839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
21939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setClickable(true);
22039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setFocusable(true);
22139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setFocusableInTouchMode(true);
22239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setVisibility(View.VISIBLE);
22339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
22439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setContentDescription(mContext.getString(
22539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    R.string.accessibility_qs_edit_position_label, position + 1));
22639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setOnClickListener(new OnClickListener() {
22739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                @Override
22839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                public void onClick(View v) {
22917d0399858306ab0a838b382c77a30217bac1d59Jason Monk                    selectPosition(holder.getAdapterPosition(), v);
23039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                }
23139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            });
23239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            if (mNeedsFocus) {
23339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                // Wait for this to get laid out then set its focus.
2340c0df7943ce2cf463917fa5a72d08ebf6a5336b4Jason Monk                // Ensure that tile gets laid out so we get the callback.
2350c0df7943ce2cf463917fa5a72d08ebf6a5336b4Jason Monk                holder.mTileView.requestLayout();
23639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
23739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    @Override
23839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
23939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
24039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        holder.mTileView.removeOnLayoutChangeListener(this);
24139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        holder.mTileView.requestFocus();
24239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    }
24339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                });
24439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                mNeedsFocus = false;
24539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            }
24639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            return;
24739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
24862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
24962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        TileInfo info = mTiles.get(position);
25039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
2510b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (position > mEditIndex) {
25239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            info.state.contentDescription = mContext.getString(
25339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    R.string.accessibility_qs_edit_add_tile_label, info.state.label);
25439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        } else if (mAccessibilityMoving) {
25539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            info.state.contentDescription = mContext.getString(
25639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    R.string.accessibility_qs_edit_position_label, position + 1);
25739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        } else {
25839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            info.state.contentDescription = mContext.getString(
25939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
26039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
26162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        holder.mTileView.onStateChanged(info.state);
2620b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        holder.mTileView.setAppLabel(info.appLabel);
263b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
26439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
26539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        if (mAccessibilityManager.isTouchExplorationEnabled()) {
2660b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
26739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setClickable(selectable);
26839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setFocusable(selectable);
26939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            holder.mTileView.setImportantForAccessibility(selectable
27039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
27139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
27239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            if (selectable) {
27339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                holder.mTileView.setOnClickListener(new OnClickListener() {
27439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    @Override
27539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    public void onClick(View v) {
27617d0399858306ab0a838b382c77a30217bac1d59Jason Monk                        int position = holder.getAdapterPosition();
27739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        if (mAccessibilityMoving) {
27839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                            selectPosition(position, v);
27939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        } else {
2800b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                            if (position < mEditIndex) {
28139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                                showAccessibilityDialog(position, v);
28239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                            } else {
28339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                                startAccessibleDrag(position);
28439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                            }
28539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        }
28639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    }
28739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                });
28839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            }
28939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
29039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    }
29139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
29239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private void selectPosition(int position, View v) {
29339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        // Remove the placeholder.
29439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mAccessibilityMoving = false;
295ad5db2979b641a80be6dc5e3f51eb4ced2c38daaJason Monk        mTiles.remove(mEditIndex--);
296a466d1639230d0ba3dc7796979e1ebb9a58afc17Jason Monk        notifyItemRemoved(mEditIndex - 1);
297ad5db2979b641a80be6dc5e3f51eb4ced2c38daaJason Monk        move(mAccessibilityFromIndex, position, v);
298ad5db2979b641a80be6dc5e3f51eb4ced2c38daaJason Monk        notifyDataSetChanged();
29939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    }
30039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
30139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private void showAccessibilityDialog(final int position, final View v) {
302b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        final TileInfo info = mTiles.get(position);
30339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        CharSequence[] options = new CharSequence[] {
30439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
30539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
30639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        };
30739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        AlertDialog dialog = new Builder(mContext)
30839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                .setItems(options, new DialogInterface.OnClickListener() {
30939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    @Override
31039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    public void onClick(DialogInterface dialog, int which) {
31139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        if (which == 0) {
31239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                            startAccessibleDrag(position);
31339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        } else {
314b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                            move(position, info.isSystem ? mEditIndex : mTileDividerIndex, v);
315b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                            notifyItemChanged(mTileDividerIndex);
316b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                            notifyDataSetChanged();
31739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                        }
31839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    }
31939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                }).setNegativeButton(android.R.string.cancel, null)
32039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                .create();
32139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        SystemUIDialog.setShowForAllUsers(dialog, true);
32239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        SystemUIDialog.applyFlags(dialog);
32339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        dialog.show();
32439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    }
32539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
32639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private void startAccessibleDrag(int position) {
32739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mAccessibilityMoving = true;
32839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mNeedsFocus = true;
32939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mAccessibilityFromIndex = position;
33039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        // Add placeholder for last slot.
3310b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        mTiles.add(mEditIndex++, null);
332a466d1639230d0ba3dc7796979e1ebb9a58afc17Jason Monk        notifyDataSetChanged();
33362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
33462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
33562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public SpanSizeLookup getSizeLookup() {
33662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        return mSizeLookup;
3375db8a4142e35d62073d81806ff7317e840e30ebcJason Monk    }
3385db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
33939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private boolean move(int from, int to, View v) {
340b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        if (to == from) {
341b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            return true;
34239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
34339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        CharSequence fromLabel = mTiles.get(from).state.label;
34439c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        move(from, to, mTiles);
3450b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        updateDividerLocations();
34639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        CharSequence announcement;
3470b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        if (to >= mEditIndex) {
34896defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
34996defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    strip(mTiles.get(to)));
35096defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
35196defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    from);
35239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
35339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    fromLabel);
3540b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        } else if (from >= mEditIndex) {
35596defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
35696defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    strip(mTiles.get(to)));
35796defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
35896defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    to);
35939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_added,
36039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    fromLabel, (to + 1));
36139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        } else {
36296defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC,
36396defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    strip(mTiles.get(to)));
36496defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE,
36596defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk                    to);
36639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_moved,
36739c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk                    fromLabel, (to + 1));
36839c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        }
36939c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        v.announceForAccessibility(announcement);
37063554eda8d74b7449766865b03736aa1b3a3f1d8Jason Monk        saveSpecs(mHost);
37139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        return true;
37239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    }
37339c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
3740b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    private void updateDividerLocations() {
3750b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        // The first null is the edit tiles label, the second null is the tile divider.
3760b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        // If there is no second null, then there are no non-system tiles.
3770b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        mEditIndex = -1;
3780b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        mTileDividerIndex = mTiles.size();
3790b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        for (int i = 0; i < mTiles.size(); i++) {
3800b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            if (mTiles.get(i) == null) {
3810b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                if (mEditIndex == -1) {
3820b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    mEditIndex = i;
3830b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                } else {
3840b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    mTileDividerIndex = i;
3850b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                }
3860b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            }
3870b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
38842317eade538975345297bb20ae3b7d2e3c4232bJason Monk        if (mTiles.size() - 1 == mTileDividerIndex) {
389dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk            notifyItemChanged(mTileDividerIndex);
3900b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        }
3910b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk    }
3920b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk
393dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk    private static String strip(TileInfo tileInfo) {
39496defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk        String spec = tileInfo.spec;
39596defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk        if (spec.startsWith(CustomTile.PREFIX)) {
39696defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            ComponentName component = CustomTile.getComponentFromSpec(spec);
39796defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk            return component.getPackageName();
39896defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk        }
39996defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk        return spec;
40096defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk    }
40196defbe2b123b316f5aecc0e9a3504b26f2bc54cJason Monk
40239c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    private <T> void move(int from, int to, List<T> list) {
403dd03659cb4ada000a7fcb2351d3dc8645139af78Jason Monk        list.add(to, list.remove(from));
40417d0399858306ab0a838b382c77a30217bac1d59Jason Monk        notifyItemMoved(from, to);
40539c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk    }
40639c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk
40762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    public class Holder extends ViewHolder {
4080b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk        private CustomizeTileView mTileView;
40962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
41062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public Holder(View itemView) {
41162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            super(itemView);
41262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            if (itemView instanceof FrameLayout) {
4130b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
41404fd24966ae5518528fe5301f054c1cf27ac497fJason Monk                mTileView.setBackground(null);
4151aec93f1819369bda9e6cb0bd282419808c304c3Jason Monk                mTileView.getIcon().disableAnimation();
41662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            }
4175db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
4185db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
41917d0399858306ab0a838b382c77a30217bac1d59Jason Monk        public void clearDrag() {
42017d0399858306ab0a838b382c77a30217bac1d59Jason Monk            itemView.clearAnimation();
42117d0399858306ab0a838b382c77a30217bac1d59Jason Monk            mTileView.findViewById(R.id.tile_label).clearAnimation();
42217d0399858306ab0a838b382c77a30217bac1d59Jason Monk            mTileView.findViewById(R.id.tile_label).setAlpha(1);
42317d0399858306ab0a838b382c77a30217bac1d59Jason Monk            mTileView.getAppLabel().clearAnimation();
42417d0399858306ab0a838b382c77a30217bac1d59Jason Monk            mTileView.getAppLabel().setAlpha(.6f);
42517d0399858306ab0a838b382c77a30217bac1d59Jason Monk        }
42617d0399858306ab0a838b382c77a30217bac1d59Jason Monk
42762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public void startDrag() {
42862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            itemView.animate()
42962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .setDuration(DRAG_LENGTH)
43062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .scaleX(DRAG_SCALE)
43162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .scaleY(DRAG_SCALE);
43262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            mTileView.findViewById(R.id.tile_label).animate()
43362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .setDuration(DRAG_LENGTH)
43462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .alpha(0);
4350b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            mTileView.getAppLabel().animate()
4360b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    .setDuration(DRAG_LENGTH)
4370b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    .alpha(0);
4385db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
4395db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
44062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public void stopDrag() {
44162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            itemView.animate()
44262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .setDuration(DRAG_LENGTH)
44362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .scaleX(1)
44462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .scaleY(1);
44562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            mTileView.findViewById(R.id.tile_label).animate()
44662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .setDuration(DRAG_LENGTH)
44762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    .alpha(1);
4480b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            mTileView.getAppLabel().animate()
4490b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    .setDuration(DRAG_LENGTH)
4500b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    .alpha(.6f);
4515db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
45262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    }
4535db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
45462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
45562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
45662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public int getSpanSize(int position) {
4570b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            final int type = getItemViewType(position);
4580b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk            return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
45962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
46062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    };
46162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
46262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private final ItemDecoration mDecoration = new ItemDecoration() {
46362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        // TODO: Move this to resource.
46462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
46562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
46662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
46762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public void onDraw(Canvas c, RecyclerView parent, State state) {
46862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            super.onDraw(c, parent, state);
46962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
47062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            final int childCount = parent.getChildCount();
47162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            final int width = parent.getWidth();
47262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            final int bottom = parent.getBottom();
47362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            for (int i = 0; i < childCount; i++) {
47462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                final View child = parent.getChildAt(i);
47562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                final ViewHolder holder = parent.getChildViewHolder(child);
476b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                if (holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) {
47762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    continue;
4785db8a4142e35d62073d81806ff7317e840e30ebcJason Monk                }
47962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
48062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
48162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                        .getLayoutParams();
48262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                final int top = child.getTop() + params.topMargin +
48362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                        Math.round(ViewCompat.getTranslationY(child));
48462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                // Draw full width, in case there aren't tiles all the way across.
48562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                mDrawable.setBounds(0, top, width, bottom);
48662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                mDrawable.draw(c);
48762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                break;
4885db8a4142e35d62073d81806ff7317e840e30ebcJason Monk            }
4895db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
49062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    };
49162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
49262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
4935db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
49462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
49562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public boolean isLongPressDragEnabled() {
49662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return true;
4975db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
4985db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
49962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
50062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public boolean isItemViewSwipeEnabled() {
50162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return false;
50262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
5035db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
5045db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        @Override
50562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
50662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            super.onSelectedChanged(viewHolder, actionState);
507b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
508b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                viewHolder = null;
509b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            }
510b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            if (viewHolder == mCurrentDrag) return;
51162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            if (mCurrentDrag != null) {
512b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                int position = mCurrentDrag.getAdapterPosition();
513b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                TileInfo info = mTiles.get(position);
514b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                mCurrentDrag.mTileView.setShowAppLabel(
515b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                        position > mEditIndex && !info.isSystem);
51662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                mCurrentDrag.stopDrag();
51724dbd51bdaee076f5b3076bb652686be68aa090aJason Monk                mCurrentDrag = null;
51862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            }
51962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            if (viewHolder != null) {
52062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                mCurrentDrag = (Holder) viewHolder;
52162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                mCurrentDrag.startDrag();
5225db8a4142e35d62073d81806ff7317e840e30ebcJason Monk            }
5231c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk            mHandler.post(new Runnable() {
5241c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk                @Override
5251c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk                public void run() {
5260b349adcd8ad85621fd2bd7fc9fc6f878a4b92d8Jason Monk                    notifyItemChanged(mEditIndex);
5271c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk                }
5281c2fea8df7054d1bc23945c38460a123ce453c4aJason Monk            });
5295db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
5305db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
5315db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        @Override
532b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
533b213ac464e7bb2f8948334da5270d3645f502128Jason Monk                ViewHolder target) {
534b213ac464e7bb2f8948334da5270d3645f502128Jason Monk            return target.getAdapterPosition() <= mEditIndex + 1;
535b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        }
536b213ac464e7bb2f8948334da5270d3645f502128Jason Monk
537b213ac464e7bb2f8948334da5270d3645f502128Jason Monk        @Override
53862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
53962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            if (viewHolder.getItemViewType() == TYPE_EDIT) {
54062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                return makeMovementFlags(0, 0);
54162b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            }
54262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
54362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk                    | ItemTouchHelper.LEFT;
54462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            return makeMovementFlags(dragFlags, 0);
5455db8a4142e35d62073d81806ff7317e840e30ebcJason Monk        }
5465db8a4142e35d62073d81806ff7317e840e30ebcJason Monk
54762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
54862b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
54962b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            int from = viewHolder.getAdapterPosition();
55062b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk            int to = target.getAdapterPosition();
55139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk            return move(from, to, target.itemView);
55262b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
55362b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk
55462b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        @Override
55562b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        public void onSwiped(ViewHolder viewHolder, int direction) {
55662b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk        }
55762b63a02d7ca630e3ad39991ea6550cab57e5d22Jason Monk    };
5585db8a4142e35d62073d81806ff7317e840e30ebcJason Monk}
559