Homepage UX revamp

- unified Search and Suggestion behavior between regular phone and two
  pane
- don't adjust padding
- update new icon drawable
- support group homepage preference with round corner on phone
- Remove avator from homepage
- Adjust homepage preference order

Bug: 333989622
Bug: 334130370
Test: visual
Change-Id: I9880b52553f164745766c8b9d5c996585285e52a
This commit is contained in:
Edgar Wang
2024-04-16 14:51:42 +00:00
parent 5ef0fe533e
commit 47400df7ae
35 changed files with 1284 additions and 36 deletions

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2024 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.core;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.widget.theme.R;
import java.util.ArrayList;
import java.util.List;
public class RoundCornerPreferenceAdapter extends PreferenceGroupAdapter {
private static final int ROUND_CORNER_CENTER = 1;
private static final int ROUND_CORNER_TOP = 1 << 1;
private static final int ROUND_CORNER_BOTTOM = 1 << 2;
private final PreferenceGroup mPreferenceGroup;
private List<Integer> mRoundCornerMappingList;
private final Handler mHandler;
private final Runnable mSyncRunnable = new Runnable() {
@Override
public void run() {
updatePreferences();
}
};
public RoundCornerPreferenceAdapter(@NonNull PreferenceGroup preferenceGroup) {
super(preferenceGroup);
mPreferenceGroup = preferenceGroup;
mHandler = new Handler(Looper.getMainLooper());
updatePreferences();
}
@Override
public void onPreferenceHierarchyChange(@NonNull Preference preference) {
super.onPreferenceHierarchyChange(preference);
mHandler.removeCallbacks(mSyncRunnable);
mHandler.post(mSyncRunnable);
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
updateBackground(holder, position);
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
private void updatePreferences() {
mRoundCornerMappingList = new ArrayList<>();
mappingPreferenceGroup(mRoundCornerMappingList, mPreferenceGroup);
}
private void mappingPreferenceGroup(List<Integer> visibleList, PreferenceGroup group) {
int groupSize = group.getPreferenceCount();
int firstVisible = 0;
int lastVisible = 0;
for (int i = 0; i < groupSize; i++) {
Preference pref = group.getPreference(i);
if (!pref.isVisible()) {
continue;
}
//the first visible preference.
Preference firstVisiblePref = group.getPreference(firstVisible);
if (!firstVisiblePref.isVisible()) {
firstVisible = i;
}
int value = 0;
if (group instanceof PreferenceCategory) {
if (pref instanceof PreferenceCategory) {
visibleList.add(value);
mappingPreferenceGroup(visibleList, (PreferenceCategory) pref);
} else {
if (i == firstVisible) {
value |= ROUND_CORNER_TOP;
}
value |= ROUND_CORNER_BOTTOM;
if (i > lastVisible) {
// the last
int lastIndex = visibleList.size() - 1;
int newValue = visibleList.get(lastIndex) & ~ROUND_CORNER_BOTTOM;
visibleList.set(lastIndex, newValue);
lastVisible = i;
}
value |= ROUND_CORNER_CENTER;
visibleList.add(value);
}
} else {
visibleList.add(value);
if (pref instanceof PreferenceCategory) {
mappingPreferenceGroup(visibleList, (PreferenceCategory) pref);
}
}
}
}
/** handle roundCorner background */
private void updateBackground(PreferenceViewHolder holder, int position) {
int CornerType = mRoundCornerMappingList.get(position);
if ((CornerType & ROUND_CORNER_CENTER) == 0) {
return;
}
View v = holder.itemView;
if (((CornerType & ROUND_CORNER_TOP) != 0) && ((CornerType & ROUND_CORNER_BOTTOM) == 0)) {
// the first
v.setBackgroundResource(R.drawable.settingslib_round_background_top);
} else if (((CornerType & ROUND_CORNER_BOTTOM) != 0)
&& ((CornerType & ROUND_CORNER_TOP) == 0)) {
// the last
v.setBackgroundResource(R.drawable.settingslib_round_background_bottom);
} else if (((CornerType & ROUND_CORNER_TOP) != 0)
&& ((CornerType & ROUND_CORNER_BOTTOM) != 0)) {
// the only one preference
v.setBackgroundResource(R.drawable.settingslib_round_background);
} else {
// in the center
v.setBackgroundResource(R.drawable.settingslib_round_background_center);
}
}
}

View File

@@ -444,7 +444,9 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
if (TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) {
iconDrawable.setTint(Utils.getHomepageIconColor(preference.getContext()));
} else if (forceRoundedIcon && !TextUtils.equals(mContext.getPackageName(), iconPackage)) {
}
if (forceRoundedIcon && !TextUtils.equals(mContext.getPackageName(), iconPackage)) {
iconDrawable = new AdaptiveIcon(mContext, iconDrawable,
R.dimen.dashboard_tile_foreground_image_inset);
((AdaptiveIcon) iconDrawable).setBackgroundColor(mContext, tile);

View File

@@ -72,6 +72,7 @@ import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.core.CategoryMixin;
import com.android.settings.core.FeatureFlags;
import com.android.settings.flags.Flags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
@@ -159,8 +160,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements
if (mAllowUpdateSuggestion) {
Log.i(TAG, "showHomepageWithSuggestion: " + showSuggestion);
mAllowUpdateSuggestion = false;
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
mTwoPaneSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
if (Flags.homepageRevamp()) {
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
} else {
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
mTwoPaneSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
}
}
if (mHomepageView == null) {
@@ -244,7 +249,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
setupEdgeToEdge();
setContentView(R.layout.settings_homepage_container);
setContentView(
Flags.homepageRevamp()
? R.layout.settings_homepage_container_v2
: R.layout.settings_homepage_container);
mIsTwoPane = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
@@ -396,19 +404,31 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
private void initSearchBarView() {
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFeatureFactory().getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
if (mIsEmbeddingActivityEnabled) {
final Toolbar toolbarTwoPaneVersion = findViewById(R.id.search_action_bar_two_pane);
if (Flags.homepageRevamp()) {
Toolbar toolbar = findViewById(R.id.search_action_bar_unified);
FeatureFactory.getFeatureFactory().getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbarTwoPaneVersion,
.initSearchToolbar(this /* activity */, toolbar,
SettingsEnums.SETTINGS_HOMEPAGE);
} else {
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFeatureFactory().getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbar,
SettingsEnums.SETTINGS_HOMEPAGE);
if (mIsEmbeddingActivityEnabled) {
final Toolbar toolbarTwoPaneVersion = findViewById(R.id.search_action_bar_two_pane);
FeatureFactory.getFeatureFactory().getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbarTwoPaneVersion,
SettingsEnums.SETTINGS_HOMEPAGE);
}
}
}
private void initAvatarView() {
if (Flags.homepageRevamp()) {
return;
}
final ImageView avatarView = findViewById(R.id.account_avatar);
final ImageView avatarTwoPaneView = findViewById(R.id.account_avatar_two_pane_version);
if (AvatarViewMixin.isAvatarSupported(this)) {
@@ -457,8 +477,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements
return;
}
mSuggestionView = findViewById(R.id.suggestion_content);
mTwoPaneSuggestionView = findViewById(R.id.two_pane_suggestion_content);
if (Flags.homepageRevamp()) {
mSuggestionView = findViewById(R.id.unified_suggestion_content);
} else {
mSuggestionView = findViewById(R.id.suggestion_content);
mTwoPaneSuggestionView = findViewById(R.id.two_pane_suggestion_content);
}
mHomepageView = findViewById(R.id.settings_homepage_container);
// Hide the homepage for preparing the suggestion. If scrolling is needed, the list views
// should be initialized in the invisible homepage view to prevent a scroll flicker.
@@ -466,11 +490,16 @@ 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);
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ false),
R.id.suggestion_content);
if (mIsEmbeddingActivityEnabled) {
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ true),
R.id.two_pane_suggestion_content);
if (Flags.homepageRevamp()) {
showFragment(new SuggestionFragCreator(fragmentClass, true),
R.id.unified_suggestion_content);
} else {
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ false),
R.id.suggestion_content);
if (mIsEmbeddingActivityEnabled) {
showFragment(new SuggestionFragCreator(fragmentClass, /* isTwoPaneLayout= */ true),
R.id.two_pane_suggestion_content);
}
}
}
@@ -735,7 +764,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
private void updateHomepageAppBar() {
if (!mIsEmbeddingActivityEnabled) {
if (Flags.homepageRevamp() || !mIsEmbeddingActivityEnabled) {
return;
}
updateAppBarMinHeight();
@@ -751,7 +780,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
private void updateHomepagePaddings() {
if (!mIsEmbeddingActivityEnabled) {
if (Flags.homepageRevamp() || !mIsEmbeddingActivityEnabled) {
return;
}
if (mIsTwoPane) {
@@ -765,6 +794,9 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
private void updateAppBarMinHeight() {
if (Flags.homepageRevamp()) {
return;
}
final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
final int margin = getResources().getDimensionPixelSize(
mIsEmbeddingActivityEnabled && mIsTwoPane

View File

@@ -42,8 +42,10 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.core.RoundCornerPreferenceAdapter;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.support.SupportPreferenceController;
@@ -84,7 +86,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
@Override
protected int getPreferenceScreenResId() {
return R.xml.top_level_settings;
return Flags.homepageRevamp() ? R.xml.top_level_settings_v2 : R.xml.top_level_settings;
}
@Override
@@ -331,10 +333,14 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
if (!mIsEmbeddingActivityEnabled || !(getActivity() instanceof SettingsHomepageActivity)) {
return super.onCreateAdapter(preferenceScreen);
if (mIsEmbeddingActivityEnabled && (getActivity() instanceof SettingsHomepageActivity)) {
return mHighlightMixin.onCreateAdapter(this, preferenceScreen, mScrollNeeded);
}
return mHighlightMixin.onCreateAdapter(this, preferenceScreen, mScrollNeeded);
if (Flags.homepageRevamp()) {
return new RoundCornerPreferenceAdapter(preferenceScreen);
}
return super.onCreateAdapter(preferenceScreen);
}
@Override
@@ -376,7 +382,10 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.top_level_settings) {
new BaseSearchIndexProvider(
Flags.homepageRevamp()
? R.xml.top_level_settings_v2
: R.xml.top_level_settings) {
@Override
protected boolean isPageSearchEnabled(Context context) {

View File

@@ -34,6 +34,7 @@ import androidx.window.embedding.ActivityEmbeddingController;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.flags.Flags;
import com.android.settings.homepage.SettingsHomepageActivity;
/**
@@ -46,9 +47,13 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 100L;
private static final int RES_NORMAL_BACKGROUND =
R.drawable.homepage_selectable_item_background;
Flags.homepageRevamp()
? R.drawable.homepage_selectable_item_background_v2
: R.drawable.homepage_selectable_item_background;
private static final int RES_HIGHLIGHTED_BACKGROUND =
R.drawable.homepage_highlighted_item_background;
Flags.homepageRevamp()
? R.drawable.homepage_highlighted_item_background_v2
: R.drawable.homepage_highlighted_item_background;
private final int mTitleColorNormal;
private final int mTitleColorHighlight;

View File

@@ -22,6 +22,7 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settings.flags.Flags;
/** Helper for homepage preference to manage layout. */
public class HomepagePreferenceLayoutHelper {
@@ -39,7 +40,10 @@ public class HomepagePreferenceLayoutHelper {
}
public HomepagePreferenceLayoutHelper(Preference preference) {
preference.setLayoutResource(R.layout.homepage_preference);
preference.setLayoutResource(
Flags.homepageRevamp()
? R.layout.homepage_preference_v2
: R.layout.homepage_preference);
}
/** Sets whether the icon should be visible */