fix: 首次提交

This commit is contained in:
2024-12-09 11:25:23 +08:00
parent d0c01071e9
commit 2c2109a5f3
4741 changed files with 290641 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_library {
name: "SettingsLibCollapsingToolbarBaseActivity",
use_resource_processor: true,
defaults: [
"SettingsLintDefaults",
],
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
static_libs: [
"androidx.annotation_annotation",
"androidx.core_core",
"com.google.android.material_material",
"SettingsLibSettingsTransition",
"SettingsLibUtils",
"SettingsLibSettingsTheme",
],
sdk_version: "system_current",
min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
"com.android.devicelock",
"com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
],
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.collapsingtoolbar">
<uses-sdk android:minSdkVersion="21" />
</manifest>

View File

@@ -0,0 +1,56 @@
/**
* Include this gradle file if you are building against this as a standalone gradle library project,
* as opposed to building it as part of the git-tree. This is typically the file you want to include
* if you create a new project in Android Studio.
*
* For example, you can include the following in your settings.gradle file:
* include ':setupcompat'
* project(':setupcompat').projectDir = new File(PATH_TO_THIS_DIRECTORY)
*
* And then you can include the :setupcompat project as one of your dependencies
* dependencies {
* implementation project(path: ':setupcompat')
* }
*/
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
// Not specifying compileSdkVersion here so clients can specify it; must be at least Q
namespace = "com.android.settingslib.collapsingtoolbar"
compileSdk 34
defaultConfig {
minSdkVersion 31
targetSdkVersion 34
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.flags'
}
}
sourceSets.main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
dependencies {
implementation libs.androidx.annotation.annotation
implementation libs.androidx.core.core
implementation libs.material
implementation project(':SettingsLib:SettingsTransition')
implementation project(':SettingsLib:Utils')
implementation project(':SettingsLib:SettingsTheme')
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="@layout/collapsing_toolbar_content_layout"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:outlineAmbientShadowColor="@android:color/transparent"
android:outlineSpotShadowColor="@android:color/transparent"
android:background="@android:color/transparent"
android:theme="@style/Theme.CollapsingToolbar.Settings">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/settingslib_toolbar_layout_height"
android:clipToPadding="false"
app:forceApplySystemWindowInsetTop="true"
app:extraMultilineHeightEnabled="true"
app:contentScrim="@color/settingslib_colorSurfaceHeader"
app:maxLines="3"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:scrimAnimationDuration="50"
app:scrimVisibleHeightTrigger="@dimen/settingslib_scrim_visible_height_trigger"
app:statusBarScrim="@null"
app:titleCollapseMode="fade"
app:collapsedTitleTextAppearance="@style/CollapsingToolbarTitle.Collapsed"
app:expandedTitleTextAppearance="@style/CollapsingToolbarTitle.Expanded"
app:expandedTitleMarginStart="@dimen/expanded_title_margin_start"
app:expandedTitleMarginEnd="@dimen/expanded_title_margin_end"
app:toolbarId="@id/action_bar">
<Toolbar
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="?android:attr/actionBarTheme"
android:transitionName="shared_element_view"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</merge>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/support_action_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="?android:attr/actionBarTheme"
android:transitionName="shared_element_view"
app:layout_collapseMode="pin" />

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<!-- The main content view -->
<LinearLayout
android:id="@+id/content_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:transitionGroup="true"
android:orientation="vertical">
<Toolbar
android:id="@+id/action_bar"
style="?android:attr/actionBarStyle"
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"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
<item name="colorPrimary">@color/settingslib_primary_dark_device_default_settings</item>
<item name="colorAccent">@color/settingslib_accent_device_default_dark</item>
</style>
</resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<declare-styleable name="CollapsingCoordinatorLayout">
<!-- assign a title of collapsing toolbar title. -->
<attr name="collapsing_toolbar_title" format="string" />
<attr name="content_frame_height_match_parent" format="boolean" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Collapsing toolbar layout dimensions -->
<dimen name="settingslib_toolbar_layout_height">179dp</dimen>
<dimen name="settingslib_scrim_visible_height_trigger">137dp</dimen>
<dimen name="expanded_title_margin_start">24dp</dimen>
<dimen name="expanded_title_margin_end">24dp</dimen>
</resources>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20dp</item>
<item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
<style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
<item name="android:textSize">36dp</item>
<item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
</resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
<item name="colorPrimary">@color/settingslib_primary_device_default_settings_light</item>
<item name="colorAccent">@color/settingslib_accent_device_default_light</item>
</style>
</resources>

View File

@@ -0,0 +1,70 @@
/*
* 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);
}
}
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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.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(com.android.settingslib.widget.theme.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;
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.content.pm.PackageManager;
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.fragment.app.FragmentActivity;
import com.android.settingslib.utils.BuildCompatUtils;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
/**
* A base Activity that has a collapsing toolbar layout is used for the activities intending to
* enable the collapsing toolbar function.
*/
public class CollapsingToolbarBaseActivity extends FragmentActivity {
private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
@Nullable
@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
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// for backward compatibility on R devices or wearable devices due to small device size.
if (mCustomizeLayoutResId > 0 && (!BuildCompatUtils.isAtLeastS() || isWatch())) {
super.setContentView(mCustomizeLayoutResId);
return;
}
View view = getToolbarDelegate().onCreateView(getLayoutInflater(), null);
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 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.
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return getToolbarDelegate().getCollapsingToolbarLayout();
}
/**
* Return an instance of app bar.
*/
@Nullable
public AppBarLayout getAppBarLayout() {
return getToolbarDelegate().getAppBarLayout();
}
private boolean isWatch() {
PackageManager packageManager = getPackageManager();
if (packageManager == null) {
return false;
}
return packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
}
private CollapsingToolbarDelegate getToolbarDelegate() {
if (mToolbardelegate == null) {
mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
}
return mToolbardelegate;
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.content.Context;
import android.os.Bundle;
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 androidx.fragment.app.Fragment;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
/**
* A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
*/
public abstract class CollapsingToolbarBaseFragment extends Fragment {
private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
@Nullable
@Override
public ActionBar setActionBar(Toolbar toolbar) {
requireActivity().setActionBar(toolbar);
return null;
}
@Override
public void setOuterTitle(CharSequence title) {
// ignore
}
}
private CollapsingToolbarDelegate mToolbardelegate;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return mToolbardelegate.onCreateView(inflater, container);
}
/**
* Return an instance of CoordinatorLayout.
*/
@Nullable
public CoordinatorLayout getCoordinatorLayout() {
return mToolbardelegate.getCoordinatorLayout();
}
/**
* Return an instance of app bar.
*/
@Nullable
public AppBarLayout getAppBarLayout() {
return mToolbardelegate.getAppBarLayout();
}
/**
* Return the collapsing toolbar layout.
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mToolbardelegate.getCollapsingToolbarLayout();
}
/**
* Return the content frame layout.
*/
@NonNull
public FrameLayout getContentFrameLayout() {
return mToolbardelegate.getContentFrameLayout();
}
}

