Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2006 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.view;
     18 
     19 import android.app.AppGlobals;
     20 import android.content.Context;
     21 import android.content.res.Configuration;
     22 import android.content.res.Resources;
     23 import android.graphics.Point;
     24 import android.os.RemoteException;
     25 import android.provider.Settings;
     26 import android.util.DisplayMetrics;
     27 import android.util.SparseArray;
     28 
     29 /**
     30  * Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
     31  */
     32 public class ViewConfiguration {
     33     /**
     34      * Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
     35      * dips
     36      */
     37     private static final int SCROLL_BAR_SIZE = 10;
     38 
     39     /**
     40      * Duration of the fade when scrollbars fade away in milliseconds
     41      */
     42     private static final int SCROLL_BAR_FADE_DURATION = 250;
     43 
     44     /**
     45      * Default delay before the scrollbars fade in milliseconds
     46      */
     47     private static final int SCROLL_BAR_DEFAULT_DELAY = 300;
     48 
     49     /**
     50      * Defines the length of the fading edges in dips
     51      */
     52     private static final int FADING_EDGE_LENGTH = 12;
     53 
     54     /**
     55      * Defines the duration in milliseconds of the pressed state in child
     56      * components.
     57      */
     58     private static final int PRESSED_STATE_DURATION = 64;
     59 
     60     /**
     61      * Defines the default duration in milliseconds before a press turns into
     62      * a long press
     63      */
     64     private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;
     65 
     66     /**
     67      * Defines the time between successive key repeats in milliseconds.
     68      */
     69     private static final int KEY_REPEAT_DELAY = 50;
     70 
     71     /**
     72      * Defines the duration in milliseconds a user needs to hold down the
     73      * appropriate button to bring up the global actions dialog (power off,
     74      * lock screen, etc).
     75      */
     76     private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;
     77 
     78     /**
     79      * Defines the duration in milliseconds we will wait to see if a touch event
     80      * is a tap or a scroll. If the user does not move within this interval, it is
     81      * considered to be a tap.
     82      */
     83     private static final int TAP_TIMEOUT = 180;
     84 
     85     /**
     86      * Defines the duration in milliseconds we will wait to see if a touch event
     87      * is a jump tap. If the user does not complete the jump tap within this interval, it is
     88      * considered to be a tap.
     89      */
     90     private static final int JUMP_TAP_TIMEOUT = 500;
     91 
     92     /**
     93      * Defines the duration in milliseconds between the first tap's up event and
     94      * the second tap's down event for an interaction to be considered a
     95      * double-tap.
     96      */
     97     private static final int DOUBLE_TAP_TIMEOUT = 300;
     98 
     99     /**
    100      * Defines the maximum duration in milliseconds between a touch pad
    101      * touch and release for a given touch to be considered a tap (click) as
    102      * opposed to a hover movement gesture.
    103      */
    104     private static final int HOVER_TAP_TIMEOUT = 150;
    105 
    106     /**
    107      * Defines the maximum distance in pixels that a touch pad touch can move
    108      * before being released for it to be considered a tap (click) as opposed
    109      * to a hover movement gesture.
    110      */
    111     private static final int HOVER_TAP_SLOP = 20;
    112 
    113     /**
    114      * Defines the duration in milliseconds we want to display zoom controls in response
    115      * to a user panning within an application.
    116      */
    117     private static final int ZOOM_CONTROLS_TIMEOUT = 3000;
    118 
    119     /**
    120      * Inset in dips to look for touchable content when the user touches the edge of the screen
    121      */
    122     private static final int EDGE_SLOP = 12;
    123 
    124     /**
    125      * Distance a touch can wander before we think the user is scrolling in dips.
    126      * Note that this value defined here is only used as a fallback by legacy/misbehaving
    127      * applications that do not provide a Context for determining density/configuration-dependent
    128      * values.
    129      *
    130      * To alter this value, see the configuration resource config_viewConfigurationTouchSlop
    131      * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay.
    132      * It may be appropriate to tweak this on a device-specific basis in an overlay based on
    133      * the characteristics of the touch panel and firmware.
    134      */
    135     private static final int TOUCH_SLOP = 8;
    136 
    137     /**
    138      * Distance the first touch can wander before we stop considering this event a double tap
    139      * (in dips)
    140      */
    141     private static final int DOUBLE_TAP_TOUCH_SLOP = TOUCH_SLOP;
    142 
    143     /**
    144      * Distance a touch can wander before we think the user is attempting a paged scroll
    145      * (in dips)
    146      *
    147      * Note that this value defined here is only used as a fallback by legacy/misbehaving
    148      * applications that do not provide a Context for determining density/configuration-dependent
    149      * values.
    150      *
    151      * See the note above on {@link #TOUCH_SLOP} regarding the dimen resource
    152      * config_viewConfigurationTouchSlop. ViewConfiguration will report a paging touch slop of
    153      * config_viewConfigurationTouchSlop * 2 when provided with a Context.
    154      */
    155     private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;
    156 
    157     /**
    158      * Distance in dips between the first touch and second touch to still be considered a double tap
    159      */
    160     private static final int DOUBLE_TAP_SLOP = 100;
    161 
    162     /**
    163      * Distance in dips a touch needs to be outside of a window's bounds for it to
    164      * count as outside for purposes of dismissing the window.
    165      */
    166     private static final int WINDOW_TOUCH_SLOP = 16;
    167 
    168     /**
    169      * Minimum velocity to initiate a fling, as measured in dips per second
    170      */
    171     private static final int MINIMUM_FLING_VELOCITY = 50;
    172 
    173     /**
    174      * Maximum velocity to initiate a fling, as measured in dips per second
    175      */
    176     private static final int MAXIMUM_FLING_VELOCITY = 8000;
    177 
    178     /**
    179      * Delay before dispatching a recurring accessibility event in milliseconds.
    180      * This delay guarantees that a recurring event will be send at most once
    181      * during the {@link #SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS} time
    182      * frame.
    183      */
    184     private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;
    185 
    186     /**
    187      * The maximum size of View's drawing cache, expressed in bytes. This size
    188      * should be at least equal to the size of the screen in ARGB888 format.
    189      */
    190     @Deprecated
    191     private static final int MAXIMUM_DRAWING_CACHE_SIZE = 480 * 800 * 4; // ARGB8888
    192 
    193     /**
    194      * The coefficient of friction applied to flings/scrolls.
    195      */
    196     private static final float SCROLL_FRICTION = 0.015f;
    197 
    198     /**
    199      * Max distance in dips to overscroll for edge effects
    200      */
    201     private static final int OVERSCROLL_DISTANCE = 0;
    202 
    203     /**
    204      * Max distance in dips to overfling for edge effects
    205      */
    206     private static final int OVERFLING_DISTANCE = 6;
    207 
    208     private final int mEdgeSlop;
    209     private final int mFadingEdgeLength;
    210     private final int mMinimumFlingVelocity;
    211     private final int mMaximumFlingVelocity;
    212     private final int mScrollbarSize;
    213     private final int mTouchSlop;
    214     private final int mDoubleTapTouchSlop;
    215     private final int mPagingTouchSlop;
    216     private final int mDoubleTapSlop;
    217     private final int mWindowTouchSlop;
    218     private final int mMaximumDrawingCacheSize;
    219     private final int mOverscrollDistance;
    220     private final int mOverflingDistance;
    221     private final boolean mFadingMarqueeEnabled;
    222 
    223     private boolean sHasPermanentMenuKey;
    224     private boolean sHasPermanentMenuKeySet;
    225 
    226     static final SparseArray<ViewConfiguration> sConfigurations =
    227             new SparseArray<ViewConfiguration>(2);
    228 
    229     /**
    230      * @deprecated Use {@link android.view.ViewConfiguration#get(android.content.Context)} instead.
    231      */
    232     @Deprecated
    233     public ViewConfiguration() {
    234         mEdgeSlop = EDGE_SLOP;
    235         mFadingEdgeLength = FADING_EDGE_LENGTH;
    236         mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
    237         mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
    238         mScrollbarSize = SCROLL_BAR_SIZE;
    239         mTouchSlop = TOUCH_SLOP;
    240         mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
    241         mPagingTouchSlop = PAGING_TOUCH_SLOP;
    242         mDoubleTapSlop = DOUBLE_TAP_SLOP;
    243         mWindowTouchSlop = WINDOW_TOUCH_SLOP;
    244         //noinspection deprecation
    245         mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
    246         mOverscrollDistance = OVERSCROLL_DISTANCE;
    247         mOverflingDistance = OVERFLING_DISTANCE;
    248         mFadingMarqueeEnabled = true;
    249     }
    250 
    251     /**
    252      * Creates a new configuration for the specified context. The configuration depends on
    253      * various parameters of the context, like the dimension of the display or the density
    254      * of the display.
    255      *
    256      * @param context The application context used to initialize this view configuration.
    257      *
    258      * @see #get(android.content.Context)
    259      * @see android.util.DisplayMetrics
    260      */
    261     private ViewConfiguration(Context context) {
    262         final Resources res = context.getResources();
    263         final DisplayMetrics metrics = res.getDisplayMetrics();
    264         final Configuration config = res.getConfiguration();
    265         final float density = metrics.density;
    266         final float sizeAndDensity;
    267         if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) {
    268             sizeAndDensity = density * 1.5f;
    269         } else {
    270             sizeAndDensity = density;
    271         }
    272 
    273         mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
    274         mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
    275         mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
    276         mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
    277         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
    278         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
    279         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
    280 
    281         // Size of the screen in bytes, in ARGB_8888 format
    282         final WindowManager win = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
    283         final Display display = win.getDefaultDisplay();
    284         final Point size = new Point();
    285         display.getRealSize(size);
    286         mMaximumDrawingCacheSize = 4 * size.x * size.y;
    287 
    288         mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
    289         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
    290 
    291         if (!sHasPermanentMenuKeySet) {
    292             IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    293             try {
    294                 sHasPermanentMenuKey = !wm.hasSystemNavBar() && !wm.hasNavigationBar();
    295                 sHasPermanentMenuKeySet = true;
    296             } catch (RemoteException ex) {
    297                 sHasPermanentMenuKey = false;
    298             }
    299         }
    300 
    301         mFadingMarqueeEnabled = res.getBoolean(
    302                 com.android.internal.R.bool.config_ui_enableFadingMarquee);
    303         mTouchSlop = res.getDimensionPixelSize(
    304                 com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
    305         mPagingTouchSlop = mTouchSlop * 2;
    306 
    307         mDoubleTapTouchSlop = mTouchSlop;
    308     }
    309 
    310     /**
    311      * Returns a configuration for the specified context. The configuration depends on
    312      * various parameters of the context, like the dimension of the display or the
    313      * density of the display.
    314      *
    315      * @param context The application context used to initialize the view configuration.
    316      */
    317     public static ViewConfiguration get(Context context) {
    318         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    319         final int density = (int) (100.0f * metrics.density);
    320 
    321         ViewConfiguration configuration = sConfigurations.get(density);
    322         if (configuration == null) {
    323             configuration = new ViewConfiguration(context);
    324             sConfigurations.put(density, configuration);
    325         }
    326 
    327         return configuration;
    328     }
    329 
    330     /**
    331      * @return The width of the horizontal scrollbar and the height of the vertical
    332      *         scrollbar in dips
    333      *
    334      * @deprecated Use {@link #getScaledScrollBarSize()} instead.
    335      */
    336     @Deprecated
    337     public static int getScrollBarSize() {
    338         return SCROLL_BAR_SIZE;
    339     }
    340 
    341     /**
    342      * @return The width of the horizontal scrollbar and the height of the vertical
    343      *         scrollbar in pixels
    344      */
    345     public int getScaledScrollBarSize() {
    346         return mScrollbarSize;
    347     }
    348 
    349     /**
    350      * @return Duration of the fade when scrollbars fade away in milliseconds
    351      */
    352     public static int getScrollBarFadeDuration() {
    353         return SCROLL_BAR_FADE_DURATION;
    354     }
    355 
    356     /**
    357      * @return Default delay before the scrollbars fade in milliseconds
    358      */
    359     public static int getScrollDefaultDelay() {
    360         return SCROLL_BAR_DEFAULT_DELAY;
    361     }
    362 
    363     /**
    364      * @return the length of the fading edges in dips
    365      *
    366      * @deprecated Use {@link #getScaledFadingEdgeLength()} instead.
    367      */
    368     @Deprecated
    369     public static int getFadingEdgeLength() {
    370         return FADING_EDGE_LENGTH;
    371     }
    372 
    373     /**
    374      * @return the length of the fading edges in pixels
    375      */
    376     public int getScaledFadingEdgeLength() {
    377         return mFadingEdgeLength;
    378     }
    379 
    380     /**
    381      * @return the duration in milliseconds of the pressed state in child
    382      * components.
    383      */
    384     public static int getPressedStateDuration() {
    385         return PRESSED_STATE_DURATION;
    386     }
    387 
    388     /**
    389      * @return the duration in milliseconds before a press turns into
    390      * a long press
    391      */
    392     public static int getLongPressTimeout() {
    393         return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT,
    394                 DEFAULT_LONG_PRESS_TIMEOUT);
    395     }
    396 
    397     /**
    398      * @return the time before the first key repeat in milliseconds.
    399      */
    400     public static int getKeyRepeatTimeout() {
    401         return getLongPressTimeout();
    402     }
    403 
    404     /**
    405      * @return the time between successive key repeats in milliseconds.
    406      */
    407     public static int getKeyRepeatDelay() {
    408         return KEY_REPEAT_DELAY;
    409     }
    410 
    411     /**
    412      * @return the duration in milliseconds we will wait to see if a touch event
    413      * is a tap or a scroll. If the user does not move within this interval, it is
    414      * considered to be a tap.
    415      */
    416     public static int getTapTimeout() {
    417         return TAP_TIMEOUT;
    418     }
    419 
    420     /**
    421      * @return the duration in milliseconds we will wait to see if a touch event
    422      * is a jump tap. If the user does not move within this interval, it is
    423      * considered to be a tap.
    424      */
    425     public static int getJumpTapTimeout() {
    426         return JUMP_TAP_TIMEOUT;
    427     }
    428 
    429     /**
    430      * @return the duration in milliseconds between the first tap's up event and
    431      * the second tap's down event for an interaction to be considered a
    432      * double-tap.
    433      */
    434     public static int getDoubleTapTimeout() {
    435         return DOUBLE_TAP_TIMEOUT;
    436     }
    437 
    438     /**
    439      * @return the maximum duration in milliseconds between a touch pad
    440      * touch and release for a given touch to be considered a tap (click) as
    441      * opposed to a hover movement gesture.
    442      * @hide
    443      */
    444     public static int getHoverTapTimeout() {
    445         return HOVER_TAP_TIMEOUT;
    446     }
    447 
    448     /**
    449      * @return the maximum distance in pixels that a touch pad touch can move
    450      * before being released for it to be considered a tap (click) as opposed
    451      * to a hover movement gesture.
    452      * @hide
    453      */
    454     public static int getHoverTapSlop() {
    455         return HOVER_TAP_SLOP;
    456     }
    457 
    458     /**
    459      * @return Inset in dips to look for touchable content when the user touches the edge of the
    460      *         screen
    461      *
    462      * @deprecated Use {@link #getScaledEdgeSlop()} instead.
    463      */
    464     @Deprecated
    465     public static int getEdgeSlop() {
    466         return EDGE_SLOP;
    467     }
    468 
    469     /**
    470      * @return Inset in pixels to look for touchable content when the user touches the edge of the
    471      *         screen
    472      */
    473     public int getScaledEdgeSlop() {
    474         return mEdgeSlop;
    475     }
    476 
    477     /**
    478      * @return Distance in dips a touch can wander before we think the user is scrolling
    479      *
    480      * @deprecated Use {@link #getScaledTouchSlop()} instead.
    481      */
    482     @Deprecated
    483     public static int getTouchSlop() {
    484         return TOUCH_SLOP;
    485     }
    486 
    487     /**
    488      * @return Distance in pixels a touch can wander before we think the user is scrolling
    489      */
    490     public int getScaledTouchSlop() {
    491         return mTouchSlop;
    492     }
    493 
    494     /**
    495      * @return Distance in pixels the first touch can wander before we do not consider this a
    496      * potential double tap event
    497      * @hide
    498      */
    499     public int getScaledDoubleTapTouchSlop() {
    500         return mDoubleTapTouchSlop;
    501     }
    502 
    503     /**
    504      * @return Distance in pixels a touch can wander before we think the user is scrolling a full
    505      * page
    506      */
    507     public int getScaledPagingTouchSlop() {
    508         return mPagingTouchSlop;
    509     }
    510 
    511     /**
    512      * @return Distance in dips between the first touch and second touch to still be
    513      *         considered a double tap
    514      * @deprecated Use {@link #getScaledDoubleTapSlop()} instead.
    515      * @hide The only client of this should be GestureDetector, which needs this
    516      *       for clients that still use its deprecated constructor.
    517      */
    518     @Deprecated
    519     public static int getDoubleTapSlop() {
    520         return DOUBLE_TAP_SLOP;
    521     }
    522 
    523     /**
    524      * @return Distance in pixels between the first touch and second touch to still be
    525      *         considered a double tap
    526      */
    527     public int getScaledDoubleTapSlop() {
    528         return mDoubleTapSlop;
    529     }
    530 
    531     /**
    532      * Interval for dispatching a recurring accessibility event in milliseconds.
    533      * This interval guarantees that a recurring event will be send at most once
    534      * during the {@link #getSendRecurringAccessibilityEventsInterval()} time frame.
    535      *
    536      * @return The delay in milliseconds.
    537      *
    538      * @hide
    539      */
    540     public static long getSendRecurringAccessibilityEventsInterval() {
    541         return SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS;
    542     }
    543 
    544     /**
    545      * @return Distance in dips a touch must be outside the bounds of a window for it
    546      * to be counted as outside the window for purposes of dismissing that
    547      * window.
    548      *
    549      * @deprecated Use {@link #getScaledWindowTouchSlop()} instead.
    550      */
    551     @Deprecated
    552     public static int getWindowTouchSlop() {
    553         return WINDOW_TOUCH_SLOP;
    554     }
    555 
    556     /**
    557      * @return Distance in pixels a touch must be outside the bounds of a window for it
    558      * to be counted as outside the window for purposes of dismissing that window.
    559      */
    560     public int getScaledWindowTouchSlop() {
    561         return mWindowTouchSlop;
    562     }
    563 
    564     /**
    565      * @return Minimum velocity to initiate a fling, as measured in dips per second.
    566      *
    567      * @deprecated Use {@link #getScaledMinimumFlingVelocity()} instead.
    568      */
    569     @Deprecated
    570     public static int getMinimumFlingVelocity() {
    571         return MINIMUM_FLING_VELOCITY;
    572     }
    573 
    574     /**
    575      * @return Minimum velocity to initiate a fling, as measured in pixels per second.
    576      */
    577     public int getScaledMinimumFlingVelocity() {
    578         return mMinimumFlingVelocity;
    579     }
    580 
    581     /**
    582      * @return Maximum velocity to initiate a fling, as measured in dips per second.
    583      *
    584      * @deprecated Use {@link #getScaledMaximumFlingVelocity()} instead.
    585      */
    586     @Deprecated
    587     public static int getMaximumFlingVelocity() {
    588         return MAXIMUM_FLING_VELOCITY;
    589     }
    590 
    591     /**
    592      * @return Maximum velocity to initiate a fling, as measured in pixels per second.
    593      */
    594     public int getScaledMaximumFlingVelocity() {
    595         return mMaximumFlingVelocity;
    596     }
    597 
    598     /**
    599      * The maximum drawing cache size expressed in bytes.
    600      *
    601      * @return the maximum size of View's drawing cache expressed in bytes
    602      *
    603      * @deprecated Use {@link #getScaledMaximumDrawingCacheSize()} instead.
    604      */
    605     @Deprecated
    606     public static int getMaximumDrawingCacheSize() {
    607         //noinspection deprecation
    608         return MAXIMUM_DRAWING_CACHE_SIZE;
    609     }
    610 
    611     /**
    612      * The maximum drawing cache size expressed in bytes.
    613      *
    614      * @return the maximum size of View's drawing cache expressed in bytes
    615      */
    616     public int getScaledMaximumDrawingCacheSize() {
    617         return mMaximumDrawingCacheSize;
    618     }
    619 
    620     /**
    621      * @return The maximum distance a View should overscroll by when showing edge effects (in
    622      * pixels).
    623      */
    624     public int getScaledOverscrollDistance() {
    625         return mOverscrollDistance;
    626     }
    627 
    628     /**
    629      * @return The maximum distance a View should overfling by when showing edge effects (in
    630      * pixels).
    631      */
    632     public int getScaledOverflingDistance() {
    633         return mOverflingDistance;
    634     }
    635 
    636     /**
    637      * The amount of time that the zoom controls should be
    638      * displayed on the screen expressed in milliseconds.
    639      *
    640      * @return the time the zoom controls should be visible expressed
    641      * in milliseconds.
    642      */
    643     public static long getZoomControlsTimeout() {
    644         return ZOOM_CONTROLS_TIMEOUT;
    645     }
    646 
    647     /**
    648      * The amount of time a user needs to press the relevant key to bring up
    649      * the global actions dialog.
    650      *
    651      * @return how long a user needs to press the relevant key to bring up
    652      *   the global actions dialog.
    653      */
    654     public static long getGlobalActionKeyTimeout() {
    655         return GLOBAL_ACTIONS_KEY_TIMEOUT;
    656     }
    657 
    658     /**
    659      * The amount of friction applied to scrolls and flings.
    660      *
    661      * @return A scalar dimensionless value representing the coefficient of
    662      *         friction.
    663      */
    664     public static float getScrollFriction() {
    665         return SCROLL_FRICTION;
    666     }
    667 
    668     /**
    669      * Report if the device has a permanent menu key available to the user.
    670      *
    671      * <p>As of Android 3.0, devices may not have a permanent menu key available.
    672      * Apps should use the action bar to present menu options to users.
    673      * However, there are some apps where the action bar is inappropriate
    674      * or undesirable. This method may be used to detect if a menu key is present.
    675      * If not, applications should provide another on-screen affordance to access
    676      * functionality.
    677      *
    678      * @return true if a permanent menu key is present, false otherwise.
    679      */
    680     public boolean hasPermanentMenuKey() {
    681         return sHasPermanentMenuKey;
    682     }
    683 
    684     /**
    685      * @hide
    686      * @return Whether or not marquee should use fading edges.
    687      */
    688     public boolean isFadingMarqueeEnabled() {
    689         return mFadingMarqueeEnabled;
    690     }
    691 }
    692