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