1/*
2 * Copyright (C) 2016 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
17package com.android.internal.widget;
18
19import android.annotation.Nullable;
20import android.content.Context;
21import android.util.AttributeSet;
22import android.view.View;
23import android.view.ViewGroup;
24import android.widget.FrameLayout;
25import android.widget.ImageView;
26import android.widget.RelativeLayout;
27import android.widget.RemoteViews;
28
29/**
30 * A TextView that can float around an image on the end.
31 *
32 * @hide
33 */
34@RemoteViews.RemoteView
35public class MediaNotificationView extends FrameLayout {
36
37    private final int mMaxImageSize;
38    private final int mImageMinTopMargin;
39    private final int mNotificationContentMarginEnd;
40    private final int mNotificationContentImageMarginEnd;
41    private ImageView mRightIcon;
42    private View mActions;
43    private View mHeader;
44    private View mMainColumn;
45
46    public MediaNotificationView(Context context) {
47        this(context, null);
48    }
49
50    public MediaNotificationView(Context context, @Nullable AttributeSet attrs) {
51        this(context, attrs, 0);
52    }
53
54    public MediaNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
55        this(context, attrs, defStyleAttr, 0);
56    }
57
58    @Override
59    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
60        int mode = MeasureSpec.getMode(widthMeasureSpec);
61        boolean hasIcon = mRightIcon.getVisibility() != GONE;
62        if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
63            measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
64            int size = MeasureSpec.getSize(widthMeasureSpec);
65            size = size - mActions.getMeasuredWidth();
66            ViewGroup.MarginLayoutParams layoutParams =
67                    (MarginLayoutParams) mRightIcon.getLayoutParams();
68            int imageEndMargin = layoutParams.getMarginEnd();
69            size -= imageEndMargin;
70            size = Math.min(size, mMaxImageSize);
71            size = Math.max(size, mRightIcon.getMinimumWidth());
72            layoutParams.width = size;
73            layoutParams.height = size;
74            mRightIcon.setLayoutParams(layoutParams);
75
76            // lets ensure that the main column doesn't run into the image
77            ViewGroup.MarginLayoutParams mainParams
78                    = (MarginLayoutParams) mMainColumn.getLayoutParams();
79            int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
80            if (marginEnd != mainParams.getMarginEnd()) {
81                mainParams.setMarginEnd(marginEnd);
82                mMainColumn.setLayoutParams(mainParams);
83            }
84
85        }
86        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
87        ViewGroup.MarginLayoutParams iconParams =
88                (MarginLayoutParams) mRightIcon.getLayoutParams();
89        int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
90                - iconParams.bottomMargin;
91        // If the topMargin is high enough we can also remove the header constraint!
92        boolean reMeasure = false;
93        if (!hasIcon || topMargin >= mImageMinTopMargin) {
94            reMeasure = resetHeaderIndention();
95        } else {
96            int paddingEnd = mNotificationContentImageMarginEnd;
97            ViewGroup.MarginLayoutParams headerParams =
98                    (MarginLayoutParams) mHeader.getLayoutParams();
99            int newMarginEnd = mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd();
100            if (headerParams.getMarginEnd() != newMarginEnd) {
101                headerParams.setMarginEnd(newMarginEnd);
102                mHeader.setLayoutParams(headerParams);
103                reMeasure = true;
104            }
105            if (mHeader.getPaddingEnd() != paddingEnd) {
106                mHeader.setPaddingRelative(mHeader.getPaddingStart(),
107                        mHeader.getPaddingTop(),
108                        paddingEnd,
109                        mHeader.getPaddingBottom());
110                reMeasure = true;
111            }
112        }
113        if (reMeasure) {
114            measureChildWithMargins(mHeader, widthMeasureSpec, 0, heightMeasureSpec, 0);
115        }
116    }
117
118    private boolean resetHeaderIndention() {
119        boolean remeasure = false;
120        if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
121            mHeader.setPaddingRelative(mHeader.getPaddingStart(),
122                    mHeader.getPaddingTop(),
123                    mNotificationContentMarginEnd,
124                    mHeader.getPaddingBottom());
125            remeasure = true;
126        }
127        ViewGroup.MarginLayoutParams headerParams =
128                (MarginLayoutParams) mHeader.getLayoutParams();
129        headerParams.setMarginEnd(0);
130        if (headerParams.getMarginEnd() != 0) {
131            headerParams.setMarginEnd(0);
132            mHeader.setLayoutParams(headerParams);
133            remeasure = true;
134        }
135        return remeasure;
136    }
137
138    public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
139            int defStyleRes) {
140        super(context, attrs, defStyleAttr, defStyleRes);
141        mMaxImageSize = context.getResources().getDimensionPixelSize(
142                com.android.internal.R.dimen.media_notification_expanded_image_max_size);
143        mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
144                com.android.internal.R.dimen.notification_content_margin_top)
145                + getResources().getDisplayMetrics().density * 2);
146        mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
147                com.android.internal.R.dimen.notification_content_margin_end);
148        mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
149                com.android.internal.R.dimen.notification_content_image_margin_end);
150    }
151
152    @Override
153    protected void onFinishInflate() {
154        super.onFinishInflate();
155        mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
156        mActions = findViewById(com.android.internal.R.id.media_actions);
157        mHeader = findViewById(com.android.internal.R.id.notification_header);
158        mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
159    }
160}
161