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 --- core/java/android/view/WindowManager.java | 6 + 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 +++++++- .../internal/policy/impl/PhoneWindowManager.java | 164 ++++++++++++++++----- services/input/InputWindow.h | 1 + 8 files changed, 407 insertions(+), 34 deletions(-) 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 diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 8a18aaf7c7ce..9395d5cfef2a 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -387,6 +387,12 @@ public interface WindowManager extends ViewManager { */ public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18; + /** + * Window type: Navigation bar (when distinct from status bar) + * @hide + */ + public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19; + /** * End of types of system windows. */ diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml new file mode 100644 index 000000000000..eba44802440c --- /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 000000000000..bcc8da1f8595 --- /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 88cd43c74da0..a2577cb738c1 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 000000000000..ec169e558306 --- /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 1e46246ab61b..97c8aee76aea 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(); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index a37ccc7d0a7e..8a29419e4c74 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -111,6 +111,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_POINTER; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.KeyCharacterMap.FallbackAction; @@ -175,14 +176,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // responsible for power management when displayed. static final int KEYGUARD_LAYER = 15; static final int KEYGUARD_DIALOG_LAYER = 16; + // the navigation bar, if available, shows atop most things + static final int NAVIGATION_BAR_LAYER = 17; // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - static final int DRAG_LAYER = 17; + static final int DRAG_LAYER = 18; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 18; - static final int SECURE_SYSTEM_OVERLAY_LAYER = 19; + static final int SYSTEM_OVERLAY_LAYER = 19; + static final int SECURE_SYSTEM_OVERLAY_LAYER = 20; // the (mouse) pointer layer - static final int POINTER_LAYER = 20; + static final int POINTER_LAYER = 21; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -228,6 +231,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mStatusBar = null; boolean mStatusBarCanHide; final ArrayList mStatusBarPanels = new ArrayList(); + WindowState mNavigationBar = null; + WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; @@ -1037,6 +1042,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return DRAG_LAYER; case TYPE_POINTER: return POINTER_LAYER; + case TYPE_NAVIGATION_BAR: + return NAVIGATION_BAR_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -1213,6 +1220,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarCanHide = mContext.getResources().getBoolean( com.android.internal.R.bool.config_statusBarCanHide); + break; + case TYPE_NAVIGATION_BAR: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.STATUS_BAR_SERVICE, + "PhoneWindowManager"); + mNavigationBar = win; + if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_STATUS_BAR_PANEL: mContext.enforceCallingOrSelfPermission( @@ -1240,9 +1254,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void removeWindowLw(WindowState win) { if (mStatusBar == win) { mStatusBar = null; - } - else if (mKeyguard == win) { + } else if (mKeyguard == win) { mKeyguard = null; + } else if (mNavigationBar == win) { + mNavigationBar = null; } else { mStatusBarPanels.remove(win); } @@ -1609,17 +1624,48 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; + // start with the current dock rect, which will be (0,0,displayWidth,displayHeight) + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect vf = mTmpVisibleFrame; + pf.left = df.left = vf.left = mDockLeft; + pf.top = df.top = vf.top = mDockTop; + pf.right = df.right = vf.right = mDockRight; + pf.bottom = df.bottom = vf.bottom = mDockBottom; + // decide where the status bar goes ahead of time if (mStatusBar != null) { - final Rect pf = mTmpParentFrame; - final Rect df = mTmpDisplayFrame; - final Rect vf = mTmpVisibleFrame; - pf.left = df.left = vf.left = 0; - pf.top = df.top = vf.top = 0; - pf.right = df.right = vf.right = displayWidth; - pf.bottom = df.bottom = vf.bottom = displayHeight; - + Rect navr = null; + if (mNavigationBar != null) { + mNavigationBar.computeFrameLw(pf, df, vf, vf); + if (mNavigationBar.isVisibleLw()) { + navr = mNavigationBar.getFrameLw(); + + if (navr.top == 0) { + // Navigation bar is vertical + if (mDockLeft == navr.left) { + mDockLeft = navr.right; + } else if (mDockRight == navr.right) { + mDockRight = navr.left; + } + } else { + // Navigation bar horizontal, at bottom + if (mDockBottom == navr.bottom) { + mDockBottom = navr.top; + } + } + } + } + if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr); + + // apply navigation bar insets + pf.left = df.left = vf.left = mDockLeft; + pf.top = df.top = vf.top = mDockTop; + pf.right = df.right = vf.right = mDockRight; + pf.bottom = df.bottom = vf.bottom = mDockBottom; + mStatusBar.computeFrameLw(pf, df, vf, vf); + if (mStatusBar.isVisibleLw()) { // If the status bar is hidden, we don't want to cause // windows behind it to scroll. @@ -1630,14 +1676,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // status bar is visible. if (mDockTop == r.top) mDockTop = r.bottom; else if (mDockBottom == r.bottom) mDockBottom = r.top; + mContentTop = mCurTop = mDockTop; mContentBottom = mCurBottom = mDockBottom; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop - + " mContentTop=" + mContentTop - + " mCurTop=" + mCurTop - + " mDockBottom=" + mDockBottom - + " mContentBottom=" + mContentBottom - + " mCurBottom=" + mCurBottom); + mContentLeft = mCurLeft = mDockLeft; + mContentRight = mCurRight = mDockRight; + + if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " + + String.format( + "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", + mDockLeft, mDockTop, mDockRight, mDockBottom, + mContentLeft, mContentTop, mContentRight, mContentBottom, + mCurLeft, mCurTop, mCurRight, mCurBottom)); } else { // Status bar can't go away; the part of the screen it // covers does not exist for anything behind it. @@ -1647,12 +1697,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { mRestrictedScreenHeight -= (r.bottom-r.top); } + + if (navr != null) { + if (navr.top == 0) { + // Navigation bar is vertical + if (mRestrictedScreenLeft == navr.left) { + mRestrictedScreenLeft = navr.right; + mRestrictedScreenWidth -= (navr.right - navr.left); + } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) { + mRestrictedScreenWidth -= (navr.right - navr.left); + } + } else { + // Navigation bar horizontal, at bottom + if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { + mRestrictedScreenHeight -= (navr.bottom-navr.top); + } + } + } + mContentTop = mCurTop = mDockTop = mRestrictedScreenTop; mContentBottom = mCurBottom = mDockBottom = mRestrictedScreenTop + mRestrictedScreenHeight; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop=" - + mRestrictedScreenTop - + " mRestrictedScreenHeight=" + mRestrictedScreenHeight); + if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: (" + + mRestrictedScreenLeft + "," + + mRestrictedScreenTop + "," + + (mRestrictedScreenLeft + mRestrictedScreenWidth) + "," + + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")"); } } } @@ -1722,6 +1792,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Rect cf = mTmpContentFrame; final Rect vf = mTmpVisibleFrame; + final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw()); + if (attrs.type == TYPE_INPUT_METHOD) { pf.left = df.left = cf.left = vf.left = mDockLeft; pf.top = df.top = cf.top = vf.top = mDockTop; @@ -1735,6 +1807,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN"); // This is the case for a normal activity window: we want it // to cover all of the screen space, and it can take care of // moving its contents to account for screen decorations that @@ -1744,15 +1819,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { // frame is the same as the one we are attached to. setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); } else { - if (attrs.type == TYPE_STATUS_BAR_PANEL) { + if (attrs.type == TYPE_STATUS_BAR_PANEL + || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { // Status bar panels are the only windows who can go on top of // the status bar. They are protected by the STATUS_BAR_SERVICE // permission, so they have the same privileges as the status // bar itself. - pf.left = df.left = mUnrestrictedScreenLeft; + // + // However, they should still dodge the navigation bar if it exists. A + // straightforward way to do this is to only allow the status bar panels to + // extend to the extrema of the allowable region for the IME dock. + + pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.right = df.right = hasNavBar + ? mDockRight + : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = hasNavBar + ? mDockBottom + : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + } else { pf.left = df.left = mRestrictedScreenLeft; pf.top = df.top = mRestrictedScreenTop; @@ -1780,15 +1866,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); // A window that has requested to fill the entire screen just // gets everything, period. - if (attrs.type == TYPE_STATUS_BAR_PANEL) { - pf.left = df.left = cf.left = mUnrestrictedScreenLeft; + if (attrs.type == TYPE_STATUS_BAR_PANEL + || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { + pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right - = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.right = df.right = cf.right = hasNavBar + ? mDockRight + : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = cf.bottom = hasNavBar + ? mDockBottom + : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + } else { pf.left = df.left = cf.left = mRestrictedScreenLeft; pf.top = df.top = cf.top = mRestrictedScreenTop; @@ -1805,10 +1897,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } else if (attached != null) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); // A child window should be placed inside of the same visible // frame that its parent had. setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf); } else { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); // Otherwise, a normal window must be placed inside the content // of all screen decorations. pf.left = mContentLeft; @@ -1844,6 +1940,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + + " attach=" + attached + " type=" + attrs.type + + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index f04fb020fff7..208353d22f2f 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -119,6 +119,7 @@ struct InputWindow { TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, + TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, LAST_SYSTEM_WINDOW = 2999, }; -- cgit v1.2.3-59-g8ed1b