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