summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java')
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java711
1 files changed, 565 insertions, 146 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
index 9326504..df45120 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
@@ -23,24 +23,35 @@ import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.res.Resources;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.UserHandle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.widget.BaseExpandableListAdapter;
import android.widget.EditText;
+import android.widget.ExpandableListView;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.FontSizeUtils;
@@ -54,14 +65,11 @@ import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.QsTuner;
-
import com.viewpagerindicator.CirclePageIndicator;
-
-import org.cyanogenmod.internal.util.QSUtils;
-
-import cyanogenmod.providers.CMSettings;
-
import cyanogenmod.app.StatusBarPanelCustomTile;
+import cyanogenmod.providers.CMSettings;
+import org.cyanogenmod.internal.logging.CMMetricsLogger;
+import org.cyanogenmod.internal.util.QSUtils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -69,6 +77,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
public class QSDragPanel extends QSPanel implements View.OnDragListener, View.OnLongClickListener {
@@ -88,7 +97,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
CirclePageIndicator mPageIndicator;
private TextView mDetailRemoveButton;
- private DragTileRecord mDraggingRecord;
+ private DragTileRecord mDraggingRecord, mLastDragRecord;
private boolean mEditing;
private boolean mDragging;
private float mLastTouchLocationX, mLastTouchLocationY;
@@ -107,6 +116,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
= Collections.synchronizedList(new ArrayList<TileRecord>());
private Collection<QSTile<?>> mTempTiles = null;
+ private Point mDisplaySize;
+ private int[] mTmpLoc;
+
public QSDragPanel(Context context) {
this(context, null);
}
@@ -150,11 +162,13 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
});
// add target click listener
- mQsPanelTop.findViewById(R.id.add_target).setOnClickListener(
+ mQsPanelTop.getAddTarget().setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
- showAddDialog();
+ TilesListAdapter adapter = new TilesListAdapter(mContext, QSDragPanel.this);
+ showDetailAdapter(true, adapter,
+ v.getLocationOnScreen());
}
});
mViewPager = new QSViewPager(getContext());
@@ -334,7 +348,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
protected void drawTile(TileRecord r, QSTile.State state) {
- final int visibility = state.visible || mEditing ? VISIBLE : GONE;
+ if (mEditing) {
+ state.visible = true;
+ }
+ final int visibility = state.visible ? VISIBLE : GONE;
setTileVisibility(r.tileView, visibility);
r.tileView.onStateChanged(state);
}
@@ -389,8 +406,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mPageIndicator.setEditing(editing);
mPagerAdapter.notifyDataSetChanged();
- ensurePagerState();
requestLayout();
+ ensurePagerState();
}
protected void onStartDrag() {
@@ -400,6 +417,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
protected void onStopDrag() {
mDraggingRecord.tileView.setAlpha(1f);
+ mLastDragRecord = mDraggingRecord;
mDraggingRecord = null;
mDragging = false;
mRestored = false;
@@ -408,7 +426,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mLastRightShift = -1;
mQsPanelTop.onStopDrag();
-
requestLayout();
ensurePagerState();
}
@@ -426,7 +443,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
protected int getPagesForCount(int tileCount) {
- tileCount -= getTilesPerPage(true);
+ if (tileCount == 0) {
+ return 1;
+ }
+ tileCount = Math.max(0, tileCount - getTilesPerPage(true));
// first page + rest of tiles
return 1 + (int) Math.ceil(tileCount / (double) getTilesPerPage(false));
}
@@ -475,25 +495,95 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return pages;
}
- public void setTiles(Collection<QSTile<?>> tiles) {
- if (DEBUG_DRAG) {
- Log.i(TAG, "setTiles() called with " + "tiles = ["
- + tiles + "], mTempTiles: " + mTempTiles);
- if (mTempTiles != null) {
- Log.e(TAG, "temp tiles being overridden... : " +
- Arrays.toString(mTempTiles.toArray()));
+ public void setTiles(final Collection<QSTile<?>> tilesCollection) {
+ final List<QSTile<?>> tiles = new ArrayList<>(tilesCollection);
+ if (isLaidOut()) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "setTiles() called with " + "tiles = ["
+ + tiles + "], mTempTiles: " + mTempTiles);
+ if (mTempTiles != null) {
+ Log.e(TAG, "temp tiles being overridden... : " +
+ Arrays.toString(mTempTiles.toArray()));
+ }
}
- }
- for (Record record : mRecords) {
- if (record instanceof DragTileRecord) {
- DragTileRecord dr = (DragTileRecord) record;
- mPages.get(dr.page).removeView(dr.tileView);
+
+ if (mLastDragRecord != null && mRecords.indexOf(mLastDragRecord) == -1) {
+ // the last removed record might be stored in mLastDragRecord if we just shifted
+ // re-add it to the list so we'll clean it up below
+ mRecords.add(mLastDragRecord);
+ mLastDragRecord = null;
}
- }
- mRecords.clear();
- if (isLaidOut()) {
- for (QSTile<?> tile : tiles) {
- addTile(tile);
+
+ Map<QSTile<?>, DragTileRecord> recordMap = new ArrayMap<>();
+ Iterator<TileRecord> iterator = mRecords.iterator();
+
+ int recordsRemoved = 0;
+ // cleanup current records
+ while (iterator.hasNext()) {
+ DragTileRecord dr = (DragTileRecord) iterator.next();
+
+ if (tiles.contains(dr.tile)) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "caching tile: " + dr.tile);
+ }
+ recordMap.put(dr.tile, dr);
+ } else {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "removing tile: " + dr.tile);
+ }
+ // clean up view
+ mPages.get(dr.page).removeView(dr.tileView);
+
+ // remove record
+ iterator.remove();
+ recordsRemoved++;
+ }
+ }
+
+
+ // at this point recordMap should have all retained tiles, no new or old tiles
+ int delta = tiles.size() - recordMap.size() - recordsRemoved;
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "record map delta: " + delta);
+ }
+ mRecords.ensureCapacity(tiles.size());
+ mPagerAdapter.notifyDataSetChanged();
+
+ // add new tiles
+ for (int i = 0; i < tiles.size(); i++) {
+ QSTile<?> tile = tiles.get(i);
+ final int tileDestPage = getPagesForCount(i + 1) - 1;
+
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "tile at : " + i + ": " + tile + " to dest page: " + tileDestPage);
+ }
+ if (!recordMap.containsKey(tile)) {
+ DragTileRecord record = makeRecord(tile);
+ record.destinationPage = tileDestPage;
+ recordMap.put(tile, record);
+ mRecords.add(i, record);
+ mPagerAdapter.notifyDataSetChanged();
+
+ // add the view
+ mPages.get(record.destinationPage).addView(record.tileView);
+ record.page = record.destinationPage;
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "added new record " + record);
+ }
+ } else {
+ DragTileRecord record = recordMap.get(tile);
+ int indexOf = mRecords.indexOf(record);
+ if (indexOf != i) {
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "moving index of " + record + " from "
+ + indexOf + " to " + i);
+ }
+ Collections.swap(mRecords, indexOf, i);
+
+ record.destinationPage = tileDestPage;
+ ensureDestinationPage(record);
+ }
+ }
}
if (isShowingDetail()) {
mDetail.bringToFront();
@@ -505,26 +595,32 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
mTempTiles = Collections.synchronizedCollection(new ArrayList<QSTile<?>>(tiles));
}
mPagerAdapter.notifyDataSetChanged();
+
+ refreshAllTiles();
requestLayout();
- ensurePagerState();
}
- protected void addTile(final QSTile<?> tile) {
+ private void ensureDestinationPage(DragTileRecord record) {
+ if (record.destinationPage != record.page) {
+ if (record.page >= 0) {
+ getPage(record.page).removeView(record.tileView);
+ }
+ getPage(record.destinationPage).addView(record.tileView);
+ record.page = record.destinationPage;
+ }
+ }
+
+ private DragTileRecord makeRecord(final QSTile<?> tile) {
if (DEBUG_DRAG) {
- Log.d(TAG, "+++ addTile() called with " + "tile = [" + tile + "]");
+ Log.d(TAG, "+++ makeRecord() called with " + "tile = [" + tile + "]");
}
final DragTileRecord r = new DragTileRecord();
- mRecords.add(r);
- mPagerAdapter.notifyDataSetChanged();
-
- int potentialPageIdx = getPagesForCount(mRecords.size()) - 1;
r.tile = tile;
- r.page = potentialPageIdx;
- r.destinationPage = r.page;
+ r.page = -1;
+ r.destinationPage = -1;
r.tileView = tile.createTileView(mContext);
- r.tileView.setVisibility(View.GONE);
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
@@ -589,13 +685,32 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
r.tileView.init(click, clickSecondary, longClick);
r.tile.setListening(mListening);
r.tile.refreshState();
- if (mEditing) {
- // force it to be visible, we'll refresh its state once editing is done
- r.tile.getState().visible = true;
- }
+ r.tileView.setVisibility(mEditing ? View.VISIBLE : View.GONE);
callback.onStateChanged(r.tile.getState());
- mPages.get(r.page).addView(r.tileView);
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "--- makeRecord() called with " + "tile = [" + tile + "]");
+ }
+ return r;
+ }
+
+ private void addTile(final QSTile<?> tile) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "+++ addTile() called with " + "tile = [" + tile + "]");
+ }
+ DragTileRecord r = makeRecord(tile);
+ mRecords.add(r);
+ mPagerAdapter.notifyDataSetChanged();
+
+ r.destinationPage = getPagesForCount(mRecords.size()) - 1;
+
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "destinationPage: " + r.destinationPage);
+ }
+
+ mPages.get(r.destinationPage).addView(r.tileView);
+ r.page = r.destinationPage;
+ drawTile(r, r.tile.getState());
ensurePagerState();
@@ -612,13 +727,20 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
public int getTilesPerPage(boolean firstPage) {
- if ((!mFirstRowLarge && firstPage)|| !firstPage) {
+ if ((!mFirstRowLarge && firstPage) || !firstPage) {
return QSTileHost.TILES_PER_PAGE + 1;
}
return QSTileHost.TILES_PER_PAGE;
}
@Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mTmpLoc = null;
+ mDisplaySize = null;
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -639,8 +761,32 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
if (mDetail.getMeasuredHeight() < h) {
mDetail.measure(exactly(width), exactly(h));
}
- mGridHeight = h;
- setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
+
+ // Check if the detail view would be overflowing below the physical height of the device
+ // and cutting the content off. If it is, reduce the detail height to fit.
+ if (isShowingDetail()) {
+ if (mDisplaySize == null) {
+ mDisplaySize = new Point();
+ getDisplay().getSize(mDisplaySize);
+ }
+ if (mTmpLoc == null) {
+ mTmpLoc = new int[2];
+ mDetail.getLocationOnScreen(mTmpLoc);
+ }
+
+ final int containerTop = mTmpLoc[1];
+ final int detailBottom = containerTop + mDetail.getMeasuredHeight();
+ if (detailBottom >= mDisplaySize.y) {
+ // panel is hanging below the screen
+ final int detailMinHeight = mDisplaySize.y - containerTop;
+ mDetail.measure(exactly(width), exactly(detailMinHeight));
+ }
+ setMeasuredDimension(width, mDetail.getMeasuredHeight());
+ mGridHeight = mDetail.getMeasuredHeight();
+ } else {
+ setMeasuredDimension(width, h);
+ mGridHeight = h;
+ }
for (TileRecord record : mRecords) {
setupRecord(record);
@@ -686,8 +832,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
// layout page indicator below view pager
mPageIndicator.layout(0, top, w, top + mPageIndicator.getMeasuredHeight());
- // detail takes up whole height
- mDetail.layout(0, 0, mDetail.getMeasuredWidth(), getMeasuredHeight());
+ mDetail.layout(0, 0, w, mDetail.getMeasuredHeight());
if (mFooter.hasFooter()) {
View footer = mFooter.getView();
@@ -703,6 +848,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
mTempTiles = null;
mPagerAdapter.notifyDataSetChanged();
+ requestLayout();
}
ensurePagerState();
}
@@ -717,7 +863,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return mColumns;
}
- public int getColumnCount(int page, int row) {
+ public int getColumnCount(int page, int row, boolean smart) {
int cols = 0;
for (Record record : mRecords) {
if (record instanceof DragTileRecord) {
@@ -728,24 +874,30 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
}
- if (isEditing() && (isDragging() || mRestoring) && !isDragRecordAttached()) {
+ if (smart && isEditing() && (isDragging() || mRestoring) && !isDragRecordAttached()) {
// if shifting tiles back, and one moved from previous page
// if it's the very last row on the last page, we should add an extra column to account
- // for where teh dragging record would go
- DragTileRecord record = (DragTileRecord) mRecords.get(mRecords.size() - 1);
-
- if (record.destinationPage == page && record.row == row && cols < getColumnCount()) {
+ // for where teh dragging lastRecord would go
+ DragTileRecord lastRecord = (DragTileRecord) mRecords.get(mRecords.size() - 1);
+ if (lastRecord.destinationPage == page && lastRecord.row == row
+ && cols < getColumnCount()) {
cols++;
if (DEBUG_DRAG) {
- Log.w(TAG, "adding another col, cols: " + cols + ", last: " + record
- + ", drag: " + mDraggingRecord + ", ");
+ boolean draggingRecordBefore = isBefore(mDraggingRecord, lastRecord);
+ Log.w(TAG, "adding another col, cols: " + cols + ", last: " + lastRecord
+ + ", drag: " + mDraggingRecord
+ + ", and dragging record before last: " + draggingRecordBefore);
}
}
}
return cols;
}
+ public int getColumnCount(int page, int row) {
+ return getColumnCount(page, row, true);
+ }
+
public int getCurrentMaxRow() {
int max = 0;
for (TileRecord record : mRecords) {
@@ -865,15 +1017,13 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return true;
} else {
mRestored = true;
- getPage(mDraggingRecord.page).removeView(mDraggingRecord.tileView);
-
// what spec is this tile?
String spec = mHost.getSpec(mDraggingRecord.tile);
if (DEBUG_DRAG) {
Log.w(TAG, "removing tile: " + mDraggingRecord + " with spec: " + spec);
}
- mHost.remove(spec);
onStopDrag();
+ mHost.remove(spec);
}
} else {
restoreDraggingTilePosition(v);
@@ -1050,9 +1200,18 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
// setup x destination to animate to
float destinationX = mDraggingRecord.destination.x;
- if (mDraggingRecord.destinationPage + 1 > mViewPager.getCurrentItem()) {
+
+ // see if we should animate this to the left or right off the page
+ // the +1's are to account for the edit page
+ if (mDraggingRecord.destinationPage > mViewPager.getCurrentItem() - 1) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "adding width to animate out >>>>>");
+ }
destinationX += getWidth();
- } else if (mDraggingRecord.destinationPage + 1 < mViewPager.getCurrentItem()) {
+ } else if (mDraggingRecord.destinationPage < mViewPager.getCurrentItem() - 1) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "removing width to animate out <<<<<");
+ }
destinationX -= getWidth();
}
@@ -1076,11 +1235,12 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
final QSPage targetP = getPage(mDraggingRecord.destinationPage);
- if (dragRecordDetached) {
- Log.i(TAG, "drag record was detached");
-
- } else {
- Log.i(TAG, "drag record was attached");
+ if (DEBUG_DRAG) {
+ if (dragRecordDetached) {
+ Log.i(TAG, "drag record was detached");
+ } else {
+ Log.i(TAG, "drag record was attached");
+ }
}
mDraggingRecord.page = mDraggingRecord.destinationPage;
targetP.addView(mDraggingRecord.tileView);
@@ -1130,18 +1290,15 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
Log.w(TAG, "tile's destination page moved to: " + tile.destinationPage);
}
}
- int columnCount = Math.max(1, getColumnCount(tile.destinationPage, tile.row));
+ int columnCount = Math.max(1, getColumnCount(tile.destinationPage, tile.row, false));
+ if (columnCount < maxCols) {
+ // if columncount gives us 1 and we're at col 2
+ columnCount = Math.max((tile.col + 1), columnCount);
+ }
if (DEBUG_DRAG) {
- Log.w(TAG, "columCount initially at: " + columnCount);
+ Log.w(TAG, "columCount at: " + columnCount);
}
- if (!mRecords.contains(tile) && tile != mDraggingRecord) {
- // increase column count for the destination location to account for this tile being added
- columnCount++;
- if (DEBUG_DRAG) {
- Log.w(TAG, "column count adjusted to: " + columnCount);
- }
- }
boolean firstRowLarge = mFirstRowLarge && tile.row == 0 && tile.destinationPage == 0;
tile.destination.x = getLeft(tile.row, tile.col, columnCount, firstRowLarge);
@@ -1153,11 +1310,34 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
}
+ private boolean isBefore(DragTileRecord r1, DragTileRecord r2) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "isBefore() called with " + "r1 = [" + r1 + "], r2 = [" + r2 + "]");
+ }
+ boolean isBefore = r1.destinationPage <= r2.destinationPage;
+ if (r1.destinationPage == r2.destinationPage) {
+ isBefore = r1.row <= r2.row;
+ if (r1.row == r2.row) {
+ isBefore = r1.col <= r2.col;
+ }
+ }
+
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "r1 isBefore r2: " + isBefore);
+ }
+ return isBefore;
+ }
+
private void setToLastDestination(DragTileRecord record) {
DragTileRecord last = (DragTileRecord) mRecords.get(mRecords.size() - 1);
- Log.d(TAG, "setToLastDestination() called with record = ["
- + record + "], and last record is: " + last);
- if (record != last && record.destinationPage <= last.destinationPage) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "setToLastDestination() called with record = ["
+ + record + "], and last record is: " + last);
+ }
+
+ if (isBefore(record, last)) {
+ // if the record is before the last record in the records list, set it to the
+ // last location, then spoof it one space forward
record.destinationPage = last.destinationPage;
record.row = last.row;
record.col = last.col;
@@ -1398,7 +1578,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
if (ti.row != lastRow) {
desiredColCount = getColumnCount(ti.destinationPage, ti.row);
- Log.e(TAG, "updating desired colum count to: " + desiredColCount);
+ if (DEBUG_DRAG) {
+ Log.e(TAG, "updating desired colum count to: " + desiredColCount);
+ }
}
// save current tile's loc
@@ -1499,14 +1681,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
}
- public int getDesiredColumnCount(int page, int row) {
- if (page == 0 && row == 0) {
- return 2; // TODO change if large tiles are disabled
- } else {
- return mColumns;
- }
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -1518,7 +1692,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
super.setExpanded(expanded);
if (!expanded) {
if (mEditing) {
- setEditing(false);
+ mHost.setEditing(false);
}
}
}
@@ -1552,74 +1726,319 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
return mCurrentlyAnimating.contains(t);
}
- // todo implement proper add tile ui
- protected void showAddDialog() {
- List<String> currentTileSpec = mHost.getTileSpecs();
- final List<String> availableTilesSpec = QSUtils.getAvailableTiles(getContext());
+ public static class TilesListAdapter extends BaseExpandableListAdapter
+ implements QSTile.DetailAdapter {
+
+ public static final String PACKAGE_ANDROID = "android";
+
+ Context mContext;
+ QSTileHost mHost;
+ QSDragPanel mPanel;
+
+ ArrayMap<String, List<String>> mPackageTileMap = new ArrayMap<>();
+
+ public TilesListAdapter(Context context, QSDragPanel panel) {
+ mContext = context;
+ mHost = panel.getHost();
+ mPanel = panel;
+
+ List<String> currentTileSpec = mHost.getTileSpecs();
+ final Collection<String> tiles = QSUtils.getAvailableTiles(mContext);
+ tiles.removeAll(currentTileSpec);
+
+ // we'll always have a system tiles category
+ mPackageTileMap.put(PACKAGE_ANDROID, new ArrayList<String>());
+
+ final Iterator<String> i = tiles.iterator();
+ while (i.hasNext()) {
+ final String spec = i.next();
+ if (QSUtils.isStaticQsTile(spec) || QSUtils.isDynamicQsTile(spec)) {
+ List<String> packageList = mPackageTileMap.get(PACKAGE_ANDROID);
+ packageList.add(spec);
+ } else {
+ String tilePackage = getCustomTilePackage(spec);
+ List<String> packageList = mPackageTileMap.get(tilePackage);
+ if (packageList == null) {
+ mPackageTileMap.put(tilePackage, packageList = new ArrayList<>());
+ }
+ packageList.add(spec);
+ }
+ }
+
+ // add broadcast tile
+ mPackageTileMap.get(PACKAGE_ANDROID).add(BROADCAST_TILE_SPEC_PLACEHOLDER);
+ }
+
+ private String getCustomTilePackage(String spec) {
+ StatusBarPanelCustomTile sbc = mHost.getCustomTileData().get(spec).sbc;
+ return sbc.getPackage();
+ }
+
+ @Override
+ public int getGroupCount() {
+ return mPackageTileMap.keySet().size();
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ return mPackageTileMap.valueAt(groupPosition).size();
+ }
+
+ @Override
+ public String getGroup(int groupPosition) {
+ return mPackageTileMap.keyAt(groupPosition);
+ }
+
+ @Override
+ public String getChild(int groupPosition, int childPosition) {
+ return mPackageTileMap.valueAt(groupPosition).get(childPosition);
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
- // Remove tiles already used
- availableTilesSpec.removeAll(currentTileSpec);
+ @Override
+ public long getChildId(int groupPosition, int childPosition) {
+ return mPackageTileMap.valueAt(groupPosition).get(childPosition).hashCode();
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
- // Populate labels
- List<String> availableTilesLabel = new ArrayList<String>();
- for (String tileSpec : availableTilesSpec) {
- int resource = QSTileHost.getLabelResource(tileSpec);
- if (resource != 0) {
- availableTilesLabel.add(getContext().getString(resource));
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ LinearLayout row = (LinearLayout) convertView;
+ if (row == null) {
+ row = (LinearLayout) LayoutInflater.from(mContext)
+ .inflate(R.layout.qs_tile_category_row, parent, false);
+ }
+ TextView title = (TextView) row.findViewById(android.R.id.title);
+
+ ImageView systemOrAppIcon = (ImageView) row.findViewById(android.R.id.icon);
+ ImageView expansionIndicator = (ImageView) row.findViewById(android.R.id.icon2);
+
+ expansionIndicator.setImageResource(isExpanded ? R.drawable.ic_qs_tile_contract
+ : R.drawable.ic_qs_tile_expand);
+ // hide indicator when there's only 1 group
+ final boolean singleGroupMode = getGroupCount() == 1;
+ expansionIndicator.setVisibility(singleGroupMode ? View.GONE : View.VISIBLE);
+
+ String group = getGroup(groupPosition);
+ if (group.equals(PACKAGE_ANDROID)) {
+ group = mContext.getText(R.string.quick_settings_tiles_category_system).toString();
+ // special icon
+ systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_system);
} else {
- availableTilesLabel.add(tileSpec);
+ systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_other);
}
+ title.setText(group);
+
+ if (isExpanded) {
+ expansionIndicator.setColorFilter(
+ mContext.getColor(
+ R.color.qs_detailed_expansion_indicator_color), PorterDuff.Mode.SRC_ATOP);
+ systemOrAppIcon.setColorFilter(
+ mContext.getColor(R.color.qs_detailed_icon_tint_color), PorterDuff.Mode.SRC_ATOP);
+ title.setTextColor(mContext.getColor(R.color.qs_detailed_title_text_color));
+ } else {
+ title.setTextColor(mContext.getColor(R.color.qs_detailed_default_text_color));
+ systemOrAppIcon.setColorFilter(null);
+ expansionIndicator.setColorFilter(null);
+ }
+ return row;
}
- // Add broadcast tile
- availableTilesLabel.add(getContext().getString(R.string.broadcast_tile));
- availableTilesSpec.add(BROADCAST_TILE_SPEC_PLACEHOLDER);
+ @Override
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ LinearLayout child = (LinearLayout) convertView;
+ if (child == null) {
+ child = (LinearLayout) LayoutInflater.from(mContext)
+ .inflate(R.layout.qs_tile_child_row, parent, false);
+ }
+ String spec = getChild(groupPosition, childPosition);
+
+ TextView title = (TextView) child.findViewById(android.R.id.title);
+ title.setText(getQSTileLabel(spec));
- String[] items = new String[availableTilesLabel.size()];
- availableTilesLabel.toArray(items);
+ ImageView icon = (ImageView) child.findViewById(android.R.id.icon);
+ icon.setImageDrawable(getQSTileIcon(spec));
- final AlertDialog d = new AlertDialog.Builder(getContext(), R.style.Theme_SystemUI_Dialog)
- .setTitle(R.string.add_tile)
- .setItems(items, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String tileSpec = availableTilesSpec.get(which);
- if (tileSpec.equals(BROADCAST_TILE_SPEC_PLACEHOLDER)) {
- showBroadcastTileDialog();
- } else {
- add(tileSpec);
- }
+ return child;
+ }
+
+ private String getQSTileLabel(String spec) {
+ if (spec.equals(BROADCAST_TILE_SPEC_PLACEHOLDER)) {
+ return mContext.getText(R.string.broadcast_tile).toString();
+ } else if (QSUtils.isStaticQsTile(spec)) {
+ int resource = QSTileHost.getLabelResource(spec);
+ return mContext.getText(resource).toString();
+ } else if (QSUtils.isDynamicQsTile(spec)) {
+ return QSUtils.getDynamicQSTileLabel(mContext,
+ UserHandle.myUserId(), spec);
+ } else {
+ return getPackageLabel(getCustomTilePackage(spec));
+ }
+ }
+
+ private Drawable getQSTileIcon(String spec) {
+ if (QSUtils.isDynamicQsTile(spec)) {
+ return QSTile.ResourceIcon.get(
+ QSUtils.getDynamicQSTileResIconId(mContext, UserHandle.myUserId(), spec))
+ .getDrawable(mContext);
+ } else if (QSUtils.isStaticQsTile(spec)) {
+ return QSTile.ResourceIcon.get(QSTileHost.getIconResource(spec))
+ .getDrawable(mContext);
+ } else {
+ QSTile<?> tile = mHost.getTile(spec);
+ if (tile != null) {
+ QSTile.State state = tile.getState();
+ if (state != null && state.icon != null) {
+ return state.icon.getDrawable(mContext);
}
- }).create();
- SystemUIDialog.makeSystemUIDialog(d);
- d.show();
- }
+ }
+ if (spec.equals(BROADCAST_TILE_SPEC_PLACEHOLDER)) {
+ return getPackageDrawable(PACKAGE_ANDROID);
+ }
+ return getPackageDrawable(getCustomTilePackage(spec));
+ }
+ }
- public void showBroadcastTileDialog() {
- final EditText editText = new EditText(getContext());
- final AlertDialog d = new AlertDialog.Builder(getContext())
- .setTitle(R.string.broadcast_tile)
- .setView(editText)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String action = editText.getText().toString();
- if (isValid(action)) {
- add(IntentTile.PREFIX + action + ')');
- }
+ private String getPackageLabel(String packageName) {
+ try {
+ return mContext.getPackageManager().getApplicationLabel(
+ mContext.getPackageManager().getApplicationInfo(packageName, 0)).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private Drawable getPackageDrawable(String packageName) {
+ try {
+ return mContext.getPackageManager().getApplicationIcon(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ @Override
+ public int getTitle() {
+ return R.string.quick_settings_tiles_add_tiles;
+ }
+
+ @Override
+ public Boolean getToggleState() {
+ return null;
+ }
+
+ @Override
+ public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ ExpandableListView lv = (ExpandableListView) convertView;
+ if (lv == null) {
+ lv = new ExpandableListView(parent.getContext());
+ lv.setOnTouchListener(new OnTouchListener() {
+ // Setting on Touch Listener for handling the touch inside ScrollView
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // Disallow the touch request for parent scroll on touch of child view
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ return false;
}
- }).create();
- SystemUIDialog.makeSystemUIDialog(d);
- d.show();
- }
+ });
+ }
+ lv.setAdapter(this);
+ lv.expandGroup(mPackageTileMap.indexOfKey(PACKAGE_ANDROID));
+ lv.setGroupIndicator(null);
+ lv.setChildIndicator(null);
+ lv.setChildDivider(new ColorDrawable(Color.TRANSPARENT));
+ lv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+ @Override
+ public boolean onChildClick(ExpandableListView parent, View v,
+ int groupPosition, int childPosition, long id) {
+ String spec = getChild(groupPosition, childPosition);
+ if (spec.equals(BROADCAST_TILE_SPEC_PLACEHOLDER)) {
+ showBroadcastTileDialog();
+ } else {
+ mPanel.add(spec);
+ mPanel.closeDetail();
+ }
+ return true;
+ }
+ });
+ lv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
+ @Override
+ public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition,
+ long id) {
+ if (getGroupCount() == 1) {
+ // disable contracting/expanding group when there's only 1
+ return true;
+ }
+ return false;
+ }
+ });
+ return lv;
+ }
+
+ @Override
+ public Intent getSettingsIntent() {
+ return null;
+ }
+
+ @Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
+ public void setToggleState(boolean state) {
+
+ }
- private boolean isValid(String action) {
- for (int i = 0; i < action.length(); i++) {
- char c = action.charAt(i);
- if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '.') {
- return false;
+ @Override
+ public int getMetricsCategory() {
+ return CMMetricsLogger.DONT_LOG;
+ }
+
+ public void showBroadcastTileDialog() {
+ final EditText editText = new EditText(mContext);
+ final AlertDialog d = new AlertDialog.Builder(mContext)
+ .setTitle(R.string.broadcast_tile)
+ .setView(editText)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String action = editText.getText().toString();
+ if (isValid(action)) {
+ mPanel.add(IntentTile.PREFIX + action + ')');
+ mPanel.closeDetail();
+ }
+ }
+ }).create();
+ SystemUIDialog.makeSystemUIDialog(d);
+ d.show();
+ }
+
+ private boolean isValid(String action) {
+ for (int i = 0; i < action.length(); i++) {
+ char c = action.charAt(i);
+ if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '.') {
+ return false;
+ }
}
+ return true;
}
- return true;
}
public void add(String tile) {
@@ -1634,7 +2053,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
}
public boolean isDragRecordAttached() {
- return mDragging && mDraggingRecord != null && mRecords.indexOf(mDraggingRecord) >= 0;
+ return mRecords.indexOf(mDraggingRecord) >= 0;
}
public void goToSettingsPage() {