From 8956dbbc5f292d8b79072ae73b25f2114c8c7479 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 22 Apr 2011 07:55:02 -0400 Subject: On-screen navigation bar (separate from the status bar). In Honeycomb we introduced navigation controls in the status bar, for xlarge devices without physical buttons. What about phones? The status bar is pretty cramped already, and besides, it's at the top of the display most of the time, not at the bottom where your thumb is likely to be. Enter the navigation bar. It's a new window type that appears atop almost everything (including the keyguard); the window manager subtracts its rectangle from the default visible rectangle of other windows (including the status bar and notification shade). However, it behaves (on phones) like the status bar in that applications that request fullscreen windows can get access to those pixels. Well, almost; they need cooperation from the navigation bar implementation to make the navbar disappear, just like the status bar. The current SystemUI implementation of the navigation bar on phones is still rough, but it has the basics: + back, home, and menu keys (NB: we're showing menu all the time right now because checking the api level of the package owning the top window is currently a poor indicator of whether the app requires the menu key) + it tries to stick to the same physical end of the device, regardless of device orientation (on a phone, this is the strip of land closest to the microphone) Change-Id: Ic613a3351220af0bbfbdef63e1d99cbefd5ed1c2 --- packages/SystemUI/res/layout/navigation_bar.xml | 124 +++++++++++++++++++++ packages/SystemUI/res/values-land/dimens.xml | 21 ++++ packages/SystemUI/res/values/dimens.xml | 2 + .../statusbar/phone/NavigationBarView.java | 59 ++++++++++ .../systemui/statusbar/phone/PhoneStatusBar.java | 64 ++++++++++- 5 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 packages/SystemUI/res/layout/navigation_bar.xml create mode 100644 packages/SystemUI/res/values-land/dimens.xml create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java (limited to 'packages') diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml new file mode 100644 index 0000000..eba4480 --- /dev/null +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml new file mode 100644 index 0000000..bcc8da1 --- /dev/null +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -0,0 +1,21 @@ + + + + + 42dp + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 88cd43c..a2577cb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -31,5 +31,7 @@ 356dp + + 42dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java new file mode 100644 index 0000000..ec169e5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Display; +import android.view.KeyEvent; +import android.view.View; +import android.view.Surface; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.content.res.Configuration; + +import com.android.systemui.R; + +public class NavigationBarView extends LinearLayout { + final Display mDisplay; + View[] mRotatedViews = new View[4]; + + public NavigationBarView(Context context, AttributeSet attrs) { + super(context, attrs); + mDisplay = ((WindowManager)context.getSystemService( + Context.WINDOW_SERVICE)).getDefaultDisplay(); + } + + public void onFinishInflate() { + mRotatedViews[Surface.ROTATION_0] = + mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0); + + mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90); + + mRotatedViews[Surface.ROTATION_270] = findViewById(R.id.rot270); + } + + public void reorient() { + final int rot = mDisplay.getRotation(); + for (int i=0; i<4; i++) { + mRotatedViews[i].setVisibility(View.GONE); + } + mRotatedViews[rot].setVisibility(View.VISIBLE); + + android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation()); + } +} 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 1e46246..97c8aee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -45,6 +45,7 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.Surface; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; @@ -141,6 +142,9 @@ public class PhoneStatusBar extends StatusBar { // for immersive activities private View mIntruderAlertView; + // on-screen navigation buttons + private NavigationBarView mNavigationBarView; + // the tracker view TrackingView mTrackingView; WindowManager.LayoutParams mTrackingParams; @@ -199,7 +203,9 @@ public class PhoneStatusBar extends StatusBar { super.start(); - addIntruderView(); + addNavigationBar(); + + //addIntruderView(); // Lastly, call to the icon policy to install/update all the icons. mIconPolicy = new PhoneStatusBarPolicy(mContext); @@ -223,6 +229,9 @@ public class PhoneStatusBar extends StatusBar { mIntruderAlertView.setVisibility(View.GONE); mIntruderAlertView.setClickable(true); + mNavigationBarView = + (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); + PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context, R.layout.status_bar, null); sb.mService = this; @@ -292,6 +301,58 @@ public class PhoneStatusBar extends StatusBar { return res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); } + // For small-screen devices (read: phones) that lack hardware navigation buttons + private void addNavigationBar() { + mNavigationBarView.reorient(); + WindowManagerImpl.getDefault().addView( + mNavigationBarView, getNavigationBarLayoutParams()); + } + + private void repositionNavigationBar() { + mNavigationBarView.reorient(); + WindowManagerImpl.getDefault().updateViewLayout( + mNavigationBarView, getNavigationBarLayoutParams()); + } + + private WindowManager.LayoutParams getNavigationBarLayoutParams() { + final int rotation = mDisplay.getRotation(); + final boolean sideways = + (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270); + + final Resources res = mContext.getResources(); + final int size = res.getDimensionPixelSize(R.dimen.navigation_bar_size); + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + sideways ? size : ViewGroup.LayoutParams.MATCH_PARENT, + sideways ? ViewGroup.LayoutParams.MATCH_PARENT : size, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + 0 + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + + lp.setTitle("NavigationBar"); + switch (rotation) { + case Surface.ROTATION_90: + // device has been turned 90deg counter-clockwise + lp.gravity = Gravity.RIGHT | Gravity.FILL_VERTICAL; + break; + case Surface.ROTATION_270: + // device has been turned 90deg clockwise + lp.gravity = Gravity.LEFT | Gravity.FILL_VERTICAL; + break; + default: + lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL; + break; + } + lp.windowAnimations = 0; + + return lp; + } + private void addIntruderView() { final int height = getStatusBarHeight(); @@ -1497,6 +1558,7 @@ public class PhoneStatusBar extends StatusBar { animateCollapse(); } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + repositionNavigationBar(); updateResources(); } } -- cgit v1.1