From b6d3dc68977eada24515a825c43eb01df9a4edb5 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Wed, 17 Nov 2010 16:51:26 -0500 Subject: [PATCH] Implement new lights-out mode in system bar. When an app requests fullscreen display, "shadows" of the visible system bar UI elements are drawn in their place. The user can still interact with these elements by poking the shadows; the widgets will temporarily shine through, long enough for the user interaction. Known issues: - if the notification panel is up for too long, the shadow will not be re-enabled on the notification area (need to route all hide/show requests through the shadowcontroller) - status bar hide/show animations have been temporarily turned off to make this work correctly; they'll be put back later Bug: 3203171 --- .../res/drawable-mdpi/ic_sysbar_shadow.9.png | Bin 0 -> 247 bytes .../SystemUI/res/layout-xlarge/status_bar.xml | 144 ++++++++++----- .../statusbar/tablet/TabletStatusBar.java | 174 ++++++++++++++---- .../statusbar/tablet/TabletStatusBarView.java | 7 + 4 files changed, 249 insertions(+), 76 deletions(-) create mode 100644 packages/SystemUI/res/drawable-mdpi/ic_sysbar_shadow.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_shadow.9.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c888c21d59bbb82c1f9aad4927eca6caefb0c2a5 GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^PC#tL!3HE>l<{f;Db50q$YKTtZeb8+WSBKa0w}oB z)5S3)gZ1q#N4_Ql2G@g+4p#k$<53ixJiVZ~Pr5ZWep&rf3A^W$AN+q@x$)umpEo~T zSnn?OXu2zhVwH1;LQ{vB!Xn!o7D1OS41#YHl{*v`v36weOFOa%>N>bo-{4T{$Y4~u zb=Xb7(S=*!qMTV1hf-8S$F~iFE&>;sT(-3Lq8U+mr@#2z+W#~5U6VR?>1xGJsq3rP fu0K}#?=g3Y8%OjO=ej*WM>BZ3`njxgN@xNAd9GOA literal 0 HcmV?d00001 diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml index 8f2bea4bf2e89..ddb5bb9d7d38b 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml @@ -25,9 +25,10 @@ android:id="@+id/bar_contents" android:layout_width="match_parent" android:layout_height="match_parent" - android:animateLayoutChanges="true" + android:animateLayoutChanges="false" > + + + + + + + + + + + - - - - diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 0531f9d47f00f..1f4c9d1a9c0b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -75,12 +75,15 @@ public class TabletStatusBar extends StatusBar { public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003; public static final int MSG_OPEN_RECENTS_PANEL = 1020; public static final int MSG_CLOSE_RECENTS_PANEL = 1021; - public static final int MSG_LIGHTS_ON = 1030; - public static final int MSG_LIGHTS_OUT = 1031; + public static final int MSG_HIDE_SHADOWS = 1030; + public static final int MSG_SHOW_SHADOWS = 1031; + public static final int MSG_SHOW_SHADOWS_NO_COLLAPSE = 1032; private static final int MAX_IMAGE_LEVEL = 10000; private static final boolean USE_2D_RECENTS = true; + public static final int LIGHTS_ON_DELAY = 5000; + int mIconSize; H mHandler = new H(); @@ -93,6 +96,9 @@ public class TabletStatusBar extends StatusBar { View mNotificationTrigger; NotificationIconArea mNotificationIconArea; View mNavigationArea; + + View mBackButton; + View mHomeButton; View mMenuButton; View mRecentButton; @@ -113,7 +119,10 @@ public class TabletStatusBar extends StatusBar { NetworkController mNetworkController; View mBarContents; - View mCurtains; + + // lights out support + View mBackShadow, mHomeShadow, mRecentShadow, mMenuShadow, mNotificationShadow; + ShadowController mShadowController; NotificationIconArea.IconLayout mIconLayout; @@ -245,14 +254,21 @@ public class TabletStatusBar extends StatusBar { sb.setHandler(mHandler); mBarContents = sb.findViewById(R.id.bar_contents); - mCurtains = sb.findViewById(R.id.lights_out); - mRecentButton = sb.findViewById(R.id.recent_apps); - mRecentButton.setOnClickListener(mOnClickListener); + // "shadows" of the status bar features, for lights-out mode + mBackShadow = sb.findViewById(R.id.back_shadow); + mHomeShadow = sb.findViewById(R.id.home_shadow); + mRecentShadow = sb.findViewById(R.id.recent_shadow); + mMenuShadow = sb.findViewById(R.id.menu_shadow); + mNotificationShadow = sb.findViewById(R.id.notification_shadow); - SetLightsOnListener on = new SetLightsOnListener(true); - mCurtains.setOnClickListener(on); - mCurtains.setOnLongClickListener(on); + mShadowController = new ShadowController(false); + + mBackShadow.setOnTouchListener(mShadowController.makeTouchListener()); + mHomeShadow.setOnTouchListener(mShadowController.makeTouchListener()); + mRecentShadow.setOnTouchListener(mShadowController.makeTouchListener()); + mMenuShadow.setOnTouchListener(mShadowController.makeTouchListener()); + mNotificationShadow.setOnTouchListener(mShadowController.makeTouchListener()); // the whole right-hand side of the bar mNotificationArea = sb.findViewById(R.id.notificationArea); @@ -282,10 +298,15 @@ public class TabletStatusBar extends StatusBar { // The navigation buttons mNavigationArea = sb.findViewById(R.id.navigationArea); + mBackButton = mNavigationArea.findViewById(R.id.back); + mHomeButton = mNavigationArea.findViewById(R.id.home); mMenuButton = mNavigationArea.findViewById(R.id.menu); + mRecentButton = mNavigationArea.findViewById(R.id.recent_apps); + Slog.d(TAG, "rec=" + mRecentButton + ", listener=" + mOnClickListener); + mRecentButton.setOnClickListener(mOnClickListener); // The bar contents buttons - mInputMethodButton = (InputMethodButton) mBarContents.findViewById(R.id.imeButton); + mInputMethodButton = (InputMethodButton) sb.findViewById(R.id.imeButton); // set the initial view visibility setAreThereNotifications(); @@ -362,6 +383,8 @@ public class TabletStatusBar extends StatusBar { mNotificationPeekWindow.setVisibility(View.GONE); mNotificationPanel.setVisibility(View.VISIBLE); + + // XXX: need to synchronize with shadows here mNotificationArea.setVisibility(View.GONE); } break; @@ -369,6 +392,8 @@ public class TabletStatusBar extends StatusBar { if (DEBUG) Slog.d(TAG, "closing notifications panel"); if (mNotificationPanel.getVisibility() == View.VISIBLE) { mNotificationPanel.setVisibility(View.GONE); + + // XXX: need to synchronize with shadows here mNotificationArea.setVisibility(View.VISIBLE); } break; @@ -380,14 +405,14 @@ public class TabletStatusBar extends StatusBar { if (DEBUG) Slog.d(TAG, "closing recents panel"); if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.GONE); break; - case MSG_LIGHTS_ON: - setViewVisibility(mCurtains, View.GONE, R.anim.lights_out_out); - setViewVisibility(mBarContents, View.VISIBLE, R.anim.status_bar_in); + case MSG_HIDE_SHADOWS: + mShadowController.hideAllShadows(); break; - case MSG_LIGHTS_OUT: + case MSG_SHOW_SHADOWS: animateCollapse(); - setViewVisibility(mCurtains, View.VISIBLE, R.anim.lights_out_in); - setViewVisibility(mBarContents, View.GONE, R.anim.status_bar_out); + // fall through + case MSG_SHOW_SHADOWS_NO_COLLAPSE: + mShadowController.showAllShadows(); break; } } @@ -605,16 +630,16 @@ public class TabletStatusBar extends StatusBar { // called by StatusBar @Override public void setLightsOn(boolean on) { - mHandler.removeMessages(MSG_LIGHTS_OUT); - mHandler.removeMessages(MSG_LIGHTS_ON); - mHandler.sendEmptyMessage(on ? MSG_LIGHTS_ON : MSG_LIGHTS_OUT); + mHandler.removeMessages(MSG_SHOW_SHADOWS); + mHandler.removeMessages(MSG_HIDE_SHADOWS); + mHandler.sendEmptyMessage(on ? MSG_HIDE_SHADOWS : MSG_SHOW_SHADOWS); } public void setMenuKeyVisible(boolean visible) { if (DEBUG) { Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button"); } - mMenuButton.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE); } public void setIMEButtonVisible(boolean visible) { @@ -664,7 +689,7 @@ public class TabletStatusBar extends StatusBar { }; public void onClickNotificationTrigger() { - if (DEBUG) Slog.d(TAG, "clicked notification icons"); + if (DEBUG) Slog.d(TAG, "clicked notification icons; disabled=" + mDisabled); if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) { if (!mNotificationsOn) { mNotificationsOn = true; @@ -681,7 +706,7 @@ public class TabletStatusBar extends StatusBar { } public void onClickRecentButton() { - if (DEBUG) Slog.d(TAG, "clicked recent apps"); + if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled); if (mRecentsPanel == null) { Intent intent = new Intent(); intent.setClass(mContext, RecentApplicationsActivity.class); @@ -1006,23 +1031,108 @@ public class TabletStatusBar extends StatusBar { return true; } - public class SetLightsOnListener implements View.OnLongClickListener, - View.OnClickListener { - private boolean mOn; + public class ShadowController { + boolean mShowShadows; + View mTouchTarget; - SetLightsOnListener(boolean on) { - mOn = on; + ShadowController(boolean showShadows) { + mShowShadows = showShadows; + mTouchTarget = null; } - public void onClick(View v) { - setLightsOn(mOn); + public boolean getShadowState() { + return mShowShadows; } - public boolean onLongClick(View v) { - setLightsOn(mOn); - return true; + public View.OnTouchListener makeTouchListener() { + return new View.OnTouchListener() { + public boolean onTouch(View v, MotionEvent ev) { + final int action = ev.getAction(); + + if (DEBUG) Slog.d(TAG, "ShadowController: v=" + v + ", ev=" + ev); + + // currently redirecting events? + if (mTouchTarget == null) { + if (v == mBackShadow) { + mTouchTarget = mBackButton; + } else if (v == mHomeShadow) { + mTouchTarget = mHomeButton; + } else if (v == mMenuShadow) { + mTouchTarget = mMenuButton; + } else if (v == mRecentShadow) { + mTouchTarget = mRecentButton; + } else if (v == mNotificationShadow) { + mTouchTarget = mNotificationArea; + } + } + + if (mTouchTarget != null && mTouchTarget.getVisibility() != View.GONE) { + boolean last = false; + switch (action) { + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + mHandler.removeMessages(MSG_SHOW_SHADOWS_NO_COLLAPSE); + if (mShowShadows) { + mHandler.sendEmptyMessageDelayed(MSG_SHOW_SHADOWS_NO_COLLAPSE, + v == mNotificationShadow ? 5000 : 500); + } + last = true; + break; + case MotionEvent.ACTION_DOWN: + mHandler.removeMessages(MSG_SHOW_SHADOWS_NO_COLLAPSE); + setShadowForButton(mTouchTarget, false); + break; + } + mTouchTarget.dispatchTouchEvent(ev); + if (last) mTouchTarget = null; + return true; + } + + return false; + } + }; } + public void showAllShadows() { + mShowShadows = true; + setShadowForButton(mBackButton, true); + setShadowForButton(mHomeButton, true); + setShadowForButton(mRecentButton, true); + setShadowForButton(mMenuButton, true); + setShadowForButton(mNotificationArea, true); + } + + public void hideAllShadows() { + mShowShadows = false; + setShadowForButton(mBackButton, false); + setShadowForButton(mHomeButton, false); + setShadowForButton(mRecentButton, false); + setShadowForButton(mMenuButton, false); + setShadowForButton(mNotificationArea, false); + } + + // Use View.INVISIBLE for things hidden due to shadowing, and View.GONE for things that are + // disabled (and should not be shadowed or re-shown) + public void setShadowForButton(View button, boolean shade) { + View shadow = null; + if (button == mBackButton) { + shadow = mBackShadow; + } else if (button == mHomeButton) { + shadow = mHomeShadow; + } else if (button == mMenuButton) { + shadow = mMenuShadow; + } else if (button == mRecentButton) { + shadow = mRecentShadow; + } else if (button == mNotificationArea) { + shadow = mNotificationShadow; + } + if (shadow != null) { + if (button.getVisibility() != View.GONE) { + shadow.setVisibility(shade ? View.VISIBLE : View.INVISIBLE); + button.setVisibility(shade ? View.INVISIBLE : View.VISIBLE); + } + } + } } public class TouchOutsideListener implements View.OnTouchListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java index bd8266ae08c32..823b793704e0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.tablet; import android.content.Context; import android.os.Handler; import android.util.AttributeSet; +import android.util.Slog; import android.view.View; import android.view.MotionEvent; import android.widget.FrameLayout; @@ -40,6 +41,9 @@ public class TabletStatusBarView extends FrameLayout { public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (TabletStatusBar.DEBUG) { + Slog.d(TabletStatusBar.TAG, "TabletStatusBarView intercepting touch event: " + ev); + } mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL); mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL); mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL); @@ -48,6 +52,9 @@ public class TabletStatusBarView extends FrameLayout { for (int i=0; i < mPanels.length; i++) { if (mPanels[i] != null && mPanels[i].getVisibility() == View.VISIBLE) { if (eventInside(mIgnoreChildren[i], ev)) { + if (TabletStatusBar.DEBUG) { + Slog.d(TabletStatusBar.TAG, "TabletStatusBarView eating event for view: " + mIgnoreChildren[i]); + } return true; } }