Revision control
Copy as Markdown
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
<!-- This layout can be used in multiple modes: see class kdoc for details.
Adding comments to explain how these views are used is redundant to the
source code and liable to go out of date: however, this file is too confusing
without the redundant comments so we use them anyway. -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We want users to click the Google search tile, type in a query, and to search upon submission, i.e. no
visible EditText. However, users can only type into an EditText so we hide this one below other views in
the layout and programmatically shift focus to it (and thus the keyboard) when appropriate.
To hide the view, we make it tiny - 1x1 dp - and set its elevation to -8, which should be below all
other views. Then we put it in the corner underneath the home tiles view.
The previous implementation added this view to the layout dynamically but that undesirably forced focus
upon the added view: instead, this view is added on inflation. -->
<EditText
android:id="@+id/googleSearchHiddenEditText"
android:layout_width="1dp"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:elevation="-8dp"
android:hint="@string/google_search_hint_text"
android:inputType="text"
android:imeActionLabel="@null"
android:imeActionId="@integer/ime_action_search"
android:importantForAccessibility="no"/>
<!-- Visible in dialog mode, this is the semi opaque background sits behind the nav overlay. We
set not focusable because if it's focusable, this view is accessible by the screen reader
through the overlay background where there aren't home tiles.
This doesn't cover the AppBar (due to marginTop): another view does. That's necessary
because this view does not cover the App Bar unless we're animating so we have to make sure
these views do not overlap. See appBarSemiOpaqueBackground for a longer explanation. -->
<View
android:id="@+id/semiOpaqueBackground"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="@dimen/appbar_height"
android:background="@color/nav_overlay_semi_opaque_background"
android:focusable="false"/>
<!-- Available in dialog mode, this is the hit target - i.e. not visible - to dismiss the overlay because the
semi opaque background does not work for screen readers (see view comment for details). -->
<View
android:id="@+id/dismissHitTarget"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/backgroundView"
app:layout_constraintStart_toStartOf="parent"
android:background="@android:color/transparent"
android:contentDescription="@string/nav_close_hint"/>
<!-- Visible in initial homescreen mode, this view sits below the toolbar, where the WebView
would be. It's only visible under the main overlay background's rounded corners. Without
it, the white WebView (or garbage graphics buffer) would be shown. -->
<View
android:id="@+id/initialHomescreenBackground"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/overlayTopAsInitialHomescreen"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/photonGrey70"/>
<!-- Android's elevation only creates shadows facing downward so we create our own upward facing shadow,
The height must be tuned such that it is large enough that the bottom of this view is not visible and that
the gradient fades at the correct speed.
This shadow is not to spec: creating a shadow that has an equal drop off on corners and the top edge is
complex. The current implementation was created to be good enough with much trial and error. -->
<View
android:id="@+id/backgroundShadowView"
android:layout_height="48dp"
android:layout_width="0dp"
app:layout_constraintTop_toTopOf="@id/backgroundShadowOffset"
app:layout_constraintStart_toStartOf="@id/backgroundView"
app:layout_constraintEnd_toEndOf="@id/backgroundView"
android:background="@drawable/navigation_overlay_background_shadow"/>
<!-- The height of this view determines the height of the shadow. Unfortunately, offseting a constraint
(constraintTop_toTopOf=backgroundView - 8dp) doesn't seem otherwise possible so we use this spacer. -->
<Space
android:id="@+id/backgroundShadowOffset"
android:layout_width="match_parent"
android:layout_height="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/backgroundView"/>
<View
android:id="@+id/backgroundView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/homeTiles"
app:layout_constraintBottom_toBottomOf="@id/homeTiles"
app:layout_constraintStart_toStartOf="@id/homeTiles"
app:layout_constraintEnd_toEndOf="@id/homeTiles"
android:background="@drawable/navigation_overlay_background"/>
<!-- This view defines the dimensions of most other views in this layout. The height constraint configuration and
bias changes dynamically based on mode. In dialog mode, the height will wrap this view's content: one
consequence is that when tiles are removed, the height of the view may change. I have not confirmed with UX if
this is desirable.
From our desired horizontal padding, we must subtract the "margins" introduced by
the extended list item width (see home_tile.xml for details).
At the time of writing, 44dp padding is expected on the parent and between elements.
Each list item adds half of this (22dp) so the parent must specify half as well (22 + 22 = 44). -->
<org.mozilla.focus.browser.HomeTileGridNavigation
android:id="@+id/homeTiles"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:paddingStart="22dp"
android:paddingEnd="22dp"
android:paddingTop="44dp"
android:clipChildren="false"
android:clipToPadding="false">
<requestFocus/>
</org.mozilla.focus.browser.HomeTileGridNavigation>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/overlayTopAsInitialHomescreen"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintGuide_begin="@dimen/appbar_height"
android:orientation="horizontal"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/overlayTopAsDialog"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintGuide_begin="@dimen/navigation_overlay_bottom_as_dialog"
android:orientation="horizontal"/>
</androidx.constraintlayout.widget.ConstraintLayout>