diff --git a/packages/SystemUI/res/drawable/ic_close_white.xml b/packages/SystemUI/res/drawable/ic_close_white.xml
new file mode 100644
index 0000000000000..ce64047e5de4a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_close_white.xml
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 6beac3175636d..fbd29b0858da3 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -21,13 +21,58 @@
android:orientation="vertical"
android:background="?android:attr/windowBackground">
-
+ android:background="?android:attr/colorPrimary">
+
+
+
+
+
+
+
+
+
+
+
+
Save
Allow long-press customize in Quick Settings
+ Info
+ Remove
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index fe752207ff611..8866e558d6fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -19,26 +19,21 @@ import android.content.ClipData;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnTouchListener;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileView;
import com.android.systemui.statusbar.phone.QSTileHost;
/**
* A version of QSPanel that allows tiles to be dragged around rather than
- * clicked on. Dragging is started here, receiving is handled in the NonPagedTileLayout,
+ * clicked on. Dragging starting and receiving is handled in the NonPagedTileLayout,
* and the saving/ordering is handled by the CustomQSTileHost.
*/
-public class CustomQSPanel extends QSPanel implements OnTouchListener {
+public class CustomQSPanel extends QSPanel {
private CustomQSTileHost mCustomHost;
- private ClipData mCurrentClip;
- private View mCurrentView;
public CustomQSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -62,52 +57,26 @@ public class CustomQSPanel extends QSPanel implements OnTouchListener {
}
}
- @Override
- protected void addTile(QSTile> tile) {
- super.addTile(tile);
- if (tile.getTileType() != QSTileView.QS_TYPE_QUICK) {
- TileRecord record = mRecords.get(mRecords.size() - 1);
- if (record.tileView.getTag() == record.tile) {
- return;
- }
- record.tileView.setTag(record.tile);
- record.tileView.setVisibility(View.VISIBLE);
- record.tileView.init(null, null, null);
- record.tileView.setOnTouchListener(this);
- if (mCurrentClip != null
- && mCurrentClip.getItemAt(0).getText().toString().equals(tile.getTileSpec())) {
- record.tileView.setAlpha(.3f);
- mCurrentView = record.tileView;
- }
- }
+ public CustomQSTileHost getCustomHost() {
+ return mCustomHost;
}
- public void tileSelected(View v) {
- String sourceSpec = mCurrentClip.getItemAt(0).getText().toString();
- String destSpec = ((QSTile>) v.getTag()).getTileSpec();
+ public void tileSelected(QSTile> tile, ClipData currentClip) {
+ String sourceSpec = getSpec(currentClip);
+ String destSpec = tile.getTileSpec();
if (!sourceSpec.equals(destSpec)) {
mCustomHost.moveTo(sourceSpec, destSpec);
}
}
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- String tileSpec = (String) ((QSTile>) v.getTag()).getTileSpec();
- mCurrentView = v;
- mCurrentClip = ClipData.newPlainText(tileSpec, tileSpec);
- View.DragShadowBuilder shadow = new View.DragShadowBuilder(v);
- ((View) getParent().getParent()).startDrag(mCurrentClip, shadow, null, 0);
- v.setAlpha(.3f);
- return true;
- }
- return false;
+ public ClipData getClip(QSTile> tile) {
+ String tileSpec = tile.getTileSpec();
+ // TODO: Something better than plain text.
+ // TODO: Once using something better than plain text, stop listening to non-QS drag events.
+ return ClipData.newPlainText(tileSpec, tileSpec);
}
- public void onDragEnded() {
- mCurrentView.setAlpha(1f);
- mCurrentView = null;
- mCurrentClip = null;
+ public String getSpec(ClipData data) {
+ return data.getItemAt(0).getText().toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
index 095112912ce51..84b05d0055ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
@@ -37,6 +37,7 @@ public class CustomQSTileHost extends QSTileHost {
private static final String TAG = "CustomHost";
private List mTiles;
private List mSavedTiles;
+ private ArrayList mStash;
public CustomQSTileHost(Context context, QSTileHost host) {
super(context, null, host.getBluetoothController(), host.getLocationController(),
@@ -70,6 +71,14 @@ public class CustomQSTileHost extends QSTileHost {
TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
}
+ public void stashCurrentTiles() {
+ mStash = new ArrayList<>(mTiles);
+ }
+
+ public void unstashTiles() {
+ setTiles(mStash);
+ }
+
public void moveTo(String from, String to) {
int fromIndex = mTiles.indexOf(from);
if (fromIndex < 0) {
@@ -86,6 +95,13 @@ public class CustomQSTileHost extends QSTileHost {
super.onTuningChanged(TILES_SETTING, null);
}
+ public void remove(String spec) {
+ if (!mTiles.remove(spec)) {
+ Log.e(TAG, "Unknown remove spec " + spec);
+ }
+ super.onTuningChanged(TILES_SETTING, null);
+ }
+
public void setTiles(List tiles) {
mTiles = new ArrayList<>(tiles);
super.onTuningChanged(TILES_SETTING, null);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java b/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java
new file mode 100644
index 0000000000000..0e15f2b121165
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 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.ClipData;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.view.View;
+import android.view.View.OnDragListener;
+import android.widget.TextView;
+
+public class DropButton extends TextView implements OnDragListener {
+
+ private OnDropListener mListener;
+
+ public DropButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ // TODO: Don't do this, instead make this view the right size...
+ ((View) getParent()).setOnDragListener(this);
+ }
+
+ public void setOnDropListener(OnDropListener listener) {
+ mListener = listener;
+ }
+
+ private void setHovering(boolean hovering) {
+ setAlpha(hovering ? .5f : 1);
+ }
+
+ @Override
+ public boolean onDrag(View v, DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_ENTERED:
+ setHovering(true);
+ break;
+ case DragEvent.ACTION_DROP:
+ if (mListener != null) {
+ mListener.onDrop(this, event.getClipData());
+ }
+ case DragEvent.ACTION_DRAG_EXITED:
+ case DragEvent.ACTION_DRAG_ENDED:
+ setHovering(false);
+ break;
+ }
+ return true;
+ }
+
+ public interface OnDropListener {
+ void onDrop(View v, ClipData data);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 47c938429f96d..fdcff1d106533 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -15,12 +15,15 @@
*/
package com.android.systemui.qs.customize;
+import android.content.ClipData;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import com.android.systemui.R;
@@ -28,6 +31,7 @@ import com.android.systemui.qs.PagedTileLayout;
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
+import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.QuickTileLayout;
@@ -38,7 +42,7 @@ import java.util.ArrayList;
* vertically and expects to be inside a ScrollView.
* @see CustomQSPanel
*/
-public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
+public class NonPagedTileLayout extends LinearLayout implements QSTileLayout, OnTouchListener {
private QuickTileLayout mQuickTiles;
private final ArrayList mPages = new ArrayList<>();
@@ -46,6 +50,9 @@ public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
private CustomQSPanel mPanel;
private final Rect mHitRect = new Rect();
+ private ClipData mCurrentClip;
+ private View mCurrentView;
+
public NonPagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -63,17 +70,23 @@ public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
mPanel = qsPanel;
}
- private void clear() {
- mQuickTiles.removeAllViews();
- for (int i = 0; i < mPages.size(); i++) {
- mPages.get(i).removeAllViews();
- }
- }
-
@Override
- public void addTile(TileRecord tile) {
- mTiles.add(tile);
+ public void addTile(TileRecord record) {
+ mTiles.add(record);
distributeTiles();
+ if (record.tile.getTileType() == QSTileView.QS_TYPE_QUICK
+ || record.tileView.getTag() == record.tile) {
+ return;
+ }
+ record.tileView.setTag(record.tile);
+ record.tileView.setVisibility(View.VISIBLE);
+ record.tileView.init(null, null, null);
+ record.tileView.setOnTouchListener(this);
+ if (mCurrentClip != null
+ && mCurrentClip.getItemAt(0).getText().toString().equals(record.tile.getTileSpec())) {
+ record.tileView.setAlpha(.3f);
+ mCurrentView = record.tileView;
+ }
}
@Override
@@ -118,8 +131,8 @@ public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
@Override
public int getOffsetTop(TileRecord tile) {
- // TODO: Fix this.
- return getTop();
+ // No touch feedback, so this isn't required.
+ return 0;
}
@Override
@@ -145,7 +158,7 @@ public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
for (int j = 0; j < NC; j++) {
View child = page.getChildAt(j);
if (contains(child, x, y)) {
- mPanel.tileSelected(child);
+ mPanel.tileSelected((QSTile>) child.getTag(), mCurrentClip);
}
}
break;
@@ -154,12 +167,35 @@ public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
}
break;
case DragEvent.ACTION_DRAG_ENDED:
- mPanel.onDragEnded();
+ onDragEnded();
break;
}
return true;
}
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ // Stash the current tiles, in case the drop is on info, that we we can restore
+ // the previous state.
+ mPanel.getCustomHost().stashCurrentTiles();
+ mCurrentView = v;
+ mCurrentClip = mPanel.getClip((QSTile>) v.getTag());
+ View.DragShadowBuilder shadow = new View.DragShadowBuilder(v);
+ ((View) getParent().getParent()).startDrag(mCurrentClip, shadow, null, 0);
+ v.setAlpha(.3f);
+ return true;
+ }
+ return false;
+ }
+
+ public void onDragEnded() {
+ mCurrentView.setAlpha(1f);
+ mCurrentView = null;
+ mCurrentClip = null;
+ }
+
private boolean contains(View v, float x, float y) {
v.getHitRect(mHitRect);
return mHitRect.contains((int) x, (int) y);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 7724a8759cbc4..13a8dba2166dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -15,13 +15,17 @@
*/
package com.android.systemui.qs.customize;
+import android.app.AlertDialog;
+import android.content.ClipData;
import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.DragEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
@@ -29,8 +33,10 @@ import android.widget.Toolbar.OnMenuItemClickListener;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.customize.DropButton.OnDropListener;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.tuner.QSPagingSwitch;
import java.util.ArrayList;
@@ -41,7 +47,8 @@ import java.util.ArrayList;
* This adds itself to the status bar window, so it can appear on top of quick settings and
* *someday* do fancy animations to get into/out of it.
*/
-public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback {
+public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback,
+ OnDropListener {
private static final int MENU_SAVE = Menu.FIRST;
private static final int MENU_RESET = Menu.FIRST + 1;
@@ -49,10 +56,13 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
private PhoneStatusBar mPhoneStatusBar;
private Toolbar mToolbar;
+ private ViewGroup mDragButtons;
private CustomQSPanel mQsPanel;
private boolean isShown;
private CustomQSTileHost mHost;
+ private DropButton mInfoButton;
+ private DropButton mRemoveButton;
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
@@ -90,6 +100,14 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mContext.getString(com.android.internal.R.string.reset));
mQsPanel = (CustomQSPanel) findViewById(R.id.quick_settings_panel);
+
+ mDragButtons = (ViewGroup) findViewById(R.id.drag_buttons);
+ setDragging(false);
+
+ mInfoButton = (DropButton) findViewById(R.id.info_button);
+ mInfoButton.setOnDropListener(this);
+ mRemoveButton = (DropButton) findViewById(R.id.remove_button);
+ mRemoveButton.setOnDropListener(this);
}
public void show() {
@@ -117,6 +135,10 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mHost.setTiles(tiles);
}
+ private void setDragging(boolean dragging) {
+ mToolbar.setVisibility(!dragging ? View.VISIBLE : View.INVISIBLE);
+ }
+
private void save() {
mHost.saveCurrentTiles();
hide();
@@ -139,4 +161,28 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
public void onTilesChanged() {
mQsPanel.setTiles(mHost.getTiles());
}
+
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ setDragging(true);
+ break;
+ case DragEvent.ACTION_DRAG_ENDED:
+ setDragging(false);
+ break;
+ }
+ return true;
+ }
+
+ public void onDrop(View v, ClipData data) {
+ if (v == mRemoveButton) {
+ mHost.remove(mQsPanel.getSpec(data));
+ } else if (v == mInfoButton) {
+ mHost.unstashTiles();
+ SystemUIDialog dialog = new SystemUIDialog(mContext);
+ dialog.setTitle(mQsPanel.getSpec(data));
+ dialog.setPositiveButton(R.string.ok, null);
+ dialog.show();
+ }
+ }
}
\ No newline at end of file