Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 package com.android.settings.widget;
     19 
     20 import android.content.Context;
     21 import android.content.res.TypedArray;
     22 import android.graphics.Canvas;
     23 import android.graphics.Rect;
     24 import android.graphics.drawable.Drawable;
     25 import android.util.AttributeSet;
     26 import android.view.Gravity;
     27 import android.view.ViewOutlineProvider;
     28 import android.widget.FrameLayout;
     29 
     30 import com.android.settings.R;
     31 
     32 /**
     33  * Class to draw the illustration of setup wizard. The aspectRatio attribute determines the aspect
     34  * ratio of the top padding, which is leaving space for the illustration. Draws an illustration
     35  * (foreground) to fit the width of the view and fills the rest with the background.
     36  *
     37  * Copied from com.google.android.setupwizard.util.SetupWizardIllustration
     38  */
     39 public class SetupWizardIllustration extends FrameLayout {
     40 
     41     private static final String TAG = "SetupWizardIllustration";
     42 
     43     // Size of the baseline grid in pixels
     44     private float mBaselineGridSize;
     45     private Drawable mBackground;
     46     private Drawable mForeground;
     47     private final Rect mViewBounds = new Rect();
     48     private final Rect mForegroundBounds = new Rect();
     49     private float mScale = 1.0f;
     50     private float mAspectRatio = 0.0f;
     51 
     52     public SetupWizardIllustration(Context context) {
     53         this(context, null);
     54     }
     55 
     56     public SetupWizardIllustration(Context context, AttributeSet attrs) {
     57         this(context, attrs, 0);
     58     }
     59 
     60     public SetupWizardIllustration(Context context, AttributeSet attrs, int defStyleAttr) {
     61         this(context, attrs, defStyleAttr, 0);
     62     }
     63 
     64     public SetupWizardIllustration(Context context, AttributeSet attrs, int defStyleAttr,
     65             int defStyleRes) {
     66         super(context, attrs, defStyleAttr, defStyleRes);
     67         if (attrs != null) {
     68             TypedArray a = context.obtainStyledAttributes(attrs,
     69                     R.styleable.SetupWizardIllustration, 0, 0);
     70             mAspectRatio = a.getFloat(R.styleable.SetupWizardIllustration_aspectRatio, 0.0f);
     71             a.recycle();
     72         }
     73         // Number of pixels of the 8dp baseline grid as defined in material design specs
     74         mBaselineGridSize = getResources().getDisplayMetrics().density * 8;
     75         setWillNotDraw(false);
     76     }
     77 
     78     /**
     79      * The background will be drawn to fill up the rest of the view. It will also be scaled by the
     80      * same amount as the foreground so their textures look the same.
     81      */
     82     @Override
     83     public void setBackground(Drawable background) {
     84         mBackground = background;
     85     }
     86 
     87     /**
     88      * Sets the drawable used as the illustration. THe drawable is expected to have intrinsic
     89      * width and height defined and will be scaled to fit the width of the view.
     90      */
     91     @Override
     92     public void setForeground(Drawable foreground) {
     93         mForeground = foreground;
     94     }
     95 
     96     @Override
     97     public void onResolveDrawables(int layoutDirection) {
     98         mBackground.setLayoutDirection(layoutDirection);
     99         mForeground.setLayoutDirection(layoutDirection);
    100     }
    101 
    102     @Override
    103     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    104         if (mAspectRatio != 0.0f) {
    105             int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
    106             int illustrationHeight = (int) (parentWidth / mAspectRatio);
    107             illustrationHeight -= illustrationHeight % mBaselineGridSize;
    108             setPaddingRelative(0, illustrationHeight, 0, 0);
    109         }
    110         setOutlineProvider(ViewOutlineProvider.BOUNDS);
    111         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    112     }
    113 
    114     @Override
    115     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    116         final int layoutWidth = right - left;
    117         final int layoutHeight = bottom - top;
    118         if (mForeground != null) {
    119             int intrinsicWidth = mForeground.getIntrinsicWidth();
    120             int intrinsicHeight = mForeground.getIntrinsicHeight();
    121             final int layoutDirection = getLayoutDirection();
    122 
    123             mViewBounds.set(0, 0, layoutWidth, layoutHeight);
    124             if (mAspectRatio != 0f) {
    125                 mScale = layoutWidth / (float) intrinsicWidth;
    126                 intrinsicWidth = layoutWidth;
    127                 intrinsicHeight = (int) (intrinsicHeight * mScale);
    128             }
    129             Gravity.apply(Gravity.FILL_HORIZONTAL | Gravity.TOP, intrinsicWidth, intrinsicHeight,
    130                     mViewBounds, mForegroundBounds, layoutDirection);
    131             mForeground.setBounds(mForegroundBounds);
    132         }
    133         if (mBackground != null) {
    134             // Scale the bounds by mScale to compensate for the scale done to the canvas before
    135             // drawing.
    136             mBackground.setBounds(0, 0, (int) Math.ceil(layoutWidth / mScale),
    137                     (int) Math.ceil((layoutHeight - mForegroundBounds.height()) / mScale));
    138         }
    139         super.onLayout(changed, left, top, right, bottom);
    140     }
    141 
    142     @Override
    143     public void onDraw(Canvas canvas) {
    144         if (mBackground != null) {
    145             canvas.save();
    146             // Draw the background filling parts not covered by the illustration
    147             canvas.translate(0, mForegroundBounds.height());
    148             // Scale the background so its size matches the foreground
    149             canvas.scale(mScale, mScale, 0, 0);
    150             mBackground.draw(canvas);
    151             canvas.restore();
    152         }
    153         if (mForeground != null) {
    154             canvas.save();
    155             // Draw the illustration
    156             mForeground.draw(canvas);
    157             canvas.restore();
    158         }
    159         super.onDraw(canvas);
    160     }
    161 }
    162