Redesign homepage layout for two-pane mode.

In a high level, I created two versions of app bar layout.
One for single pane design, another for two-pane design.

Then, app initilizes two different layouts in the beginning,
we simply show/hide one version while app is receiving the
configuration changes update.

Test: Rebuilt apk and observed the screen.
Bug: 195293058
Change-Id: Icd19ea02ab1be4e964701b22ae9e20c9e00d3c0d
This commit is contained in:
Tsung-Mao Fang
2021-11-18 17:37:56 +08:00
parent b4d3278a45
commit 251e326d21
5 changed files with 214 additions and 37 deletions

View File

@@ -0,0 +1,41 @@
<?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.
-->
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/SearchBarStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="@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:background="@drawable/search_bar_selected_background"
android:contentInsetStartWithNavigation="@dimen/search_bar_content_inset"
android:navigationIcon="@drawable/ic_homepage_search">
<TextView
style="@style/TextAppearance.SearchBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="-4dp"
android:layout_gravity="start"
android:text="@string/search_menu"/>
</Toolbar>
</com.google.android.material.card.MaterialCardView>

View File

@@ -0,0 +1,47 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/account_avatar"
android:layout_width="@dimen/avatar_length"
android:layout_height="@dimen/avatar_length"
android:layout_marginTop="@dimen/avatar_margin_top"
android:layout_marginEnd="@dimen/avatar_margin_end"
android:layout_gravity="end"
android:visibility="invisible"
android:accessibilityTraversalAfter="@id/homepage_title"
android:contentDescription="@string/search_bar_account_avatar_content_description"/>
<TextView
android:id="@+id/homepage_title"
android:text="@string/settings_label"
style="@style/HomepageTitleText"/>
<FrameLayout
android:id="@+id/suggestion_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include layout="@layout/search_bar"/>
</LinearLayout>

View File

@@ -0,0 +1,46 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/two_pane_suggestion_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<include layout="@layout/search_bar_two_pane_version"/>
<ImageView
android:id="@+id/account_avatar_two_pane_version"
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>
</LinearLayout>

View File

