blob: 876f41798521bd18ea17f7e83f8da34c9174b783 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.systemui.qs.customize;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.statusbar.phone.QSTileHost;
import java.util.ArrayList;
import java.util.List;
public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
private static final long DRAG_LENGTH = 100;
private static final float DRAG_SCALE = 1.2f;
public static final long MOVE_DURATION = 150;
private static final int TYPE_TILE = 0;
private static final int TYPE_EDIT = 1;
private final Context mContext;
private final List<TileInfo> mTiles = new ArrayList<>();
private final ItemTouchHelper mItemTouchHelper;
private int mDividerIndex;
private List<String> mCurrentSpecs;
private List<TileInfo> mOtherTiles;
private List<TileInfo> mAllTiles;
private Holder mCurrentDrag;
public TileAdapter(Context context) {
mContext = context;
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
setHasStableIds(true);
}
@Override
public long getItemId(int position) {
return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
}
public ItemTouchHelper getItemTouchHelper() {
return mItemTouchHelper;
}
public ItemDecoration getItemDecoration() {
return mDecoration;
}
public void saveSpecs(QSTileHost host) {
List<String> newSpecs = new ArrayList<>();
for (int i = 0; mTiles.get(i) != null; i++) {
newSpecs.add(mTiles.get(i).spec);
}
host.changeTiles(mCurrentSpecs, newSpecs);
setTileSpecs(newSpecs);
}
public void setTileSpecs(List<String> currentSpecs) {
mCurrentSpecs = currentSpecs;
recalcSpecs();
}
@Override
public void onTilesChanged(List<TileInfo> tiles) {
mAllTiles = tiles;
recalcSpecs();
}
private void recalcSpecs() {
if (mCurrentSpecs == null || mAllTiles == null) {
return;
}
mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
mTiles.clear();
for (int i = 0; i < mCurrentSpecs.size(); i++) {
mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i)));
}
mTiles.add(null);
mTiles.addAll(mOtherTiles);
mDividerIndex = mTiles.indexOf(null);
notifyDataSetChanged();
}
private TileInfo getAndRemoveOther(String s) {
for (int i = 0; i < mOtherTiles.size(); i++) {
if (mOtherTiles.get(i).spec.equals(s)) {
return mOtherTiles.remove(i);
}
}
return null;
}
@Override
public int getItemViewType(int position) {
if (mTiles.get(position) == null) {
return TYPE_EDIT;
}
return TYPE_TILE;
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
final Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == 1) {
return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
}
FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
false);
frame.addView(new QSTileView(context, new QSIconView(context)));
return new Holder(frame);
}
@Override
public int getItemCount() {
return mTiles.size();
}
@Override
public void onBindViewHolder(final Holder holder, int position) {
if (holder.getItemViewType() == TYPE_EDIT) return;
TileInfo info = mTiles.get(position);
holder.mTileView.onStateChanged(info.state);
holder.mTileView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mItemTouchHelper.startDrag(holder);
return true;
}
});
}
public SpanSizeLookup getSizeLookup() {
return mSizeLookup;
}
public class Holder extends ViewHolder {
private QSTileView mTileView;
public Holder(View itemView) {
super(itemView);
if (itemView instanceof FrameLayout) {
mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
}
}
public void startDrag() {
itemView.animate()
.setDuration(DRAG_LENGTH)
.scaleX(DRAG_SCALE)
.scaleY(DRAG_SCALE);
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(0);
}
public void stopDrag() {
itemView.animate()
.setDuration(DRAG_LENGTH)
.scaleX(1)
.scaleY(1);
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(1);
}
}
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
}
};
private final ItemDecoration mDecoration = new ItemDecoration() {
// TODO: Move this to resource.
private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
super.onDraw(c, parent, state);
final int childCount = parent.getChildCount();
final int width = parent.getWidth();
final int bottom = parent.getBottom();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
if (holder.getAdapterPosition() < mDividerIndex) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() + params.topMargin +
Math.round(ViewCompat.getTranslationY(child));
// Draw full width, in case there aren't tiles all the way across.
mDrawable.setBounds(0, top, width, bottom);
mDrawable.draw(c);
break;
}
}
};
private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (mCurrentDrag != null) {
mCurrentDrag.stopDrag();
}
if (viewHolder != null) {
mCurrentDrag = (Holder) viewHolder;
mCurrentDrag.startDrag();
}
}
@Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
if (viewHolder.getItemViewType() == TYPE_EDIT) {
return makeMovementFlags(0, 0);
}
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
| ItemTouchHelper.LEFT;
return makeMovementFlags(dragFlags, 0);
}
@Override
public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
if (to > mDividerIndex) {
if (from >= mDividerIndex) {
return false;
}
}
if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
to++;
}
move(from, to, mTiles);
mDividerIndex = mTiles.indexOf(null);
notifyItemMoved(from, to);
return true;
}
private <T> void move(int from, int to, List<T> list) {
list.add(from > to ? to : to + 1, list.get(from));
list.remove(from > to ? from + 1 : from);
}
@Override
public void onSwiped(ViewHolder viewHolder, int direction) {
}
};
}