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