View File

@@ -0,0 +1,228 @@
/*
* 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 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;
import android.widget.FrameLayout;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
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 {
private static final String TAG = "CTBdelegate";
/** 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 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);
}
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) {
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) {
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);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
mCollapsingToolbarLayout.setStaticLayoutBuilderConfigurer(builder ->
builder.setLineBreakConfig(
new LineBreakConfig.Builder()
.setLineBreakWordStyle(
LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
.build()));
}
}
autoSetCollapsingToolbarLayoutScrolling();
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() {
return mCoordinatorLayout;
}
/** Sets the title on the collapsing layout and delegates to host. */
public void setTitle(CharSequence title) {
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setTitle(title);
}
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 autoSetCollapsingToolbarLayoutScrolling() {
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) {
// 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);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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;
/**
* A base Activity for Settings-specific page transition. Activities extending it will get
* Settings transition applied.
*/
public abstract class SettingsTransitionActivity extends FragmentActivity {
protected boolean isSettingsTransitionEnabled() {
return false;
}
}

View File

@@ -0,0 +1,288 @@
/*
* 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.widget;
import static android.text.Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.text.LineBreakConfig;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.android.settingslib.collapsingtoolbar.R;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
/**
* This widget is wrapping the collapsing toolbar and can be directly used by the
* {@link AppCompatActivity}.
*/
@RequiresApi(Build.VERSION_CODES.S)
public class CollapsingCoordinatorLayout extends CoordinatorLayout {
private static final String TAG = "CollapsingCoordinator";
private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
private CharSequence mToolbarTitle;
private boolean mIsMatchParentHeight;
private CollapsingToolbarLayout mCollapsingToolbarLayout;
private AppBarLayout mAppBarLayout;
public CollapsingCoordinatorLayout(@NonNull Context context) {
this(context, /* attrs= */ null);
}
public CollapsingCoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, /* defStyleAttr= */ 0);
}
public CollapsingCoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
mIsMatchParentHeight = false;
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CollapsingCoordinatorLayout);
mToolbarTitle = a.getText(
R.styleable.CollapsingCoordinatorLayout_collapsing_toolbar_title);
mIsMatchParentHeight = a.getBoolean(
R.styleable.CollapsingCoordinatorLayout_content_frame_height_match_parent,
false);
a.recycle();
}
init();
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (child.getId() == R.id.content_frame && mIsMatchParentHeight) {
// User want to change the height of content_frame view as match_parent.
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
}
final ViewGroup contentView = findViewById(R.id.content_frame);
if (contentView != null && isContentFrameChild(child.getId())) {
contentView.addView(child, index, params);
} else {
super.addView(child, index, params);
}
}
private boolean isContentFrameChild(int id) {
if (id == R.id.app_bar || id == R.id.content_frame) {
return false;
}
return true;
}
private void init() {
inflate(getContext(), R.layout.collapsing_toolbar_content_layout, this);
mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
mAppBarLayout = findViewById(R.id.app_bar);
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
mCollapsingToolbarLayout.setStaticLayoutBuilderConfigurer(builder ->
builder.setLineBreakConfig(
new LineBreakConfig.Builder()
.setLineBreakWordStyle(
LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
.build()));
}
if (!TextUtils.isEmpty(mToolbarTitle)) {
mCollapsingToolbarLayout.setTitle(mToolbarTitle);
}
}
autoSetCollapsingToolbarLayoutScrolling();
}
/**
* Initialize some attributes of {@link ActionBar}.
*
* @param activity The host activity using the CollapsingCoordinatorLayout.
*/
public void initSettingsStyleToolBar(Activity activity) {
if (activity == null) {
Log.w(TAG, "initSettingsStyleToolBar: activity is null");
return;
}
if (activity instanceof AppCompatActivity) {
initSettingsStyleToolBar((SupportActionBarHost)
toolBar -> {
AppCompatActivity appCompatActivity = (AppCompatActivity) activity;
appCompatActivity.setSupportActionBar(toolBar);
return appCompatActivity.getSupportActionBar();
});
} else {
initSettingsStyleToolBar((ActionBarHost)
toolBar -> {
activity.setActionBar(toolBar);
return activity.getActionBar();
});
}
}
/**
* Initialize some attributes of {@link ActionBar}.
*
* @param actionBarHost Host Activity that is not AppCompat.
*/
public void initSettingsStyleToolBar(ActionBarHost actionBarHost) {
if (actionBarHost == null) {
Log.w(TAG, "initSettingsStyleToolBar: actionBarHost is null");
return;
}
final Toolbar toolbar = findViewById(R.id.action_bar);
final ActionBar actionBar = actionBarHost.setupActionBar(toolbar);
// Enable title and home button by default
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
}
}
/**
* Initialize some attributes of {@link ActionBar}.
*
* @param supportActionBarHost Host Activity that is AppCompat.
*/
public void initSettingsStyleToolBar(SupportActionBarHost supportActionBarHost) {
if (supportActionBarHost == null) {
Log.w(TAG, "initSettingsStyleToolBar: supportActionBarHost is null");
return;
}
if (mCollapsingToolbarLayout == null) {
return;
}
mCollapsingToolbarLayout.removeAllViews();
inflate(getContext(), R.layout.support_toolbar, mCollapsingToolbarLayout);
final androidx.appcompat.widget.Toolbar supportToolbar =
mCollapsingToolbarLayout.findViewById(R.id.support_action_bar);
final androidx.appcompat.app.ActionBar actionBar =
supportActionBarHost.setupSupportActionBar(supportToolbar);
// Enable title and home button by default
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
}
}
/**
* Initialize some attributes of {@link ActionBar} and assign the title of collapsing toolbar.
*
* @param activity The host activity using the CollapsingCoordinatorLayout.
* @param title The new title of collapsing toolbar.
*/
public void initSettingsStyleToolBar(Activity activity, CharSequence title) {
if (activity == null) {
Log.w(TAG, "initSettingsStyleToolBar: activity is null");
return;
}
initSettingsStyleToolBar(activity);
if (!TextUtils.isEmpty(title) && mCollapsingToolbarLayout != null) {
mToolbarTitle = title;
mCollapsingToolbarLayout.setTitle(mToolbarTitle);
}
}
/** Returns an instance of collapsing toolbar. */
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mCollapsingToolbarLayout;
}
/** Return an instance of app bar. */
public AppBarLayout getAppBarLayout() {
return mAppBarLayout;
}
/** Returns the content frame layout. */
public View getContentFrameLayout() {
return findViewById(R.id.content_frame);
}
/** Returns the AppCompat Toolbar. */
public androidx.appcompat.widget.Toolbar getSupportToolbar() {
return (androidx.appcompat.widget.Toolbar)
mCollapsingToolbarLayout.findViewById(R.id.support_action_bar);
}
private void autoSetCollapsingToolbarLayoutScrolling() {
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) {
// 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);
}
/** Interface to be implemented by a host Activity that is not AppCompat. */
public interface ActionBarHost {
/**
* Sets a Toolbar as an actionBar and optionally returns an ActionBar represented by
* this toolbar if it should be used.
*/
@Nullable ActionBar setupActionBar(Toolbar toolbar);
}
/** Interface to be implemented by a host Activity that is AppCompat. */
public interface SupportActionBarHost {
/**
* Sets a Toolbar as an actionBar and optionally returns an ActionBar represented by
* this toolbar if it should be used.
*/
@Nullable androidx.appcompat.app.ActionBar setupSupportActionBar(
androidx.appcompat.widget.Toolbar toolbar);
}
}