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 SetupWizardIllustration(Context context)52 public SetupWizardIllustration(Context context) { 53 this(context, null); 54 } 55 SetupWizardIllustration(Context context, AttributeSet attrs)56 public SetupWizardIllustration(Context context, AttributeSet attrs) { 57 this(context, attrs, 0); 58 } 59 SetupWizardIllustration(Context context, AttributeSet attrs, int defStyleAttr)60 public SetupWizardIllustration(Context context, AttributeSet attrs, int defStyleAttr) { 61 this(context, attrs, defStyleAttr, 0); 62 } 63 SetupWizardIllustration(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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 setBackground(Drawable background)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 setForeground(Drawable foreground)92 public void setForeground(Drawable foreground) { 93 mForeground = foreground; 94 } 95 96 @Override onResolveDrawables(int layoutDirection)97 public void onResolveDrawables(int layoutDirection) { 98 mBackground.setLayoutDirection(layoutDirection); 99 mForeground.setLayoutDirection(layoutDirection); 100 } 101 102 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)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 onLayout(boolean changed, int left, int top, int right, int bottom)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 onDraw(Canvas canvas)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