diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png index 092b5613931b1..3c0dc4e00b5b0 100644 Binary files a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png and b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png differ diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png index 064860d45d76c..3b1944db7af26 100644 Binary files a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png and b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png differ diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png deleted file mode 100644 index 13f6b7f1c8bbb..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_open_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png deleted file mode 100644 index ecdb24095eabd..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_quicksettings_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png deleted file mode 100644 index c98911c903cd8..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_open_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png deleted file mode 100644 index bb9902248db32..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_quicksettings_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png deleted file mode 100644 index d9d8b13716492..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_open_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png deleted file mode 100644 index 09e0a3c4d28e2..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_quicksettings_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png deleted file mode 100644 index c0855b59e45f6..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_open_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png deleted file mode 100644 index e3fb992f5500f..0000000000000 Binary files a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_quicksettings_normal.png and /dev/null differ diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png index ae5d2633a2e1f..8010ce7e2e590 100644 Binary files a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png and b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png differ diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png index 32fbed4d8f7e0..807f607e8b20b 100644 Binary files a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png and b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png differ diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png index 990f8bbf7a3b9..6d46fddcc1952 100644 Binary files a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png and b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png differ diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png index 96eaafe2324c4..e562bc28749c8 100644 Binary files a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png and b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png differ diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png index 60579f916d5f2..774220779087d 100644 Binary files a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png and b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png differ diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png index abb9b1801f747..a2e8fe1b2d255 100644 Binary files a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png and b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png differ diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml index 1b8898c502ed4..28d962500411b 100644 --- a/packages/SystemUI/res/layout/flip_settings.xml +++ b/packages/SystemUI/res/layout/flip_settings.xml @@ -14,18 +14,12 @@ limitations under the License. --> - - - \ No newline at end of file + android:background="#5f000000" + android:animateLayoutChanges="true" + android:columnCount="@integer/quick_settings_num_columns" /> \ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 8f4417ee83331..8a3f090375408 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -41,7 +41,7 @@ android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="right|top" - android:layout_marginTop="@*android:dimen/status_bar_height" + android:layout_marginTop="@dimen/status_bar_height" android:visibility="gone" /> + android:layout_height="@dimen/status_bar_height" /> + android:layout_marginBottom="@dimen/navigation_bar_height"> 6 + + 2 + 2 diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 440ead6f1331d..c6bc44d5a9f51 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -26,6 +26,9 @@ 3 + + 4 + 1 diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 73e3e051de114..f908a1ead9d0a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -81,6 +81,12 @@ 3 + + 4 + + + 3 + 1 diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e7959ab858f16..9aacf42221b6a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -269,4 +269,7 @@ 100dp + + 8dp + 30dp diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml new file mode 100644 index 0000000000000..ddaab9422d79b --- /dev/null +++ b/packages/SystemUI/res/values/internal.xml @@ -0,0 +1,22 @@ + + + + + @*android:dimen/status_bar_height + @*android:dimen/navigation_bar_height + @*android:drawable/notification_quantum_bg + + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 6f93bedbaf5db..45ac50b6f6866 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -30,11 +30,14 @@ public class NotificationPanelView extends PanelView { public static final boolean DEBUG_GESTURES = true; PhoneStatusBar mStatusBar; + private View mHeader; + private View mKeyguardStatusView; + private NotificationStackScrollLayout mNotificationStackScroller; private int[] mTempLocation = new int[2]; private int[] mTempChildLocation = new int[2]; private View mNotificationParent; - + private boolean mTrackingSettings; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -59,6 +62,8 @@ public class NotificationPanelView extends PanelView { protected void onFinishInflate() { super.onFinishInflate(); + mHeader = findViewById(R.id.header); + mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mNotificationStackScroller = (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller); mNotificationParent = findViewById(R.id.notification_container_parent); @@ -98,10 +103,39 @@ public class NotificationPanelView extends PanelView { return mTempChildLocation[1] - mTempLocation[1]; } + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + // intercept for quick settings + if (event.getAction() == MotionEvent.ACTION_DOWN) { + final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader; + final boolean inTarget = PhoneStatusBar.inBounds(target, event, true); + if (inTarget && !isInSettings()) { + mTrackingSettings = true; + return true; + } + if (!inTarget && isInSettings()) { + mTrackingSettings = true; + return true; + } + } + return super.onInterceptTouchEvent(event); + } + @Override public boolean onTouchEvent(MotionEvent event) { // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference // implementation. + if (mTrackingSettings) { + mStatusBar.onSettingsEvent(event); + if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + mTrackingSettings = false; + } + return true; + } + if (isInSettings()) { + return true; + } return super.onTouchEvent(event); } 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 5f71516992772..d5770702e6a5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -73,6 +73,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; @@ -97,11 +98,9 @@ import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.InterceptedNotifications; -import com.android.systemui.statusbar.LatestItemView; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationData.Entry; import com.android.systemui.statusbar.NotificationOverflowContainer; -import com.android.systemui.statusbar.NotificationOverflowIconsView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.policy.BatteryController; @@ -233,8 +232,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { int mKeyguardMaxNotificationCount; View mDateTimeView; View mClearButton; - ImageView mSettingsButton, mNotificationButton; - View mKeyguardSettingsFlipButton; + FlipperButton mHeaderFlipper, mKeyguardFlipper; // carrier/wifi label private TextView mCarrierLabel; @@ -314,9 +312,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + "selfChange=%s userSetup=%s mUserSetup=%s", selfChange, userSetup, mUserSetup)); - if (mSettingsButton != null && mHasFlipSettings) { - mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); - } + mHeaderFlipper.userSetup(userSetup); + mKeyguardFlipper.userSetup(userSetup); + if (mSettingsPanel != null) { mSettingsPanel.setEnabled(userSetup); } @@ -371,6 +369,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private Runnable mOnFlipRunnable; private InterceptedNotifications mIntercepted; + private VelocityTracker mSettingsTracker; + private float mSettingsDownY; + private boolean mSettingsCancelled; + private boolean mSettingsClosing; + private int mNotificationPadding; private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = new OnChildLocationsChangedListener() { @@ -631,35 +634,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mDateTimeView.setEnabled(true); } - mSettingsButton = (ImageView) mStatusBarWindow.findViewById(R.id.settings_button); - if (mSettingsButton != null) { - mSettingsButton.setOnClickListener(mSettingsButtonListener); - if (mHasSettingsPanel) { - if (mStatusBarView.hasFullWidthNotifications()) { - // the settings panel is hiding behind this button - mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - mSettingsButton.setVisibility(View.VISIBLE); - } else { - // there is a settings panel, but it's on the other side of the (large) screen - final View buttonHolder = mStatusBarWindow.findViewById( - R.id.settings_button_holder); - if (buttonHolder != null) { - buttonHolder.setVisibility(View.GONE); - } - } - } else { - // no settings panel, go straight to settings - mSettingsButton.setVisibility(View.VISIBLE); - mSettingsButton.setImageResource(R.drawable.ic_notify_settings); - } - } - if (mHasFlipSettings) { - mNotificationButton = (ImageView) mStatusBarWindow.findViewById( - R.id.notification_button); - if (mNotificationButton != null) { - mNotificationButton.setOnClickListener(mNotificationButtonListener); - } - } + mHeaderFlipper = new FlipperButton(mNotificationPanelHeader + .findViewById(R.id.settings_button_holder)); + ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub); + mKeyguardFlipper = new FlipperButton(flipStub.inflate()); if (!mNotificationPanelIsFullScreenWidth) { mNotificationPanel.setSystemUiVisibility( @@ -735,6 +713,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } // Quick Settings (where available, some restrictions apply) + mNotificationPadding = mContext.getResources() + .getDimensionPixelSize(R.dimen.notification_side_padding); if (mHasSettingsPanel) { // first, figure out where quick settings should be inflated final View settings_stub; @@ -803,6 +783,87 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { return mStatusBarView; } + public boolean onSettingsEvent(MotionEvent event) { + if (mSettingsTracker != null) { + mSettingsTracker.addMovement(event); + } + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mSettingsTracker = VelocityTracker.obtain(); + mSettingsDownY = event.getY(); + mSettingsCancelled = false; + mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE; + mFlipSettingsView.setVisibility(View.VISIBLE); + mStackScroller.setVisibility(View.VISIBLE); + positionSettings(0); + if (!mSettingsClosing) { + mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight()); + } + dispatchSettingsEvent(event); + } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL)) { + final float dy = event.getY() - mSettingsDownY; + final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper; + final boolean inButton = flipper.inHolderBounds(event); + final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop; + if (!qsTap && !inButton) { + mSettingsTracker.computeCurrentVelocity(1000); + final float vy = mSettingsTracker.getYVelocity(); + if (dy <= slop || vy <= 0) { + flipToNotifications(); + } else { + flipToSettings(); + } + } + mSettingsTracker.recycle(); + mSettingsTracker = null; + dispatchSettingsEvent(event); + } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) { + final float dy = event.getY() - mSettingsDownY; + positionSettings(dy); + if (mSettingsClosing) { + final boolean qsTap = + Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop(); + if (!mSettingsCancelled && !qsTap) { + MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event); + cancelEvent.setAction(MotionEvent.ACTION_CANCEL); + dispatchSettingsEvent(cancelEvent); + mSettingsCancelled = true; + } + } else { + dispatchSettingsEvent(event); + } + } + return true; + } + + private void dispatchSettingsEvent(MotionEvent event) { + final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader; + final int[] targetLoc = new int[2]; + target.getLocationInWindow(targetLoc); + final int[] panelLoc = new int[2]; + mNotificationPanel.getLocationInWindow(panelLoc); + final int dx = targetLoc[0] - panelLoc[0]; + final int dy = targetLoc[1] - panelLoc[1]; + event.offsetLocation(-dx, -dy); + target.dispatchTouchEvent(event); + } + + private void positionSettings(float dy) { + final int h = mFlipSettingsView.getMeasuredHeight(); + final int ph = mNotificationPanel.getMeasuredHeight(); + if (mSettingsClosing) { + dy = Math.min(Math.max(-ph, dy), 0); + mFlipSettingsView.setTranslationY(dy); + mStackScroller.setTranslationY(ph + dy); + } else { + dy = Math.min(Math.max(0, dy), ph); + mFlipSettingsView.setTranslationY(-h + dy - mNotificationPadding * 2); + mStackScroller.setTranslationY(dy); + } + } + private void startKeyguard() { KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, @@ -1163,17 +1224,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear); } - if (mSettingsButton != null) { - // Force asset reloading - mSettingsButton.setImageDrawable(null); - mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - } - - if (mNotificationButton != null) { - // Force asset reloading - mNotificationButton.setImageDrawable(null); - mNotificationButton.setImageResource(R.drawable.ic_notifications); - } + mHeaderFlipper.refreshLayout(); + mKeyguardFlipper.refreshLayout(); refreshAllStatusBarIcons(); } @@ -1228,9 +1280,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } - if (mSettingsButton != null) { - mSettingsButton.setEnabled(isDeviceProvisioned()); - } + mHeaderFlipper.provisionCheck(provisioned); + mKeyguardFlipper.provisionCheck(provisioned); } @Override @@ -1647,6 +1698,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mStatusBarWindow.cancelExpandHelper(); mStatusBarView.collapseAllPanels(true); + if (isFlippedToSettings()) { + flipToNotifications(); + } } } @@ -1694,8 +1748,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { final int FLIP_DURATION_IN = 225; final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); - Animator mScrollViewAnim, mFlipSettingsViewAnim, mNotificationButtonAnim, - mSettingsButtonAnim, mClearButtonAnim; + Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim; @Override public void animateExpandNotificationsPanel() { @@ -1715,33 +1768,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { public void flipToNotifications() { if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + mHeaderFlipper.cancel(); + mKeyguardFlipper.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); mStackScroller.setVisibility(View.VISIBLE); + final int h = mNotificationPanel.getMeasuredHeight(); + final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0; + final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h; mScrollViewAnim = start( - startDelay(FLIP_DURATION_OUT, + startDelay(0, interpolator(mDecelerateInterpolator, - ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f) - .setDuration(FLIP_DURATION_IN) + ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0) + .setDuration(FLIP_DURATION) ))); mFlipSettingsViewAnim = start( setVisibilityWhenDone( - interpolator(mAccelerateInterpolator, - ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f) + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h) ) - .setDuration(FLIP_DURATION_OUT), - mFlipSettingsView, View.INVISIBLE)); - mNotificationButtonAnim = start( - setVisibilityWhenDone( - ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) .setDuration(FLIP_DURATION), - mNotificationButton, View.INVISIBLE)); - mSettingsButton.setVisibility(View.VISIBLE); - mSettingsButtonAnim = start( - ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + mFlipSettingsView, View.INVISIBLE)); + mHeaderFlipper.flipToNotifications(); + mKeyguardFlipper.flipToNotifications(); mClearButton.setVisibility(View.VISIBLE); mClearButton.setAlpha(0f); setAreThereNotifications(); // this will show/hide the button as necessary @@ -1767,7 +1816,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (mHasFlipSettings) { mNotificationPanel.expand(); - if (mFlipSettingsView.getVisibility() != View.VISIBLE) { + if (mFlipSettingsView.getVisibility() != View.VISIBLE + || mFlipSettingsView.getTranslationY() < 0) { flipToSettings(); } } else if (mSettingsPanel != null) { @@ -1777,23 +1827,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (false) postStartTracing(); } - public void switchToSettings() { - // Settings are not available in setup - if (!mUserSetup) return; - - mFlipSettingsView.setScaleX(1f); - mFlipSettingsView.setVisibility(View.VISIBLE); - mSettingsButton.setVisibility(View.GONE); - mStackScroller.setVisibility(View.GONE); - mStackScroller.setScaleX(0f); - mNotificationButton.setVisibility(View.VISIBLE); - mNotificationButton.setAlpha(1f); - mClearButton.setVisibility(View.GONE); - if (mOnFlipRunnable != null) { - mOnFlipRunnable.run(); - } - } - public boolean isFlippedToSettings() { if (mFlipSettingsView != null) { return mFlipSettingsView.getVisibility() == View.VISIBLE; @@ -1807,34 +1840,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + mHeaderFlipper.cancel(); + mKeyguardFlipper.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); mFlipSettingsView.setVisibility(View.VISIBLE); - mFlipSettingsView.setScaleX(0f); + final int h = mNotificationPanel.getMeasuredHeight(); + final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h; + final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0; mFlipSettingsViewAnim = start( - startDelay(FLIP_DURATION_OUT, - interpolator(mDecelerateInterpolator, - ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f) - .setDuration(FLIP_DURATION_IN) - ))); + startDelay(0, + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, 0f) + .setDuration(FLIP_DURATION) + ))); mScrollViewAnim = start( setVisibilityWhenDone( - interpolator(mAccelerateInterpolator, - ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f) + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h) ) - .setDuration(FLIP_DURATION_OUT), - mStackScroller, View.INVISIBLE)); - mSettingsButtonAnim = start( - setVisibilityWhenDone( - ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) .setDuration(FLIP_DURATION), mStackScroller, View.INVISIBLE)); - mNotificationButton.setVisibility(View.VISIBLE); - mNotificationButtonAnim = start( - ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + mHeaderFlipper.flipToSettings(); + mKeyguardFlipper.flipToSettings(); mClearButtonAnim = start( setVisibilityWhenDone( ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f) @@ -1883,18 +1911,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // reset things to their proper state if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); - mStackScroller.setScaleX(1f); mStackScroller.setVisibility(View.VISIBLE); - mSettingsButton.setAlpha(1f); - mSettingsButton.setVisibility(View.VISIBLE); mNotificationPanel.setVisibility(View.GONE); mFlipSettingsView.setVisibility(View.GONE); - mNotificationButton.setVisibility(View.GONE); + setAreThereNotifications(); // show the clear button + + mHeaderFlipper.reset(); + mKeyguardFlipper.reset(); } mExpandedVisible = false; @@ -2947,15 +2973,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } mKeyguardStatusView.setVisibility(View.VISIBLE); mNotificationPanelHeader.setVisibility(View.GONE); - if (mKeyguardSettingsFlipButton == null) { - ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub); - mKeyguardSettingsFlipButton = flipStub.inflate(); - installSettingsButton(mKeyguardSettingsFlipButton); - } - mKeyguardSettingsFlipButton.setVisibility(View.VISIBLE); - mKeyguardSettingsFlipButton.findViewById(R.id.settings_button).setVisibility(View.VISIBLE); - mKeyguardSettingsFlipButton.findViewById(R.id.notification_button) - .setVisibility(View.INVISIBLE); + + mKeyguardFlipper.setVisibility(View.VISIBLE); + mSettingsContainer.setKeyguardShowing(true); updateRowStates(); } @@ -2963,9 +2983,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mOnKeyguard = false; mKeyguardStatusView.setVisibility(View.GONE); mNotificationPanelHeader.setVisibility(View.VISIBLE); - if (mKeyguardSettingsFlipButton != null) { - mKeyguardSettingsFlipButton.setVisibility(View.GONE); - } + + mKeyguardFlipper.setVisibility(View.GONE); + mSettingsContainer.setKeyguardShowing(false); updateRowStates(); instantCollapseNotificationPanel(); } @@ -3030,39 +3050,112 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } - private void installSettingsButton(View parent) { - final ImageView settingsButton = - (ImageView) mStatusBarWindow.findViewById(R.id.settings_button); - final ImageView notificationButton = - (ImageView) mStatusBarWindow.findViewById(R.id.notification_button); - if (settingsButton != null) { - settingsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - animateExpandSettingsPanel(); - v.setVisibility(View.INVISIBLE); - notificationButton.setVisibility(View.VISIBLE); + public static boolean inBounds(View view, MotionEvent event, boolean orAbove) { + final int[] location = new int[2]; + view.getLocationInWindow(location); + final int rx = (int) event.getRawX(); + final int ry = (int) event.getRawY(); + return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth() + && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight(); + } + + private final class FlipperButton { + private final View mHolder; + + private ImageView mSettingsButton, mNotificationButton; + private Animator mSettingsButtonAnim, mNotificationButtonAnim; + + public FlipperButton(View holder) { + mHolder = holder; + mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button); + if (mSettingsButton != null) { + mSettingsButton.setOnClickListener(mSettingsButtonListener); + if (mHasSettingsPanel) { + // the settings panel is hiding behind this button + mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); + mSettingsButton.setVisibility(View.VISIBLE); + } else { + // no settings panel, go straight to settings + mSettingsButton.setVisibility(View.VISIBLE); + mSettingsButton.setImageResource(R.drawable.ic_notify_settings); + } + } + if (mHasFlipSettings) { + mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button); + if (mNotificationButton != null) { + mNotificationButton.setOnClickListener(mNotificationButtonListener); } - }); - settingsButton.setVisibility(View.VISIBLE); - if (mHasSettingsPanel) { - // the settings panel is hiding behind this button - settingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - } else { - // no settings panel, go straight to settings - settingsButton.setImageResource(R.drawable.ic_notify_settings); } } - if (notificationButton != null) { - notificationButton.setVisibility(View.INVISIBLE); - notificationButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - flipToNotifications(); - v.setVisibility(View.INVISIBLE); - settingsButton.setVisibility(View.VISIBLE); - } - }); + + public boolean inHolderBounds(MotionEvent event) { + return inBounds(mHolder, event, false); + } + + public void provisionCheck(boolean provisioned) { + if (mSettingsButton != null) { + mSettingsButton.setEnabled(provisioned); + } + } + + public void userSetup(boolean userSetup) { + if (mSettingsButton != null && mHasFlipSettings) { + mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); + } + } + + public void reset() { + cancel(); + mSettingsButton.setVisibility(View.VISIBLE); + mNotificationButton.setVisibility(View.GONE); + } + + public void refreshLayout() { + if (mSettingsButton != null) { + // Force asset reloading + mSettingsButton.setImageDrawable(null); + mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); + } + + if (mNotificationButton != null) { + // Force asset reloading + mNotificationButton.setImageDrawable(null); + mNotificationButton.setImageResource(R.drawable.ic_notifications); + } + } + + public void flipToSettings() { + mSettingsButtonAnim = start( + setVisibilityWhenDone( + ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) + .setDuration(FLIP_DURATION), + mStackScroller, View.INVISIBLE)); + mNotificationButton.setVisibility(View.VISIBLE); + mNotificationButtonAnim = start( + ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION)); + } + + public void flipToNotifications() { + mNotificationButtonAnim = start( + setVisibilityWhenDone( + ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) + .setDuration(FLIP_DURATION), + mNotificationButton, View.INVISIBLE)); + + mSettingsButton.setVisibility(View.VISIBLE); + mSettingsButtonAnim = start( + ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION)); + } + + public void cancel() { + if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); + if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + } + + public void setVisibility(int vis) { + mHolder.setVisibility(vis); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java index 17ee0177252eb..02e9c0d7ce57f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java @@ -19,7 +19,13 @@ package com.android.systemui.statusbar.phone; import android.animation.LayoutTransition; import android.content.Context; import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Typeface; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -31,30 +37,58 @@ import com.android.systemui.R; */ class QuickSettingsContainerView extends FrameLayout { + private static boolean sShowScrim = true; + + private final Context mContext; + // The number of columns in the QuickSettings grid private int mNumColumns; + private boolean mKeyguardShowing; + private int mMaxRows; + private int mMaxRowsOnKeyguard; + // The gap between tiles in the QuickSettings grid private float mCellGap; + private ScrimView mScrim; + public QuickSettingsContainerView(Context context, AttributeSet attrs) { super(context, attrs); - + mContext = context; updateResources(); } @Override protected void onFinishInflate() { super.onFinishInflate(); - + mScrim = new ScrimView(mContext); + addView(mScrim); + mScrim.setAlpha(sShowScrim ? 1 : 0); // TODO: Setup the layout transitions LayoutTransition transitions = getLayoutTransition(); } + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mScrim.getAlpha() == 1) { + mScrim.animate().alpha(0).setDuration(1000).start(); + sShowScrim = false; + } + return super.onTouchEvent(event); + } + void updateResources() { Resources r = getContext().getResources(); mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap); mNumColumns = r.getInteger(R.integer.quick_settings_num_columns); + mMaxRows = r.getInteger(R.integer.quick_settings_max_rows); + mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard); + requestLayout(); + } + + void setKeyguardShowing(boolean showing) { + mKeyguardShowing = showing; requestLayout(); } @@ -71,10 +105,18 @@ class QuickSettingsContainerView extends FrameLayout { final int N = getChildCount(); int cellHeight = 0; int cursor = 0; + int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; + for (int i = 0; i < N; ++i) { + if (getChildAt(i).equals(mScrim)) { + continue; + } // Update the child's width QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i); if (v.getVisibility() != View.GONE) { + int row = (int) (cursor / mNumColumns); + if (row >= maxRows) continue; + ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); int colSpan = v.getColumnSpan(); lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap); @@ -102,6 +144,7 @@ class QuickSettingsContainerView extends FrameLayout { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mScrim.bringToFront(); final int N = getChildCount(); final boolean isLayoutRtl = isLayoutRtl(); final int width = getWidth(); @@ -109,8 +152,18 @@ class QuickSettingsContainerView extends FrameLayout { int x = getPaddingStart(); int y = getPaddingTop(); int cursor = 0; + int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; for (int i = 0; i < N; ++i) { + if (getChildAt(i).equals(mScrim)) { + int w = right - left - getPaddingLeft() - getPaddingRight(); + int h = bottom - top - getPaddingTop() - getPaddingBottom(); + mScrim.measure( + MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); + mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom); + continue; + } QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i); ViewGroup.LayoutParams lp = child.getLayoutParams(); if (child.getVisibility() != GONE) { @@ -121,6 +174,7 @@ class QuickSettingsContainerView extends FrameLayout { final int childHeight = lp.height; int row = (int) (cursor / mNumColumns); + if (row >= maxRows) continue; // Push the item to the next row if it can't fit on this one if ((col + colSpan) > mNumColumns) { @@ -150,4 +204,87 @@ class QuickSettingsContainerView extends FrameLayout { } } } + + private static final class ScrimView extends View { + private static final int COLOR = 0xaf4285f4; + + private final Paint mLinePaint; + private final int mStrokeWidth; + private final Rect mTmp = new Rect(); + private final Paint mTextPaint; + private final int mTextSize; + + public ScrimView(Context context) { + super(context); + setFocusable(false); + final Resources res = context.getResources(); + mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width); + mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size); + + mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mLinePaint.setColor(COLOR); + mLinePaint.setStrokeWidth(mStrokeWidth); + mLinePaint.setStrokeJoin(Paint.Join.ROUND); + mLinePaint.setStrokeCap(Paint.Cap.ROUND); + mLinePaint.setStyle(Paint.Style.STROKE); + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(COLOR); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD)); + } + + @Override + protected void onDraw(Canvas canvas) { + final int w = getMeasuredWidth(); + final int h = getMeasuredHeight(); + final int f = mStrokeWidth * 3 / 4; + + canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint); + canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint); + + final int s = mStrokeWidth; + mTextPaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint); + mTextPaint.setTextAlign(Paint.Align.LEFT); + canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint); + mTextPaint.setTextAlign(Paint.Align.RIGHT); + drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s); + mTextPaint.setTextAlign(Paint.Align.LEFT); + drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s); + } + + private void drawUnder(Canvas c, String text, float x, float y) { + if (mTmp.isEmpty()) { + mTextPaint.getTextBounds(text, 0, text.length(), mTmp); + } + c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint); + } + + private Path line(float x1, float y1, float x2, float y2) { + final int a = mStrokeWidth * 2; + final Path p = new Path(); + p.moveTo(x1, y1); + p.lineTo(x2, y2); + if (y1 == y2) { + p.moveTo(x1 + a, y1 + a); + p.lineTo(x1, y1); + p.lineTo(x1 + a, y1 - a); + + p.moveTo(x2 - a, y2 - a); + p.lineTo(x2, y2); + p.lineTo(x2 - a, y2 + a); + } + if (x1 == x2) { + p.moveTo(x1 - a, y1 + a); + p.lineTo(x1, y1); + p.lineTo(x1 + a, y1 + a); + + p.moveTo(x2 - a, y2 - a); + p.lineTo(x2, y2); + p.lineTo(x2 + a, y2 - a); + } + return p; + } + } } \ No newline at end of file