Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b567b75f authored by chihhangchuang's avatar chihhangchuang
Browse files

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
parent a276799c
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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
+71 −0
Original line number Diff line number Diff line
<?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
+1 −1
Original line number Diff line number Diff line
@@ -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>
+8 −1
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ public class ThemeFragment extends AppbarFragment {
    private TimeTicker mTicker;
    private BottomActionBar mBottomActionBar;
    private WallpaperPreviewer mWallpaperPreviewer;
    private ThemeOptionPreviewer mThemeOptionPreviewer;

    @Override
    public void onAttach(Context context) {
@@ -153,6 +154,10 @@ public class ThemeFragment extends AppbarFragment {
                    view.removeOnLayoutChangeListener(this);
                }
            });
            mThemeOptionPreviewer = new ThemeOptionPreviewer(
                    getLifecycle(),
                    getContext(),
                    view.findViewById(R.id.theme_preview_container));
        }
        return view;
    }
@@ -302,7 +307,9 @@ public class ThemeFragment extends AppbarFragment {
                        }
                        mEventLogger.logThemeSelected(mSelectedTheme,
                                selected instanceof CustomTheme);
                        if (!USE_NEW_PREVIEW) {
                        if (USE_NEW_PREVIEW) {
                            mThemeOptionPreviewer.setThemeBundle(mSelectedTheme);
                        } else {
                            createAdapter(options);
                        }
                        mBottomActionBar.show();
+160 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}