Refine layouts for large screen
- Support dynamic paddings depending on app's screen width - Add round corners to homepage ripple effect to improve the transition of being highlighted - Add an interface to support dynamic split layout for suggestion cards Bug: 223300824 Test: robotest, manual Change-Id: Iaca6b4fd3f7369179416ef084a800d7eb2ee4640
This commit is contained in:
@@ -14,13 +14,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:insetLeft="@dimen/homepage_menu_entry_padding_horizontal"
|
||||
android:insetRight="@dimen/homepage_menu_entry_padding_horizontal">
|
||||
<shape android:shape="rectangle">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid
|
||||
android:color="?android:attr/textColorPrimary" />
|
||||
<corners
|
||||
android:radius="@dimen/homepage_menu_entry_corner_radius" />
|
||||
</shape>
|
||||
</inset>
|
||||
android:radius="@dimen/homepage_preference_corner_radius" />
|
||||
</shape>
|
27
res/drawable/homepage_selectable_item_background.xml
Normal file
27
res/drawable/homepage_selectable_item_background.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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.
|
||||
-->
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid
|
||||
android:color="@android:color/white" />
|
||||
<corners
|
||||
android:radius="@dimen/homepage_preference_corner_radius" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
@@ -20,10 +20,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:minHeight="@dimen/homepage_preference_min_height"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/homepage_menu_entry_padding_horizontal"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clipToPadding="false"
|
||||
android:baselineAligned="false">
|
||||
@@ -32,11 +30,10 @@
|
||||
android:id="@+id/icon_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="56dp"
|
||||
android:gravity="center"
|
||||
android:minWidth="48dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingStart="@dimen/homepage_preference_icon_padding_start"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
@@ -44,18 +41,20 @@
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:maxWidth="40dp"
|
||||
app:maxHeight="40dp"/>
|
||||
app:maxWidth="48dp"
|
||||
app:maxHeight="48dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/text_frame"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
android:paddingStart="@dimen/homepage_preference_text_padding_start"
|
||||
android:paddingEnd="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
|
@@ -31,7 +31,8 @@
|
||||
android:id="@+id/search_action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/search_bar_height"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingStart="@dimen/search_bar_padding_start"
|
||||
android:paddingEnd="@dimen/search_bar_padding_end"
|
||||
android:background="@drawable/search_bar_selected_background"
|
||||
android:contentInsetStartWithNavigation="@dimen/search_bar_content_inset"
|
||||
android:navigationIcon="@drawable/ic_homepage_search">
|
||||
@@ -40,7 +41,7 @@
|
||||
style="@style/TextAppearance.SearchBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="-4dp"
|
||||
android:paddingStart="@dimen/search_bar_title_padding_start"
|
||||
android:layout_gravity="start"
|
||||
android:text="@string/search_menu"/>
|
||||
</Toolbar>
|
||||
|
@@ -21,20 +21,23 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_margin="@dimen/search_bar_margin">
|
||||
android:layout_marginEnd="@dimen/search_bar_margin"
|
||||
android:layout_marginVertical="@dimen/search_bar_margin">
|
||||
<Toolbar
|
||||
android:id="@+id/search_action_bar_two_pane"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/search_bar_height"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingStart="@dimen/search_bar_padding_start_two_pane"
|
||||
android:paddingEnd="@dimen/search_bar_padding_end_two_pane"
|
||||
android:background="@drawable/search_bar_selected_background"
|
||||
android:contentInsetStartWithNavigation="@dimen/search_bar_content_inset"
|
||||
android:navigationIcon="@drawable/ic_homepage_search">
|
||||
<TextView
|
||||
android:id="@+id/search_bar_title"
|
||||
style="@style/TextAppearance.SearchBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="-4dp"
|
||||
android:paddingStart="@dimen/search_bar_title_padding_start_regular_two_pane"
|
||||
android:layout_gravity="start"
|
||||
android:text="@string/search_menu"/>
|
||||
</Toolbar>
|
||||
|
@@ -20,7 +20,6 @@
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?androidprv:attr/colorSurface"
|
||||
android:orientation="vertical">
|
||||
|
||||
@@ -41,7 +40,6 @@
|
||||
android:layout_width="@dimen/avatar_length"
|
||||
android:layout_height="@dimen/avatar_length"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:contentDescription="@string/search_bar_account_avatar_content_description"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
@@ -35,9 +35,6 @@
|
||||
<!-- SwitchBar sub settings margin start / end -->
|
||||
<dimen name="switchbar_subsettings_margin_start">80dp</dimen>
|
||||
|
||||
<dimen name="search_bar_height">64dp</dimen>
|
||||
<dimen name="search_bar_half_height">32dp</dimen>
|
||||
|
||||
<!-- Dimensions for Wifi Assistant Card -->
|
||||
<dimen name="wifi_assistant_padding_top_bottom">24dp</dimen>
|
||||
<dimen name="wifi_assistant_padding_start_end">24dp</dimen>
|
||||
|
@@ -129,6 +129,12 @@
|
||||
<dimen name="search_bar_text_size">20sp</dimen>
|
||||
<dimen name="search_bar_corner_radius">28dp</dimen>
|
||||
<dimen name="search_bar_content_inset">56dp</dimen>
|
||||
<dimen name="search_bar_padding_start">4dp</dimen>
|
||||
<dimen name="search_bar_padding_start_two_pane">8dp</dimen>
|
||||
<dimen name="search_bar_padding_end">16dp</dimen>
|
||||
<dimen name="search_bar_padding_end_two_pane">24dp</dimen>
|
||||
<dimen name="search_bar_title_padding_start">-4dp</dimen>
|
||||
<dimen name="search_bar_title_padding_start_regular_two_pane">8dp</dimen>
|
||||
|
||||
<!-- Avatar -->
|
||||
<dimen name="avatar_length">48dp</dimen>
|
||||
@@ -136,13 +142,16 @@
|
||||
<dimen name="avatar_margin_end">24dp</dimen>
|
||||
<dimen name="multiple_users_avatar_size">20dp</dimen>
|
||||
|
||||
<!-- Homepage title -->
|
||||
<!-- Homepage -->
|
||||
<dimen name="homepage_title_margin_bottom">8dp</dimen>
|
||||
<dimen name="homepage_title_margin_horizontal">24dp</dimen>
|
||||
|
||||
<!-- Homepage menu entry -->
|
||||
<dimen name="homepage_menu_entry_padding_horizontal">16dp</dimen>
|
||||
<dimen name="homepage_menu_entry_corner_radius">28dp</dimen>
|
||||
<dimen name="homepage_padding_horizontal_two_pane">24dp</dimen>
|
||||
<dimen name="homepage_preference_corner_radius">28dp</dimen>
|
||||
<dimen name="homepage_preference_min_height">88sp</dimen>
|
||||
<dimen name="homepage_preference_icon_padding_start">32dp</dimen>
|
||||
<dimen name="homepage_preference_icon_padding_start_two_pane">8dp</dimen>
|
||||
<dimen name="homepage_preference_text_padding_start">16dp</dimen>
|
||||
<dimen name="homepage_preference_text_padding_start_two_pane">24dp</dimen>
|
||||
|
||||
<!-- Dimensions for Wifi Assistant Card -->
|
||||
<dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.activityembedding;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.FeatureFlagUtils;
|
||||
@@ -33,6 +34,8 @@ public class ActivityEmbeddingUtils {
|
||||
// The smallest value of the smallest-width (sw) of the window in any rotation when
|
||||
// the split should be used.
|
||||
private static final float MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP = 600f;
|
||||
// The minimum width of the activity to show the regular homepage layout.
|
||||
private static final float MIN_REGULAR_HOMEPAGE_LAYOUT_WIDTH_DP = 380f;
|
||||
private static final String TAG = "ActivityEmbeddingUtils";
|
||||
|
||||
/** Get the smallest pixel value of width of the window when the split should be used. */
|
||||
@@ -71,4 +74,11 @@ public class ActivityEmbeddingUtils {
|
||||
|
||||
return isFlagEnabled && isSplitSupported;
|
||||
}
|
||||
|
||||
/** Whether to show the regular or simplified homepage layout. */
|
||||
public static boolean isRegularHomepageLayout(Activity activity) {
|
||||
DisplayMetrics dm = activity.getResources().getDisplayMetrics();
|
||||
return dm.widthPixels >= (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, MIN_REGULAR_HOMEPAGE_LAYOUT_WIDTH_DP, dm);
|
||||
}
|
||||
}
|
||||
|
@@ -86,6 +86,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
|
||||
private TopLevelSettings mMainFragment;
|
||||
private View mHomepageView;
|
||||
private View mAppBar;
|
||||
private View mSuggestionView;
|
||||
private View mTwoPaneSuggestionView;
|
||||
private CategoryMixin mCategoryMixin;
|
||||
@@ -93,6 +94,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
private SplitController mSplitController;
|
||||
private boolean mIsEmbeddingActivityEnabled;
|
||||
private boolean mIsTwoPane;
|
||||
// A regular layout shows icons on homepage, whereas a simplified layout doesn't.
|
||||
private boolean mIsRegularLayout = true;
|
||||
|
||||
/** A listener receiving homepage loaded events. */
|
||||
public interface HomepageLoadedListener {
|
||||
@@ -100,8 +103,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
void onHomepageLoaded();
|
||||
}
|
||||
|
||||
private interface FragmentBuilder<T extends Fragment> {
|
||||
T build();
|
||||
private interface FragmentCreator<T extends Fragment> {
|
||||
T create();
|
||||
|
||||
/** To initialize after {@link #create} */
|
||||
default void init(Fragment fragment) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,6 +151,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
return mMainFragment;
|
||||
}
|
||||
|
||||
/** Whether the activity is showing in two-pane */
|
||||
public boolean isTwoPane() {
|
||||
return mIsTwoPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CategoryMixin getCategoryMixin() {
|
||||
return mCategoryMixin;
|
||||
@@ -160,8 +171,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
mSplitController = SplitController.getInstance();
|
||||
mIsTwoPane = mSplitController.isActivityEmbedded(this);
|
||||
|
||||
final View appBar = findViewById(R.id.app_bar_container);
|
||||
appBar.setMinimumHeight(getSearchBoxHeight());
|
||||
mAppBar = findViewById(R.id.app_bar_container);
|
||||
mAppBar.setMinimumHeight(getSearchBoxHeight());
|
||||
initHomepageContainer();
|
||||
updateHomepageAppBar();
|
||||
updateHomepageBackground();
|
||||
@@ -195,6 +206,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
|
||||
// Launch the intent from deep link for large screen devices.
|
||||
launchDeepLinkIntentToRight();
|
||||
updateHomepagePaddings();
|
||||
updateSplitLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,7 +239,42 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
mIsTwoPane = newTwoPaneState;
|
||||
updateHomepageAppBar();
|
||||
updateHomepageBackground();
|
||||
updateHomepagePaddings();
|
||||
}
|
||||
updateSplitLayout();
|
||||
}
|
||||
|
||||
private void updateSplitLayout() {
|
||||
if (!mIsEmbeddingActivityEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsTwoPane) {
|
||||
if (mIsRegularLayout == ActivityEmbeddingUtils.isRegularHomepageLayout(this)) {
|
||||
// Layout unchanged
|
||||
return;
|
||||
}
|
||||
} else if (mIsRegularLayout) {
|
||||
// One pane mode with the regular layout, not needed to change
|
||||
return;
|
||||
}
|
||||
mIsRegularLayout = !mIsRegularLayout;
|
||||
|
||||
// Update search title padding
|
||||
View searchTitle = findViewById(R.id.search_bar_title);
|
||||
if (searchTitle != null) {
|
||||
int paddingStart = getResources().getDimensionPixelSize(
|
||||
mIsRegularLayout
|
||||
? R.dimen.search_bar_title_padding_start_regular_two_pane
|
||||
: R.dimen.search_bar_title_padding_start);
|
||||
searchTitle.setPaddingRelative(paddingStart, 0, 0, 0);
|
||||
}
|
||||
// Notify fragments
|
||||
getSupportFragmentManager().getFragments().forEach(fragment -> {
|
||||
if (fragment instanceof SplitLayoutListener) {
|
||||
((SplitLayoutListener) fragment).onSplitLayoutChanged(mIsRegularLayout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupEdgeToEdge() {
|
||||
@@ -303,29 +351,25 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
// Schedule a timer to show the homepage and hide the suggestion on timeout.
|
||||
mHomepageView.postDelayed(() -> showHomepageWithSuggestion(false),
|
||||
HOMEPAGE_LOADING_TIMEOUT_MS);
|
||||
final FragmentBuilder<?> fragmentBuilder = () -> {
|
||||
try {
|
||||
return fragmentClass.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Cannot show fragment", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
showFragment(fragmentBuilder, R.id.suggestion_content);
|
||||
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ false),
|
||||
R.id.suggestion_content);
|
||||
if (mIsEmbeddingActivityEnabled) {
|
||||
showFragment(fragmentBuilder, R.id.two_pane_suggestion_content);
|
||||
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ true),
|
||||
R.id.two_pane_suggestion_content);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Fragment> T showFragment(FragmentBuilder<T> fragmentBuilder, int id) {
|
||||
private <T extends Fragment> T showFragment(FragmentCreator<T> fragmentCreator, int id) {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
T showFragment = (T) fragmentManager.findFragmentById(id);
|
||||
|
||||
if (showFragment == null) {
|
||||
showFragment = fragmentBuilder.build();
|
||||
showFragment = fragmentCreator.create();
|
||||
fragmentCreator.init(showFragment);
|
||||
fragmentTransaction.add(id, showFragment);
|
||||
} else {
|
||||
fragmentCreator.init(showFragment);
|
||||
fragmentTransaction.show(showFragment);
|
||||
}
|
||||
fragmentTransaction.commit();
|
||||
@@ -447,9 +491,54 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHomepagePaddings() {
|
||||
if (!mIsEmbeddingActivityEnabled) {
|
||||
return;
|
||||
}
|
||||
if (mIsTwoPane) {
|
||||
int padding = getResources().getDimensionPixelSize(
|
||||
R.dimen.homepage_padding_horizontal_two_pane);
|
||||
mAppBar.setPaddingRelative(padding, 0, padding, 0);
|
||||
mMainFragment.setPaddingHorizontal(padding);
|
||||
} else {
|
||||
mAppBar.setPaddingRelative(0, 0, 0, 0);
|
||||
mMainFragment.setPaddingHorizontal(0);
|
||||
}
|
||||
mMainFragment.updatePreferencePadding(mIsTwoPane);
|
||||
}
|
||||
|
||||
private int getSearchBoxHeight() {
|
||||
final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
|
||||
final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);
|
||||
return searchBarHeight + searchBarMargin * 2;
|
||||
}
|
||||
|
||||
private static class SuggestionFragCreator implements FragmentCreator {
|
||||
|
||||
private final Class<? extends Fragment> mClass;
|
||||
private final boolean mIsTwoPaneLayout;
|
||||
|
||||
SuggestionFragCreator(Class<? extends Fragment> clazz, boolean isTwoPaneLayout) {
|
||||
mClass = clazz;
|
||||
mIsTwoPaneLayout = isTwoPaneLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment create() {
|
||||
try {
|
||||
Fragment fragment = mClass.getConstructor().newInstance();
|
||||
return fragment;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Cannot show fragment", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Fragment fragment) {
|
||||
if (fragment instanceof SplitLayoutListener) {
|
||||
((SplitLayoutListener) fragment).setSplitLayoutSupported(mIsTwoPaneLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
src/com/android/settings/homepage/SplitLayoutListener.java
Normal file
34
src/com/android/settings/homepage/SplitLayoutListener.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.settings.homepage;
|
||||
|
||||
/** A listener receiving the spilt layout change */
|
||||
public interface SplitLayoutListener {
|
||||
|
||||
/**
|
||||
* Called when the spilt layout is changed.
|
||||
*
|
||||
* @param isRegularLayout whether the layout should be regular or simplified
|
||||
*/
|
||||
void onSplitLayoutChanged(boolean isRegularLayout);
|
||||
|
||||
/**
|
||||
* Notifies the listener whether the split layout is supported.
|
||||
*/
|
||||
default void setSplitLayoutSupported(boolean supported) {
|
||||
}
|
||||
}
|
@@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
@@ -44,12 +46,13 @@ import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.support.SupportPreferenceController;
|
||||
import com.android.settings.widget.HomepagePreference;
|
||||
import com.android.settings.widget.HomepagePreferenceLayoutHelper.HomepagePreferenceLayout;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
@SearchIndexable(forTarget = MOBILE)
|
||||
public class TopLevelSettings extends DashboardFragment implements
|
||||
public class TopLevelSettings extends DashboardFragment implements SplitLayoutListener,
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
|
||||
private static final String TAG = "TopLevelSettings";
|
||||
@@ -58,6 +61,7 @@ public class TopLevelSettings extends DashboardFragment implements
|
||||
|
||||
private boolean mIsEmbeddingActivityEnabled;
|
||||
private TopLevelHighlightMixin mHighlightMixin;
|
||||
private int mPaddingHorizontal;
|
||||
private boolean mScrollNeeded = true;
|
||||
private boolean mFirstStarted = true;
|
||||
|
||||
@@ -177,23 +181,13 @@ public class TopLevelSettings extends DashboardFragment implements
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
if (screen == null) {
|
||||
return;
|
||||
}
|
||||
// Tint the homepage icons
|
||||
final int tintColor = Utils.getHomepageIconColor(getContext());
|
||||
final int count = screen.getPreferenceCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final Preference preference = screen.getPreference(i);
|
||||
if (preference == null) {
|
||||
break;
|
||||
}
|
||||
final Drawable icon = preference.getIcon();
|
||||
int tintColor = Utils.getHomepageIconColor(getContext());
|
||||
iteratePreferences(preference -> {
|
||||
Drawable icon = preference.getIcon();
|
||||
if (icon != null) {
|
||||
icon.setTint(tintColor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,6 +196,15 @@ public class TopLevelSettings extends DashboardFragment implements
|
||||
highlightPreferenceIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplitLayoutChanged(boolean isRegularLayout) {
|
||||
iteratePreferences(preference -> {
|
||||
if (preference instanceof HomepagePreferenceLayout) {
|
||||
((HomepagePreferenceLayout) preference).getHelper().setIconVisible(isRegularLayout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void highlightPreferenceIfNeeded() {
|
||||
if (mHighlightMixin != null) {
|
||||
@@ -209,6 +212,52 @@ public class TopLevelSettings extends DashboardFragment implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
|
||||
Bundle savedInstanceState) {
|
||||
RecyclerView recyclerView = super.onCreateRecyclerView(inflater, parent,
|
||||
savedInstanceState);
|
||||
recyclerView.setPadding(mPaddingHorizontal, 0, mPaddingHorizontal, 0);
|
||||
return recyclerView;
|
||||
}
|
||||
|
||||
/** Sets the horizontal padding */
|
||||
public void setPaddingHorizontal(int padding) {
|
||||
mPaddingHorizontal = padding;
|
||||
RecyclerView recyclerView = getListView();
|
||||
if (recyclerView != null) {
|
||||
recyclerView.setPadding(padding, 0, padding, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the preference internal paddings */
|
||||
public void updatePreferencePadding(boolean isTwoPane) {
|
||||
iteratePreferences(new PreferenceJob() {
|
||||
private int mIconPaddingStart;
|
||||
private int mTextPaddingStart;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
mIconPaddingStart = getResources().getDimensionPixelSize(isTwoPane
|
||||
? R.dimen.homepage_preference_icon_padding_start_two_pane
|
||||
: R.dimen.homepage_preference_icon_padding_start);
|
||||
mTextPaddingStart = getResources().getDimensionPixelSize(isTwoPane
|
||||
? R.dimen.homepage_preference_text_padding_start_two_pane
|
||||
: R.dimen.homepage_preference_text_padding_start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doForEach(Preference preference) {
|
||||
if (preference instanceof HomepagePreferenceLayout) {
|
||||
((HomepagePreferenceLayout) preference).getHelper()
|
||||
.setIconPaddingStart(mIconPaddingStart);
|
||||
((HomepagePreferenceLayout) preference).getHelper()
|
||||
.setTextPaddingStart(mTextPaddingStart);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns a {@link TopLevelHighlightMixin} that performs highlighting */
|
||||
public TopLevelHighlightMixin getHighlightMixin() {
|
||||
return mHighlightMixin;
|
||||
@@ -261,6 +310,31 @@ public class TopLevelSettings extends DashboardFragment implements
|
||||
}
|
||||
}
|
||||
|
||||
private void iteratePreferences(PreferenceJob job) {
|
||||
if (job == null || getPreferenceManager() == null) {
|
||||
return;
|
||||
}
|
||||
PreferenceScreen screen = getPreferenceScreen();
|
||||
if (screen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
job.init();
|
||||
int count = screen.getPreferenceCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Preference preference = screen.getPreference(i);
|
||||
if (preference == null) {
|
||||
break;
|
||||
}
|
||||
job.doForEach(preference);
|
||||
}
|
||||
}
|
||||
|
||||
private interface PreferenceJob {
|
||||
default void init() {}
|
||||
void doForEach(Preference preference);
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.top_level_settings) {
|
||||
|
||||
|
@@ -21,7 +21,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -46,6 +45,10 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
||||
private static final String TAG = "HighlightableTopLevelAdapter";
|
||||
|
||||
static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 100L;
|
||||
private static final int RES_NORMAL_BACKGROUND =
|
||||
R.drawable.homepage_selectable_item_background;
|
||||
private static final int RES_HIGHLIGHTED_BACKGROUND =
|
||||
R.drawable.homepage_highlighted_item_background;
|
||||
|
||||
private final int mTitleColorNormal;
|
||||
private final int mTitleColorHighlight;
|
||||
@@ -54,11 +57,8 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
||||
private final int mIconColorNormal;
|
||||
private final int mIconColorHighlight;
|
||||
|
||||
private final Context mContext;
|
||||
private final SettingsHomepageActivity mHomepageActivity;
|
||||
private final RecyclerView mRecyclerView;
|
||||
private final int mNormalBackgroundRes;
|
||||
private final int mHighlightBackgroundRes;
|
||||
private String mHighlightKey;
|
||||
private int mHighlightPosition = RecyclerView.NO_POSITION;
|
||||
private int mScrollPosition = RecyclerView.NO_POSITION;
|
||||
@@ -74,23 +74,18 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
||||
mHighlightKey = key;
|
||||
mScrolled = !scrollNeeded;
|
||||
mViewHolders = new SparseArray<>();
|
||||
mContext = preferenceGroup.getContext();
|
||||
mHomepageActivity = homepageActivity;
|
||||
final TypedValue outValue = new TypedValue();
|
||||
mContext.getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
|
||||
outValue, true /* resolveRefs */);
|
||||
mNormalBackgroundRes = outValue.resourceId;
|
||||
mHighlightBackgroundRes = R.drawable.homepage_highlighted_item_background;
|
||||
mTitleColorNormal = Utils.getColorAttrDefaultColor(mContext,
|
||||
Context context = preferenceGroup.getContext();
|
||||
mTitleColorNormal = Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.textColorPrimary);
|
||||
mTitleColorHighlight = Utils.getColorAttrDefaultColor(mContext,
|
||||
mTitleColorHighlight = Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.textColorPrimaryInverse);
|
||||
mSummaryColorNormal = Utils.getColorAttrDefaultColor(mContext,
|
||||
mSummaryColorNormal = Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.textColorSecondary);
|
||||
mSummaryColorHighlight = Utils.getColorAttrDefaultColor(mContext,
|
||||
mSummaryColorHighlight = Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.textColorSecondaryInverse);
|
||||
mIconColorNormal = Utils.getHomepageIconColor(mContext);
|
||||
mIconColorHighlight = Utils.getHomepageIconColorHighlight(mContext);
|
||||
mIconColorNormal = Utils.getHomepageIconColor(context);
|
||||
mIconColorHighlight = Utils.getHomepageIconColorHighlight(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -236,7 +231,7 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
||||
|
||||
private void addHighlightBackground(PreferenceViewHolder holder) {
|
||||
final View v = holder.itemView;
|
||||
v.setBackgroundResource(mHighlightBackgroundRes);
|
||||
v.setBackgroundResource(RES_HIGHLIGHTED_BACKGROUND);
|
||||
((TextView) v.findViewById(android.R.id.title)).setTextColor(mTitleColorHighlight);
|
||||
((TextView) v.findViewById(android.R.id.summary)).setTextColor(mSummaryColorHighlight);
|
||||
final Drawable drawable = ((ImageView) v.findViewById(android.R.id.icon)).getDrawable();
|
||||
@@ -247,7 +242,7 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
||||
|
||||
private void removeHighlightBackground(PreferenceViewHolder holder) {
|
||||
final View v = holder.itemView;
|
||||
v.setBackgroundResource(mNormalBackgroundRes);
|
||||
v.setBackgroundResource(RES_NORMAL_BACKGROUND);
|
||||
((TextView) v.findViewById(android.R.id.title)).setTextColor(mTitleColorNormal);
|
||||
((TextView) v.findViewById(android.R.id.summary)).setTextColor(mSummaryColorNormal);
|
||||
final Drawable drawable = ((ImageView) v.findViewById(android.R.id.icon)).getDrawable();
|
||||
|
@@ -20,29 +20,43 @@ import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
/** A customized layout for homepage preference. */
|
||||
public class HomepagePreference extends Preference {
|
||||
public class HomepagePreference extends Preference implements
|
||||
HomepagePreferenceLayoutHelper.HomepagePreferenceLayout {
|
||||
|
||||
private final HomepagePreferenceLayoutHelper mHelper;
|
||||
|
||||
public HomepagePreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public HomepagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public HomepagePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public HomepagePreference(Context context) {
|
||||
super(context);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
mHelper.onBindViewHolder(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomepagePreferenceLayoutHelper getHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.settings.widget;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/** Helper for homepage preference to manage layout. */
|
||||
public class HomepagePreferenceLayoutHelper {
|
||||
|
||||
private View mIcon;
|
||||
private View mText;
|
||||
private boolean mIconVisible = true;
|
||||
private int mIconPaddingStart = -1;
|
||||
private int mTextPaddingStart = -1;
|
||||
|
||||
/** The interface for managing preference layouts on homepage */
|
||||
public interface HomepagePreferenceLayout {
|
||||
/** Returns a {@link HomepagePreferenceLayoutHelper} */
|
||||
HomepagePreferenceLayoutHelper getHelper();
|
||||
}
|
||||
|
||||
public HomepagePreferenceLayoutHelper(Preference preference) {
|
||||
preference.setLayoutResource(R.layout.homepage_preference);
|
||||
}
|
||||
|
||||
/** Sets whether the icon should be visible */
|
||||
public void setIconVisible(boolean visible) {
|
||||
mIconVisible = visible;
|
||||
if (mIcon != null) {
|
||||
mIcon.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the icon padding start */
|
||||
public void setIconPaddingStart(int paddingStart) {
|
||||
mIconPaddingStart = paddingStart;
|
||||
if (mIcon != null && paddingStart >= 0) {
|
||||
mIcon.setPaddingRelative(paddingStart, mIcon.getPaddingTop(), mIcon.getPaddingEnd(),
|
||||
mIcon.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the text padding start */
|
||||
public void setTextPaddingStart(int paddingStart) {
|
||||
mTextPaddingStart = paddingStart;
|
||||
if (mText != null && paddingStart >= 0) {
|
||||
mText.setPaddingRelative(paddingStart, mText.getPaddingTop(), mText.getPaddingEnd(),
|
||||
mText.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
||||
void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
mIcon = holder.findViewById(R.id.icon_frame);
|
||||
mText = holder.findViewById(R.id.text_frame);
|
||||
setIconVisible(mIconVisible);
|
||||
setIconPaddingStart(mIconPaddingStart);
|
||||
setTextPaddingStart(mTextPaddingStart);
|
||||
}
|
||||
}
|
@@ -19,29 +19,45 @@ package com.android.settings.widget;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.settings.R;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settingslib.RestrictedTopLevelPreference;
|
||||
|
||||
/** Homepage preference that can be disabled by a device admin using a user restriction. */
|
||||
public class RestrictedHomepagePreference extends RestrictedTopLevelPreference {
|
||||
public class RestrictedHomepagePreference extends RestrictedTopLevelPreference implements
|
||||
HomepagePreferenceLayoutHelper.HomepagePreferenceLayout {
|
||||
|
||||
private final HomepagePreferenceLayoutHelper mHelper;
|
||||
|
||||
public RestrictedHomepagePreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public RestrictedHomepagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public RestrictedHomepagePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
public RestrictedHomepagePreference(Context context) {
|
||||
super(context);
|
||||
setLayoutResource(R.layout.homepage_preference);
|
||||
mHelper = new HomepagePreferenceLayoutHelper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
mHelper.onBindViewHolder(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomepagePreferenceLayoutHelper getHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -73,6 +74,7 @@ public class TopLevelSettingsTest {
|
||||
doReturn(1).when(screen).getPreferenceCount();
|
||||
doReturn(preference).when(screen).getPreference(anyInt());
|
||||
doReturn(screen).when(mSettings).getPreferenceScreen();
|
||||
doReturn(new PreferenceManager(mContext)).when(mSettings).getPreferenceManager();
|
||||
doReturn(0).when(mSettings).getPreferenceScreenResId();
|
||||
|
||||
mSettings.onCreatePreferences(new Bundle(), "rootKey");
|
||||
|
Reference in New Issue
Block a user