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

Commit 20b67790 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow to use the collapsing toolbar without forcing specific...

Merge "Allow to use the collapsing toolbar without forcing specific inheritance structure on the host."
parents 4090f0da 2dc15360
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.settingslib.collapsingtoolbar;

import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceFragmentCompat;

import com.android.settingslib.utils.BuildCompatUtils;

import com.google.android.material.appbar.AppBarLayout;

/**
 * A base fragment that supports multi-fragments in one activity. The activity likes to switch the
 * different fragments which extend this base fragment and must use the following code to add the
 * fragment to stack.
 *
 * protected void onCreate(Bundle savedState) {
 *    // omitted…
 *    getFragmentManager()
 *            .beginTransaction()
 *            .add(R.id.content_frame, new Your_Fragment())
 *            // Add root page to back-history
 *            .addToBackStack( null)
 *            .commit();
 *    // omitted
 * }
 */
public abstract class BasePreferencesFragment extends PreferenceFragmentCompat {

    /**
     * Gets the title which the fragment likes to show on app bar. The child class must implement
     * this
     * function.
     *
     * @return The title of the fragment will show on app bar.
     */
    public abstract CharSequence getTitle();

    @Override
    public void onResume() {
        super.onResume();

        FragmentActivity activity = getActivity();
        if (activity != null) {
            activity.setTitle(getTitle());

            if (BuildCompatUtils.isAtLeastS()) {
                AppBarLayout appBarLayout = (AppBarLayout) activity.findViewById(R.id.app_bar);

                if (appBarLayout != null) {
                    appBarLayout.setExpanded(/* expanded= */ true);
                }
            }
        }
    }
}
+28 −59
Original line number Diff line number Diff line
@@ -23,16 +23,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentActivity;

import com.android.settingslib.utils.BuildCompatUtils;

import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.resources.TextAppearanceConfig;

/**
 * A base Activity that has a collapsing toolbar layout is used for the activities intending to
@@ -40,12 +37,22 @@ import com.google.android.material.resources.TextAppearanceConfig;
 */
public class CollapsingToolbarBaseActivity extends FragmentActivity {

    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;

    @Nullable
    private CollapsingToolbarLayout mCollapsingToolbarLayout;
    private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
        @Nullable
    private AppBarLayout mAppBarLayout;
        @Override
        public ActionBar setActionBar(Toolbar toolbar) {
            CollapsingToolbarBaseActivity.super.setActionBar(toolbar);
            return CollapsingToolbarBaseActivity.super.getActionBar();
        }

        @Override
        public void setOuterTitle(CharSequence title) {
            CollapsingToolbarBaseActivity.super.setTitle(title);
        }
    }

    private CollapsingToolbarDelegate mToolbardelegate;

    private int mCustomizeLayoutResId = 0;

    @Override
@@ -55,31 +62,16 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
            super.setContentView(mCustomizeLayoutResId);
            return;
        }
        // Force loading font synchronously for collapsing toolbar layout
        TextAppearanceConfig.setShouldLoadFontSynchronously(true);
        super.setContentView(R.layout.collapsing_toolbar_base_layout);
        mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
        mAppBarLayout = findViewById(R.id.app_bar);
        if (mCollapsingToolbarLayout != null) {
            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
        }
        disableCollapsingToolbarLayoutScrollingBehavior();

        final Toolbar toolbar = findViewById(R.id.action_bar);
        setActionBar(toolbar);

        // Enable title and home button by default
        final ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayShowTitleEnabled(true);
        }
        mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
        View view = mToolbardelegate.onCreateView(getLayoutInflater(), null);
        super.setContentView(view);
    }

    @Override
    public void setContentView(int layoutResID) {
        final ViewGroup parent = findViewById(R.id.content_frame);
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.removeAllViews();
        }
@@ -88,7 +80,8 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {

    @Override
    public void setContentView(View view) {
        final ViewGroup parent = findViewById(R.id.content_frame);
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.addView(view);
        }
@@ -96,7 +89,8 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        final ViewGroup parent = findViewById(R.id.content_frame);
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.addView(view, params);
        }
