1be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi/*
2be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
3be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
4be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
5be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * you may not use this file except in compliance with the License.
6be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * You may obtain a copy of the License at
7be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
8be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
9be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
10be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
11be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
12be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * See the License for the specific language governing permissions and
14be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * limitations under the License
15be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi */
16be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
17be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggipackage com.android.systemui.statusbar;
18be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
19be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.content.Context;
20be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.graphics.Outline;
217b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craikimport android.graphics.Rect;
228efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinekimport android.graphics.RectF;
23be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.util.AttributeSet;
247b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craikimport android.view.View;
257b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craikimport android.view.ViewOutlineProvider;
26be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
27be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi/**
28be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Like {@link ExpandableView}, but setting an outline for the height and clipping.
29be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi */
30be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggipublic abstract class ExpandableOutlineView extends ExpandableView {
31be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
327b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik    private final Rect mOutlineRect = new Rect();
338efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek    private boolean mCustomOutline;
34d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    private float mOutlineAlpha = -1f;
35be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
36b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    ViewOutlineProvider mProvider = new ViewOutlineProvider() {
37b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        @Override
38b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        public void getOutline(View view, Outline outline) {
39b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            int translation = (int) getTranslation();
40b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            if (!mCustomOutline) {
41b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor                outline.setRect(translation,
42b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor                        mClipTopAmount,
43b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor                        getWidth() + translation,
44b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor                        Math.max(getActualHeight(), mClipTopAmount));
45b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            } else {
46b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor                outline.setRect(mOutlineRect);
47b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            }
48b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            outline.setAlpha(mOutlineAlpha);
49b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        }
50b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    };
51b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor
52be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public ExpandableOutlineView(Context context, AttributeSet attrs) {
53be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super(context, attrs);
54b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        setOutlineProvider(mProvider);
55be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
56be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
57be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
58d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    public void setActualHeight(int actualHeight, boolean notifyListeners) {
59d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi        super.setActualHeight(actualHeight, notifyListeners);
607b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik        invalidateOutline();
61be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
62be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
63be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
64be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setClipTopAmount(int clipTopAmount) {
65be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super.setClipTopAmount(clipTopAmount);
667b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik        invalidateOutline();
67be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
68be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
6983eb6bb5d83d3994a3750b566a2109a049ab1388Jorim Jaggi    protected void setOutlineAlpha(float alpha) {
70d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        if (alpha != mOutlineAlpha) {
71d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            mOutlineAlpha = alpha;
72d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            invalidateOutline();
73d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        }
7483eb6bb5d83d3994a3750b566a2109a049ab1388Jorim Jaggi    }
7583eb6bb5d83d3994a3750b566a2109a049ab1388Jorim Jaggi
763322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    @Override
773322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    public float getOutlineAlpha() {
783322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek        return mOutlineAlpha;
793322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    }
803322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek
818efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek    protected void setOutlineRect(RectF rect) {
828efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek        if (rect != null) {
838efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek            setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
848efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek        } else {
858efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek            mCustomOutline = false;
86560e64d3d95a17123048bebe2fb06ffe4567fb78Selim Cinek            setClipToOutline(false);
877b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik            invalidateOutline();
888efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek        }
898efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek    }
908efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek
913322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    @Override
923322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    public int getOutlineTranslation() {
93b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        return mCustomOutline ? mOutlineRect.left : (int) getTranslation();
943322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek    }
953322357b5045fdcc3e3b04c65219d39ce1ae441fSelim Cinek
96b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    public void updateOutline() {
97b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        if (mCustomOutline) {
98b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            return;
99b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        }
100b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        boolean hasOutline = true;
101b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        if (isChildInGroup()) {
102b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            hasOutline = isGroupExpanded() && !isGroupExpansionChanging();
103b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        } else if (isSummaryWithChildren()) {
104b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor            hasOutline = !isGroupExpanded() || isGroupExpansionChanging();
105b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        }
106b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        setOutlineProvider(hasOutline ? mProvider : null);
1074b80b1025f82fa7becc8e126bfa4aea39affcf65Mady Mellor    }
1084b80b1025f82fa7becc8e126bfa4aea39affcf65Mady Mellor
109b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    public boolean isOutlineShowing() {
110b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        ViewOutlineProvider op = getOutlineProvider();
111b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        return op != null;
112b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    }
113b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor
114b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor    protected void setOutlineRect(float left, float top, float right, float bottom) {
1158efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek        mCustomOutline = true;
116b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor        setClipToOutline(true);
1178efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek
1187b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik        mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
1198efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek
1208efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek        // Outlines need to be at least 1 dp
1213969ffa2f5830a680490d03fbb113a7fee900b56Selim Cinek        mOutlineRect.bottom = (int) Math.max(top, mOutlineRect.bottom);
1223969ffa2f5830a680490d03fbb113a7fee900b56Selim Cinek        mOutlineRect.right = (int) Math.max(left, mOutlineRect.right);
1238efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek
1247b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik        invalidateOutline();
1258efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek    }
1267b7ca3cdf25bee73aa9e58aaaf6ce75fe81bd045Chris Craik
127be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi}
128