1 /*
2  * Copyright (C) 2015 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 package android.support.design.widget;
18 
19 import android.content.res.ColorStateList;
20 import android.content.res.Resources;
21 import android.graphics.Color;
22 import android.graphics.PorterDuff;
23 import android.graphics.Rect;
24 import android.graphics.drawable.Drawable;
25 import android.graphics.drawable.GradientDrawable;
26 import android.support.annotation.Nullable;
27 import android.support.design.R;
28 import android.view.ViewTreeObserver;
29 
30 abstract class FloatingActionButtonImpl {
31 
32     Drawable mShapeDrawable;
33     Drawable mRippleDrawable;
34     CircularBorderDrawable mBorderDrawable;
35     Drawable mContentBackground;
36 
37     float mElevation;
38     float mPressedTranslationZ;
39 
40     interface InternalVisibilityChangedListener {
onShown()41         public void onShown();
onHidden()42         public void onHidden();
43     }
44 
45     static final int SHOW_HIDE_ANIM_DURATION = 200;
46 
47     static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed,
48             android.R.attr.state_enabled};
49     static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused,
50             android.R.attr.state_enabled};
51     static final int[] EMPTY_STATE_SET = new int[0];
52 
53     final VisibilityAwareImageButton mView;
54     final ShadowViewDelegate mShadowViewDelegate;
55 
56     private final Rect mTmpRect = new Rect();
57     private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
58 
FloatingActionButtonImpl(VisibilityAwareImageButton view, ShadowViewDelegate shadowViewDelegate)59     FloatingActionButtonImpl(VisibilityAwareImageButton view,
60             ShadowViewDelegate shadowViewDelegate) {
61         mView = view;
62         mShadowViewDelegate = shadowViewDelegate;
63     }
64 
setBackgroundDrawable(ColorStateList backgroundTint, PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth)65     abstract void setBackgroundDrawable(ColorStateList backgroundTint,
66             PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth);
67 
setBackgroundTintList(ColorStateList tint)68     abstract void setBackgroundTintList(ColorStateList tint);
69 
setBackgroundTintMode(PorterDuff.Mode tintMode)70     abstract void setBackgroundTintMode(PorterDuff.Mode tintMode);
71 
setRippleColor(int rippleColor)72     abstract void setRippleColor(int rippleColor);
73 
setElevation(float elevation)74     final void setElevation(float elevation) {
75         if (mElevation != elevation) {
76             mElevation = elevation;
77             onElevationChanged(elevation);
78         }
79     }
80 
getElevation()81     abstract float getElevation();
82 
setPressedTranslationZ(float translationZ)83     final void setPressedTranslationZ(float translationZ) {
84         if (mPressedTranslationZ != translationZ) {
85             mPressedTranslationZ = translationZ;
86             onTranslationZChanged(translationZ);
87         }
88     }
89 
onElevationChanged(float elevation)90     abstract void onElevationChanged(float elevation);
91 
onTranslationZChanged(float translationZ)92     abstract void onTranslationZChanged(float translationZ);
93 
onDrawableStateChanged(int[] state)94     abstract void onDrawableStateChanged(int[] state);
95 
jumpDrawableToCurrentState()96     abstract void jumpDrawableToCurrentState();
97 
hide(@ullable InternalVisibilityChangedListener listener, boolean fromUser)98     abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
99 
show(@ullable InternalVisibilityChangedListener listener, boolean fromUser)100     abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
101 
getContentBackground()102     final Drawable getContentBackground() {
103         return mContentBackground;
104     }
105 
onCompatShadowChanged()106     abstract void onCompatShadowChanged();
107 
updatePadding()108     final void updatePadding() {
109         Rect rect = mTmpRect;
110         getPadding(rect);
111         onPaddingUpdated(rect);
112         mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
113     }
114 
getPadding(Rect rect)115     abstract void getPadding(Rect rect);
116 
onPaddingUpdated(Rect padding)117     void onPaddingUpdated(Rect padding) {}
118 
onAttachedToWindow()119     void onAttachedToWindow() {
120         if (requirePreDrawListener()) {
121             ensurePreDrawListener();
122             mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
123         }
124     }
125 
onDetachedFromWindow()126     void onDetachedFromWindow() {
127         if (mPreDrawListener != null) {
128             mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
129             mPreDrawListener = null;
130         }
131     }
132 
requirePreDrawListener()133     boolean requirePreDrawListener() {
134         return false;
135     }
136 
createBorderDrawable(int borderWidth, ColorStateList backgroundTint)137     CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
138         final Resources resources = mView.getResources();
139         CircularBorderDrawable borderDrawable = newCircularDrawable();
140         borderDrawable.setGradientColors(
141                 resources.getColor(R.color.design_fab_stroke_top_outer_color),
142                 resources.getColor(R.color.design_fab_stroke_top_inner_color),
143                 resources.getColor(R.color.design_fab_stroke_end_inner_color),
144                 resources.getColor(R.color.design_fab_stroke_end_outer_color));
145         borderDrawable.setBorderWidth(borderWidth);
146         borderDrawable.setBorderTint(backgroundTint);
147         return borderDrawable;
148     }
149 
newCircularDrawable()150     CircularBorderDrawable newCircularDrawable() {
151         return new CircularBorderDrawable();
152     }
153 
onPreDraw()154     void onPreDraw() {
155     }
156 
ensurePreDrawListener()157     private void ensurePreDrawListener() {
158         if (mPreDrawListener == null) {
159             mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
160                 @Override
161                 public boolean onPreDraw() {
162                     FloatingActionButtonImpl.this.onPreDraw();
163                     return true;
164                 }
165             };
166         }
167     }
168 
createShapeDrawable()169     GradientDrawable createShapeDrawable() {
170         GradientDrawable d = new GradientDrawable();
171         d.setShape(GradientDrawable.OVAL);
172         d.setColor(Color.WHITE);
173         return d;
174     }
175 }
176