@@ -65,29 +65,14 @@
android:orientation="vertical"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
<ImageView
android:id="@+id/account_avatar"
android:layout_width="@dimen/avatar_length"
android:layout_height="@dimen/avatar_length"
android:layout_marginTop="@dimen/avatar_margin_top"
android:layout_marginEnd="@dimen/avatar_margin_end"
android:layout_gravity="end"
android:visibility="invisible"
android:accessibilityTraversalAfter="@id/homepage_title"
android:contentDescription="@string/search_bar_account_avatar_content_description"/>
<TextView
android:id="@+id/homepage_title"
android:text="@string/settings_label"
style="@style/HomepageTitleText"/>
<FrameLayout
android:id="@+id/suggestion_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include layout="@layout/search_bar"/>
<include
android:id="@+id/homepage_app_bar_regular_phone_view"
layout="@layout/settings_homepage_app_bar_regular_phone_layout"/>
<include
android:id="@+id/homepage_app_bar_two_pane_view"
layout="@layout/settings_homepage_app_bar_two_pane_layout"
android:visibility="gone"/>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -25,6 +25,7 @@ import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -77,8 +78,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
private TopLevelSettings mMainFragment;
private View mHomepageView;
private View mSuggestionView;
private View mTwoPaneSuggestionView;
private CategoryMixin mCategoryMixin;
private Set<HomepageLoadedListener> mLoadedListeners;
private boolean mIsEmbeddingActivityEnabled;
private boolean mIsTwoPaneLastTime;
/** A listener receiving homepage loaded events. */
public interface HomepageLoadedListener {
@@ -87,10 +91,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
/**
* Try to add a {@link HomepageLoadedListener}. If homepage is already loaded, the listener
* will not be notified.
* Try to add a {@link HomepageLoadedListener}. If homepage is already loaded, the listener
* will not be notified.
*
* @return Whether the listener is added.
* @return Whether the listener is added.
*/
public boolean addHomepageLoadedListener(HomepageLoadedListener listener) {
if (mHomepageView == null) {
@@ -113,7 +117,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
Log.i(TAG, "showHomepageWithSuggestion: " + showSuggestion);
final View homepageView = mHomepageView;
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
if (!mIsTwoPaneLastTime) {
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
} else {
mTwoPaneSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
}
mHomepageView = null;
mLoadedListeners.forEach(listener -> listener.onHomepageLoaded());
@@ -135,30 +143,25 @@ public class SettingsHomepageActivity extends FragmentActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_homepage_container);
mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this);
mIsTwoPaneLastTime = ActivityEmbeddingUtils.isTwoPaneResolution(this);
final View appBar = findViewById(R.id.app_bar_container);
appBar.setMinimumHeight(getSearchBoxHeight());
initHomepageContainer();
updateHomepageAppBar();
mLoadedListeners = new ArraySet<>();
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFactory(this).getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
initSearchBarView();
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
mCategoryMixin = new CategoryMixin(this);
getLifecycle().addObserver(mCategoryMixin);
// Only allow features on high ram devices.
if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
// Only allow features on high ram devices.
final ImageView avatarView = findViewById(R.id.account_avatar);
if (AvatarViewMixin.isAvatarSupported(this)) {
avatarView.setVisibility(View.VISIBLE);
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
}
initAvatarView();
showSuggestionFragment();
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
}
@@ -196,6 +199,43 @@ public class SettingsHomepageActivity extends FragmentActivity implements
launchDeepLinkIntentToRight();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
final boolean isTwoPane = ActivityEmbeddingUtils.isTwoPaneResolution(this);
if (mIsTwoPaneLastTime != isTwoPane) {
mIsTwoPaneLastTime = isTwoPane;
updateHomepageAppBar();
}
}
private void initSearchBarView() {
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFactory(this).getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
if (mIsEmbeddingActivityEnabled) {
final Toolbar toolbarTwoPaneVersion = findViewById(R.id.search_action_bar_two_pane);
FeatureFactory.getFactory(this).getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbarTwoPaneVersion,
SettingsEnums.SETTINGS_HOMEPAGE);
}
}
private void initAvatarView() {
final ImageView avatarView = findViewById(R.id.account_avatar);
final ImageView avatarTwoPaneView = findViewById(R.id.account_avatar_two_pane_version);
if (AvatarViewMixin.isAvatarSupported(this)) {
avatarView.setVisibility(View.VISIBLE);
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
if (mIsEmbeddingActivityEnabled) {
avatarTwoPaneView.setVisibility(View.VISIBLE);
getLifecycle().addObserver(new AvatarViewMixin(this, avatarTwoPaneView));
}
}
}
private void showSuggestionFragment() {
final Class<? extends Fragment> fragment = FeatureFactory.getFactory(this)
.getSuggestionFeatureProvider(this).getContextualSuggestionFragment();
@@ -204,6 +244,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
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.
mHomepageView.setVisibility(View.INVISIBLE);
@@ -212,6 +253,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements
HOMEPAGE_LOADING_TIMEOUT_MS);
try {
showFragment(fragment.getConstructor().newInstance(), R.id.suggestion_content);
if (mIsEmbeddingActivityEnabled) {
showFragment(fragment.getConstructor().newInstance(),
R.id.two_pane_suggestion_content);
}
} catch (Exception e) {
Log.w(TAG, "Cannot show fragment", e);
}
@@ -332,6 +377,19 @@ public class SettingsHomepageActivity extends FragmentActivity implements
view.requestFocus();
}
private void updateHomepageAppBar() {
if (!mIsEmbeddingActivityEnabled) {
return;
}
if (ActivityEmbeddingUtils.isTwoPaneResolution(this)) {
findViewById(R.id.homepage_app_bar_regular_phone_view).setVisibility(View.GONE);
findViewById(R.id.homepage_app_bar_two_pane_view).setVisibility(View.VISIBLE);
} else {
findViewById(R.id.homepage_app_bar_regular_phone_view).setVisibility(View.VISIBLE);
findViewById(R.id.homepage_app_bar_two_pane_view).setVisibility(View.GONE);
}
}
private int getSearchBoxHeight() {
final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);