Add new preview for theme picker (Part2)
- Add some contents to the preview screen(Mostly reuse the old one)
- Will check with UX the small preview spec, now we just put them there first.
- Video: https://drive.google.com/file/d/18rrT6XsqVnhuMTrLM-A6jVn_sHF379eE/view?usp=sharing
Test: Manually
Bug: 146475648
Change-Id: I06f1a38454861f46531dca228b649068f46c71ad
diff --git a/res/layout/theme_preview_card_v2.xml b/res/layout/theme_preview_card_v2.xml
index b6e8d49..f0852e6 100644
--- a/res/layout/theme_preview_card_v2.xml
+++ b/res/layout/theme_preview_card_v2.xml
@@ -32,4 +32,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <FrameLayout
+ android:id="@+id/theme_preview_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingVertical="@dimen/preview_card_top_padding"
+ android:paddingHorizontal="@dimen/preview_card_padding"/>
</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/theme_preview_content_v2.xml b/res/layout/theme_preview_content_v2.xml
new file mode 100644
index 0000000..6370168
--- /dev/null
+++ b/res/layout/theme_preview_content_v2.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 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="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/theme_preview_topbar" />
+
+ <!-- App icons for shapes. -->
+ <GridLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="horizontal"
+ android:columnCount="2"
+ android:rowCount="2"
+ android:useDefaultMargins="true"
+ android:layout_marginTop="12dp">
+
+ <ImageView
+ android:id="@+id/shape_preview_icon_0"
+ android:layout_width="@dimen/preview_theme_shape_size"
+ android:layout_height="@dimen/preview_theme_shape_size"
+ android:layout_gravity="start"
+ android:elevation="4dp"/>
+ <ImageView
+ android:id="@+id/shape_preview_icon_1"
+ android:layout_width="@dimen/preview_theme_shape_size"
+ android:layout_height="@dimen/preview_theme_shape_size"
+ android:layout_gravity="end"
+ android:elevation="4dp"/>
+
+ <ImageView
+ android:id="@+id/shape_preview_icon_2"
+ android:layout_width="@dimen/preview_theme_shape_size"
+ android:layout_height="@dimen/preview_theme_shape_size"
+ android:layout_gravity="start"
+ android:elevation="4dp"/>
+
+ <ImageView
+ android:id="@+id/shape_preview_icon_3"
+ android:layout_width="@dimen/preview_theme_shape_size"
+ android:layout_height="@dimen/preview_theme_shape_size"
+ android:layout_gravity="end"
+ android:elevation="4dp"/>
+ </GridLayout>
+
+ <!-- Placeholder, will add more content later. -->
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <include layout="@layout/theme_cover_qsb" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b8fe190..c4d51af 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -64,7 +64,7 @@
<dimen name="preview_theme_icon_size">30dp</dimen>
<dimen name="preview_theme_tile_size">16dp</dimen>
<dimen name="preview_theme_shape_size">36dp</dimen>
- <dimen name="preview_theme_cover_topbar_clock_size">14sp</dimen>
+ <dimen name="preview_theme_cover_topbar_clock_size">12sp</dimen>
<dimen name="preview_theme_cover_topbar_icon_size">16dp</dimen>
<dimen name="preview_theme_cover_content_extra_margin">16dp</dimen>
<dimen name="preview_theme_content_bottom">@dimen/min_taptarget_height</dimen>
diff --git a/src/com/android/customization/picker/theme/ThemeFragment.java b/src/com/android/customization/picker/theme/ThemeFragment.java
index d8f3a6e..84705c2 100644
--- a/src/com/android/customization/picker/theme/ThemeFragment.java
+++ b/src/com/android/customization/picker/theme/ThemeFragment.java
@@ -112,6 +112,7 @@
private TimeTicker mTicker;
private BottomActionBar mBottomActionBar;
private WallpaperPreviewer mWallpaperPreviewer;
+ private ThemeOptionPreviewer mThemeOptionPreviewer;
@Override
public void onAttach(Context context) {
@@ -153,6 +154,10 @@
view.removeOnLayoutChangeListener(this);
}
});
+ mThemeOptionPreviewer = new ThemeOptionPreviewer(
+ getLifecycle(),
+ getContext(),
+ view.findViewById(R.id.theme_preview_container));
}
return view;
}
@@ -302,7 +307,9 @@
}
mEventLogger.logThemeSelected(mSelectedTheme,
selected instanceof CustomTheme);
- if (!USE_NEW_PREVIEW) {
+ if (USE_NEW_PREVIEW) {
+ mThemeOptionPreviewer.setThemeBundle(mSelectedTheme);
+ } else {
createAdapter(options);
}
mBottomActionBar.show();
diff --git a/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java b/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java
new file mode 100644
index 0000000..d1c6dcd
--- /dev/null
+++ b/src/com/android/customization/picker/theme/ThemeOptionPreviewer.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 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.customization.picker.theme;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.MainThread;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+
+import com.android.customization.model.theme.ThemeBundle;
+import com.android.customization.model.theme.ThemeBundle.PreviewInfo;
+import com.android.customization.picker.TimeTicker;
+import com.android.wallpaper.R;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.util.Calendar;
+import java.util.List;
+import java.util.TimeZone;
+
+/** A class to load the {@link ThemeBundle} preview to the view. */
+class ThemeOptionPreviewer implements LifecycleObserver {
+
+ /**
+ * Maps which icon from ResourceConstants#ICONS_FOR_PREVIEW to use for each icon in the
+ * top bar (fake "status bar") of the cover page.
+ */
+ private static final int [] sTopBarIconToPreviewIcon = new int [] { 0, 6, 7 };
+
+ private int[] mShapeIconIds = {
+ R.id.shape_preview_icon_0, R.id.shape_preview_icon_1,
+ R.id.shape_preview_icon_2, R.id.shape_preview_icon_3
+ };
+
+ private final Context mContext;
+
+ private View mContentView;
+ private TextView mClock;
+ private TimeTicker mTicker;
+
+ ThemeOptionPreviewer(Lifecycle lifecycle, Context context, ViewGroup previewContainer) {
+ lifecycle.addObserver(this);
+
+ mContext = context;
+ mContentView = LayoutInflater.from(context).inflate(
+ R.layout.theme_preview_content_v2, previewContainer);
+ mClock = mContentView.findViewById(R.id.theme_preview_clock);
+ updateTime();
+ }
+
+ /** Loads the Theme option into the container view. */
+ public void setThemeBundle(ThemeBundle themeBundle) {
+ PreviewInfo previewInfo = themeBundle.getPreviewInfo();
+ setHeadlineFont(previewInfo.headlineFontFamily);
+ setTopBarIcons(previewInfo.icons);
+ setShapeIcons(previewInfo.shapeAppIcons);
+ setQsbRadius(previewInfo.bottomSheeetCornerRadius);
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ @MainThread
+ public void onResume() {
+ mTicker = TimeTicker.registerNewReceiver(mContext, this::updateTime);
+ updateTime();
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+ @MainThread
+ public void onPause() {
+ if (mContext != null) {
+ mContext.unregisterReceiver(mTicker);
+ }
+ }
+
+ private void setHeadlineFont(Typeface headlineFont) {
+ mClock.setTypeface(headlineFont);
+
+ // Update other text style here.
+ }
+
+ private void setTopBarIcons(List<Drawable> icons) {
+ ViewGroup iconsContainer = mContentView.findViewById(R.id.theme_preview_top_bar_icons);
+ for (int i = 0; i < iconsContainer.getChildCount(); i++) {
+ int iconIndex = sTopBarIconToPreviewIcon[i];
+ if (iconIndex < icons.size()) {
+ ((ImageView) iconsContainer.getChildAt(i))
+ .setImageDrawable(icons.get(iconIndex).getConstantState()
+ .newDrawable().mutate());
+ } else {
+ iconsContainer.getChildAt(i).setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void setShapeIcons(List<Drawable> icons) {
+ for (int i = 0; i < mShapeIconIds.length && i < icons.size(); i++) {
+ ImageView iconView = mContentView.findViewById(mShapeIconIds[i]);
+ iconView.setBackground(icons.get(i));
+ }
+ }
+
+ private void setQsbRadius(int cornerRadius) {
+ View qsb = mContentView.findViewById(R.id.theme_qsb);
+ if (qsb != null && qsb.getVisibility() == View.VISIBLE) {
+ if (qsb.getBackground() instanceof GradientDrawable) {
+ GradientDrawable bg = (GradientDrawable) qsb.getBackground();
+ float radius = useRoundedQSB(cornerRadius)
+ ? (float) qsb.getLayoutParams().height / 2 : cornerRadius;
+ bg.setCornerRadii(new float[]{
+ radius, radius, radius, radius,
+ radius, radius, radius, radius});
+ }
+ }
+ }
+
+ private void updateTime() {
+ if (mClock != null) {
+ mClock.setText(getFormattedTime());
+ }
+ }
+
+ private String getFormattedTime() {
+ DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
+ StringBuffer time = new StringBuffer();
+ FieldPosition amPmPosition = new FieldPosition(DateFormat.Field.AM_PM);
+ df.format(Calendar.getInstance(TimeZone.getDefault()).getTime(), time, amPmPosition);
+ if (amPmPosition.getBeginIndex() > 0) {
+ time.delete(amPmPosition.getBeginIndex(), amPmPosition.getEndIndex());
+ }
+ return time.toString();
+ }
+
+ private boolean useRoundedQSB(int cornerRadius) {
+ return cornerRadius >= mContext.getResources().getDimensionPixelSize(
+ R.dimen.roundCornerThreshold);
+ }
+}