1/* 2 * Copyright (C) 2013 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 android.support.v4.widget; 18 19import android.view.View; 20import android.view.WindowManager; 21import android.widget.PopupWindow; 22 23/** 24 * Helper for accessing features in PopupWindow introduced after API level 4 25 * in a backwards compatible fashion. 26 */ 27public class PopupWindowCompat { 28 /** 29 * Interface for the full API. 30 */ 31 interface PopupWindowImpl { 32 void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, int gravity); 33 void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor); 34 boolean getOverlapAnchor(PopupWindow popupWindow); 35 void setWindowLayoutType(PopupWindow popupWindow, int layoutType); 36 int getWindowLayoutType(PopupWindow popupWindow); 37 } 38 39 /** 40 * Interface implementation that doesn't use anything above v4 APIs. 41 */ 42 static class BasePopupWindowImpl implements PopupWindowImpl { 43 @Override 44 public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, 45 int gravity) { 46 popup.showAsDropDown(anchor, xoff, yoff); 47 } 48 49 @Override 50 public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) { 51 // noop 52 } 53 54 @Override 55 public boolean getOverlapAnchor(PopupWindow popupWindow) { 56 return false; 57 } 58 59 @Override 60 public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) { 61 // no-op 62 } 63 64 @Override 65 public int getWindowLayoutType(PopupWindow popupWindow) { 66 return 0; 67 } 68 } 69 70 /** 71 * Interface implementation that doesn't use anything above v4 APIs. 72 */ 73 static class GingerbreadPopupWindowImpl extends BasePopupWindowImpl { 74 @Override 75 public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) { 76 PopupWindowCompatGingerbread.setWindowLayoutType(popupWindow, layoutType); 77 } 78 79 @Override 80 public int getWindowLayoutType(PopupWindow popupWindow) { 81 return PopupWindowCompatGingerbread.getWindowLayoutType(popupWindow); 82 } 83 } 84 85 /** 86 * Interface implementation for devices with at least KitKat APIs. 87 */ 88 static class KitKatPopupWindowImpl extends GingerbreadPopupWindowImpl { 89 @Override 90 public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, 91 int gravity) { 92 PopupWindowCompatKitKat.showAsDropDown(popup, anchor, xoff, yoff, gravity); 93 } 94 } 95 96 static class Api21PopupWindowImpl extends KitKatPopupWindowImpl { 97 @Override 98 public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) { 99 PopupWindowCompatApi21.setOverlapAnchor(popupWindow, overlapAnchor); 100 } 101 102 @Override 103 public boolean getOverlapAnchor(PopupWindow popupWindow) { 104 return PopupWindowCompatApi21.getOverlapAnchor(popupWindow); 105 } 106 } 107 108 static class Api23PopupWindowImpl extends Api21PopupWindowImpl { 109 @Override 110 public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) { 111 PopupWindowCompatApi23.setOverlapAnchor(popupWindow, overlapAnchor); 112 } 113 114 @Override 115 public boolean getOverlapAnchor(PopupWindow popupWindow) { 116 return PopupWindowCompatApi23.getOverlapAnchor(popupWindow); 117 } 118 119 @Override 120 public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) { 121 PopupWindowCompatApi23.setWindowLayoutType(popupWindow, layoutType); 122 } 123 124 @Override 125 public int getWindowLayoutType(PopupWindow popupWindow) { 126 return PopupWindowCompatApi23.getWindowLayoutType(popupWindow); 127 } 128 } 129 130 /** 131 * Select the correct implementation to use for the current platform. 132 */ 133 static final PopupWindowImpl IMPL; 134 static { 135 final int version = android.os.Build.VERSION.SDK_INT; 136 if (version >= 23) { 137 IMPL = new Api23PopupWindowImpl(); 138 } else if (version >= 21) { 139 IMPL = new Api21PopupWindowImpl(); 140 } else if (version >= 19) { 141 IMPL = new KitKatPopupWindowImpl(); 142 } else if (version >= 9) { 143 IMPL = new GingerbreadPopupWindowImpl(); 144 } else { 145 IMPL = new BasePopupWindowImpl(); 146 } 147 } 148 149 private PopupWindowCompat() { 150 // This class is not publicly instantiable. 151 } 152 153 /** 154 * <p>Display the content view in a popup window anchored to the bottom-left 155 * corner of the anchor view offset by the specified x and y coordinates. 156 * If there is not enough room on screen to show 157 * the popup in its entirety, this method tries to find a parent scroll 158 * view to scroll. If no parent scroll view can be scrolled, the bottom-left 159 * corner of the popup is pinned at the top left corner of the anchor view.</p> 160 * <p>If the view later scrolls to move <code>anchor</code> to a different 161 * location, the popup will be moved correspondingly.</p> 162 * 163 * @param popup the PopupWindow to show 164 * @param anchor the view on which to pin the popup window 165 * @param xoff A horizontal offset from the anchor in pixels 166 * @param yoff A vertical offset from the anchor in pixels 167 * @param gravity Alignment of the popup relative to the anchor 168 */ 169 public static void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, 170 int gravity) { 171 IMPL.showAsDropDown(popup, anchor, xoff, yoff, gravity); 172 } 173 174 /** 175 * Sets whether the popup window should overlap its anchor view when 176 * displayed as a drop-down. 177 * 178 * @param overlapAnchor Whether the popup should overlap its anchor. 179 */ 180 public static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) { 181 IMPL.setOverlapAnchor(popupWindow, overlapAnchor); 182 } 183 184 /** 185 * Returns whether the popup window should overlap its anchor view when 186 * displayed as a drop-down. 187 * 188 * @return Whether the popup should overlap its anchor. 189 */ 190 public static boolean getOverlapAnchor(PopupWindow popupWindow) { 191 return IMPL.getOverlapAnchor(popupWindow); 192 } 193 194 /** 195 * Set the layout type for this window. This value will be passed through to 196 * {@link WindowManager.LayoutParams#type} therefore the value should match any value 197 * {@link WindowManager.LayoutParams#type} accepts. 198 * 199 * @param layoutType Layout type for this window. 200 * 201 * @see WindowManager.LayoutParams#type 202 */ 203 public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) { 204 IMPL.setWindowLayoutType(popupWindow, layoutType); 205 } 206 207 /** 208 * Returns the layout type for this window. 209 * 210 * @see #setWindowLayoutType(PopupWindow popupWindow, int) 211 */ 212 public static int getWindowLayoutType(PopupWindow popupWindow) { 213 return IMPL.getWindowLayoutType(popupWindow); 214 } 215} 216