summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/tuner
diff options
context:
space:
mode:
authorJason Monk <jmonk@google.com>2015-05-12 19:29:02 -0400
committerJason Monk <jmonk@google.com>2015-05-13 20:59:23 -0400
commit11a77446c575f420d8acc163ff1f9b1050853e27 (patch)
tree5b48373fa37b0fafc68414e1dc6d4fe39eb83524 /packages/SystemUI/src/com/android/systemui/tuner
parentcf304fb35c2086601178858e307d3dda36dbbff7 (diff)
downloadframeworks_base-11a77446c575f420d8acc163ff1f9b1050853e27.zip
frameworks_base-11a77446c575f420d8acc163ff1f9b1050853e27.tar.gz
frameworks_base-11a77446c575f420d8acc163ff1f9b1050853e27.tar.bz2
Add QS Tuner
Change-Id: I908d0161b7209b8e99299f5cb3eb58f3d7b52752
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/tuner')
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java451
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java16
3 files changed, 513 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java b/packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java
new file mode 100644
index 0000000..6aea2cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tuner;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.widget.ScrollView;
+
+public class AutoScrollView extends ScrollView {
+
+ private static final float SCROLL_PERCENT = .10f;
+
+ public AutoScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_LOCATION:
+ int y = (int) event.getY();
+ int height = getHeight();
+ int scrollPadding = (int) (height * SCROLL_PERCENT);
+ if (y < scrollPadding) {
+ scrollBy(0, y - scrollPadding);
+ } else if (y > height - scrollPadding) {
+ scrollBy(0, y - height + scrollPadding);
+ }
+ break;
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
new file mode 100644
index 0000000..5cf0813
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -0,0 +1,451 @@
+/*
+ * 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.tuner;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.ClipData;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings.Secure;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnDragListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ScrollView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.QSTile.ResourceIcon;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.tiles.IntentTile;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.List;
+
+public class QsTuner extends Fragment implements Callback {
+
+ private static final String TAG = "QsTuner";
+
+ private static final int MENU_RESET = Menu.FIRST;
+
+ private DraggableQsPanel mQsPanel;
+ private CustomHost mTileHost;
+
+ private FrameLayout mDropTarget;
+
+ private ScrollView mScrollRoot;
+
+ private FrameLayout mAddTarget;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(0, MENU_RESET, 0, com.android.internal.R.string.reset);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ mTileHost.reset();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mScrollRoot = (ScrollView) inflater.inflate(R.layout.tuner_qs, container, false);
+
+ mQsPanel = new DraggableQsPanel(getContext());
+ mTileHost = new CustomHost(getContext());
+ mTileHost.setCallback(this);
+ mQsPanel.setTiles(mTileHost.getTiles());
+ mQsPanel.setHost(mTileHost);
+ mQsPanel.refreshAllTiles();
+ ((ViewGroup) mScrollRoot.findViewById(R.id.all_details)).addView(mQsPanel, 0);
+
+ mDropTarget = (FrameLayout) mScrollRoot.findViewById(R.id.remove_target);
+ setupDropTarget();
+ mAddTarget = (FrameLayout) mScrollRoot.findViewById(R.id.add_target);
+ setupAddTarget();
+ return mScrollRoot;
+ }
+
+ private void setupDropTarget() {
+ QSTileView tileView = new QSTileView(getContext());
+ QSTile.State state = new QSTile.State();
+ state.visible = true;
+ state.icon = ResourceIcon.get(R.drawable.ic_delete);
+ state.label = getString(com.android.internal.R.string.delete);
+ tileView.onStateChanged(state);
+ mDropTarget.addView(tileView);
+ mDropTarget.setVisibility(View.GONE);
+ new DragHelper(tileView, new DropListener() {
+ @Override
+ public void onDrop(String sourceText) {
+ mTileHost.remove(sourceText);
+ }
+ });
+ }
+
+ private void setupAddTarget() {
+ QSTileView tileView = new QSTileView(getContext());
+ QSTile.State state = new QSTile.State();
+ state.visible = true;
+ state.icon = ResourceIcon.get(R.drawable.ic_add_circle_qs);
+ state.label = getString(R.string.add_tile);
+ tileView.onStateChanged(state);
+ mAddTarget.addView(tileView);
+ tileView.setClickable(true);
+ tileView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mTileHost.showAddDialog();
+ }
+ });
+ }
+
+ public void onStartDrag() {
+ mDropTarget.setVisibility(View.VISIBLE);
+ mAddTarget.setVisibility(View.GONE);
+ }
+
+ public void stopDrag() {
+ mDropTarget.setVisibility(View.GONE);
+ mAddTarget.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onTilesChanged() {
+ mQsPanel.setTiles(mTileHost.getTiles());
+ }
+
+ private static int getLabelResource(String spec) {
+ if (spec.equals("wifi")) return R.string.quick_settings_wifi_label;
+ else if (spec.equals("bt")) return R.string.quick_settings_bluetooth_label;
+ else if (spec.equals("inversion")) return R.string.quick_settings_inversion_label;
+ else if (spec.equals("cell")) return R.string.quick_settings_cellular_detail_title;
+ else if (spec.equals("airplane")) return R.string.quick_settings_airplane_mode_label;
+ else if (spec.equals("dnd")) return R.string.quick_settings_dnd_label;
+ else if (spec.equals("rotation")) return R.string.quick_settings_rotation_locked_label;
+ else if (spec.equals("flashlight")) return R.string.quick_settings_flashlight_label;
+ else if (spec.equals("location")) return R.string.quick_settings_location_label;
+ else if (spec.equals("cast")) return R.string.quick_settings_cast_title;
+ else if (spec.equals("hotspot")) return R.string.quick_settings_hotspot_label;
+ return 0;
+ }
+
+ private static class CustomHost extends QSTileHost {
+
+ public CustomHost(Context context) {
+ super(context, null, null, null, null, null, null, null, null, null,
+ null, null, null);
+ }
+
+ @Override
+ protected QSTile<?> createTile(String tileSpec) {
+ return new DraggableTile(this, tileSpec);
+ }
+
+ public void replace(String oldTile, String newTile) {
+ if (oldTile.equals(newTile)) {
+ return;
+ }
+ List<String> order = loadTileSpecs();
+ 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);
+ }
+
+ public void remove(String tile) {
+ List<String> tiles = loadTileSpecs();
+ tiles.remove(tile);
+ setTiles(tiles);
+ }
+
+ public void add(String tile) {
+ List<String> tiles = loadTileSpecs();
+ tiles.add(tile);
+ setTiles(tiles);
+ }
+
+ public void reset() {
+ Secure.putStringForUser(getContext().getContentResolver(),
+ TILES_SETTING, "default", mUserTracker.getCurrentUserId());
+ }
+
+ private void setTiles(List<String> tiles) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < tiles.size(); i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(tiles.get(i));
+ }
+ Secure.putStringForUser(getContext().getContentResolver(),
+ TILES_SETTING, builder.toString(), mUserTracker.getCurrentUserId());
+ }
+
+ public void showAddDialog() {
+ List<String> tiles = loadTileSpecs();
+ String[] defaults =
+ getContext().getString(R.string.quick_settings_tiles_default).split(",");
+ final String[] available = new String[defaults.length + 1 - tiles.size()];
+ int index = 0;
+ for (int i = 0; i < defaults.length; i++) {
+ if (tiles.contains(defaults[i])) {
+ continue;
+ }
+ int resource = getLabelResource(defaults[i]);
+ if (resource != 0) {
+ available[index++] = getContext().getString(resource);
+ } else {
+ available[index++] = defaults[i];
+ }
+ }
+ available[index++] = getContext().getString(R.string.broadcast_tile);
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.add_tile)
+ .setItems(available, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which < available.length - 1) {
+ add(available[which]);
+ } else {
+ showBroadcastTileDialog();
+ }
+ }
+ }).show();
+ }
+
+ public void showBroadcastTileDialog() {
+ final EditText editText = new EditText(getContext());
+ 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 + ')');
+ }
+ }
+ }).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;
+ }
+ }
+
+ private static class DraggableTile extends QSTile<QSTile.State>
+ implements DropListener {
+ private String mSpec;
+ private QSTileView mView;
+
+ protected DraggableTile(QSTile.Host host, String tileSpec) {
+ super(host);
+ Log.d(TAG, "Creating tile " + tileSpec);
+ mSpec = tileSpec;
+ }
+
+ @Override
+ public QSTileView createTileView(Context context) {
+ mView = super.createTileView(context);
+ return mView;
+ }
+
+ @Override
+ public boolean supportsDualTargets() {
+ return "wifi".equals(mSpec) || "bt".equals(mSpec);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ }
+
+ @Override
+ protected QSTile.State newTileState() {
+ return new QSTile.State();
+ }
+
+ @Override
+ protected void handleClick() {
+ }
+
+ @Override
+ protected void handleUpdateState(QSTile.State state, Object arg) {
+ state.visible = true;
+ state.icon = ResourceIcon.get(getIcon());
+ state.label = getLabel();
+ }
+
+ private String getLabel() {
+ int resource = getLabelResource(mSpec);
+ if (resource != 0) {
+ return mContext.getString(resource);
+ }
+ if (mSpec.startsWith(IntentTile.PREFIX)) {
+ int lastDot = mSpec.lastIndexOf('.');
+ if (lastDot >= 0) {
+ return mSpec.substring(lastDot + 1, mSpec.length() - 1);
+ } else {
+ return mSpec.substring(IntentTile.PREFIX.length(), mSpec.length() - 1);
+ }
+ }
+ return mSpec;
+ }
+
+ private int getIcon() {
+ if (mSpec.equals("wifi")) return R.drawable.ic_qs_wifi_full_3;
+ else if (mSpec.equals("bt")) return R.drawable.ic_qs_bluetooth_connected;
+ else if (mSpec.equals("inversion")) return R.drawable.ic_invert_colors_enable;
+ else if (mSpec.equals("cell")) return R.drawable.ic_qs_signal_full_3;
+ else if (mSpec.equals("airplane")) return R.drawable.ic_signal_airplane_enable;
+ else if (mSpec.equals("dnd")) return R.drawable.ic_qs_dnd_on;
+ else if (mSpec.equals("rotation")) return R.drawable.ic_portrait_from_auto_rotate;
+ else if (mSpec.equals("flashlight")) return R.drawable.ic_signal_flashlight_enable;
+ else if (mSpec.equals("location")) return R.drawable.ic_signal_location_enable;
+ else if (mSpec.equals("cast")) return R.drawable.ic_qs_cast_on;
+ else if (mSpec.equals("hotspot")) return R.drawable.ic_hotspot_enable;
+ return R.drawable.android;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return 20000;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof DraggableTile) {
+ return mSpec.equals(((DraggableTile) o).mSpec);
+ }
+ return false;
+ }
+
+ @Override
+ public void onDrop(String sourceText) {
+ ((CustomHost) mHost).replace(mSpec, sourceText);
+ }
+
+ }
+
+ private class DragHelper implements OnDragListener {
+
+ private final View mView;
+ private final DropListener mListener;
+
+ public DragHelper(View view, DropListener dropListener) {
+ mView = view;
+ mListener = dropListener;
+ mView.setOnDragListener(this);
+ }
+
+ @Override
+ public boolean onDrag(View v, DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_ENTERED:
+ mView.setBackgroundColor(0x77ffffff);
+ break;
+ case DragEvent.ACTION_DRAG_ENDED:
+ stopDrag();
+ case DragEvent.ACTION_DRAG_EXITED:
+ mView.setBackgroundColor(0x0);
+ break;
+ case DragEvent.ACTION_DROP:
+ stopDrag();
+ String text = event.getClipData().getItemAt(0).getText().toString();
+ mListener.onDrop(text);
+ break;
+ }
+ return true;
+ }
+
+ }
+
+ public interface DropListener {
+ void onDrop(String sourceText);
+ }
+
+ private class DraggableQsPanel extends QSPanel implements OnTouchListener {
+ public DraggableQsPanel(Context context) {
+ super(context);
+ mBrightnessView.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ for (TileRecord r : mRecords) {
+ new DragHelper(r.tileView, (DraggableTile) r.tile);
+ r.tileView.setTag(r.tile);
+ r.tileView.setOnTouchListener(this);
+
+ for (int i = 0; i < r.tileView.getChildCount(); i++) {
+ r.tileView.getChildAt(i).setClickable(false);
+ }
+ }
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ String tileSpec = (String) ((DraggableTile) v.getTag()).mSpec;
+ ClipData data = ClipData.newPlainText(tileSpec, tileSpec);
+ v.startDrag(data, new View.DragShadowBuilder(v), null, 0);
+ onStartDrag();
+ return true;
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index df1b0d0..457bade 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -15,7 +15,10 @@
*/
package com.android.systemui.tuner;
+import android.app.FragmentTransaction;
import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.view.MenuItem;
@@ -23,12 +26,25 @@ import com.android.systemui.R;
public class TunerFragment extends PreferenceFragment {
+ private static final String KEY_QS_TUNER = "qs_tuner";
+
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.tuner_prefs);
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
setHasOptionsMenu(true);
+
+ findPreference(KEY_QS_TUNER).setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, new QsTuner(), "QsTuner");
+ ft.addToBackStack(null);
+ ft.commit();
+ return false;
+ }
+ });
}
@Override