summaryrefslogtreecommitdiffstats
path: root/core/java/com
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2012-03-30 17:36:32 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-03-30 17:36:32 -0700
commit61d6c8ca49d4a3d5bf4c961878a3f71145d75058 (patch)
treedac339e3067c6e8cd20e759f1d1e5b0d402d05e4 /core/java/com
parent96695f9ba04f85b24f906c59673e92f00f89adbe (diff)
parent3a3a6cfd8ec12208ca75c0d0d871d19d76c34194 (diff)
downloadframeworks_base-61d6c8ca49d4a3d5bf4c961878a3f71145d75058.zip
frameworks_base-61d6c8ca49d4a3d5bf4c961878a3f71145d75058.tar.gz
frameworks_base-61d6c8ca49d4a3d5bf4c961878a3f71145d75058.tar.bz2
Merge "Add new feature to let apps layout over status bar / system bar."
Diffstat (limited to 'core/java/com')
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java107
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl2
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl2
-rw-r--r--core/java/com/android/internal/widget/ActionBarOverlayLayout.java193
4 files changed, 275 insertions, 29 deletions
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f3486bd..3115eff 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -21,6 +21,7 @@ import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
+import com.android.internal.widget.ActionBarOverlayLayout;
import com.android.internal.widget.ActionBarView;
import com.android.internal.widget.ScrollingTabContainerView;
@@ -47,6 +48,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
import android.widget.SpinnerAdapter;
@@ -69,7 +71,9 @@ public class ActionBarImpl extends ActionBar {
private Activity mActivity;
private Dialog mDialog;
+ private ActionBarOverlayLayout mOverlayLayout;
private ActionBarContainer mContainerView;
+ private ViewGroup mTopVisibilityView;
private ActionBarView mActionView;
private ActionBarContextView mContextView;
private ActionBarContainer mSplitView;
@@ -100,6 +104,8 @@ public class ActionBarImpl extends ActionBar {
final Handler mHandler = new Handler();
Runnable mTabSelector;
+ private int mCurWindowVisibility = View.VISIBLE;
+
private Animator mCurrentShowAnim;
private Animator mCurrentModeAnim;
private boolean mShowHideAnimationEnabled;
@@ -110,12 +116,12 @@ public class ActionBarImpl extends ActionBar {
public void onAnimationEnd(Animator animation) {
if (mContentView != null) {
mContentView.setTranslationY(0);
- mContainerView.setTranslationY(0);
+ mTopVisibilityView.setTranslationY(0);
}
if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
mSplitView.setVisibility(View.GONE);
}
- mContainerView.setVisibility(View.GONE);
+ mTopVisibilityView.setVisibility(View.GONE);
mContainerView.setTransitioning(false);
mCurrentShowAnim = null;
completeDeferredDestroyActionMode();
@@ -126,7 +132,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentShowAnim = null;
- mContainerView.requestLayout();
+ mTopVisibilityView.requestLayout();
}
};
@@ -147,11 +153,21 @@ public class ActionBarImpl extends ActionBar {
private void init(View decor) {
mContext = decor.getContext();
+ mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
+ com.android.internal.R.id.action_bar_overlay_layout);
+ if (mOverlayLayout != null) {
+ mOverlayLayout.setActionBar(this);
+ }
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
mContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
mContainerView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.action_bar_container);
+ mTopVisibilityView = (ViewGroup)decor.findViewById(
+ com.android.internal.R.id.top_action_bar);
+ if (mTopVisibilityView == null) {
+ mTopVisibilityView = mContainerView;
+ }
mSplitView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.split_action_bar);
@@ -190,11 +206,22 @@ public class ActionBarImpl extends ActionBar {
}
final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
if (mTabScrollView != null) {
- mTabScrollView.setVisibility(isInTabMode ? View.VISIBLE : View.GONE);
+ if (isInTabMode) {
+ mTabScrollView.setVisibility(View.VISIBLE);
+ if (mOverlayLayout != null) {
+ mOverlayLayout.requestFitSystemWindows();
+ }
+ } else {
+ mTabScrollView.setVisibility(View.GONE);
+ }
}
mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
}
+ public boolean hasNonEmbeddedTabs() {
+ return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
+ }
+
private void ensureTabsExist() {
if (mTabScrollView != null) {
return;
@@ -206,8 +233,14 @@ public class ActionBarImpl extends ActionBar {
tabScroller.setVisibility(View.VISIBLE);
mActionView.setEmbeddedTabView(tabScroller);
} else {
- tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
- View.VISIBLE : View.GONE);
+ if (getNavigationMode() == NAVIGATION_MODE_TABS) {
+ tabScroller.setVisibility(View.VISIBLE);
+ if (mOverlayLayout != null) {
+ mOverlayLayout.requestFitSystemWindows();
+ }
+ } else {
+ tabScroller.setVisibility(View.GONE);
+ }
mContainerView.setTabContainer(tabScroller);
}
mTabScrollView = tabScroller;
@@ -221,6 +254,10 @@ public class ActionBarImpl extends ActionBar {
}
}
+ public void setWindowVisibility(int visibility) {
+ mCurWindowVisibility = visibility;
+ }
+
/**
* Enables or disables animation between show/hide states.
* If animation is disabled using this method, animations in progress
@@ -396,7 +433,12 @@ public class ActionBarImpl extends ActionBar {
animateToMode(true);
if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
// TODO animate this
- mSplitView.setVisibility(View.VISIBLE);
+ if (mSplitView.getVisibility() != View.VISIBLE) {
+ mSplitView.setVisibility(View.VISIBLE);
+ if (mOverlayLayout != null) {
+ mOverlayLayout.requestFitSystemWindows();
+ }
+ }
}
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mActionMode = mode;
@@ -530,28 +572,29 @@ public class ActionBarImpl extends ActionBar {
@Override
public void show() {
- show(true);
+ show(true, false);
}
- void show(boolean markHiddenBeforeMode) {
+ public void show(boolean markHiddenBeforeMode, boolean alwaysAnimate) {
if (mCurrentShowAnim != null) {
mCurrentShowAnim.end();
}
- if (mContainerView.getVisibility() == View.VISIBLE) {
+ if (mTopVisibilityView.getVisibility() == View.VISIBLE) {
if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
return;
}
- mContainerView.setVisibility(View.VISIBLE);
+ mTopVisibilityView.setVisibility(View.VISIBLE);
- if (mShowHideAnimationEnabled) {
- mContainerView.setAlpha(0);
+ if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
+ || alwaysAnimate)) {
+ mTopVisibilityView.setAlpha(0);
AnimatorSet anim = new AnimatorSet();
- AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
+ AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 1));
if (mContentView != null) {
b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
- -mContainerView.getHeight(), 0));
- mContainerView.setTranslationY(-mContainerView.getHeight());
- b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
+ -mTopVisibilityView.getHeight(), 0));
+ mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
+ b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
}
if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
mSplitView.setAlpha(0);
@@ -562,7 +605,7 @@ public class ActionBarImpl extends ActionBar {
mCurrentShowAnim = anim;
anim.start();
} else {
- mContainerView.setAlpha(1);
+ mTopVisibilityView.setAlpha(1);
mContainerView.setTranslationY(0);
mShowListener.onAnimationEnd(null);
}
@@ -570,23 +613,28 @@ public class ActionBarImpl extends ActionBar {
@Override
public void hide() {
+ hide(false);
+ }
+
+ public void hide(boolean alwaysAnimate) {
if (mCurrentShowAnim != null) {
mCurrentShowAnim.end();
}
- if (mContainerView.getVisibility() == View.GONE) {
+ if (mTopVisibilityView.getVisibility() == View.GONE) {
return;
}
- if (mShowHideAnimationEnabled) {
- mContainerView.setAlpha(1);
+ if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
+ || alwaysAnimate)) {
+ mTopVisibilityView.setAlpha(1);
mContainerView.setTransitioning(true);
AnimatorSet anim = new AnimatorSet();
- AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
+ AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 0));
if (mContentView != null) {
b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
- 0, -mContainerView.getHeight()));
- b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
- -mContainerView.getHeight()));
+ 0, -mTopVisibilityView.getHeight()));
+ b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
+ -mTopVisibilityView.getHeight()));
}
if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
mSplitView.setAlpha(1);
@@ -601,12 +649,12 @@ public class ActionBarImpl extends ActionBar {
}
public boolean isShowing() {
- return mContainerView.getVisibility() == View.VISIBLE;
+ return mTopVisibilityView.getVisibility() == View.VISIBLE;
}
void animateToMode(boolean toActionMode) {
if (toActionMode) {
- show(false);
+ show(false, false);
}
if (mCurrentModeAnim != null) {
mCurrentModeAnim.end();
@@ -980,6 +1028,11 @@ public class ActionBarImpl extends ActionBar {
mTabScrollView.setVisibility(View.GONE);
break;
}
+ if (oldMode != mode && !mHasEmbeddedTabs) {
+ if (mOverlayLayout != null) {
+ mOverlayLayout.requestFitSystemWindows();
+ }
+ }
mActionView.setNavigationMode(mode);
switch (mode) {
case NAVIGATION_MODE_TABS:
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6e36fdb..294d4c4 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -30,7 +30,7 @@ oneway interface IStatusBar
void disable(int state);
void animateExpand();
void animateCollapse();
- void setSystemUiVisibility(int vis);
+ void setSystemUiVisibility(int vis, int mask);
void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
void setHardKeyboardStatus(boolean available, boolean enabled);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 118e541..c64f170 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -44,7 +44,7 @@ interface IStatusBarService
int uid, int initialPid, String message);
void onClearAllNotifications();
void onNotificationClear(String pkg, String tag, int id);
- void setSystemUiVisibility(int vis);
+ void setSystemUiVisibility(int vis, int mask);
void setHardKeyboardEnabled(boolean enabled);
void toggleRecentApps();
void preloadRecentApps();
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
new file mode 100644
index 0000000..5f36bb6
--- /dev/null
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.app.ActionBarImpl;
+
+import android.animation.LayoutTransition;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+
+/**
+ * Special layout for the containing of an overlay action bar (and its
+ * content) to correctly handle fitting system windows when the content
+ * has request that its layout ignore them.
+ */
+public class ActionBarOverlayLayout extends FrameLayout {
+ private int mActionBarHeight;
+ private ActionBarImpl mActionBar;
+ private int mWindowVisibility = View.VISIBLE;
+ private View mContent;
+ private View mActionBarTop;
+ private ActionBarContainer mContainerView;
+ private ActionBarView mActionView;
+ private View mActionBarBottom;
+ private int mLastSystemUiVisibility;
+ private final Rect mZeroRect = new Rect(0, 0, 0, 0);
+
+ static final int[] mActionBarSizeAttr = new int [] {
+ com.android.internal.R.attr.actionBarSize
+ };
+
+ public ActionBarOverlayLayout(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public ActionBarOverlayLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ private void init(Context context) {
+ TypedArray ta = getContext().getTheme().obtainStyledAttributes(mActionBarSizeAttr);
+ mActionBarHeight = ta.getDimensionPixelSize(0, 0);
+ ta.recycle();
+ }
+
+ public void setActionBar(ActionBarImpl impl) {
+ mActionBar = impl;
+ if (getWindowToken() != null) {
+ // This is being initialized after being added to a window;
+ // make sure to update all state now.
+ mActionBar.setWindowVisibility(mWindowVisibility);
+ if (mLastSystemUiVisibility != 0) {
+ int newVis = mLastSystemUiVisibility;
+ onWindowSystemUiVisibilityChanged(newVis);
+ requestFitSystemWindows();
+ }
+ }
+ }
+
+ @Override
+ public void onWindowSystemUiVisibilityChanged(int visible) {
+ super.onWindowSystemUiVisibilityChanged(visible);
+ pullChildren();
+ final int diff = mLastSystemUiVisibility ^ visible;
+ mLastSystemUiVisibility = visible;
+ final boolean barVisible = (visible&SYSTEM_UI_FLAG_FULLSCREEN) == 0;
+ final boolean wasVisible = mActionBar != null ? mActionBar.isShowing() : true;
+ if (barVisible != wasVisible || (diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ if (mActionBar != null) {
+ if (barVisible) mActionBar.show(true, true);
+ else mActionBar.hide(true);
+ requestFitSystemWindows();
+ }
+ }
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ mWindowVisibility = visibility;
+ if (mActionBar != null) {
+ mActionBar.setWindowVisibility(visibility);
+ }
+ }
+
+ private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
+ boolean bottom, boolean right) {
+ boolean changed = false;
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)view.getLayoutParams();
+ if (left && lp.leftMargin != insets.left) {
+ changed = true;
+ lp.leftMargin = insets.left;
+ }
+ if (top && lp.topMargin != insets.top) {
+ changed = true;
+ lp.topMargin = insets.top;
+ }
+ if (right && lp.rightMargin != insets.right) {
+ changed = true;
+ lp.rightMargin = insets.right;
+ }
+ if (bottom && lp.bottomMargin != insets.bottom) {
+ changed = true;
+ lp.bottomMargin = insets.bottom;
+ }
+ return changed;
+ }
+
+ @Override
+ protected boolean fitSystemWindows(Rect insets) {
+ pullChildren();
+
+ final int vis = getWindowSystemUiVisibility();
+ final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+
+ // The top and bottom action bars are always within the content area.
+ boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+ changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+
+ // If the window has not requested system UI layout flags, we need to
+ // make sure its content is not being covered by system UI... though it
+ // will still be covered by the action bar since they have requested it to
+ // overlay.
+ if ((vis & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
+ changed |= applyInsets(mContent, insets, true, true, true, true);
+ // The insets are now consumed.
+ insets.set(0, 0, 0, 0);
+ } else {
+ changed |= applyInsets(mContent, mZeroRect, true, true, true, true);
+ }
+
+
+ if (stable || mActionBarTop.getVisibility() == VISIBLE) {
+ // The action bar creates additional insets for its content to use.
+ insets.top += mActionBarHeight;
+ }
+
+ if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
+ View tabs = mContainerView.getTabContainer();
+ if (stable || (tabs != null && tabs.getVisibility() == VISIBLE)) {
+ // If tabs are not embedded, adjust insets to account for them.
+ insets.top += mActionBarHeight;
+ }
+ }
+
+ if (mActionView.isSplitActionBar()) {
+ if (stable || (mActionBarBottom != null
+ && mActionBarBottom.getVisibility() == VISIBLE)) {
+ // If action bar is split, adjust buttom insets for it.
+ insets.bottom += mActionBarHeight;
+ }
+ }
+
+ if (changed) {
+ requestLayout();
+ }
+
+ return super.fitSystemWindows(insets);
+ }
+
+ void pullChildren() {
+ if (mContent == null) {
+ mContent = findViewById(com.android.internal.R.id.content);
+ mActionBarTop = findViewById(com.android.internal.R.id.top_action_bar);
+ mContainerView = (ActionBarContainer)findViewById(
+ com.android.internal.R.id.action_bar_container);
+ mActionView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+ mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
+ }
+ }
+}