@@ -113,20 +107,12 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {

    @Override
    public void setTitle(CharSequence title) {
        if (mCollapsingToolbarLayout != null) {
            mCollapsingToolbarLayout.setTitle(title);
        } else {
            super.setTitle(title);
        }
        mToolbardelegate.setTitle(title);
    }

    @Override
    public void setTitle(int titleId) {
        if (mCollapsingToolbarLayout != null) {
            mCollapsingToolbarLayout.setTitle(getText(titleId));
        } else {
            super.setTitle(titleId);
        }
        setTitle(getText(titleId));
    }

    @Override
@@ -142,7 +128,7 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
     */
    @Nullable
    public CollapsingToolbarLayout getCollapsingToolbarLayout() {
        return mCollapsingToolbarLayout;
        return mToolbardelegate.getCollapsingToolbarLayout();
    }

    /**
@@ -150,23 +136,6 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
     */
    @Nullable
    public AppBarLayout getAppBarLayout() {
        return mAppBarLayout;
    }

    private void disableCollapsingToolbarLayoutScrollingBehavior() {
        if (mAppBarLayout == null) {
            return;
        }
        final CoordinatorLayout.LayoutParams params =
                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
        behavior.setDragCallback(
                new AppBarLayout.Behavior.DragCallback() {
                    @Override
                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                        return false;
                    }
                });
        params.setBehavior(behavior);
        return mToolbardelegate.getAppBarLayout();
    }
}
+27 −54
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@

package com.android.settingslib.collapsingtoolbar;

import android.os.Build;
import android.app.ActionBar;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,44 +38,33 @@ import com.google.android.material.appbar.CollapsingToolbarLayout;
 */
public abstract class CollapsingToolbarBaseFragment extends Fragment {

    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;

    @Nullable
    private CoordinatorLayout mCoordinatorLayout;
    @Nullable
    private CollapsingToolbarLayout mCollapsingToolbarLayout;
    @Nullable
    private AppBarLayout mAppBarLayout;
    @NonNull
    private Toolbar mToolbar;
    @NonNull
    private FrameLayout mContentFrameLayout;

    private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
        @Nullable
        @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
                false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            mCoordinatorLayout = view.findViewById(R.id.content_parent);
        public ActionBar setActionBar(Toolbar toolbar) {
            requireActivity().setActionBar(toolbar);
            return null;
        }
        mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
        mAppBarLayout = view.findViewById(R.id.app_bar);
        if (mCollapsingToolbarLayout != null) {
            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);

        @Override
        public void setOuterTitle(CharSequence title) {
            // ignore
        }
        disableCollapsingToolbarLayoutScrollingBehavior();
        mToolbar = view.findViewById(R.id.action_bar);
        mContentFrameLayout = view.findViewById(R.id.content_frame);
        return view;
    }

    private CollapsingToolbarDelegate mToolbardelegate;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    public void onAttach(Context context) {
        super.onAttach(context);
        mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
    }

        requireActivity().setActionBar(mToolbar);
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return mToolbardelegate.onCreateView(inflater, container);
    }

    /**
@@ -82,7 +72,7 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
     */
    @Nullable
    public CoordinatorLayout getCoordinatorLayout() {
        return mCoordinatorLayout;
        return mToolbardelegate.getCoordinatorLayout();
    }

    /**
@@ -90,7 +80,7 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
     */
    @Nullable
    public AppBarLayout getAppBarLayout() {
        return mAppBarLayout;
        return mToolbardelegate.getAppBarLayout();
    }

    /**
@@ -98,7 +88,7 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
     */
    @Nullable
    public CollapsingToolbarLayout getCollapsingToolbarLayout() {
        return mCollapsingToolbarLayout;
        return mToolbardelegate.getCollapsingToolbarLayout();
    }

    /**
@@ -106,23 +96,6 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
     */
    @NonNull
    public FrameLayout getContentFrameLayout() {
        return mContentFrameLayout;
    }

    private void disableCollapsingToolbarLayoutScrollingBehavior() {
        if (mAppBarLayout == null) {
            return;
        }
        final CoordinatorLayout.LayoutParams params =
                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
        behavior.setDragCallback(
                new AppBarLayout.Behavior.DragCallback() {
                    @Override
                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                        return false;
                    }
                });
        params.setBehavior(behavior);
        return mToolbardelegate.getContentFrameLayout();
    }
}
+153 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.settingslib.collapsingtoolbar;

