• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.view;
18 
19 import android.view.KeyEvent;
20 import android.view.View;
21 
22 /**
23  * Helper for accessing features in {@link KeyEvent} introduced after
24  * API level 4 in a backwards compatible fashion.
25  */
26 public class KeyEventCompat {
27     /**
28      * Interface for the full API.
29      */
30     interface KeyEventVersionImpl {
normalizeMetaState(int metaState)31         public int normalizeMetaState(int metaState);
metaStateHasModifiers(int metaState, int modifiers)32         public boolean metaStateHasModifiers(int metaState, int modifiers);
metaStateHasNoModifiers(int metaState)33         public boolean metaStateHasNoModifiers(int metaState);
startTracking(KeyEvent event)34         public void startTracking(KeyEvent event);
isTracking(KeyEvent event)35         public boolean isTracking(KeyEvent event);
getKeyDispatcherState(View view)36         public Object getKeyDispatcherState(View view);
dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state, Object target)37         public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
38                     Object target);
39     }
40 
41     /**
42      * Interface implementation that doesn't use anything about v4 APIs.
43      */
44     static class BaseKeyEventVersionImpl implements KeyEventVersionImpl {
45         private static final int META_MODIFIER_MASK =
46                 KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON
47                 | KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON
48                 | KeyEvent.META_SYM_ON;
49 
50         // Mask of all lock key meta states.
51         private static final int META_ALL_MASK = META_MODIFIER_MASK;
52 
metaStateFilterDirectionalModifiers(int metaState, int modifiers, int basic, int left, int right)53         private static int metaStateFilterDirectionalModifiers(int metaState,
54                 int modifiers, int basic, int left, int right) {
55             final boolean wantBasic = (modifiers & basic) != 0;
56             final int directional = left | right;
57             final boolean wantLeftOrRight = (modifiers & directional) != 0;
58 
59             if (wantBasic) {
60                 if (wantLeftOrRight) {
61                     throw new IllegalArgumentException("bad arguments");
62                 }
63                 return metaState & ~directional;
64             } else if (wantLeftOrRight) {
65                 return metaState & ~basic;
66             } else {
67                 return metaState;
68             }
69         }
70 
71         @Override
normalizeMetaState(int metaState)72         public int normalizeMetaState(int metaState) {
73             if ((metaState & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON)) != 0) {
74                 metaState |= KeyEvent.META_SHIFT_ON;
75             }
76             if ((metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0) {
77                 metaState |= KeyEvent.META_ALT_ON;
78             }
79             return metaState & META_ALL_MASK;
80         }
81 
82         @Override
metaStateHasModifiers(int metaState, int modifiers)83         public boolean metaStateHasModifiers(int metaState, int modifiers) {
84             metaState = normalizeMetaState(metaState) & META_MODIFIER_MASK;
85             metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
86                     KeyEvent.META_SHIFT_ON, KeyEvent.META_SHIFT_LEFT_ON, KeyEvent.META_SHIFT_RIGHT_ON);
87             metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
88                     KeyEvent.META_ALT_ON, KeyEvent.META_ALT_LEFT_ON, KeyEvent.META_ALT_RIGHT_ON);
89             return metaState == modifiers;
90         }
91 
92         @Override
metaStateHasNoModifiers(int metaState)93         public boolean metaStateHasNoModifiers(int metaState) {
94             return (normalizeMetaState(metaState) & META_MODIFIER_MASK) == 0;
95         }
96 
97         @Override
startTracking(KeyEvent event)98         public void startTracking(KeyEvent event) {
99         }
100 
101         @Override
isTracking(KeyEvent event)102         public boolean isTracking(KeyEvent event) {
103             return false;
104         }
105 
106         @Override
getKeyDispatcherState(View view)107         public Object getKeyDispatcherState(View view) {
108             return null;
109         }
110 
111         @Override
dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state, Object target)112         public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
113                     Object target) {
114             return event.dispatch(receiver);
115         }
116     }
117 
118     static class EclairKeyEventVersionImpl extends BaseKeyEventVersionImpl {
119         @Override
startTracking(KeyEvent event)120         public void startTracking(KeyEvent event) {
121             KeyEventCompatEclair.startTracking(event);
122         }
123 
124         @Override
isTracking(KeyEvent event)125         public boolean isTracking(KeyEvent event) {
126             return KeyEventCompatEclair.isTracking(event);
127         }
128 
129         @Override
getKeyDispatcherState(View view)130         public Object getKeyDispatcherState(View view) {
131             return KeyEventCompatEclair.getKeyDispatcherState(view);
132         }
133 
134         @Override
dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state, Object target)135         public boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
136                     Object target) {
137             return KeyEventCompatEclair.dispatch(event, receiver, state, target);
138         }
139     }
140 
141     /**
142      * Interface implementation for devices with at least v11 APIs.
143      */
144     static class HoneycombKeyEventVersionImpl extends EclairKeyEventVersionImpl {
145         @Override
normalizeMetaState(int metaState)146         public int normalizeMetaState(int metaState) {
147             return KeyEventCompatHoneycomb.normalizeMetaState(metaState);
148         }
149 
150         @Override
metaStateHasModifiers(int metaState, int modifiers)151         public boolean metaStateHasModifiers(int metaState, int modifiers) {
152             return KeyEventCompatHoneycomb.metaStateHasModifiers(metaState, modifiers);
153         }
154 
155         @Override
metaStateHasNoModifiers(int metaState)156         public boolean metaStateHasNoModifiers(int metaState) {
157             return KeyEventCompatHoneycomb.metaStateHasNoModifiers(metaState);
158         }
159     }
160 
161     /**
162      * Select the correct implementation to use for the current platform.
163      */
164     static final KeyEventVersionImpl IMPL;
165     static {
166         if (android.os.Build.VERSION.SDK_INT >= 11) {
167             IMPL = new HoneycombKeyEventVersionImpl();
168         } else {
169             IMPL = new BaseKeyEventVersionImpl();
170         }
171     }
172 
173     // -------------------------------------------------------------------
174 
normalizeMetaState(int metaState)175     public static int normalizeMetaState(int metaState) {
176         return IMPL.normalizeMetaState(metaState);
177     }
178 
metaStateHasModifiers(int metaState, int modifiers)179     public static boolean metaStateHasModifiers(int metaState, int modifiers) {
180         return IMPL.metaStateHasModifiers(metaState, modifiers);
181     }
182 
metaStateHasNoModifiers(int metaState)183     public static boolean metaStateHasNoModifiers(int metaState) {
184         return IMPL.metaStateHasNoModifiers(metaState);
185     }
186 
hasModifiers(KeyEvent event, int modifiers)187     public static boolean hasModifiers(KeyEvent event, int modifiers) {
188         return IMPL.metaStateHasModifiers(event.getMetaState(), modifiers);
189     }
190 
hasNoModifiers(KeyEvent event)191     public static boolean hasNoModifiers(KeyEvent event) {
192         return IMPL.metaStateHasNoModifiers(event.getMetaState());
193     }
194 
startTracking(KeyEvent event)195     public static void startTracking(KeyEvent event) {
196         IMPL.startTracking(event);
197     }
198 
isTracking(KeyEvent event)199     public static boolean isTracking(KeyEvent event) {
200         return IMPL.isTracking(event);
201     }
202 
getKeyDispatcherState(View view)203     public static Object getKeyDispatcherState(View view) {
204         return IMPL.getKeyDispatcherState(view);
205     }
206 
dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state, Object target)207     public static boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
208                 Object target) {
209         return IMPL.dispatch(event, receiver, state, target);
210     }
211 }
212