Add CollapsingToolbarLayout for sub settings
Settings app is planning to make toolbar collapsible for next Android release. This CL is to add a new layout for CollapsingToolbarLayout in the Settings app and to update the theme correspondly. This feature will be controlled by feature flag, which makes Settings app compacitible with the existing layout. Bug: 174451673 Test: manul test and visual verification 1) Enable the feature and open Settings app 2) Navigate to each sub page and check if toolbar is collapsible Change-Id: Ibef524bbaa7ae3f0a43db7e40e599f42e009437f
This commit is contained in:
@@ -174,7 +174,8 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".SubSettings"/>
|
||||
<activity android:name=".SubSettings"
|
||||
android:theme="@style/Theme.SubSettings" />
|
||||
|
||||
<activity android:name=".Settings$CreateShortcutActivity"
|
||||
android:exported="true"
|
||||
|
64
res/layout/settings_collapsing_base_layout.xml
Normal file
64
res/layout/settings_collapsing_base_layout.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/content_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="160dp"
|
||||
android:theme="@style/Theme.CollapsingToolbar.Settings">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/collapsing_toolbar"
|
||||
android:background="?android:attr/colorPrimary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:maxLines="3"
|
||||
app:contentScrim="?android:attr/colorPrimary"
|
||||
app:collapsedTitleTextAppearance="@style/ToolbarText.Collapsed"
|
||||
app:statusBarScrim="?android:attr/colorPrimary"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||
app:toolbarId="@id/tool_bar">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/tool_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_collapseMode="pin"
|
||||
app:contentInsetStart="68dp"/>
|
||||
|
||||
<Toolbar
|
||||
android:id="@+id/action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_collapseMode="pin"
|
||||
android:theme="?android:attr/actionBarTheme"/>
|
||||
|
||||
</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"/>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@@ -44,4 +44,10 @@
|
||||
<style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorPrimary">@*android:color/edge_effect_device_default_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.CollapsingToolbar.Settings"
|
||||
parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
|
||||
<item name="colorAccent">@*android:color/accent_device_default_dark</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
@@ -874,4 +874,17 @@
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
|
||||
<style name="ToolbarText.Collapsed"
|
||||
parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
|
||||
</style>
|
||||
|
||||
<style name="ToolbarText"
|
||||
parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" >
|
||||
<item name="android:textSize">32sp</item>
|
||||
</style>
|
||||
|
||||
<style name="ToolbarText.MoreThanTwoLines">
|
||||
<item name="android:textSize">24sp</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
@@ -72,7 +72,7 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SubSettings.Base" parent="Theme.Settings">
|
||||
<style name="Theme.SubSettings.Base" parent="Theme.Settings.NoActionBar">
|
||||
<!-- Redefine the ActionBar style for contentInsetStart -->
|
||||
<item name="android:actionBarStyle">@style/Widget.ActionBar.SubSettings</item>
|
||||
|
||||
@@ -276,4 +276,10 @@
|
||||
<style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorPrimary">@*android:color/edge_effect_device_default_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.CollapsingToolbar.Settings"
|
||||
parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
|
||||
<item name="colorAccent">@*android:color/accent_device_default_light</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
@@ -288,7 +288,9 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(!isInSetupWizard);
|
||||
actionBar.setHomeButtonEnabled(!isInSetupWizard);
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
// TODO(b/176882938): Enable title after material component updated
|
||||
// If CollapsingToolbarLayout is applied, the old action bar won't show title.
|
||||
actionBar.setDisplayShowTitleEnabled(mCollapsingToolbarLayout == null);
|
||||
}
|
||||
mSwitchBar = findViewById(R.id.switch_bar);
|
||||
if (mSwitchBar != null) {
|
||||
|
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -42,6 +43,7 @@ import androidx.preference.PreferenceScreen;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.core.FeatureFlags;
|
||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.search.actionbar.SearchMenuController;
|
||||
@@ -126,8 +128,11 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
// TODO(b/176883483): Remove both search and help menu if this feature rolled out
|
||||
if (!FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) {
|
||||
SearchMenuController.init(this /* host */);
|
||||
HelpMenuController.init(this /* host */);
|
||||
}
|
||||
|
||||
if (icicle != null) {
|
||||
mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
|
||||
|
@@ -29,6 +29,7 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -43,8 +44,11 @@ import com.android.settings.SubSettings;
|
||||
import com.android.settings.dashboard.CategoryManager;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -55,6 +59,7 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
protected static final boolean DEBUG_TIMING = false;
|
||||
private static final String TAG = "SettingsBaseActivity";
|
||||
private static final String DATA_SCHEME_PKG = "package";
|
||||
private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
|
||||
|
||||
// Serves as a temporary list of tiles to ignore until we heard back from the PM that they
|
||||
// are disabled.
|
||||
@@ -62,6 +67,8 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
|
||||
private final PackageReceiver mPackageReceiver = new PackageReceiver();
|
||||
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
|
||||
|
||||
protected CollapsingToolbarLayout mCollapsingToolbarLayout;
|
||||
private int mCategoriesUpdateTaskCount;
|
||||
|
||||
@Override
|
||||
@@ -79,21 +86,30 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
}
|
||||
// Apply SetupWizard light theme during setup flow. This is for SubSettings pages.
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent()) && this instanceof SubSettings) {
|
||||
final boolean isAnySetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (isAnySetupWizard && this instanceof SubSettings) {
|
||||
setTheme(R.style.LightTheme_SubSettings_SetupWizard);
|
||||
}
|
||||
super.setContentView(R.layout.settings_base_layout);
|
||||
|
||||
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME)
|
||||
&& isToolbarEnabled() && !isAnySetupWizard) {
|
||||
super.setContentView(R.layout.settings_collapsing_base_layout);
|
||||
mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
|
||||
} else {
|
||||
super.setContentView(R.layout.settings_base_layout);
|
||||
}
|
||||
|
||||
// This is to hide the toolbar from those pages which don't need a toolbar originally.
|
||||
final Toolbar toolbar = findViewById(R.id.action_bar);
|
||||
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
|
||||
if (!isToolbarEnabled() || isAnySetupWizard) {
|
||||
toolbar.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
setActionBar(toolbar);
|
||||
initCollapsingToolbar();
|
||||
|
||||
if (DEBUG_TIMING) {
|
||||
Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
|
||||
+ " ms");
|
||||
Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +167,70 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
if (mCollapsingToolbarLayout != null) {
|
||||
mCollapsingToolbarLayout.setTitle(title);
|
||||
}
|
||||
super.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int titleId) {
|
||||
if (mCollapsingToolbarLayout != null) {
|
||||
mCollapsingToolbarLayout.setTitle(getText(titleId));
|
||||
}
|
||||
super.setTitle(titleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* SubSetting page should show a toolbar by default. If the page wouldn't show a toolbar,
|
||||
* override this method and return false value.
|
||||
* @return ture by default
|
||||
*/
|
||||
protected boolean isToolbarEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initCollapsingToolbar() {
|
||||
if (mCollapsingToolbarLayout == null) {
|
||||
return;
|
||||
}
|
||||
mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
v.removeOnLayoutChangeListener(this);
|
||||
final int count = getLineCount();
|
||||
if (count > TOOLBAR_MAX_LINE_NUMBER) {
|
||||
mCollapsingToolbarLayout
|
||||
.setExpandedTitleTextAppearance(R.style.ToolbarText_MoreThanTwoLines);
|
||||
} else {
|
||||
mCollapsingToolbarLayout.setExpandedTitleTextAppearance(R.style.ToolbarText);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getLineCount() {
|
||||
try {
|
||||
final Class<?> toolbarClazz = mCollapsingToolbarLayout.getClass();
|
||||
final Field textHelperField = toolbarClazz.getDeclaredField("collapsingTextHelper");
|
||||
textHelperField.setAccessible(true);
|
||||
final Object textHelperObj = textHelperField.get(mCollapsingToolbarLayout);
|
||||
|
||||
final Field layoutField = textHelperObj.getClass().getDeclaredField("textLayout");
|
||||
layoutField.setAccessible(true);
|
||||
final Object layoutObj = layoutField.get(textHelperObj);
|
||||
|
||||
final Method method = layoutObj.getClass().getDeclaredMethod("getLineCount");
|
||||
return (int) method.invoke(layoutObj);
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onCategoriesChanged(Set<String> categories) {
|
||||
final int N = mCategoryListeners.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
|
Reference in New Issue
Block a user