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

Commit c4859863 authored by Edgar Wang's avatar Edgar Wang
Browse files

SettingsLib synced by Copybara

CollapsingToolbarBaseActivity
 - Add CollapsingToolbarAppCompatActivity to support AppCompatActivity
 - Adjust minSDK back to 21
MainSwitchPreference
 - support iconSpaceReserved before S

Test: manual & robotest
Change-Id: I184764c476cb0142a7f8c967fb09588d8ff6879d
parent 37f3eda7
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