149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/*
249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2013 The Android Open Source Project
349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes *
449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * you may not use this file except in compliance with the License.
649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * You may obtain a copy of the License at
749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes *
849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes *
1049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Unless required by applicable law or agreed to in writing, software
1149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
1249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * See the License for the specific language governing permissions and
1449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * limitations under the License.
1549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */
1649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
1749c78900da0d43140fb602431fb93212bd7f6c70Chris Banespackage android.support.v4.widget;
1849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
1949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.View;
20322f8748f9d8de6f79345f660c859f163ad363b7Chris Banesimport android.view.WindowManager;
2149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.PopupWindow;
2249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/**
2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Helper for accessing features in PopupWindow introduced after API level 4
2549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * in a backwards compatible fashion.
2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */
2749c78900da0d43140fb602431fb93212bd7f6c70Chris Banespublic class PopupWindowCompat {
2849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
2949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Interface for the full API.
3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
3149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    interface PopupWindowImpl {
32322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, int gravity);
33322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor);
34322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        boolean getOverlapAnchor(PopupWindow popupWindow);
35322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        void setWindowLayoutType(PopupWindow popupWindow, int layoutType);
36322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        int getWindowLayoutType(PopupWindow popupWindow);
3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
3849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
3949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
4049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Interface implementation that doesn't use anything above v4 APIs.
4149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
4249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    static class BasePopupWindowImpl implements PopupWindowImpl {
4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
4449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
4549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                int gravity) {
4649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            popup.showAsDropDown(anchor, xoff, yoff);
4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
4844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
4944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
5044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
5144918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            // noop
5244918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
5344918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
5444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
5544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public boolean getOverlapAnchor(PopupWindow popupWindow) {
5644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            return false;
5744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
58322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
59322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
60322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
61322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            // no-op
62322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
63322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
64322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
65322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public int getWindowLayoutType(PopupWindow popupWindow) {
66322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            return 0;
67322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
68322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    }
69322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
70322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    /**
71322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * Interface implementation that doesn't use anything above v4 APIs.
72322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     */
73322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    static class GingerbreadPopupWindowImpl extends BasePopupWindowImpl {
74322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
75322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
76322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            PopupWindowCompatGingerbread.setWindowLayoutType(popupWindow, layoutType);
77322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
78322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
79322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
80322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public int getWindowLayoutType(PopupWindow popupWindow) {
81322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            return PopupWindowCompatGingerbread.getWindowLayoutType(popupWindow);
82322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
8349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
8549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
8649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Interface implementation for devices with at least KitKat APIs.
8749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
88322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    static class KitKatPopupWindowImpl extends GingerbreadPopupWindowImpl {
8949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
9149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                int gravity) {
9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            PopupWindowCompatKitKat.showAsDropDown(popup, anchor, xoff, yoff, gravity);
9349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
9549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
9644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    static class Api21PopupWindowImpl extends KitKatPopupWindowImpl {
9744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
9844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
9944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            PopupWindowCompatApi21.setOverlapAnchor(popupWindow, overlapAnchor);
10044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
10144918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
10244918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
10344918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public boolean getOverlapAnchor(PopupWindow popupWindow) {
10444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            return PopupWindowCompatApi21.getOverlapAnchor(popupWindow);
10544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
10644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    }
10744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
10844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    static class Api23PopupWindowImpl extends Api21PopupWindowImpl {
10944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
11044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
11144918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            PopupWindowCompatApi23.setOverlapAnchor(popupWindow, overlapAnchor);
11244918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
11344918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
11444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        @Override
11544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        public boolean getOverlapAnchor(PopupWindow popupWindow) {
11644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            return PopupWindowCompatApi23.getOverlapAnchor(popupWindow);
11744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        }
118322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
119322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
120322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
121322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            PopupWindowCompatApi23.setWindowLayoutType(popupWindow, layoutType);
122322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
123322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
124322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        @Override
125322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        public int getWindowLayoutType(PopupWindow popupWindow) {
126322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            return PopupWindowCompatApi23.getWindowLayoutType(popupWindow);
127322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        }
12844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    }
12944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
13049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
13149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Select the correct implementation to use for the current platform.
13249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
13349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    static final PopupWindowImpl IMPL;
13449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    static {
13549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int version = android.os.Build.VERSION.SDK_INT;
13644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        if (version >= 23) {
13744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            IMPL = new Api23PopupWindowImpl();
13844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        } else if (version >= 21) {
13944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes            IMPL = new Api21PopupWindowImpl();
14044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        } else if (version >= 19) {
14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            IMPL = new KitKatPopupWindowImpl();
142322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        } else if (version >= 9) {
143322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes            IMPL = new GingerbreadPopupWindowImpl();
14449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        } else {
14549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            IMPL = new BasePopupWindowImpl();
14649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
14749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
14849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private PopupWindowCompat() {
15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        // This class is not publicly instantiable.
15149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
15249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
15349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>Display the content view in a popup window anchored to the bottom-left
15549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * corner of the anchor view offset by the specified x and y coordinates.
15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * If there is not enough room on screen to show
15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the popup in its entirety, this method tries to find a parent scroll
15849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * view to scroll. If no parent scroll view can be scrolled, the bottom-left
15949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * corner of the popup is pinned at the top left corner of the anchor view.</p>
16049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>If the view later scrolls to move <code>anchor</code> to a different
16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * location, the popup will be moved correspondingly.</p>
16249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
16349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param popup the PopupWindow to show
16449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param anchor the view on which to pin the popup window
16549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param xoff A horizontal offset from the anchor in pixels
16649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param yoff A vertical offset from the anchor in pixels
16749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param gravity Alignment of the popup relative to the anchor
16849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
16949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public static void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
17049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            int gravity) {
17149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        IMPL.showAsDropDown(popup, anchor, xoff, yoff, gravity);
17249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
17344918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
17444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    /**
17544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * Sets whether the popup window should overlap its anchor view when
17644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * displayed as a drop-down.
17744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     *
17844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * @param overlapAnchor Whether the popup should overlap its anchor.
17944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     */
18044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    public static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
18144918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        IMPL.setOverlapAnchor(popupWindow, overlapAnchor);
18244918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    }
18344918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
18444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    /**
18544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * Returns whether the popup window should overlap its anchor view when
18644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * displayed as a drop-down.
18744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     *
18844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     * @return Whether the popup should overlap its anchor.
18944918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes     */
19044918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    public static boolean getOverlapAnchor(PopupWindow popupWindow) {
19144918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        return IMPL.getOverlapAnchor(popupWindow);
19244918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    }
193322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
194322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    /**
195322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * Set the layout type for this window. This value will be passed through to
196322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * {@link WindowManager.LayoutParams#type} therefore the value should match any value
197322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * {@link WindowManager.LayoutParams#type} accepts.
198322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     *
199322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * @param layoutType Layout type for this window.
200322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     *
201322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * @see WindowManager.LayoutParams#type
202322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     */
203322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
204322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        IMPL.setWindowLayoutType(popupWindow, layoutType);
205322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    }
206322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes
207322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    /**
208322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * Returns the layout type for this window.
209322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     *
210322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     * @see #setWindowLayoutType(PopupWindow popupWindow, int)
211322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes     */
212322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    public static int getWindowLayoutType(PopupWindow popupWindow) {
213322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes        return IMPL.getWindowLayoutType(popupWindow);
214322f8748f9d8de6f79345f660c859f163ad363b7Chris Banes    }
21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes}
216