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

Commit e6342bec authored by Edgar Wang's avatar Edgar Wang Committed by Android (Google) Code Review
Browse files

Merge "SettingsLib synced by Copybara"

parents 38b4352d c4859863
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -18,6 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.settingslib.widget">

    <uses-sdk android:minSdkVersion="29" />
    <uses-sdk android:minSdkVersion="21" />

</manifest>
+6 −0
Original line number Diff line number Diff line
@@ -29,6 +29,12 @@
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="?android:attr/actionBarTheme" />
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/support_action_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="?android:attr/actionBarTheme"
        android:visibility="gone" />
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
+179 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.android.settingslib.utils.BuildCompatUtils;
import com.android.settingslib.widget.R;

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

/**
 * A base Activity that has a collapsing toolbar layout is used for the activities intending to
 * enable the collapsing toolbar function.
 */
public class CollapsingToolbarAppCompatActivity extends AppCompatActivity {

    private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
        @Nullable
        @Override
        public ActionBar setActionBar(Toolbar toolbar) {
            return null;
        }

        @Nullable
        @Override
        public androidx.appcompat.app.ActionBar setActionBar(
                androidx.appcompat.widget.Toolbar toolbar) {
            CollapsingToolbarAppCompatActivity.super.setSupportActionBar(toolbar);
            return CollapsingToolbarAppCompatActivity.super.getSupportActionBar();
        }

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

    private CollapsingToolbarDelegate mToolbardelegate;

    private int mCustomizeLayoutResId = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (BuildCompatUtils.isAtLeastS()) {
            DynamicColors.applyToActivityIfAvailable(this);
        }
        setTheme(R.style.Theme_SubSettingsBase);

        if (mCustomizeLayoutResId > 0 && !BuildCompatUtils.isAtLeastS()) {
            super.setContentView(mCustomizeLayoutResId);
            return;
        }

        View view = getToolbarDelegate().onCreateView(getLayoutInflater(), null, this);
        super.setContentView(view);
    }

    @Override
    public void setContentView(int layoutResID) {
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.removeAllViews();
        }
        LayoutInflater.from(this).inflate(layoutResID, parent);
    }

    @Override
    public void setContentView(View view) {
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.addView(view);
        }
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
                : mToolbardelegate.getContentFrameLayout();
        if (parent != null) {
            parent.addView(view, params);
        }
    }

    /**
     * This method allows an activity to replace the default layout with a customize layout. Notice
     * that it will no longer apply the features being provided by this class when this method
     * gets called.
     */
    protected void setCustomizeContentView(int layoutResId) {
        mCustomizeLayoutResId = layoutResId;
    }

    @Override
    public void setTitle(CharSequence title) {
        getToolbarDelegate().setTitle(title);
    }

    @Override
    public void setTitle(int titleId) {
        setTitle(getText(titleId));
    }

    @Override
    public boolean onSupportNavigateUp() {
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStackImmediate();
        }

        // Closes the activity if there is no fragment inside the stack. Otherwise the activity will
        // has a blank screen since there is no any fragment.
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            finishAfterTransition();
        }
        return true;
    }

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

        // Closes the activity if there is no fragment inside the stack. Otherwise the activity will
        // has a blank screen since there is no any fragment. onBackPressed() in Activity.java only
        // handles popBackStackImmediate(). This will close activity to avoid a blank screen.
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            finishAfterTransition();
        }
    }

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

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

    private CollapsingToolbarDelegate getToolbarDelegate() {
        if (mToolbardelegate == null) {
            mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
        }
        return mToolbardelegate;
    }
}
+19 −1
Original line number Diff line number Diff line
@@ -117,12 +117,30 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {

    @Override
    public boolean onNavigateUp() {
        if (!super.onNavigateUp()) {
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStackImmediate();
        }

        // Closes the activity if there is no fragment inside the stack. Otherwise the activity will
        // has a blank screen since there is no any fragment.
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            finishAfterTransition();
        }
        return true;
    }

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

        // Closes the activity if there is no fragment inside the stack. Otherwise the activity will
        // has a blank screen since there is no any fragment. onBackPressed() in Activity.java only
        // handles popBackStackImmediate(). This will close activity to avoid a blank screen.
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            finishAfterTransition();
        }
    }

    /**
     * Returns an instance of collapsing toolbar.
     */
