Home | History | Annotate | Download | only in widget
      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 
     17 package android.support.v4.widget;
     18 
     19 import android.view.View;
     20 import android.view.WindowManager;
     21 import android.widget.PopupWindow;
     22 
     23 /**
     24  * Helper for accessing features in PopupWindow introduced after API level 4
     25  * in a backwards compatible fashion.
     26  */
     27 public 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