QS: Add long-press to customize prototype - part 1
Start adding prototype to long-press to go to customization view for QS. Currently it allows re-arranging and resetting. Later it will have more. Change-Id: Ib2ba0f93ac2f4cced4f146d39771a8a17ac05bc2
This commit is contained in:
25
packages/SystemUI/res/layout/horizontal_divider.xml
Normal file
25
packages/SystemUI/res/layout/horizontal_divider.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<View
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:background="#4dffffff" />
|
||||
39
packages/SystemUI/res/layout/qs_customize_layout.xml
Normal file
39
packages/SystemUI/res/layout/qs_customize_layout.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<com.android.systemui.qs.customize.NonPagedTileLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/tiles_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.systemui.qs.QuickTileLayout
|
||||
android:id="@+id/quick_tile_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/qs_quick_actions_height"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/qs_quick_actions_padding"
|
||||
android:paddingEnd="@dimen/qs_quick_actions_padding" />
|
||||
|
||||
<view
|
||||
class="com.android.systemui.qs.PagedTileLayout$TilePage"
|
||||
android:id="@+id/tile_page"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.android.systemui.qs.customize.NonPagedTileLayout>
|
||||
|
||||
47
packages/SystemUI/res/layout/qs_customize_panel.xml
Normal file
47
packages/SystemUI/res/layout/qs_customize_panel.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<com.android.systemui.qs.customize.QSCustomizer
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="?android:attr/windowBackground">
|
||||
|
||||
<Toolbar
|
||||
android:id="@*android:id/action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:navigationContentDescription="@*android:string/action_bar_up_description"
|
||||
android:background="?android:attr/colorPrimary"
|
||||
style="?android:attr/toolbarStyle" />
|
||||
|
||||
<com.android.systemui.tuner.AutoScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:elevation="2dp">
|
||||
|
||||
<com.android.systemui.qs.customize.CustomQSPanel
|
||||
android:id="@+id/quick_settings_panel"
|
||||
android:background="#0000"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.android.systemui.tuner.AutoScrollView>
|
||||
|
||||
</com.android.systemui.qs.customize.QSCustomizer>
|
||||
@@ -1156,4 +1156,7 @@
|
||||
settings are -->
|
||||
<string name="experimental">Experimental</string>
|
||||
|
||||
<string name="save" translatable="false">Save</string>
|
||||
<string name="qs_customize" translatable="false">Allow long-press customize in Quick Settings</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
android:key="qs_paged_panel"
|
||||
android:title="@string/qs_paging" />
|
||||
|
||||
<com.android.systemui.tuner.TunerSwitch
|
||||
android:key="qs_allow_customize"
|
||||
android:title="@string/qs_customize" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -75,8 +75,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
|
||||
@Override
|
||||
public void setTileVisibility(TileRecord tile, int visibility) {
|
||||
tile.tileView.setVisibility(visibility);
|
||||
// TODO: Do something smarter here.
|
||||
distributeTiles();
|
||||
// // TODO: Do something smarter here.
|
||||
// distributeTiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,13 +183,17 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
|
||||
mAllowDual = false;
|
||||
}
|
||||
|
||||
public void setMaxRows(int maxRows) {
|
||||
mMaxRows = maxRows;
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
if (DEBUG) Log.d(TAG, "Clearing page");
|
||||
removeAllViews();
|
||||
mRecords.clear();
|
||||
}
|
||||
|
||||
private boolean isFull() {
|
||||
public boolean isFull() {
|
||||
return mRecords.size() >= mColumns * mMaxRows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.FontSizeUtils;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile.DetailAdapter;
|
||||
import com.android.systemui.qs.customize.QSCustomizer;
|
||||
import com.android.systemui.settings.BrightnessController;
|
||||
import com.android.systemui.settings.ToggleSlider;
|
||||
import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
@@ -54,8 +55,9 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
|
||||
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
|
||||
public static final String QS_PAGED_PANEL = "qs_paged_panel";
|
||||
public static final String QS_ALLOW_CUSTOMIZE = "qs_allow_customize";
|
||||
|
||||
private final Context mContext;
|
||||
protected final Context mContext;
|
||||
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
|
||||
private final View mDetail;
|
||||
private final ViewGroup mDetailContent;
|
||||
@@ -79,8 +81,10 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
private QSFooter mFooter;
|
||||
private boolean mGridContentVisible = true;
|
||||
|
||||
private LinearLayout mQsContainer;
|
||||
private QSTileLayout mTileLayout;
|
||||
protected LinearLayout mQsContainer;
|
||||
protected QSTileLayout mTileLayout;
|
||||
|
||||
private QSCustomizer mCustomizePanel;
|
||||
|
||||
public QSPanel(Context context) {
|
||||
this(context, null);
|
||||
@@ -131,7 +135,8 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS, QS_PAGED_PANEL);
|
||||
TunerService.get(mContext).addTunable(this,
|
||||
QS_SHOW_BRIGHTNESS, QS_PAGED_PANEL, QS_ALLOW_CUSTOMIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,6 +165,17 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
for (int i = 0; i < mRecords.size(); i++) {
|
||||
mTileLayout.addTile(mRecords.get(i));
|
||||
}
|
||||
} else if (QS_ALLOW_CUSTOMIZE.equals(key)) {
|
||||
if (newValue != null && Integer.parseInt(newValue) != 0) {
|
||||
mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
|
||||
.inflate(R.layout.qs_customize_panel, null);
|
||||
mCustomizePanel.setHost(mHost);
|
||||
} else {
|
||||
if (mCustomizePanel != null && mCustomizePanel.isCustomizing()) {
|
||||
mCustomizePanel.hide();
|
||||
}
|
||||
mCustomizePanel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +240,12 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
mFooter.onConfigurationChanged();
|
||||
}
|
||||
|
||||
public void onCollapse() {
|
||||
if (mCustomizePanel != null && mCustomizePanel.isCustomizing()) {
|
||||
mCustomizePanel.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
if (mExpanded == expanded) return;
|
||||
mExpanded = expanded;
|
||||
@@ -307,7 +329,7 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
r.tileView.onStateChanged(state);
|
||||
}
|
||||
|
||||
private void addTile(final QSTile<?> tile) {
|
||||
protected void addTile(final QSTile<?> tile) {
|
||||
final TileRecord r = new TileRecord();
|
||||
r.tile = tile;
|
||||
r.tileView = tile.createTileView(mContext);
|
||||
@@ -358,7 +380,13 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
r.tile.longClick();
|
||||
if (mCustomizePanel != null) {
|
||||
if (!mCustomizePanel.isCustomizing()) {
|
||||
mCustomizePanel.show();
|
||||
}
|
||||
} else {
|
||||
r.tile.longClick();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -374,10 +402,16 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
}
|
||||
|
||||
public boolean isShowingDetail() {
|
||||
return mDetailRecord != null;
|
||||
return mDetailRecord != null
|
||||
|| (mCustomizePanel != null && mCustomizePanel.isCustomizing());
|
||||
}
|
||||
|
||||
public void closeDetail() {
|
||||
if (mCustomizePanel != null && mCustomizePanel.isCustomizing()) {
|
||||
// Treat this as a detail panel for now, to make things easy.
|
||||
mCustomizePanel.hide();
|
||||
return;
|
||||
}
|
||||
showDetail(false, mDetailRecord);
|
||||
}
|
||||
|
||||
@@ -527,7 +561,7 @@ public class QSPanel extends FrameLayout implements Tunable {
|
||||
int y;
|
||||
}
|
||||
|
||||
protected static final class TileRecord extends Record {
|
||||
public static final class TileRecord extends Record {
|
||||
public QSTile<?> tile;
|
||||
public QSTileView tileView;
|
||||
public int row;
|
||||
|
||||
@@ -65,6 +65,8 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
private TState mTmpState = newTileState();
|
||||
private boolean mAnnounceNextStateChange;
|
||||
|
||||
private String mTileSpec;
|
||||
|
||||
abstract protected TState newTileState();
|
||||
abstract protected void handleClick();
|
||||
abstract protected void handleUpdateState(TState state, Object arg);
|
||||
@@ -83,7 +85,15 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
mContext = host.getContext();
|
||||
mHandler = new H(host.getLooper());
|
||||
}
|
||||
|
||||
|
||||
public String getTileSpec() {
|
||||
return mTileSpec;
|
||||
}
|
||||
|
||||
public void setTileSpec(String tileSpec) {
|
||||
mTileSpec = tileSpec;
|
||||
}
|
||||
|
||||
public int getTileType() {
|
||||
return QSTileView.QS_TYPE_NORMAL;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,11 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
|
||||
removeView(tile.tileView);
|
||||
}
|
||||
|
||||
public void removeAllViews() {
|
||||
mRecords.clear();
|
||||
super.removeAllViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTileVisibility(TileRecord tile, int visibility) {
|
||||
tile.tileView.setVisibility(visibility);
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.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,
|
||||
* and the saving/ordering is handled by the CustomQSTileHost.
|
||||
*/
|
||||
public class CustomQSPanel extends QSPanel implements OnTouchListener {
|
||||
|
||||
private CustomQSTileHost mCustomHost;
|
||||
private ClipData mCurrentClip;
|
||||
private View mCurrentView;
|
||||
|
||||
public CustomQSPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext)
|
||||
.inflate(R.layout.qs_customize_layout, mQsContainer, false);
|
||||
mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
|
||||
((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHost(QSTileHost host) {
|
||||
super.setHost(host);
|
||||
mCustomHost = (CustomQSTileHost) host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTuningChanged(String key, String newValue) {
|
||||
if (key.equals(QS_SHOW_BRIGHTNESS)) {
|
||||
// No Brightness for you.
|
||||
super.onTuningChanged(key, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@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 void tileSelected(View v) {
|
||||
String sourceSpec = mCurrentClip.getItemAt(0).getText().toString();
|
||||
String destSpec = ((QSTile<?>) v.getTag()).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 void onDragEnded() {
|
||||
mCurrentView.setAlpha(1f);
|
||||
mCurrentView = null;
|
||||
mCurrentClip = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
import com.android.systemui.statusbar.policy.SecurityController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @see CustomQSPanel
|
||||
*/
|
||||
public class CustomQSTileHost extends QSTileHost {
|
||||
|
||||
private static final String TAG = "CustomHost";
|
||||
private List<String> mTiles;
|
||||
private List<String> mSavedTiles;
|
||||
|
||||
public CustomQSTileHost(Context context, QSTileHost host) {
|
||||
super(context, null, host.getBluetoothController(), host.getLocationController(),
|
||||
host.getRotationLockController(), host.getNetworkController(),
|
||||
host.getZenModeController(), host.getHotspotController(), host.getCastController(),
|
||||
host.getFlashlightController(), host.getUserSwitcherController(),
|
||||
host.getKeyguardMonitor(), new BlankSecurityController());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QSTile<?> createTile(String tileSpec) {
|
||||
QSTile<?> tile = super.createTile(tileSpec);
|
||||
tile.setTileSpec(tileSpec);
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTuningChanged(String key, String newValue) {
|
||||
// No Tunings For You.
|
||||
if (TILES_SETTING.equals(key)) {
|
||||
mSavedTiles = super.loadTileSpecs(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSavedTiles() {
|
||||
setTiles(mSavedTiles);
|
||||
}
|
||||
|
||||
public void saveCurrentTiles() {
|
||||
Secure.putStringForUser(getContext().getContentResolver(), TILES_SETTING,
|
||||
TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
|
||||
}
|
||||
|
||||
public void moveTo(String from, String to) {
|
||||
int fromIndex = mTiles.indexOf(from);
|
||||
if (fromIndex < 0) {
|
||||
Log.e(TAG, "Unknown from tile " + from);
|
||||
return;
|
||||
}
|
||||
int index = mTiles.indexOf(to);
|
||||
if (index < 0) {
|
||||
Log.e(TAG, "Unknown to tile " + to);
|
||||
return;
|
||||
}
|
||||
mTiles.remove(fromIndex);
|
||||
mTiles.add(index, from);
|
||||
super.onTuningChanged(TILES_SETTING, null);
|
||||
}
|
||||
|
||||
public void setTiles(List<String> tiles) {
|
||||
mTiles = new ArrayList<>(tiles);
|
||||
super.onTuningChanged(TILES_SETTING, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> loadTileSpecs(String tileList) {
|
||||
return mTiles;
|
||||
}
|
||||
|
||||
public void replace(String oldTile, String newTile) {
|
||||
if (oldTile.equals(newTile)) {
|
||||
return;
|
||||
}
|
||||
MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REORDER, oldTile + ","
|
||||
+ newTile);
|
||||
List<String> order = new ArrayList<>(mTileSpecs);
|
||||
int index = order.indexOf(oldTile);
|
||||
if (index < 0) {
|
||||
Log.e(TAG, "Can't find " + oldTile);
|
||||
return;
|
||||
}
|
||||
order.remove(newTile);
|
||||
order.add(index, newTile);
|
||||
setTiles(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blank so that the customizing QS view doesn't show any security messages in the footer.
|
||||
*/
|
||||
private static class BlankSecurityController implements SecurityController {
|
||||
@Override
|
||||
public boolean hasDeviceOwner() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProfileOwner() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceOwnerName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfileOwnerName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVpnEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryVpnName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfileVpnName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitched(int newUserId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(SecurityControllerCallback callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(SecurityControllerCallback callback) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DragEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
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.QSTileView;
|
||||
import com.android.systemui.qs.QuickTileLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Similar to PagedTileLayout, except that instead of pages it lays them out
|
||||
* vertically and expects to be inside a ScrollView.
|
||||
* @see CustomQSPanel
|
||||
*/
|
||||
public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
|
||||
|
||||
private QuickTileLayout mQuickTiles;
|
||||
private final ArrayList<TilePage> mPages = new ArrayList<>();
|
||||
private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
|
||||
private CustomQSPanel mPanel;
|
||||
private final Rect mHitRect = new Rect();
|
||||
|
||||
public NonPagedTileLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mQuickTiles = (QuickTileLayout) findViewById(R.id.quick_tile_layout);
|
||||
TilePage page = (PagedTileLayout.TilePage) findViewById(R.id.tile_page);
|
||||
page.setMaxRows(3 /* First page only gets 3 */);
|
||||
mPages.add(page);
|
||||
}
|
||||
|
||||
public void setCustomQsPanel(CustomQSPanel qsPanel) {
|
||||
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);
|
||||
distributeTiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTile(TileRecord tile) {
|
||||
if (mTiles.remove(tile)) {
|
||||
distributeTiles();
|
||||
}
|
||||
}
|
||||
|
||||
private void distributeTiles() {
|
||||
mQuickTiles.removeAllViews();
|
||||
final int NP = mPages.size();
|
||||
for (int i = 0; i < NP; i++) {
|
||||
mPages.get(i).removeAllViews();
|
||||
}
|
||||
int index = 0;
|
||||
final int NT = mTiles.size();
|
||||
for (int i = 0; i < NT; i++) {
|
||||
TileRecord tile = mTiles.get(i);
|
||||
if (tile.tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
|
||||
tile.tileView.setType(QSTileView.QS_TYPE_QUICK);
|
||||
mQuickTiles.addView(tile.tileView);
|
||||
continue;
|
||||
}
|
||||
mPages.get(index).addTile(tile);
|
||||
if (mPages.get(index).isFull()) {
|
||||
if (++index == mPages.size()) {
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
inflater.inflate(R.layout.horizontal_divider, this);
|
||||
mPages.add((TilePage) inflater.inflate(R.layout.qs_paged_page, this, false));
|
||||
addView(mPages.get(mPages.size() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTileVisibility(TileRecord tile, int visibility) {
|
||||
// All tiles visible here, so that they can be re-arranged.
|
||||
tile.tileView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffsetTop(TileRecord tile) {
|
||||
// TODO: Fix this.
|
||||
return getTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateResources() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent(DragEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case DragEvent.ACTION_DRAG_LOCATION:
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
if (contains(mQuickTiles, x, y)) {
|
||||
// TODO: Reset to pre-drag state.
|
||||
} else {
|
||||
final int NP = mPages.size();
|
||||
for (int i = 0; i < NP; i++) {
|
||||
TilePage page = mPages.get(i);
|
||||
if (contains(page, x, y)) {
|
||||
x -= page.getLeft();
|
||||
y -= page.getTop();
|
||||
final int NC = page.getChildCount();
|
||||
for (int j = 0; j < NC; j++) {
|
||||
View child = page.getChildAt(j);
|
||||
if (contains(child, x, y)) {
|
||||
mPanel.tileSelected(child);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DragEvent.ACTION_DRAG_ENDED:
|
||||
mPanel.onDragEnded();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean contains(View v, float x, float y) {
|
||||
v.getHitRect(mHitRect);
|
||||
return mHitRect.contains((int) x, (int) y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toolbar;
|
||||
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.statusbar.phone.PhoneStatusBar;
|
||||
import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
import com.android.systemui.tuner.QSPagingSwitch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Allows full-screen customization of QS, through show() and hide().
|
||||
*
|
||||
* 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 {
|
||||
|
||||
private static final int MENU_SAVE = Menu.FIRST;
|
||||
private static final int MENU_RESET = Menu.FIRST + 1;
|
||||
|
||||
private PhoneStatusBar mPhoneStatusBar;
|
||||
|
||||
private Toolbar mToolbar;
|
||||
private CustomQSPanel mQsPanel;
|
||||
|
||||
private boolean isShown;
|
||||
private CustomQSTileHost mHost;
|
||||
|
||||
public QSCustomizer(Context context, AttributeSet attrs) {
|
||||
super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
|
||||
mPhoneStatusBar = ((SystemUIApplication) mContext.getApplicationContext())
|
||||
.getComponent(PhoneStatusBar.class);
|
||||
}
|
||||
|
||||
public void setHost(QSTileHost host) {
|
||||
mHost = new CustomQSTileHost(mContext, host);
|
||||
mHost.setCallback(this);
|
||||
mQsPanel.setTiles(mHost.getTiles());
|
||||
mQsPanel.setHost(mHost);
|
||||
mHost.setSavedTiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
|
||||
TypedValue value = new TypedValue();
|
||||
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
|
||||
mToolbar.setNavigationIcon(
|
||||
getResources().getDrawable(value.resourceId, mContext.getTheme()));
|
||||
mToolbar.setNavigationOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// TODO: Is this all we want...?
|
||||
hide();
|
||||
}
|
||||
});
|
||||
mToolbar.setOnMenuItemClickListener(this);
|
||||
mToolbar.getMenu().add(Menu.NONE, MENU_SAVE, 0, mContext.getString(R.string.save))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
|
||||
mContext.getString(com.android.internal.R.string.reset));
|
||||
|
||||
mQsPanel = (CustomQSPanel) findViewById(R.id.quick_settings_panel);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
isShown = true;
|
||||
mHost.setSavedTiles();
|
||||
// TODO: Fancy shmancy reveal.
|
||||
mPhoneStatusBar.getStatusBarWindow().addView(this);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
isShown = false;
|
||||
// TODO: Similarly awesome or better hide.
|
||||
mPhoneStatusBar.getStatusBarWindow().removeView(this);
|
||||
}
|
||||
|
||||
public boolean isCustomizing() {
|
||||
return isShown;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
ArrayList<String> tiles = new ArrayList<>();
|
||||
for (String tile : QSPagingSwitch.QS_PAGE_TILES.split(",")) {
|
||||
tiles.add(tile);
|
||||
}
|
||||
mHost.setTiles(tiles);
|
||||
}
|
||||
|
||||
private void save() {
|
||||
mHost.saveCurrentTiles();
|
||||
hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_SAVE:
|
||||
save();
|
||||
break;
|
||||
case MENU_RESET:
|
||||
reset();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTilesChanged() {
|
||||
mQsPanel.setTiles(mHost.getTiles());
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
|
||||
public class QSPagingSwitch extends TunerSwitch {
|
||||
|
||||
private static final String QS_PAGE_TILES =
|
||||
public static final String QS_PAGE_TILES =
|
||||
"dwifi,dbt,inversion,dnd,cell,airplane,rotation,flashlight,location,"
|
||||
+ "hotspot,qwifi,qbt,qrotation,qflashlight,qairplane,cast";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user