Merge "Add app attribution to QS editing" into nyc-dev
This commit is contained in:
25
packages/SystemUI/res/layout/qs_customize_tile_divider.xml
Normal file
25
packages/SystemUI/res/layout/qs_customize_tile_divider.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<View
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?android:attr/listDivider"
|
||||
android:importantForAccessibility="no" />
|
||||
@@ -37,7 +37,7 @@ public class QSTileView extends QSTileBaseView {
|
||||
private final int mTileSpacingPx;
|
||||
private int mTilePaddingTopPx;
|
||||
|
||||
private TextView mLabel;
|
||||
protected TextView mLabel;
|
||||
private ImageView mPadLock;
|
||||
|
||||
public QSTileView(Context context, QSIconView icon) {
|
||||
@@ -81,7 +81,7 @@ public class QSTileView extends QSTileBaseView {
|
||||
FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
|
||||
}
|
||||
|
||||
private void createLabel() {
|
||||
protected void createLabel() {
|
||||
final Resources res = mContext.getResources();
|
||||
View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
|
||||
mLabel = (TextView) view.findViewById(R.id.tile_label);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSIconView;
|
||||
import com.android.systemui.qs.QSTileView;
|
||||
import libcore.util.Objects;
|
||||
|
||||
public class CustomizeTileView extends QSTileView {
|
||||
|
||||
private TextView mAppLabel;
|
||||
|
||||
public CustomizeTileView(Context context, QSIconView icon) {
|
||||
super(context, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createLabel() {
|
||||
super.createLabel();
|
||||
View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
|
||||
mAppLabel = (TextView) view.findViewById(R.id.tile_label);
|
||||
mAppLabel.setAlpha(.6f);
|
||||
mAppLabel.setSingleLine(true);
|
||||
addView(view);
|
||||
}
|
||||
|
||||
public void setShowAppLabel(boolean showAppLabel) {
|
||||
mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
|
||||
mLabel.setSingleLine(showAppLabel);
|
||||
}
|
||||
|
||||
public void setAppLabel(CharSequence label) {
|
||||
if (!Objects.equal(label, mAppLabel.getText())) {
|
||||
mAppLabel.setText(label);
|
||||
}
|
||||
}
|
||||
|
||||
public TextView getAppLabel() {
|
||||
return mAppLabel;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.MetricsProto;
|
||||
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;
|
||||
@@ -61,6 +60,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
private static final int TYPE_TILE = 0;
|
||||
private static final int TYPE_EDIT = 1;
|
||||
private static final int TYPE_ACCESSIBLE_DROP = 2;
|
||||
private static final int TYPE_DIVIDER = 4;
|
||||
|
||||
private static final long EDIT_ID = 10000;
|
||||
private static final long DIVIDER_ID = 20000;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
@@ -68,7 +71,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
private final List<TileInfo> mTiles = new ArrayList<>();
|
||||
private final ItemTouchHelper mItemTouchHelper;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private int mDividerIndex;
|
||||
private int mEditIndex;
|
||||
private int mTileDividerIndex;
|
||||
private boolean mNeedsFocus;
|
||||
private List<String> mCurrentSpecs;
|
||||
private List<TileInfo> mOtherTiles;
|
||||
@@ -87,7 +91,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
|
||||
return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
|
||||
: position == mEditIndex ? EDIT_ID : DIVIDER_ID;
|
||||
}
|
||||
|
||||
public ItemTouchHelper getItemTouchHelper() {
|
||||
@@ -131,8 +136,19 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
}
|
||||
}
|
||||
mTiles.add(null);
|
||||
for (int i = 0; i < mOtherTiles.size(); i++) {
|
||||
final TileInfo tile = mOtherTiles.get(i);
|
||||
if (tile.isSystem) {
|
||||
mOtherTiles.remove(i--);
|
||||
mTiles.add(tile);
|
||||
}
|
||||
}
|
||||
if (mOtherTiles.size() != 0) {
|
||||
mTileDividerIndex = mTiles.size();
|
||||
mTiles.add(null);
|
||||
}
|
||||
mTiles.addAll(mOtherTiles);
|
||||
mDividerIndex = mTiles.indexOf(null);
|
||||
mEditIndex = mTiles.indexOf(null);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -147,9 +163,12 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (mAccessibilityMoving && position == mDividerIndex - 1) {
|
||||
if (mAccessibilityMoving && position == mEditIndex - 1) {
|
||||
return TYPE_ACCESSIBLE_DROP;
|
||||
}
|
||||
if (position == mTileDividerIndex) {
|
||||
return TYPE_DIVIDER;
|
||||
}
|
||||
if (mTiles.get(position) == null) {
|
||||
return TYPE_EDIT;
|
||||
}
|
||||
@@ -160,12 +179,15 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final Context context = parent.getContext();
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
if (viewType == TYPE_DIVIDER) {
|
||||
return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
|
||||
}
|
||||
if (viewType == TYPE_EDIT) {
|
||||
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)));
|
||||
frame.addView(new CustomizeTileView(context, new QSIconView(context)));
|
||||
return new Holder(frame);
|
||||
}
|
||||
|
||||
@@ -176,6 +198,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final Holder holder, final int position) {
|
||||
if (holder.getItemViewType() == TYPE_DIVIDER) {
|
||||
return;
|
||||
}
|
||||
if (holder.getItemViewType() == TYPE_EDIT) {
|
||||
((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
|
||||
mCurrentDrag != null ? R.string.drag_to_remove_tiles
|
||||
@@ -213,7 +238,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
|
||||
TileInfo info = mTiles.get(position);
|
||||
|
||||
if (position > mDividerIndex) {
|
||||
if (position > mEditIndex) {
|
||||
info.state.contentDescription = mContext.getString(
|
||||
R.string.accessibility_qs_edit_add_tile_label, info.state.label);
|
||||
} else if (mAccessibilityMoving) {
|
||||
@@ -224,9 +249,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
|
||||
}
|
||||
holder.mTileView.onStateChanged(info.state);
|
||||
holder.mTileView.setAppLabel(info.appLabel);
|
||||
holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
|
||||
|
||||
if (mAccessibilityManager.isTouchExplorationEnabled()) {
|
||||
final boolean selectable = !mAccessibilityMoving || position < mDividerIndex;
|
||||
final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
|
||||
holder.mTileView.setClickable(selectable);
|
||||
holder.mTileView.setFocusable(selectable);
|
||||
holder.mTileView.setImportantForAccessibility(selectable
|
||||
@@ -239,7 +266,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
if (mAccessibilityMoving) {
|
||||
selectPosition(position, v);
|
||||
} else {
|
||||
if (position < mDividerIndex) {
|
||||
if (position < mEditIndex) {
|
||||
showAccessibilityDialog(position, v);
|
||||
} else {
|
||||
startAccessibleDrag(position);
|
||||
@@ -253,7 +280,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
|
||||
private void selectPosition(int position, View v) {
|
||||
// Remove the placeholder.
|
||||
mTiles.remove(mDividerIndex--);
|
||||
mTiles.remove(mEditIndex--);
|
||||
mAccessibilityMoving = false;
|
||||
move(mAccessibilityFromIndex, position, v);
|
||||
notifyDataSetChanged();
|
||||
@@ -272,7 +299,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
if (which == 0) {
|
||||
startAccessibleDrag(position);
|
||||
} else {
|
||||
move(position, mDividerIndex, v);
|
||||
move(position, mEditIndex, v);
|
||||
}
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, null)
|
||||
@@ -287,7 +314,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
mNeedsFocus = true;
|
||||
mAccessibilityFromIndex = position;
|
||||
// Add placeholder for last slot.
|
||||
mTiles.add(mDividerIndex++, null);
|
||||
mTiles.add(mEditIndex++, null);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -296,25 +323,38 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
}
|
||||
|
||||
private boolean move(int from, int to, View v) {
|
||||
if (to > mDividerIndex) {
|
||||
if (from >= mDividerIndex) {
|
||||
if (to >= mEditIndex) {
|
||||
if (from >= mEditIndex) {
|
||||
return false;
|
||||
}
|
||||
// Sort tiles into system/non-system groups.
|
||||
TileInfo tile = mTiles.get(from);
|
||||
if (tile.isSystem) {
|
||||
if (to > mTileDividerIndex) {
|
||||
to = mTileDividerIndex;
|
||||
}
|
||||
} else {
|
||||
if (mTileDividerIndex == mTiles.size()) {
|
||||
mTiles.add(null);
|
||||
}
|
||||
if (to <= mTileDividerIndex) {
|
||||
to = mTileDividerIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
CharSequence fromLabel = mTiles.get(from).state.label;
|
||||
move(from, to, mTiles);
|
||||
mDividerIndex = mTiles.indexOf(null);
|
||||
notifyItemChanged(from);
|
||||
notifyItemMoved(from, to);
|
||||
notifyDataSetChanged();
|
||||
updateDividerLocations();
|
||||
CharSequence announcement;
|
||||
if (to >= mDividerIndex) {
|
||||
if (to >= mEditIndex) {
|
||||
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
|
||||
strip(mTiles.get(to)));
|
||||
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
|
||||
from);
|
||||
announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
|
||||
fromLabel);
|
||||
} else if (from >= mDividerIndex) {
|
||||
} else if (from >= mEditIndex) {
|
||||
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
|
||||
strip(mTiles.get(to)));
|
||||
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
|
||||
@@ -333,6 +373,25 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateDividerLocations() {
|
||||
// The first null is the edit tiles label, the second null is the tile divider.
|
||||
// If there is no second null, then there are no non-system tiles.
|
||||
mEditIndex = -1;
|
||||
mTileDividerIndex = mTiles.size();
|
||||
for (int i = 0; i < mTiles.size(); i++) {
|
||||
if (mTiles.get(i) == null) {
|
||||
if (mEditIndex == -1) {
|
||||
mEditIndex = i;
|
||||
} else {
|
||||
mTileDividerIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mTiles.get(mTiles.size() - 1) == null) {
|
||||
mTiles.remove(mTiles.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private String strip(TileInfo tileInfo) {
|
||||
String spec = tileInfo.spec;
|
||||
if (spec.startsWith(CustomTile.PREFIX)) {
|
||||
@@ -348,12 +407,12 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
}
|
||||
|
||||
public class Holder extends ViewHolder {
|
||||
private QSTileView mTileView;
|
||||
private CustomizeTileView mTileView;
|
||||
|
||||
public Holder(View itemView) {
|
||||
super(itemView);
|
||||
if (itemView instanceof FrameLayout) {
|
||||
mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
|
||||
mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
|
||||
mTileView.setBackground(null);
|
||||
mTileView.getIcon().disableAnimation();
|
||||
}
|
||||
@@ -367,6 +426,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
mTileView.findViewById(R.id.tile_label).animate()
|
||||
.setDuration(DRAG_LENGTH)
|
||||
.alpha(0);
|
||||
mTileView.getAppLabel().animate()
|
||||
.setDuration(DRAG_LENGTH)
|
||||
.alpha(0);
|
||||
}
|
||||
|
||||
public void stopDrag() {
|
||||
@@ -377,13 +439,17 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
mTileView.findViewById(R.id.tile_label).animate()
|
||||
.setDuration(DRAG_LENGTH)
|
||||
.alpha(1);
|
||||
mTileView.getAppLabel().animate()
|
||||
.setDuration(DRAG_LENGTH)
|
||||
.alpha(.6f);
|
||||
}
|
||||
}
|
||||
|
||||
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
|
||||
final int type = getItemViewType(position);
|
||||
return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -401,7 +467,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = parent.getChildAt(i);
|
||||
final ViewHolder holder = parent.getChildViewHolder(child);
|
||||
if (holder.getAdapterPosition() < mDividerIndex) {
|
||||
if (holder.getAdapterPosition() < mEditIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -443,7 +509,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifyItemChanged(mDividerIndex);
|
||||
notifyItemChanged(mEditIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.service.quicksettings.TileService;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.qs.QSTile.DrawableIcon;
|
||||
import com.android.systemui.qs.QSTile.State;
|
||||
import com.android.systemui.qs.external.CustomTile;
|
||||
import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
|
||||
@@ -79,7 +80,7 @@ public class TileQueryHelper {
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addTile(spec, state);
|
||||
addTile(spec, null, state, true);
|
||||
mListener.onTilesChanged(mTiles);
|
||||
}
|
||||
});
|
||||
@@ -103,28 +104,33 @@ public class TileQueryHelper {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void addTile(String spec, QSTile.State state) {
|
||||
private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
|
||||
if (mSpecs.contains(spec)) {
|
||||
return;
|
||||
}
|
||||
TileInfo info = new TileInfo();
|
||||
info.state = state;
|
||||
info.spec = spec;
|
||||
info.appLabel = appLabel;
|
||||
info.isSystem = isSystem;
|
||||
mTiles.add(info);
|
||||
mSpecs.add(spec);
|
||||
}
|
||||
|
||||
private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
|
||||
private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
|
||||
Context context) {
|
||||
QSTile.State state = new QSTile.State();
|
||||
state.label = label;
|
||||
state.contentDescription = label;
|
||||
state.icon = new DrawableIcon(drawable);
|
||||
addTile(spec, state);
|
||||
addTile(spec, appLabel, state, false);
|
||||
}
|
||||
|
||||
public static class TileInfo {
|
||||
public String spec;
|
||||
public CharSequence appLabel;
|
||||
public QSTile.State state;
|
||||
public boolean isSystem;
|
||||
}
|
||||
|
||||
private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
|
||||
@@ -147,7 +153,8 @@ public class TileQueryHelper {
|
||||
icon.setTint(mContext.getColor(android.R.color.white));
|
||||
}
|
||||
CharSequence label = info.serviceInfo.loadLabel(pm);
|
||||
addTile(spec, icon, label != null ? label.toString() : "null", mContext);
|
||||
final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
|
||||
addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
|
||||
}
|
||||
return tiles;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user