12a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn/*
22a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
32a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn *
42a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
52a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * you may not use this file except in compliance with the License.
62a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You may obtain a copy of the License at
72a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn *
82a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
92a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn *
102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * See the License for the specific language governing permissions and
142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * limitations under the License.
152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */
162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornpackage android.support.v4.view;
182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent;
20d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.view.View;
212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn/**
230574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * Helper for accessing features in {@link KeyEvent} introduced after
240574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * API level 4 in a backwards compatible fashion.
252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */
262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornpublic class KeyEventCompat {
272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * Interface for the full API.
292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    interface KeyEventVersionImpl {
312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public int normalizeMetaState(int metaState);
322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasModifiers(int metaState, int modifiers);
332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasNoModifiers(int metaState);
34791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public void startTracking(KeyEvent event);
35791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public boolean isTracking(KeyEvent event);
36d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public Object getKeyDispatcherState(View view);
37d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
38d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn                    Object target);
392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * Interface implementation that doesn't use anything about v4 APIs.
432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    static class BaseKeyEventVersionImpl implements KeyEventVersionImpl {
452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        private static final int META_MODIFIER_MASK =
462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON
472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                | KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON
482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                | KeyEvent.META_SYM_ON;
492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Mask of all lock key meta states.
512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        private static final int META_ALL_MASK = META_MODIFIER_MASK;
522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        private static int metaStateFilterDirectionalModifiers(int metaState,
542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                int modifiers, int basic, int left, int right) {
552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final boolean wantBasic = (modifiers & basic) != 0;
562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final int directional = left | right;
572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final boolean wantLeftOrRight = (modifiers & directional) != 0;
582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (wantBasic) {
602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (wantLeftOrRight) {
612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    throw new IllegalArgumentException("bad arguments");
622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return metaState & ~directional;
642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            } else if (wantLeftOrRight) {
652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return metaState & ~basic;
662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            } else {
672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return metaState;
682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public int normalizeMetaState(int metaState) {
732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if ((metaState & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON)) != 0) {
742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                metaState |= KeyEvent.META_SHIFT_ON;
752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if ((metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0) {
772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                metaState |= KeyEvent.META_ALT_ON;
782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return metaState & META_ALL_MASK;
802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasModifiers(int metaState, int modifiers) {
842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            metaState = normalizeMetaState(metaState) & META_MODIFIER_MASK;
852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    KeyEvent.META_SHIFT_ON, KeyEvent.META_SHIFT_LEFT_ON, KeyEvent.META_SHIFT_RIGHT_ON);
872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    KeyEvent.META_ALT_ON, KeyEvent.META_ALT_LEFT_ON, KeyEvent.META_ALT_RIGHT_ON);
892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return metaState == modifiers;
902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasNoModifiers(int metaState) {
942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return (normalizeMetaState(metaState) & META_MODIFIER_MASK) == 0;
952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
96791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
97791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        @Override
98791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public void startTracking(KeyEvent event) {
99791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
100791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
101791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        @Override
102791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public boolean isTracking(KeyEvent event) {
103791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            return false;
104791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
105d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
106d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        @Override
107d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public Object getKeyDispatcherState(View view) {
108d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn            return null;
109d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        }
110d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
111d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        @Override
112d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
113d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn                    Object target) {
114d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn            return event.dispatch(receiver);
115d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        }
116791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
117791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
118791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    static class EclairKeyEventVersionImpl extends BaseKeyEventVersionImpl {
119791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        @Override
120791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public void startTracking(KeyEvent event) {
121791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            KeyEventCompatEclair.startTracking(event);
122791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
123791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
124791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        @Override
125791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        public boolean isTracking(KeyEvent event) {
126791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            return KeyEventCompatEclair.isTracking(event);
127791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
128d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
129d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        @Override
130d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public Object getKeyDispatcherState(View view) {
131d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn            return KeyEventCompatEclair.getKeyDispatcherState(view);
132d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        }
133d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
134d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        @Override
135d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
136d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn                    Object target) {
137d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn            return KeyEventCompatEclair.dispatch(event, receiver, state, target);
138d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        }
1392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
1422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * Interface implementation for devices with at least v11 APIs.
1432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
144791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    static class HoneycombKeyEventVersionImpl extends EclairKeyEventVersionImpl {
1452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
1462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public int normalizeMetaState(int metaState) {
1472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return KeyEventCompatHoneycomb.normalizeMetaState(metaState);
1482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
1512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasModifiers(int metaState, int modifiers) {
1522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return KeyEventCompatHoneycomb.metaStateHasModifiers(metaState, modifiers);
1532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        @Override
1562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        public boolean metaStateHasNoModifiers(int metaState) {
1572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return KeyEventCompatHoneycomb.metaStateHasNoModifiers(metaState);
1582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
1622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * Select the correct implementation to use for the current platform.
1632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
1642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    static final KeyEventVersionImpl IMPL;
1652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    static {
1662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (android.os.Build.VERSION.SDK_INT >= 11) {
1672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            IMPL = new HoneycombKeyEventVersionImpl();
1682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else {
1692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            IMPL = new BaseKeyEventVersionImpl();
1702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    // -------------------------------------------------------------------
1742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public static int normalizeMetaState(int metaState) {
1762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return IMPL.normalizeMetaState(metaState);
1772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public static boolean metaStateHasModifiers(int metaState, int modifiers) {
1802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return IMPL.metaStateHasModifiers(metaState, modifiers);
1812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public static boolean metaStateHasNoModifiers(int metaState) {
1842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return IMPL.metaStateHasNoModifiers(metaState);
1852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public static boolean hasModifiers(KeyEvent event, int modifiers) {
1882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return IMPL.metaStateHasModifiers(event.getMetaState(), modifiers);
1892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public static boolean hasNoModifiers(KeyEvent event) {
1922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return IMPL.metaStateHasNoModifiers(event.getMetaState());
1932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
194791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
195791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    public static void startTracking(KeyEvent event) {
196791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        IMPL.startTracking(event);
197791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
198791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
199791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    public static boolean isTracking(KeyEvent event) {
200791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        return IMPL.isTracking(event);
201791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
202d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
203d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn    public static Object getKeyDispatcherState(View view) {
204d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        return IMPL.getKeyDispatcherState(view);
205d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn    }
206d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn
207d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn    public static boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
208d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn                Object target) {
209d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn        return IMPL.dispatch(event, receiver, state, target);
210d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn    }
2112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn}
212