import android.app.ActionBar;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toolbar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;

/**
 * A delegate that allows to use the collapsing toolbar layout in hosts that doesn't want/need to
 * extend from {@link CollapsingToolbarBaseActivity} or from {@link CollapsingToolbarBaseFragment}.
 */
public class CollapsingToolbarDelegate {

    /** Interface to be implemented by the host of the Collapsing Toolbar. */
    public interface HostCallback {
        /**
         * Called when a Toolbar should be set on the host.
         *
         * <p>If the host wants action bar to be modified, it should return it.
         */
        @Nullable
        ActionBar setActionBar(Toolbar toolbar);

        /** Sets a title on the host. */
        void setOuterTitle(CharSequence title);
    }

    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;

    @Nullable
    private CoordinatorLayout mCoordinatorLayout;
    @Nullable
    private CollapsingToolbarLayout mCollapsingToolbarLayout;
    @Nullable
    private AppBarLayout mAppBarLayout;
    @NonNull
    private Toolbar mToolbar;
    @NonNull
    private FrameLayout mContentFrameLayout;
    @NonNull
    private final HostCallback mHostCallback;

    public CollapsingToolbarDelegate(@NonNull HostCallback hostCallback) {
        mHostCallback = hostCallback;
    }

    /** Method to call that creates the root view of the collapsing toolbar. */
    @SuppressWarnings("RestrictTo")
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
        final View view =
                inflater.inflate(R.layout.collapsing_toolbar_base_layout, container, false);
        if (view instanceof CoordinatorLayout) {
            mCoordinatorLayout = (CoordinatorLayout) view;
        }
        mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
        mAppBarLayout = view.findViewById(R.id.app_bar);
        if (mCollapsingToolbarLayout != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
        }
        disableCollapsingToolbarLayoutScrollingBehavior();
        mToolbar = view.findViewById(R.id.action_bar);
        mContentFrameLayout = view.findViewById(R.id.content_frame);
        final ActionBar actionBar = mHostCallback.setActionBar(mToolbar);

        // Enable title and home button by default
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayShowTitleEnabled(true);
        }
        return view;
    }

    /** Return an instance of CoordinatorLayout. */
    @Nullable
    public CoordinatorLayout getCoordinatorLayout() {
        return mCoordinatorLayout;
    }

    /** Sets the title on the collapsing layout, delegating to host if needed. */
    public void setTitle(CharSequence title) {
        if (mCollapsingToolbarLayout != null) {
            mCollapsingToolbarLayout.setTitle(title);
        } else {
            mHostCallback.setOuterTitle(title);
        }
    }

    /** Returns an instance of collapsing toolbar. */
    @Nullable
    public CollapsingToolbarLayout getCollapsingToolbarLayout() {
        return mCollapsingToolbarLayout;
    }

    /** Return the content frame layout. */
    @NonNull
    public FrameLayout getContentFrameLayout() {
        return mContentFrameLayout;
    }

    public Toolbar getToolbar() {
        return mToolbar;
    }

    /** Return an instance of app bar. */
    @Nullable
    public AppBarLayout getAppBarLayout() {
        return mAppBarLayout;
    }

    private void disableCollapsingToolbarLayoutScrollingBehavior() {
        if (mAppBarLayout == null) {
            return;
        }
        final CoordinatorLayout.LayoutParams params =
                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
        behavior.setDragCallback(
                new AppBarLayout.Behavior.DragCallback() {
                    @Override
                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                        return false;
                    }
                });
        params.setBehavior(behavior);
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import androidx.fragment.app.FragmentActivity;
 * Settings transition applied.
 */
public abstract class SettingsTransitionActivity extends FragmentActivity {
    private static final String TAG = "SettingsTransitionActivity";

    protected boolean isSettingsTransitionEnabled() {
        return false;