Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 43b62a8e authored by Ben Lin's avatar Ben Lin
Browse files

Implementing breadcrumb for tablet devices for navigation in the bar.

Bug: 29214736
Change-Id: I37de2c39a55c33d7111496e896a0c85e1c7fa553
(cherry picked from commit 6fb1dfcc47b795b7071550a4524667d2f8f4d9a2)
parent d2f712d2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -41,8 +41,8 @@
                android:theme="?actionBarTheme"
                android:popupTheme="?actionBarPopupTheme">

                <Spinner
                    android:id="@+id/stack"
                <com.android.documentsui.DropdownBreadcrumb
                    android:id="@+id/breadcrumb"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="4dp"
+4 −8
Original line number Diff line number Diff line
@@ -39,14 +39,10 @@
            android:theme="?actionBarTheme"
            android:popupTheme="?actionBarPopupTheme">

            <Spinner
                android:id="@+id/stack"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="4dp"
                android:popupTheme="?actionBarPopupTheme"
                android:background="@android:color/transparent"
                android:overlapAnchor="true" />
            <com.android.documentsui.HorizontalBreadcrumb
                android:id="@+id/breadcrumb"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </com.android.documentsui.DocumentsToolbar>

+52 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2016 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.
-->


<!--
     CoordinatorLayout is necessary for various components (e.g. Snackbars, and
     floating action buttons) to operate correctly.
-->
<!--
     focusableInTouchMode is set in order to force key events to go to the activity's global key
     callback, which is necessary for proper event routing. See BaseActivity.onKeyDown.
-->

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="match_parent"
  android:layout_alignParentTop="true"
  android:gravity="center_vertical"
  android:orientation="horizontal">

    <TextView
        android:id="@+id/breadcrumb_text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:textAppearance="@android:style/TextAppearance.Material.Widget.ActionBar.Title" />

    <ImageView
        android:id="@+id/breadcrumb_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_breadcrumb_arrow"
        android:layout_marginTop="2dp"
        android:layout_marginRight="3dp"
        android:layout_marginLeft="3dp" />

</LinearLayout>
 No newline at end of file
+5 −9
Original line number Diff line number Diff line
@@ -48,9 +48,9 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Spinner;

import com.android.documentsui.MenuManager.DirectoryDetails;
import com.android.documentsui.NavigationViewManager.Breadcrumb;
import com.android.documentsui.SearchViewManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.AnimationView;
@@ -69,7 +69,7 @@ import java.util.List;
import java.util.concurrent.Executor;