+69 −8
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ package com.android.settingslib.collapsingtoolbar;
import static android.text.Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;

import android.app.ActionBar;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.text.LineBreakConfig;
import android.os.Build;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -30,6 +32,7 @@ import android.widget.Toolbar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import com.android.settingslib.widget.R;
@@ -42,7 +45,7 @@ import com.google.android.material.appbar.CollapsingToolbarLayout;
 * extend from {@link CollapsingToolbarBaseActivity} or from {@link CollapsingToolbarBaseFragment}.
 */
public class CollapsingToolbarDelegate {

    private static final String TAG = "CTBdelegate";
    /** Interface to be implemented by the host of the Collapsing Toolbar. */
    public interface HostCallback {
        /**
@@ -53,6 +56,13 @@ public class CollapsingToolbarDelegate {
        @Nullable
        ActionBar setActionBar(Toolbar toolbar);

        /** Sets support tool bar and return support action bar, this is for AppCompatActivity. */
        @Nullable
        default androidx.appcompat.app.ActionBar setActionBar(
                androidx.appcompat.widget.Toolbar toolbar) {
            return null;
        }

        /** Sets a title on the host. */
        void setOuterTitle(CharSequence title);
    }
@@ -79,6 +89,13 @@ public class CollapsingToolbarDelegate {
    /** Method to call that creates the root view of the collapsing toolbar. */
    @SuppressWarnings("RestrictTo")
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
        return onCreateView(inflater, container, null);
    }

    /** Method to call that creates the root view of the collapsing toolbar. */
    @SuppressWarnings("RestrictTo")
    View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            Activity activity) {
        final View view =
                inflater.inflate(R.layout.collapsing_toolbar_base_layout, container, false);
        if (view instanceof CoordinatorLayout) {
@@ -99,19 +116,59 @@ public class CollapsingToolbarDelegate {
            }
        }
        autoSetCollapsingToolbarLayoutScrolling();
        mToolbar = view.findViewById(R.id.action_bar);
        mContentFrameLayout = view.findViewById(R.id.content_frame);
        if (activity instanceof AppCompatActivity) {
            Log.d(TAG, "onCreateView: from AppCompatActivity and sub-class.");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                initSupportActionBar(inflater);
            } else {
                initRSupportActionBar(view);
            }
        } else {
            Log.d(TAG, "onCreateView: from NonAppCompatActivity.");
            mToolbar = view.findViewById(R.id.action_bar);
            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;
    }

    private void initSupportActionBar(@NonNull LayoutInflater inflater) {
        if (mCollapsingToolbarLayout == null) {
            return;
        }
        mCollapsingToolbarLayout.removeAllViews();
        inflater.inflate(R.layout.support_toolbar, mCollapsingToolbarLayout);
        final androidx.appcompat.widget.Toolbar supportToolbar =
                mCollapsingToolbarLayout.findViewById(R.id.support_action_bar);
        final androidx.appcompat.app.ActionBar actionBar =
                mHostCallback.setActionBar(supportToolbar);
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayShowTitleEnabled(true);
        }
    }

    private void initRSupportActionBar(View view) {
        view.findViewById(R.id.action_bar).setVisibility(View.GONE);
        final androidx.appcompat.widget.Toolbar supportToolbar =
                view.findViewById(R.id.support_action_bar);
        supportToolbar.setVisibility(View.VISIBLE);
        final androidx.appcompat.app.ActionBar actionBar =
                mHostCallback.setActionBar(supportToolbar);
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayShowTitleEnabled(true);
        }
    }

    /** Return an instance of CoordinatorLayout. */
    @Nullable
    public CoordinatorLayout getCoordinatorLayout() {
@@ -160,10 +217,14 @@ public class CollapsingToolbarDelegate {
                new AppBarLayout.Behavior.DragCallback() {
                    @Override
                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                        // Header can be scrolling while device in landscape mode.
                        // Header can be scrolling while device in landscape mode and SDK > 33
                        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
                            return false;
                        } else {
                            return appBarLayout.getResources().getConfiguration().orientation
                                    == Configuration.ORIENTATION_LANDSCAPE;
                        }
                    }
                });
        params.setBehavior(behavior);
    }
Loading