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 package androidx.appcompat.widget;
18 
19 import android.content.Context;
20 import android.os.Build;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.widget.PopupWindow;
24 
25 import androidx.annotation.AttrRes;
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.StyleRes;
29 import androidx.appcompat.R;
30 import androidx.core.widget.PopupWindowCompat;
31 
32 class AppCompatPopupWindow extends PopupWindow {
33 
34     private static final boolean COMPAT_OVERLAP_ANCHOR = Build.VERSION.SDK_INT < 21;
35 
36     private boolean mOverlapAnchor;
37 
38     public AppCompatPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
39             @AttrRes int defStyleAttr) {
40         super(context, attrs, defStyleAttr);
41         init(context, attrs, defStyleAttr, 0);
42     }
43 
44     public AppCompatPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
45             @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
46         super(context, attrs, defStyleAttr, defStyleRes);
47         init(context, attrs, defStyleAttr, defStyleRes);
48     }
49 
50     private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
51         TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
52                 R.styleable.PopupWindow, defStyleAttr, defStyleRes);
53         if (a.hasValue(R.styleable.PopupWindow_overlapAnchor)) {
54             setSupportOverlapAnchor(a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false));
55         }
56         // We re-set this for tinting purposes
57         setBackgroundDrawable(a.getDrawable(R.styleable.PopupWindow_android_popupBackground));
58 
59         a.recycle();
60     }
61 
62     @Override
63     public void showAsDropDown(View anchor, int xoff, int yoff) {
64         if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
65             // If we're pre-L, emulate overlapAnchor by modifying the yOff
66             yoff -= anchor.getHeight();
67         }
68         super.showAsDropDown(anchor, xoff, yoff);
69     }
70 
71     @Override
72     public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
73         if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
74             // If we're pre-L, emulate overlapAnchor by modifying the yOff
75             yoff -= anchor.getHeight();
76         }
77         super.showAsDropDown(anchor, xoff, yoff, gravity);
78     }
79 
80     @Override
81     public void update(View anchor, int xoff, int yoff, int width, int height) {
82         if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
83             // If we're pre-L, emulate overlapAnchor by modifying the yOff
84             yoff -= anchor.getHeight();
85         }
86         super.update(anchor, xoff, yoff, width, height);
87     }
88 
89     private void setSupportOverlapAnchor(boolean overlapAnchor) {
90         if (COMPAT_OVERLAP_ANCHOR) {
91             mOverlapAnchor = overlapAnchor;
92         } else {
93             PopupWindowCompat.setOverlapAnchor(this, overlapAnchor);
94         }
95     }
96 }
97