public abstract class BaseActivity extends Activity
        implements SearchManagerListener, NavigationView.Environment {
        implements SearchManagerListener, NavigationViewManager.Environment {

    private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests";

@@ -78,7 +78,7 @@ public abstract class BaseActivity extends Activity
    RootsCache mRoots;
    SearchViewManager mSearchManager;
    DrawerController mDrawer;
    NavigationView mNavigator;
    NavigationViewManager mNavigator;
    List<EventListener> mEventListeners = new ArrayList<>();

    private final String mTag;
@@ -141,13 +141,9 @@ public abstract class BaseActivity extends Activity
        mSearchManager = new SearchViewManager(this, icicle);

        DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
        Breadcrumb breadcrumb = (Breadcrumb) findViewById(R.id.breadcrumb);
        setActionBar(toolbar);
        mNavigator = new NavigationView(
                mDrawer,
                toolbar,
                (Spinner) findViewById(R.id.stack),
                mState,
                this);
        mNavigator = new NavigationViewManager(mDrawer, toolbar, mState, this, breadcrumb);

        // Base classes must update result in their onCreate.
        setResult(Activity.RESULT_CANCELED);
+158 −0
Original line number Diff line number Diff line
@@ -16,159 +16,85 @@

package com.android.documentsui;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.android.documentsui.Shared.DEBUG;

import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.NavigationViewManager.Breadcrumb;
import com.android.documentsui.NavigationViewManager.Environment;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;

import java.util.function.Consumer;

/**
 * A facade over the portions of the app and drawer toolbars.
 * Dropdown implementation of breadcrumb used for phone device layouts
 */
class NavigationView {

    private static final String TAG = "NavigationView";

    private final DrawerController mDrawer;
    private final DocumentsToolbar mToolbar;
    private final Spinner mBreadcrumb;
    private final State mState;
    private final NavigationView.Environment mEnv;
    private final BreadcrumbAdapter mBreadcrumbAdapter;
public final class DropdownBreadcrumb extends Spinner implements Breadcrumb {

    private boolean mIgnoreNextNavigation;
    private DropdownAdapter mAdapter;

    public NavigationView(
            DrawerController drawer,
            DocumentsToolbar toolbar,
            Spinner breadcrumb,
            State state,
            NavigationView.Environment env) {
    public DropdownBreadcrumb(
            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

        mToolbar = toolbar;
        mBreadcrumb = breadcrumb;
        mDrawer = drawer;
        mState = state;
        mEnv = env;
    public DropdownBreadcrumb(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

        mBreadcrumbAdapter = new BreadcrumbAdapter(mState, mEnv);
        mToolbar.setNavigationOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        onNavigationIconClicked();
    public DropdownBreadcrumb(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

                });
    public DropdownBreadcrumb(Context context) {
        super(context);
    }

        mBreadcrumb.setOnItemSelectedListener(
    @Override
    public void setup(Environment env, State state, Consumer<Integer> listener) {
        mAdapter = new DropdownAdapter(state, env);
        setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    @Override
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) {
                        onBreadcrumbItemSelected(position);
                        listener.accept(position);
                    }

                    @Override
                    public void onNothingSelected(AdapterView<?> parent) {}
                });

    }

    private void onNavigationIconClicked() {
        if (mDrawer.isPresent()) {
            mDrawer.setOpen(true, DrawerController.OPENED_HAMBURGER);
        }
    }

    private void onBreadcrumbItemSelected(int position) {
        if (mIgnoreNextNavigation) {
            mIgnoreNextNavigation = false;
            return;
        }

        while (mState.stack.size() > position + 1) {
            mState.popDocument();
        }
        mEnv.refreshCurrentRootAndDirectory(AnimationView.ANIM_LEAVE);
    }

    void update() {

        // TODO: Looks to me like this block is never getting hit.
        if (mEnv.isSearchExpanded()) {
            mToolbar.setTitle(null);
            mBreadcrumb.setVisibility(View.GONE);
            mBreadcrumb.setAdapter(null);
            return;
        }

        mDrawer.setTitle(mEnv.getDrawerTitle());

        mToolbar.setNavigationIcon(getActionBarIcon());
        mToolbar.setNavigationContentDescription(R.string.drawer_open);

        if (mState.stack.size() <= 1) {
            showBreadcrumb(false);
            String title = mEnv.getCurrentRoot().title;
            if (DEBUG) Log.d(TAG, "New toolbar title is: " + title);
            mToolbar.setTitle(title);
        } else {
            showBreadcrumb(true);
            mToolbar.setTitle(null);
            mIgnoreNextNavigation = true;
            mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1, false);
        }

        if (DEBUG) Log.d(TAG, "Final toolbar title is: " + mToolbar.getTitle());
    }

    private void showBreadcrumb(boolean visibility) {
    @Override
    public void show(boolean visibility) {
        if (visibility) {
            mBreadcrumb.setVisibility(VISIBLE);
            mBreadcrumb.setAdapter(mBreadcrumbAdapter);
        } else {
            mBreadcrumb.setVisibility(GONE);
            mBreadcrumb.setAdapter(null);
        }
    }

    // Hamburger if drawer is present, else sad nullness.
    private @Nullable Drawable getActionBarIcon() {
        if (mDrawer.isPresent()) {
            return mToolbar.getContext().getDrawable(R.drawable.ic_hamburger);
            setVisibility(VISIBLE);
            setAdapter(mAdapter);
        } else {
            return null;
            setVisibility(GONE);
            setAdapter(null);
        }
    }

    void revealRootsDrawer(boolean open) {
        mDrawer.setOpen(open);
    @Override
    public void postUpdate() {
        setSelection(mAdapter.getCount() - 1, false);
    }

    /**
     * Class providing toolbar with runtime access to useful activity data.
     */
    static final class BreadcrumbAdapter extends BaseAdapter {

    private static final class DropdownAdapter extends BaseAdapter {
        private Environment mEnv;
        private State mState;

        public BreadcrumbAdapter(State state, Environment env) {
        public DropdownAdapter(State state, Environment env) {
            mState = state;
            mEnv = env;
        }
@@ -229,10 +155,4 @@ class NavigationView {
        }
    }

    interface Environment {
        RootInfo getCurrentRoot();
        String getDrawerTitle();
        void refreshCurrentRootAndDirectory(int animation);
        boolean isSearchExpanded();
    }
}
Loading