diff options
27 files changed, 937 insertions, 268 deletions
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png Binary files differnew file mode 100755 index 0000000..4759a1c --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png Binary files differnew file mode 100755 index 0000000..878169b --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png Binary files differnew file mode 100755 index 0000000..84807e8 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png Binary files differnew file mode 100755 index 0000000..78bbc25 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png Binary files differnew file mode 100755 index 0000000..6a6536e --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml index 5a96dc3..6f07543 100644 --- a/packages/SystemUI/res/layout/qs_detail_header.xml +++ b/packages/SystemUI/res/layout/qs_detail_header.xml @@ -37,4 +37,15 @@ android:clickable="false" android:textAppearance="@style/TextAppearance.QS.DetailHeader" /> -</com.android.keyguard.AlphaOptimizedLinearLayout>
\ No newline at end of file + <TextView + android:id="@+id/done" + android:text="@string/quick_settings_done" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center" + android:minWidth="88dp" + android:paddingRight="12dp" + android:textAppearance="@style/TextAppearance.QS.DetailButton" + android:clickable="false" + android:focusable="false" /> +</com.android.keyguard.AlphaOptimizedLinearLayout> diff --git a/packages/SystemUI/res/layout/qs_settings.xml b/packages/SystemUI/res/layout/qs_settings.xml new file mode 100644 index 0000000..203364e --- /dev/null +++ b/packages/SystemUI/res/layout/qs_settings.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The CyanogenMod 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.QSSettings + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/quick_settings_settings_recursion_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:orientation="vertical"> + + <TextView + android:layout_width="match_parent" + android:layout_height="48dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:gravity="center_vertical" + android:textColor="#80cbc4" + android:text="@string/quick_settings_title_header"/> + + <!-- show weather --> + <com.android.systemui.qs.QSBooleanSettingRow + style="@style/SettingRow" + android:key="status_bar_show_weather" + android:title="@string/quick_settings_title_show_weather" + systemui:table="cm_system" + /> + + <TextView + android:layout_width="match_parent" + android:layout_height="48dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:gravity="center_vertical" + android:textColor="#80cbc4" + android:text="@string/quick_settings_title_tiles"/> + + <!-- TODO implement! + first row large + <com.android.systemui.qs.QSBooleanSettingRow + style="@style/SettingRow" + android:key="someKey1" + android:title="@string/quick_settings_title_enlarge_first_row" + systemui:table="system" + />--> + + <LinearLayout + android:id="@+id/reset_tiles" + style="@style/SettingRow"> + <TextView + android:layout_width="0dp" + android:layout_height="24dp" + android:gravity="center_vertical" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:id="@+id/title" + android:textColor="@android:color/white" + android:text="@string/quick_settings_tile_reset_to_default" + android:contentDescription="@null"/> + + </LinearLayout> + +</com.android.systemui.qs.QSSettings> + diff --git a/packages/SystemUI/res/layout/qs_settings_row.xml b/packages/SystemUI/res/layout/qs_settings_row.xml new file mode 100644 index 0000000..98ac6fc --- /dev/null +++ b/packages/SystemUI/res/layout/qs_settings_row.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The CyanogenMod 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. +--> +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + <TextView + android:layout_width="0dp" + android:layout_height="24dp" + android:gravity="center_vertical" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:id="@+id/title" + android:textColor="@android:color/white" + android:contentDescription="@null"/> + + <Switch + android:id="@+id/switcher" + android:layout_width="wrap_content" + android:layout_height="24dp" + android:gravity="center_vertical" + android:layout_gravity="center_vertical" + /> +</merge> diff --git a/packages/SystemUI/res/layout/qs_tile_top b/packages/SystemUI/res/layout/qs_tile_top.xml index 6d455ab..4847c77 100644 --- a/packages/SystemUI/res/layout/qs_tile_top +++ b/packages/SystemUI/res/layout/qs_tile_top.xml @@ -15,21 +15,21 @@ --> <com.android.systemui.qs.QSPanelTopView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/qs_panel_top" android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingBottom="@dimen/qs_brightness_padding_top"> + android:layout_height="match_parent"> <!-- brightness --> <include android:id="@+id/brightness_container" + android:paddingTop="@dimen/qs_brightness_padding_top" layout="@layout/quick_settings_brightness_dialog"/> <!-- delete target --> <LinearLayout android:id="@+id/delete_container" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="match_parent" + android:paddingTop="@dimen/qs_brightness_padding_top" android:paddingLeft="16dp" android:paddingRight="16dp" android:orientation="horizontal"> @@ -39,6 +39,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" + android:layout_gravity="center" android:src="@drawable/ic_delete" /> </LinearLayout> @@ -47,7 +48,8 @@ <LinearLayout android:id="@+id/edit_container" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="match_parent" + android:paddingTop="@dimen/qs_brightness_padding_top" android:paddingLeft="16dp" android:paddingRight="16dp" android:orientation="horizontal"> @@ -72,13 +74,14 @@ <TextView android:id="@+id/qs_toast" - android:layout_height="wrap_content" + android:layout_height="match_parent" + android:paddingTop="@dimen/qs_brightness_padding_top" android:paddingLeft="16dp" android:paddingRight="16dp" android:gravity="center_vertical" + android:layout_gravity="center_vertical" android:layout_width="match_parent" - android:textColor="@color/quick_settings_toast_color" - android:visibility="invisible"/> + android:textColor="@color/quick_settings_toast_color"/> </com.android.systemui.qs.QSPanelTopView> diff --git a/packages/SystemUI/res/values/cm_attrs.xml b/packages/SystemUI/res/values/cm_attrs.xml new file mode 100644 index 0000000..8e88e67 --- /dev/null +++ b/packages/SystemUI/res/values/cm_attrs.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The CyanogenMod 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. +--> + +<resources> + <declare-styleable name="QuickSettingsRow"> + <attr name="table" format="enum"> + <enum name="system" value="0"/> + <enum name="global" value="1"/> + <enum name="secure" value="2"/> + + <enum name="cm_system" value="3"/> + <enum name="cm_global" value="4"/> + <enum name="cm_secure" value="5"/> + </attr> + + <attr name="android:key"/> + <attr name="android:title" /> + </declare-styleable> +</resources> + diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml index bba5d96..7b56807 100644 --- a/packages/SystemUI/res/values/cm_strings.xml +++ b/packages/SystemUI/res/values/cm_strings.xml @@ -73,10 +73,15 @@ <string name="led_notification_title">Light settings</string> <string name="led_notification_text">LED light enabled by settings</string> - <string name="qs_tile_edit_header_instruction">Press and hold a tile to edit</string> - <string name="quick_settings_edit_label">Edit Tiles</string> + <string name="qs_tile_edit_header_instruction">Press and hold tiles to rearrange</string> + <string name="quick_settings_edit_label">Edit tiles</string> <string name="quick_settings_cannot_delete_edit_tile">Cannot delete the Edit tile</string> <string name="qs_tiles_reset_confirmation">Reset quick settings tiles to default configuration?</string> + <string name="quick_settings_tile_reset_to_default">Reset to default layout</string> + <string name="quick_settings_title_header">Header</string> + <string name="quick_settings_title_tiles">Tiles</string> + <string name="quick_settings_title_show_weather">Show weather</string> + <string name="quick_settings_title_enlarge_first_row">Enlarge first row</string> <!-- Screen pinning dialog description (for devices without navbar) --> <string name="screen_pinning_description_no_navbar">This keeps it in view until you unpin. Touch and hold the Back button to unpin.</string> diff --git a/packages/SystemUI/res/values/cm_styles.xml b/packages/SystemUI/res/values/cm_styles.xml index 40b8929..36d8614 100644 --- a/packages/SystemUI/res/values/cm_styles.xml +++ b/packages/SystemUI/res/values/cm_styles.xml @@ -16,6 +16,15 @@ --> <resources> + <style name="SettingRow"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">48dp</item> + <item name="android:paddingLeft">16dp</item> + <item name="android:paddingRight">16dp</item> + <item name="android:background">?android:attr/selectableItemBackground</item> + <item name="android:clickable">true</item> + </style> + <style name="TextAppearance.StatusBar.Expanded.WeatherTemp"> <item name="android:textSize">12sp</item> <item name="android:textStyle">normal</item> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java b/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java new file mode 100644 index 0000000..9cb4fbb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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; + +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.TypedArray; +import android.provider.Settings; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.LinearLayout; +import android.widget.Switch; +import android.widget.TextView; + +import com.android.systemui.R; +import cyanogenmod.providers.CMSettings; + +public class QSBooleanSettingRow extends LinearLayout implements View.OnClickListener { + + private static final String TAG = "QSSettingRow"; + + public static final int TABLE_SYSTEM = 0; + public static final int TABLE_GLOBAL = 1; + public static final int TABLE_SECURE = 2; + + public static final int TABLE_CM_SYSTEM = 3; + public static final int TABLE_CM_GLOBAL = 4; + public static final int TABLE_CM_SECURE = 5; + + int mWhichTable; + String mTitle; + String mKey; + private TextView mText; + private Switch mSwitch; + + public QSBooleanSettingRow(Context context) { + this(context, null); + } + + public QSBooleanSettingRow(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public QSBooleanSettingRow(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public QSBooleanSettingRow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + View.inflate(context, R.layout.qs_settings_row, this); + + setOrientation(HORIZONTAL); + setClickable(true); + setOnClickListener(this); + + mText = (TextView) findViewById(R.id.title); + mSwitch = (Switch) findViewById(R.id.switcher); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.QuickSettingsRow, + defStyleAttr, defStyleRes); + + mWhichTable = a.getInteger(R.styleable.QuickSettingsRow_table, -1); + + mTitle = a.getString(R.styleable.QuickSettingsRow_android_title); + mKey = a.getString(R.styleable.QuickSettingsRow_android_key); + + if (mText != null) { + mText.setText(mTitle); + mText.setClickable(false); + mText.setFocusable(false); + } + + if (mSwitch != null) { + mSwitch.setClickable(false); + mSwitch.setFocusable(false); + mSwitch.setChecked(getCurrent()); + mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + applyChange(isChecked); + // TODO update table with new value + Log.d(TAG, "onCheckedChanged() called with " + + "buttonView = [" + buttonView + "], isChecked = [" + isChecked + + "] and table: " + mWhichTable + ", and key: " + mKey); + } + }); + } + + a.recycle(); + } + + private void applyChange(boolean value) { + ContentResolver cr = getContext().getContentResolver(); + switch (mWhichTable) { + case TABLE_GLOBAL: + Settings.Global.putInt(cr, mKey, value ? 1 : 0); + break; + case TABLE_SECURE: + Settings.Secure.putInt(cr, mKey, value ? 1 : 0); + break; + case TABLE_SYSTEM: + Settings.System.putInt(cr, mKey, value ? 1 : 0); + break; + case TABLE_CM_GLOBAL: + CMSettings.Global.putInt(cr, mKey, value ? 1 : 0); + break; + case TABLE_CM_SECURE: + CMSettings.Secure.putInt(cr, mKey, value ? 1 : 0); + break; + case TABLE_CM_SYSTEM: + CMSettings.System.putInt(cr, mKey, value ? 1 : 0); + break; + } + } + + private boolean getCurrent() { + ContentResolver cr = getContext().getContentResolver(); + int ret = 0; + try { + switch (mWhichTable) { + case TABLE_GLOBAL: + ret = Settings.Global.getInt(cr, mKey); + break; + case TABLE_SECURE: + ret = Settings.Secure.getInt(cr, mKey); + break; + case TABLE_SYSTEM: + ret = Settings.System.getInt(cr, mKey); + break; + case TABLE_CM_GLOBAL: + ret = CMSettings.Global.getInt(cr, mKey); + break; + case TABLE_CM_SECURE: + ret = CMSettings.Secure.getInt(cr, mKey); + break; + case TABLE_CM_SYSTEM: + ret = CMSettings.System.getInt(cr, mKey); + break; + } + } catch (Settings.SettingNotFoundException|CMSettings.CMSettingNotFoundException e) { + Log.e(TAG, "need to add a default setting for key: " + mKey + + " in table: " + mWhichTable); + e.printStackTrace(); + } + return ret == 1; + } + + @Override + public void onClick(View v) { + mSwitch.setChecked(!mSwitch.isChecked()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java index 3d0745c..3ca1d05 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.drawable.Drawable; @@ -32,6 +33,7 @@ import android.view.DragEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; @@ -43,6 +45,7 @@ import com.android.systemui.settings.BrightnessController; import com.android.systemui.settings.ToggleSlider; 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; @@ -57,7 +60,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On private static final String TAG = "QSDragPanel"; - public static final boolean DEBUG_DRAG = true; + public static final boolean DEBUG_DRAG = false; + private static final int INITIAL_OFFSCREEN_PAGE_LIMIT = 3; protected final ArrayList<QSPage> mPages = new ArrayList<>(); @@ -92,6 +96,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On @Override protected void setupViews() { + updateResources(); + mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false); mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content); mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2); @@ -100,11 +106,27 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On mDetail.setVisibility(GONE); mDetail.setClickable(true); - LayoutInflater.from(mContext).inflate(R.layout.qs_tile_top, this, true); - mQsPanelTop = (QSPanelTopView) findViewById(R.id.qs_panel_top); + mQsPanelTop = (QSPanelTopView) LayoutInflater.from(mContext).inflate(R.layout.qs_tile_top, this, false); + mBrightnessView = mQsPanelTop.getBrightnessView(); mFooter = new QSFooter(this, mContext); + getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + getViewTreeObserver().removeOnGlobalLayoutListener(this); + + ViewPager.LayoutParams params = new ViewPager.LayoutParams(); + params.isDecor = true; + + mViewPager.addView(mQsPanelTop, params); + + mQsPanelTop.setOnDragListener(QSDragPanel.this); + mPageIndicator.setOnDragListener(QSDragPanel.this); + mViewPager.setOnDragListener(QSDragPanel.this); + } + }); + // add target click listener mQsPanelTop.findViewById(R.id.add_target).setOnClickListener( new OnClickListener() { @@ -114,6 +136,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On } }); mViewPager = new QSViewPager(getContext()); + mViewPager.setDragPanel(this); mPageIndicator = new CirclePageIndicator(getContext()); addView(mDetail); @@ -143,13 +166,26 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On Log.d(TAG, "instantiateItem() called with " + "container = [" + container + "], position = [" + position + "]"); } - QSPage page = new QSPage(container.getContext(), QSDragPanel.this, position); - LayoutParams params = - new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.FILL_PARENT); - container.addView(page, params); - mPages.add(page); - return page; + + if (mEditing && position == 0) { + QSSettings qss = (QSSettings) + View.inflate(container.getContext(), R.layout.qs_settings, null); + qss.setHost(mHost); + container.addView(qss, 0); + return qss; + } else { + QSPage page = new QSPage(container.getContext(), + QSDragPanel.this, mEditing ? position - 1 : position); + + container.addView(page); + int viewPos = page.getPageIndex(); + if (viewPos > mPages.size()) { + mPages.add(page); + } else { + mPages.add(viewPos, page); + } + return page; + } } @Override @@ -160,14 +196,37 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On + object + "]"); } if (object instanceof View) { - mPages.remove(object); + if (object instanceof QSPage) { + mPages.remove(object); + } container.removeView((View) object); } } @Override + public int getItemPosition(Object object) { + if (object instanceof QSPage) { + + final int indexOf = ((QSPage) object).getPageIndex(); + Log.v(TAG, "getItemPosition() for: " + object + ", returning: " + indexOf); + if (mEditing) return indexOf + 1; + else return indexOf; + + } else if (object instanceof QSSettings) { + + if (mEditing) return 0; + else return POSITION_NONE; + + } + return super.getItemPosition(object); + } + + @Override public int getCount() { - return Math.max(getCurrentMaxPageCount(), 1); + final int qsPages = Math.max(getCurrentMaxPageCount(), 1); + + if (mEditing) return qsPages + 1; + return qsPages; } @Override @@ -176,13 +235,31 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On } }; mViewPager.setAdapter(mPagerAdapter); + mViewPager.setOffscreenPageLimit(INITIAL_OFFSCREEN_PAGE_LIMIT); mPageIndicator.setViewPager(mViewPager); mPageIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + Log.i(TAG, "onPageScrolled() called with " + "position = [" + + position + "], positionOffset = [" + positionOffset + + "], positionOffsetPixels = [" + positionOffsetPixels + "]"); + + if (mEditing) { + float targetTranslationX = 0; + // targetTranslationX = where it's supposed to be - diff + int homeLocation = mViewPager.getMeasuredWidth(); + + // how far away from homeLocation is the scroll? + if (positionOffsetPixels < homeLocation + && position == 0) { + targetTranslationX = homeLocation - positionOffsetPixels; + } + mQsPanelTop.setTranslationX(targetTranslationX); + } } @Override @@ -207,23 +284,26 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On @Override public void onPageScrollStateChanged(int state) { - } }); - mPageIndicator.setCurrentItem(0); mViewPager.setOverScrollMode(OVER_SCROLL_NEVER); - updateResources(); - - mViewPager.setOnDragListener(this); - mPageIndicator.setOnDragListener(this); - mQsPanelTop.getBrightnessView().setOnDragListener(this); - mQsPanelTop.getDropTarget().setOnDragListener(this); + setClipChildren(false); } @Override public boolean hasOverlappingRendering() { - return mClipper.isAnimating(); + return mClipper.isAnimating() || mEditing; + } + + @Override + public void setBrightnessMirror(BrightnessMirrorController c) { + super.onFinishInflate(); + ToggleSlider brightnessSlider = + (ToggleSlider) mQsPanelTop.findViewById(R.id.brightness_slider); + ToggleSlider mirror = (ToggleSlider) c.getMirror().findViewById(R.id.brightness_slider); + brightnessSlider.setMirror(mirror); + brightnessSlider.setMirrorController(c); } protected void drawTile(TileRecord r, QSTile.State state) { @@ -232,6 +312,24 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On r.tileView.onStateChanged(state); } + @Override + public void setListening(boolean listening) { + if (mListening == listening) return; + mListening = listening; + for (TileRecord r : mRecords) { + r.tile.setListening(mListening); + } + mFooter.setListening(mListening); + if (mListening) { + refreshAllTiles(); + } + if (isLaidOut() && listening && showBrightnessSlider()) { + mBrightnessController.registerCallbacks(); + } else { + mBrightnessController.unregisterCallbacks(); + } + } + public void setEditing(boolean editing) { if (mEditing == editing) return; mEditing = editing; @@ -245,6 +343,8 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On mHost.setTiles(newTiles); refreshAllTiles(); + + mQsPanelTop.animate().translationX(0).start(); } // clear the record state @@ -253,6 +353,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On drawTile(record, record.tile.getState()); } mQsPanelTop.setEditing(editing); + mPageIndicator.setEditing(editing); + mPagerAdapter.notifyDataSetChanged(); + ensurePagerState(); requestLayout(); } @@ -460,8 +563,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On } public void ensurePagerState() { - final boolean pagingEnabled = getVisibleTilePageCount() > 1 || mDragging; - mViewPager.setPagingEnabled(pagingEnabled); + if (!isShowingDetail()) { + final boolean pagingEnabled = getVisibleTilePageCount() > 1 || mDragging || mEditing; + mViewPager.setPagingEnabled(pagingEnabled); + } } public int getTilesPerPage() { @@ -470,17 +575,16 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (DEBUG_DRAG) Log.d(TAG, "onMeasure()"); - final int width = MeasureSpec.getSize(widthMeasureSpec); - mQsPanelTop.measure(exactly(width), MeasureSpec.UNSPECIFIED); + if (isLaidOut()) { + mQsPanelTop.measure(exactly(width), MeasureSpec.UNSPECIFIED); + } mViewPager.measure(exactly(width), MeasureSpec.UNSPECIFIED); mPageIndicator.measure(exactly(width), MeasureSpec.UNSPECIFIED); mFooter.getView().measure(exactly(width), MeasureSpec.UNSPECIFIED); int h = mBrightnessPaddingTop - + mQsPanelTop.getMeasuredHeight() + mViewPager.getMeasuredHeight() + mPageIndicator.getMeasuredHeight(); if (mFooter.hasFooter()) { @@ -527,12 +631,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { - if (DEBUG_DRAG) Log.d(TAG, "onLayout()"); final int w = getWidth(); int top = mBrightnessPaddingTop; - mQsPanelTop.layout(0, top, w, top + mQsPanelTop.getMeasuredHeight()); - top += mQsPanelTop.getMeasuredHeight(); mViewPager.layout(0, top, w, top + mViewPager.getMeasuredHeight()); top += mViewPager.getMeasuredHeight(); @@ -562,8 +663,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On } protected int getRowTop(int row) { - if (row <= 0) return 0; - return mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight; + int baseHeight = mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop; + if (row <= 0) return baseHeight; + return baseHeight + mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight; } public int getColumnCount() { @@ -708,13 +810,13 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On mLastTouchLocationX = event.getX(); mLastTouchLocationY = event.getY(); - if (v == getDropTarget()) { + if (isDropTargetEvent(event, v)) { if (DEBUG_DRAG) { Log.d(TAG, "dropping on delete target!!"); } if (mDraggingRecord.tile instanceof EditTile) { - restoreDraggingTilePosition(v); mQsPanelTop.toast(R.string.quick_settings_cannot_delete_edit_tile); + restoreDraggingTilePosition(v); return true; } else { mRestored = true; @@ -831,6 +933,27 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On return false; } + private boolean isDropTargetEvent(DragEvent event, View v) { + if (DEBUG_DRAG) { + Log.d(TAG, "isDropTargetEvent() called with " + "event = [" + event + "], v = [" + v + "]"); + } + if (v == getDropTarget() || v == mQsPanelTop) { + if (DEBUG_DRAG) { + Log.d(TAG, "isDropTargetEvent() returns true by view"); + } + return true; + } + + if (v == mViewPager && mLastTouchLocationY <= getRowTop(0)) { + if (DEBUG_DRAG) { + Log.d(TAG, "isDropTargetEvent() returns true by loc"); + } + return true; + } + + return false; + } + private void restoreDraggingTilePosition(View v) { if (mRestored) { return; @@ -855,8 +978,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On addTransientView(mDraggingRecord.tileView, 0); mDraggingRecord.tileView.setTransitionVisibility(View.VISIBLE); - mLastTouchLocationY += mViewPager.getTop(); // we are in the threshold of the viewpager meow - // need to move center of the dragging view to the coords of the event. final float touchEventBoxLeft = v.getX() + (mLastTouchLocationX - (mDraggingRecord.tileView.getWidth() / 2)); @@ -884,9 +1005,9 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On // setup x destination to animate to float destinationX = mDraggingRecord.destination.x; - if (mDraggingRecord.destinationPage > mViewPager.getCurrentItem()) { + if (mDraggingRecord.destinationPage + 1 > mViewPager.getCurrentItem()) { destinationX += getWidth(); - } else if (mDraggingRecord.destinationPage < mViewPager.getCurrentItem()) { + } else if (mDraggingRecord.destinationPage + 1 < mViewPager.getCurrentItem()) { destinationX -= getWidth(); } @@ -1331,6 +1452,31 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On } } + public void updateResources() { + final Resources res = mContext.getResources(); + final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns)); + mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height); + mCellWidth = (int) (mCellHeight * TILE_ASPECT); + mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height); + mLargeCellWidth = (int) (mLargeCellHeight * TILE_ASPECT); + mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom); + mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical); + mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top); + if (isLaidOut()) { + if (mColumns != columns) { + mColumns = columns; + postInvalidate(); + } + for (TileRecord r : mRecords) { + r.tile.clearState(); + } + if (mListening) { + refreshAllTiles(); + } + updateDetailText(); + } + } + public boolean isAnimating(TileRecord t) { return mCurrentlyAnimating.contains(t); } @@ -1426,6 +1572,12 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On return mDragging && mDraggingRecord != null && mRecords.indexOf(mDraggingRecord) >= 0; } + public void goToSettingsPage() { + if (mEditing) { + mViewPager.setCurrentItem(0, true); + } + } + public static final class DragTileRecord extends TileRecord { public int page; public int destinationPage; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 2a1bef8..1cdaeb8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -51,7 +51,7 @@ import cyanogenmod.providers.CMSettings; /** View that represents the quick settings tile panel. **/ public class QSPanel extends ViewGroup { - private static final float TILE_ASPECT = 1.2f; + protected static final float TILE_ASPECT = 1.2f; protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); protected View mDetail; @@ -127,7 +127,7 @@ public class QSPanel extends ViewGroup { /** * Enable/disable brightness slider. */ - private boolean showBrightnessSlider() { + protected boolean showBrightnessSlider() { boolean brightnessSliderEnabled = CMSettings.System.getIntForUser( mContext.getContentResolver(), CMSettings.System.QS_SHOW_BRIGHTNESS_SLIDER, 1, UserHandle.USER_CURRENT) == 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java index c724ace..c2862e6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java @@ -1,17 +1,39 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.Nullable; import android.content.Context; +import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; +import android.util.Log; import android.view.View; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.TextView; import com.android.systemui.R; public class QSPanelTopView extends FrameLayout { + private static final String TAG = "QSPanelTopView"; + public static final int TOAST_DURATION = 2000; protected View mEditTileInstructionView; @@ -19,10 +41,12 @@ public class QSPanelTopView extends FrameLayout { protected View mBrightnessView; protected TextView mToastView; - private boolean mEditing; - private boolean mDisplayingInstructions; - private boolean mDisplayingTrash; - private boolean mDisplayingToast; + private boolean mEditing = false; + private boolean mDisplayingInstructions = false; + private boolean mDisplayingTrash = false; + private boolean mDisplayingToast = false; + + private AnimatorSet mAnimator; public QSPanelTopView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); @@ -35,7 +59,11 @@ public class QSPanelTopView extends FrameLayout { public QSPanelTopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - setClipToPadding(false); + } + + @Override + public boolean hasOverlappingRendering() { + return mEditing; } public View getDropTarget() { @@ -53,9 +81,37 @@ public class QSPanelTopView extends FrameLayout { mEditTileInstructionView = findViewById(R.id.edit_container); mBrightnessView = findViewById(R.id.brightness_container); mToastView = (TextView) findViewById(R.id.qs_toast); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = MeasureSpec.getSize(widthMeasureSpec); + mBrightnessView.measure(exactly(width), MeasureSpec.UNSPECIFIED); + int dh = mBrightnessView.getMeasuredHeight(); + + mDropTarget.measure(exactly(width), atMost(dh)); + mEditTileInstructionView.measure(exactly(width), atMost(dh)); + mToastView.measure(exactly(width), atMost(dh)); + + setMeasuredDimension(width, mBrightnessView.getMeasuredHeight()); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + boolean animateToState = !isLaidOut(); + super.onLayout(changed, left, top, right, bottom); + if (animateToState) { + Log.e(TAG, "first layout animating to state!"); + animateToState(); + } + } - mDropTarget.setVisibility(View.GONE); - mEditTileInstructionView.setVisibility(View.GONE); + private static int atMost(int height) { + return MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + } + + private static int exactly(int size) { + return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); } public void setEditing(boolean editing) { @@ -86,143 +142,110 @@ public class QSPanelTopView extends FrameLayout { animateToState(); } - private void animateToState() { - showBrightnessSlider(!mEditing && !mDisplayingToast); - showInstructions(mEditing - && mDisplayingInstructions - && !mDisplayingTrash - && !mDisplayingToast); - showTrash(mEditing && mDisplayingTrash && !mDisplayingToast); - showToast(mDisplayingToast); - } - - private void showBrightnessSlider(boolean show) { - if (show) { - // slide brightness in - mBrightnessView - .animate() - .withLayer() - .y(getTop()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mBrightnessView.setVisibility(View.VISIBLE); - } - }); - } else { - // slide out brightness - mBrightnessView - .animate() - .withLayer() - .y(-getHeight()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBrightnessView.setVisibility(View.INVISIBLE); - } - }); + private Runnable mAnimateRunnable = new Runnable() { + @Override + public void run() { + if (mAnimator != null) { + mAnimator.cancel(); + } + mAnimator = new AnimatorSet(); + + final boolean showToast = mDisplayingToast; + final boolean showTrash = mDisplayingTrash && !mDisplayingToast; + final boolean showBrightness = !mEditing && !mDisplayingToast; + final boolean showInstructions = mEditing + && mDisplayingInstructions + && !mDisplayingTrash + && !mDisplayingToast; + + /*Log.d(TAG, "animating to state: " + + " showBrightness: " + showBrightness + + " showInstructions: " + showInstructions + + " showTrash: " + showTrash + + " showToast: " + showToast + );*/ + + final Animator brightnessAnimator = showBrightnessSlider(showBrightness); + final Animator instructionAnimator = showInstructions(showInstructions); + final Animator trashAnimator = showTrash(showTrash); + final Animator toastAnimator = showToast(showToast); + + mAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + setLayerType(LAYER_TYPE_HARDWARE, null); + + mDropTarget.setLayerType(LAYER_TYPE_HARDWARE, null); + mEditTileInstructionView.setLayerType(LAYER_TYPE_HARDWARE, null); + mBrightnessView.setLayerType(LAYER_TYPE_HARDWARE, null); + mToastView.setLayerType(LAYER_TYPE_HARDWARE, null); + + mDropTarget.setVisibility(View.VISIBLE); + mEditTileInstructionView.setVisibility(View.VISIBLE); + mBrightnessView.setVisibility(View.VISIBLE); + mToastView.setVisibility(View.VISIBLE); + + if (showToast) { + mToastView.bringToFront(); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + mToastView.setVisibility(showToast ? View.VISIBLE : View.GONE); + mEditTileInstructionView.setVisibility(showInstructions ? View.VISIBLE : View.GONE); + mDropTarget.setVisibility(showTrash ? View.VISIBLE : View.GONE); + mBrightnessView.setVisibility(showBrightness ? View.VISIBLE : View.GONE); + + setLayerType(LAYER_TYPE_NONE, null); + + mDropTarget.setLayerType(LAYER_TYPE_NONE, null); + mEditTileInstructionView.setLayerType(LAYER_TYPE_NONE, null); + mBrightnessView.setLayerType(LAYER_TYPE_NONE, null); + mToastView.setLayerType(LAYER_TYPE_NONE, null); + + if (showToast) { + mToastView.postDelayed(new Runnable() { + @Override + public void run() { + mDisplayingToast = false; + animateToState(); + } + }, TOAST_DURATION); + } + } + }); + + mAnimator.setDuration(500); + mAnimator.setInterpolator(new FastOutSlowInInterpolator()); + mAnimator.setStartDelay(100); + mAnimator.playTogether(instructionAnimator, trashAnimator, + brightnessAnimator, toastAnimator); + mAnimator.start(); } + }; + + private void animateToState() { + post(mAnimateRunnable); + } + private Animator animateView(View v, boolean show) { + return ObjectAnimator.ofFloat(v, "translationY", + show ? 0 : -mBrightnessView.getMeasuredHeight()); } - private void showInstructions(boolean show) { - if (show) { - // slide in instructions - mEditTileInstructionView.animate() - .withLayer() - .y(getTop()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mEditTileInstructionView.setVisibility(View.VISIBLE); - } - }); - } else { - // animate instructions out - mEditTileInstructionView.animate() - .withLayer() - .y(-getHeight()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mEditTileInstructionView.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - mEditTileInstructionView.setVisibility(View.GONE); - } - }); - } + private Animator showBrightnessSlider(boolean show) { + return animateView(mBrightnessView, show); } - private void showTrash(boolean show) { - if (show) { - // animate drop target in - mDropTarget.animate() - .withLayer() - .y(getTop()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mDropTarget.setVisibility(View.VISIBLE); - } - }); - } else { - // drop target animates up - mDropTarget.animate() - .withLayer() - .y(-getHeight()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mDropTarget.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - mDropTarget.setVisibility(View.GONE); - } - }); - } + private Animator showInstructions(boolean show) { + return animateView(mEditTileInstructionView, show); } - private void showToast(boolean show) { - if (show) { - mToastView.animate() - .withLayer() - .y(getTop()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mToastView.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - mDisplayingToast = false; - mToastView.postDelayed(new Runnable() { - @Override - public void run() { - animateToState(); - } - }, TOAST_DURATION); - } - }); - } else { - mToastView.animate() - .withLayer() - .y(-getHeight()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mToastView.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - mToastView.setVisibility(View.GONE); - } - }); - } + private Animator showTrash(boolean show) { + return animateView(mDropTarget, show); + } + + private Animator showToast(boolean show) { + return animateView(mToastView, show); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java b/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java new file mode 100644 index 0000000..959a1ee --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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; + +import android.annotation.Nullable; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import com.android.systemui.statusbar.phone.QSTileHost; +import com.android.systemui.statusbar.phone.SystemUIDialog; + +import com.android.systemui.R; + +public class QSSettings extends LinearLayout { + private QSTileHost mHost; + + public QSSettings(Context context) { + super(context); + } + + public QSSettings(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + findViewById(R.id.reset_tiles).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + initiateTileReset(); + } + }); + } + + private void initiateTileReset() { + final AlertDialog d = new AlertDialog.Builder(mContext) + .setMessage(R.string.qs_tiles_reset_confirmation) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(com.android.internal.R.string.reset, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mHost.resetTiles(); + } + }).create(); + SystemUIDialog.makeSystemUIDialog(d); + d.show(); + } + + public void setHost(QSTileHost host) { + mHost = host; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index da73e15..6fa304d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -338,11 +338,13 @@ public abstract class QSTile<TState extends State> implements Listenable { boolean isEditing(); void setEditing(boolean editing); void resetTiles(); + void goToSettingsPage(); public interface Callback { void onTilesChanged(); void setEditing(boolean editing); boolean isEditing(); + void goToSettingsPage(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index dc54c16..667bd30 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -392,6 +392,7 @@ public class QSTileView extends ViewGroup { if (mLabel != null) { mLabel.setFocusable(!editing); } + mRipple.setVisible(!editing, false); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java b/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java index 427fbf4..01c48b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java @@ -9,23 +9,37 @@ import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateInterpolator; -/** - * Created by roman on 11/5/15. - */ public class QSViewPager extends ViewPager { private static final String TAG = "QSViewPager"; protected static final float SCROLL_PERCENT = .10f; private boolean mPagingEnabled; + QSDragPanel mDragPanel; public QSViewPager(Context context) { super(context); } + public void setDragPanel(QSDragPanel p) { + mDragPanel = p; + } + @Override public boolean hasOverlappingRendering() { - return false; + return mDragPanel.isEditing(); + } + + @Override + public boolean canScrollHorizontally(int direction) { + if (direction < 0 + && mDragPanel.isDragging() + && mPagingEnabled + && getCurrentItem() == 1) { + // can't scroll left while not editing, OR dragging on the first page + return false; + } + return super.canScrollHorizontally(direction); } @Override @@ -109,9 +123,9 @@ public class QSViewPager extends ViewPager { public void setPagingEnabled(boolean enabled) { if (mPagingEnabled == enabled) return; mPagingEnabled = enabled; - Log.i(TAG, "setPagingEnabled() called with " + "enabled = [" + enabled + "]"); + //Log.i(TAG, "setPagingEnabled() called with " + "enabled = [" + enabled + "]"); if (getCurrentItem() > 0 && !mPagingEnabled) { - Log.w(TAG, "resetting to item 0 because paging is disabled."); + //Log.w(TAG, "resetting to item 0 because paging is disabled."); setCurrentItem(0, true); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java index beea16b..eaa5ff5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java @@ -16,19 +16,17 @@ package com.android.systemui.qs.tiles; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; -import com.android.systemui.qs.QSDragPanel; import com.android.systemui.qs.QSTile; -import com.android.systemui.statusbar.phone.SystemUIDialog; public class EditTile extends QSTile<QSTile.BooleanState> { + private boolean mListening; + public EditTile(Host host) { super(host); + refreshState(); } @Override @@ -42,11 +40,6 @@ public class EditTile extends QSTile<QSTile.BooleanState> { } @Override - public void setCallback(Callback callback) { - super.setCallback(callback); - } - - @Override protected void handleClick() { getHost().setEditing(!mState.value); refreshState(!mState.value); @@ -54,19 +47,8 @@ public class EditTile extends QSTile<QSTile.BooleanState> { @Override protected void handleLongClick() { - final AlertDialog d = new AlertDialog.Builder(mContext) - .setMessage(R.string.qs_tiles_reset_confirmation) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(com.android.internal.R.string.reset, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - getHost().resetTiles(); - refreshState(false); - } - }).create(); - SystemUIDialog.makeSystemUIDialog(d); - d.show(); + getHost().goToSettingsPage(); + refreshState(true); } @Override @@ -95,6 +77,8 @@ public class EditTile extends QSTile<QSTile.BooleanState> { @Override public void setListening(boolean listening) { - // not interested + if (mListening == listening) return; + mListening = listening; + refreshState(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 761fc9b..454bba6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1153,6 +1153,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void run() { mQSPanel.setEditing(editing); + mHeader.setEditing(editing); } }); } @@ -1161,6 +1162,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public boolean isEditing() { return mQSPanel.isEditing(); } + + @Override + public void goToSettingsPage() { + setEditing(true); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mQSPanel.goToSettingsPage(); + } + }, 500); + } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 15e0c02..a748aa3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -125,7 +125,10 @@ public class QSTileHost implements QSTile.Host, Tunable { } public boolean isEditing() { - return mCallback.isEditing(); + if (mCallback != null) { + return mCallback.isEditing(); + } + return false; } public void setEditing(boolean editing) { @@ -269,6 +272,13 @@ public class QSTileHost implements QSTile.Host, Tunable { } } + @Override + public void goToSettingsPage() { + if (mCallback != null) { + mCallback.goToSettingsPage(); + } + } + public QSTile<?> createTile(String tileSpec) { if (tileSpec.equals("wifi")) return new WifiTile(this); else if (tileSpec.equals("bt")) return new BluetoothTile(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java index 18db5b8..3e0aa18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java @@ -17,18 +17,18 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; -import android.graphics.drawable.RippleDrawable; -import android.os.Handler; -import android.os.Message; import android.util.AttributeSet; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.animation.DecelerateInterpolator; import com.android.keyguard.AlphaOptimizedImageButton; public class SettingsButton extends AlphaOptimizedImageButton { @@ -56,6 +56,10 @@ public class SettingsButton extends AlphaOptimizedImageButton { return mUpToSpeed; } + public void consumeClick() { + mUpToSpeed = false; + } + @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { @@ -78,6 +82,7 @@ public class SettingsButton extends AlphaOptimizedImageButton { if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop) || (y > getHeight() + mSlop)) { cancelLongClick(); + startExitAnimation(); } break; } @@ -99,32 +104,11 @@ public class SettingsButton extends AlphaOptimizedImageButton { } private void startExitAnimation() { + cancelAnimation(); animate() - .translationX(((View) getParent().getParent()).getWidth() - getX()) - .alpha(0) - .setDuration(RUN_DURATION) - .setInterpolator(AnimationUtils.loadInterpolator(mContext, - android.R.interpolator.accelerate_cubic)) - .setListener(new AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - setAlpha(1f); - setTranslationX(0); - cancelLongClick(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }) + .rotation(0) + .setDuration(ACCEL_LENGTH) + .setInterpolator(new DecelerateInterpolator(4)) .start(); } @@ -164,6 +148,8 @@ public class SettingsButton extends AlphaOptimizedImageButton { mAnimator.setDuration(FULL_SPEED_LENGTH); mAnimator.setRepeatCount(Animation.INFINITE); mAnimator.start(); + + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } private final Runnable mLongPressCallback = new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 7e5a860..b8293f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -55,12 +55,14 @@ import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; +import com.android.internal.logging.MetricsConstants; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.BatteryLevelTextView; import com.android.systemui.BatteryMeterView; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.cm.UserContentObserver; +import com.android.systemui.qs.QSDragPanel; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; @@ -107,6 +109,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private BatteryLevelTextView mBatteryLevel; private TextView mAlarmStatus; private TextView mWeatherLine1, mWeatherLine2; + private TextView mEditTileDoneText; private boolean mShowEmergencyCallsOnly; private boolean mAlarmShowing; @@ -137,7 +140,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private BatteryController mBatteryController; private NextAlarmController mNextAlarmController; private WeatherController mWeatherController; - private QSPanel mQSPanel; + private QSDragPanel mQSPanel; private final Rect mClipBounds = new Rect(); @@ -153,6 +156,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private SettingsObserver mSettingsObserver; private boolean mShowWeather; private boolean mShowBatteryTextExpanded; + private boolean mEditing; public StatusBarHeaderView(Context context, AttributeSet attrs) { super(context, attrs); @@ -192,6 +196,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mWeatherContainer.setOnClickListener(this); mWeatherLine1 = (TextView) findViewById(R.id.weather_line_1); mWeatherLine2 = (TextView) findViewById(R.id.weather_line_2); + mEditTileDoneText = (TextView) findViewById(R.id.done); mSettingsObserver = new SettingsObserver(new Handler()); loadDimens(); updateVisibilities(); @@ -345,6 +350,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL boolean changed = expanded != mExpanded; mExpanded = expanded; if (changed) { + if (mShowingDetail && !expanded) { + mQsPanelCallback.onShowingDetail(null); + } updateEverything(); } } @@ -383,8 +391,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); mBatteryLevel.setForceShown(mExpanded && mShowBatteryTextExpanded); mBatteryLevel.setVisibility(View.VISIBLE); - mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( - TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); } private void updateSignalClusterDetachment() { @@ -555,20 +561,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL public void onClick(View v) { if (v == mSettingsButton) { if (mSettingsButton.isTunerClick()) { - if (TunerService.isTunerEnabled(mContext)) { - TunerService.showResetRequest(mContext, new Runnable() { - @Override - public void run() { - // Relaunch settings so that the tuner disappears. - startSettingsActivity(); - } - }); - } else { - Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show(); - TunerService.setTunerEnabled(mContext, true); - } + mSettingsButton.consumeClick(); + mQSPanel.getHost().setEditing(!mQSPanel.getHost().isEditing()); + } else { + startSettingsActivity(); } - startSettingsActivity(); } else if (v == mSystemIconsSuperContainer) { startBatteryActivity(); } else if (v == mAlarmStatus && mNextAlarm != null) { @@ -615,7 +612,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mActivityStarter.startActivity(intent, true /* dismissShade */); } - public void setQSPanel(QSPanel qsp) { + public void setQSPanel(QSDragPanel qsp) { mQSPanel = qsp; if (mQSPanel != null) { mQSPanel.setCallback(mQsPanelCallback); @@ -747,6 +744,45 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateAmPmTranslation(); } + public void setEditing(boolean editing) { + mEditing = editing; + if (mEditing) { + mQsPanelCallback.onShowingDetail(new QSTile.DetailAdapter() { + @Override + public int getTitle() { + return R.string.quick_settings_edit_label; + } + + @Override + public Boolean getToggleState() { + return null; + } + + @Override + public View createDetailView(Context context, View convertView, ViewGroup parent) { + return null; + } + + @Override + public Intent getSettingsIntent() { + return null; + } + + @Override + public void setToggleState(boolean state) { + + } + + @Override + public int getMetricsCategory() { + return MetricsConstants.DONT_TRACK_ME_BRO; + } + }); + } else { + mQsPanelCallback.onShowingDetail(null); + } + } + /** * Captures all layout values (position, visibility) for a certain state. This is used for * animations. @@ -863,17 +899,29 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL transition(mWeatherContainer, !showingDetail); } if (mAlarmShowing) { - transition(mAlarmStatus, !showingDetail); + transition(mAlarmStatus, !showingDetail && !mDetailTransitioning); } transition(mQsDetailHeader, showingDetail); mShowingDetail = showingDetail; if (showingDetail) { mQsDetailHeaderTitle.setText(detail.getTitle()); final Boolean toggleState = detail.getToggleState(); - if (toggleState == null) { + if (detail.getTitle() == R.string.quick_settings_edit_label) { + mEditTileDoneText.setVisibility(View.VISIBLE); + mQsDetailHeaderSwitch.setVisibility(INVISIBLE); + mQsDetailHeader.setClickable(true); + mQsDetailHeader.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mQSPanel.getHost().setEditing(false); + } + }); + } else if (toggleState == null) { mQsDetailHeaderSwitch.setVisibility(INVISIBLE); + mEditTileDoneText.setVisibility(View.GONE); mQsDetailHeader.setClickable(false); } else { + mEditTileDoneText.setVisibility(View.GONE); mQsDetailHeaderSwitch.setVisibility(VISIBLE); mQsDetailHeaderSwitch.setChecked(toggleState); mQsDetailHeader.setClickable(true); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java index a38993d..95ca509 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java @@ -151,6 +151,10 @@ public class QsTuner extends Fragment implements Callback { return mTileHost.isEditing(); } + @Override + public void goToSettingsPage() { + } + private static class CustomHost extends QSTileHost { public CustomHost(Context context) { diff --git a/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java b/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java index b1c08b98..4286983 100644 --- a/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java +++ b/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java @@ -19,6 +19,8 @@ package com.viewpagerindicator; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; @@ -62,6 +64,8 @@ public class CirclePageIndicator extends View implements PageIndicator { private int mActivePointerId = INVALID_POINTER; private boolean mIsDragging; + private Bitmap mSettingsIcon; + private boolean mEditing; public CirclePageIndicator(Context context) { this(context, null); @@ -110,8 +114,14 @@ public class CirclePageIndicator extends View implements PageIndicator { final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); + + mSettingsIcon = BitmapFactory.decodeResource(res, R.drawable.ic_mini_settings); } + @Override + public boolean hasOverlappingRendering() { + return false; + } public void setCentered(boolean centered) { mCentered = centered; @@ -253,7 +263,14 @@ public class CirclePageIndicator extends View implements PageIndicator { } // Only paint fill if not completely transparent if (mPaintPageFill.getAlpha() > 0) { - canvas.drawCircle(dX, dY, (float) (pageFillRadius/1.5f), mPaintPageFill); + if (mEditing && iLoop == 0) { + canvas.drawBitmap(mSettingsIcon, + (int) (dX - mRadius), + (int) (dY - mRadius), + mPaintPageFill); + } else { + canvas.drawCircle(dX, dY, (float) (pageFillRadius / 1.5f), mPaintPageFill); + } } // Only paint stroke if a stroke width was non-zero @@ -502,4 +519,9 @@ public class CirclePageIndicator extends View implements PageIndicator { } return result; } + + public void setEditing(boolean editing) { + mEditing = editing; + invalidate(); + } } |