1 /* 2 * Copyright 2020 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 com.android.server.media; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.PendingIntent; 23 import android.content.Context; 24 import android.media.session.ISessionManager; 25 import android.media.session.MediaSession; 26 import android.os.Binder; 27 import android.view.KeyEvent; 28 import android.view.ViewConfiguration; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.HashMap; 33 import java.util.Map; 34 35 /** 36 * Provides a way to customize behavior for media key events. 37 * <p> 38 * In order to override the implementation of the single/double/triple tap or long press, 39 * {@link #setOverriddenKeyEvents(int, int)} should be called for each key code with the 40 * overridden {@link KeyEventType} bit value set, and the corresponding method, 41 * {@link #onSingleTap(KeyEvent)}, {@link #onDoubleTap(KeyEvent)}, 42 * {@link #onTripleTap(KeyEvent)}, {@link #onLongPress(KeyEvent)} should be implemented. 43 * <p> 44 * Note: When instantiating this class, {@link MediaSessionService} will only use the constructor 45 * without any parameters. 46 */ 47 // TODO: Move this class to apex/media/ 48 public abstract class MediaKeyDispatcher { 49 @IntDef(flag = true, value = { 50 KEY_EVENT_SINGLE_TAP, 51 KEY_EVENT_DOUBLE_TAP, 52 KEY_EVENT_TRIPLE_TAP, 53 KEY_EVENT_LONG_PRESS 54 }) 55 @Retention(RetentionPolicy.SOURCE) 56 @interface KeyEventType {} 57 static final int KEY_EVENT_SINGLE_TAP = 1 << 0; 58 static final int KEY_EVENT_DOUBLE_TAP = 1 << 1; 59 static final int KEY_EVENT_TRIPLE_TAP = 1 << 2; 60 static final int KEY_EVENT_LONG_PRESS = 1 << 3; 61 62 private Map<Integer, Integer> mOverriddenKeyEvents; 63 MediaKeyDispatcher(Context context)64 public MediaKeyDispatcher(Context context) { 65 // Constructor used for reflection 66 mOverriddenKeyEvents = new HashMap<>(); 67 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PLAY, 0); 68 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PAUSE, 0); 69 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0); 70 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MUTE, 0); 71 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_HEADSETHOOK, 0); 72 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_STOP, 0); 73 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_NEXT, 0); 74 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0); 75 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_DOWN, 0); 76 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_UP, 0); 77 mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_MUTE, 0); 78 } 79 80 // TODO: Move this method into MediaSessionPolicyProvider.java for better readability. 81 /** 82 * Implement this to customize the logic for which MediaSession should consume which key event. 83 * 84 * Note: This session will have greater priority over the {@link PendingIntent} returned from 85 * {@link #getMediaButtonReceiver(KeyEvent, int, boolean)}. 86 * 87 * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons. 88 * @param uid the uid value retrieved by calling {@link Binder#getCallingUid()} from 89 * {@link ISessionManager#dispatchMediaKeyEvent(String, boolean, KeyEvent, boolean)} 90 * @param asSystemService {@code true} if the event came from the system service via hardware 91 * devices. {@code false} if the event came from the app process through key injection. 92 * @return a {@link MediaSession.Token} instance that should consume the given key event. 93 */ 94 @Nullable getMediaSession(@onNull KeyEvent keyEvent, int uid, boolean asSystemService)95 MediaSession.Token getMediaSession(@NonNull KeyEvent keyEvent, int uid, 96 boolean asSystemService) { 97 return null; 98 } 99 100 /** 101 * Implement this to customize the logic for which MediaButtonReceiver should consume a 102 * dispatched key event. 103 * <p> 104 * This pending intent will have lower priority over the {@link MediaSession.Token} 105 * returned from {@link #getMediaSession(KeyEvent, int, boolean)}. 106 * <p> 107 * Use a pending intent with an explicit intent; setting a pending intent with an implicit 108 * intent that cannot be resolved to a certain component name will fail. 109 * 110 * @return a {@link PendingIntent} instance that should receive the dispatched key event. 111 */ 112 @Nullable getMediaButtonReceiver(@onNull KeyEvent keyEvent, int uid, boolean asSystemService)113 PendingIntent getMediaButtonReceiver(@NonNull KeyEvent keyEvent, int uid, 114 boolean asSystemService) { 115 return null; 116 } 117 118 /** 119 * Gets the map of key code -> {@link KeyEventType} that have been overridden. 120 * <p> 121 * The list of valid key codes are the following: 122 * <ul> 123 * <li> {@link KeyEvent#KEYCODE_MEDIA_PLAY} 124 * <li> {@link KeyEvent#KEYCODE_MEDIA_PAUSE} 125 * <li> {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} 126 * <li> {@link KeyEvent#KEYCODE_MUTE} 127 * <li> {@link KeyEvent#KEYCODE_HEADSETHOOK} 128 * <li> {@link KeyEvent#KEYCODE_MEDIA_STOP} 129 * <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT} 130 * <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS} 131 * <li> {@link KeyEvent#KEYCODE_VOLUME_UP} 132 * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN} 133 * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE} 134 * </ul> 135 * @see {@link KeyEvent#isMediaSessionKey(int)} 136 */ getOverriddenKeyEvents()137 @KeyEventType Map<Integer, Integer> getOverriddenKeyEvents() { 138 return mOverriddenKeyEvents; 139 } 140 isSingleTapOverridden(@eyEventType int overriddenKeyEvents)141 static boolean isSingleTapOverridden(@KeyEventType int overriddenKeyEvents) { 142 return (overriddenKeyEvents & MediaKeyDispatcher.KEY_EVENT_SINGLE_TAP) != 0; 143 } 144 isDoubleTapOverridden(@eyEventType int overriddenKeyEvents)145 static boolean isDoubleTapOverridden(@KeyEventType int overriddenKeyEvents) { 146 return (overriddenKeyEvents & MediaKeyDispatcher.KEY_EVENT_DOUBLE_TAP) != 0; 147 } 148 isTripleTapOverridden(@eyEventType int overriddenKeyEvents)149 static boolean isTripleTapOverridden(@KeyEventType int overriddenKeyEvents) { 150 return (overriddenKeyEvents & MediaKeyDispatcher.KEY_EVENT_TRIPLE_TAP) != 0; 151 } 152 isLongPressOverridden(@eyEventType int overriddenKeyEvents)153 static boolean isLongPressOverridden(@KeyEventType int overriddenKeyEvents) { 154 return (overriddenKeyEvents & MediaKeyDispatcher.KEY_EVENT_LONG_PRESS) != 0; 155 } 156 157 /** 158 * Sets the value of the given key event type flagged with overridden {@link KeyEventType} to 159 * the given key code. If called multiple times for the same key code, will be overwritten to 160 * the most recently called {@link KeyEventType} value. 161 * <p> 162 * The list of valid key codes are the following: 163 * <ul> 164 * <li> {@link KeyEvent#KEYCODE_MEDIA_PLAY} 165 * <li> {@link KeyEvent#KEYCODE_MEDIA_PAUSE} 166 * <li> {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} 167 * <li> {@link KeyEvent#KEYCODE_MUTE} 168 * <li> {@link KeyEvent#KEYCODE_HEADSETHOOK} 169 * <li> {@link KeyEvent#KEYCODE_MEDIA_STOP} 170 * <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT} 171 * <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS} 172 * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN} 173 * <li> {@link KeyEvent#KEYCODE_VOLUME_UP} 174 * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE} 175 * </ul> 176 * @see {@link KeyEvent#isMediaSessionKey(int)} 177 * @param keyCode 178 */ setOverriddenKeyEvents(int keyCode, @KeyEventType int keyEventType)179 void setOverriddenKeyEvents(int keyCode, @KeyEventType int keyEventType) { 180 mOverriddenKeyEvents.put(keyCode, keyEventType); 181 } 182 183 /** 184 * Customized implementation for single tap event. Will be run if 185 * {@link #KEY_EVENT_SINGLE_TAP} flag is on for the corresponding key code from 186 * {@link #getOverriddenKeyEvents()}. 187 * 188 * It is considered a single tap if only one {@link KeyEvent} with the same 189 * {@link KeyEvent#getKeyCode()} is dispatched within 190 * {@link ViewConfiguration#getMultiPressTimeout()} milliseconds. Change the 191 * {@link android.provider.Settings.Secure#MULTI_PRESS_TIMEOUT} value to adjust the interval. 192 * 193 * Note: This will only be called once with the {@link KeyEvent#ACTION_UP} KeyEvent. 194 * 195 * @param keyEvent 196 */ onSingleTap(KeyEvent keyEvent)197 void onSingleTap(KeyEvent keyEvent) { 198 } 199 200 /** 201 * Customized implementation for double tap event. Will be run if 202 * {@link #KEY_EVENT_DOUBLE_TAP} flag is on for the corresponding key code from 203 * {@link #getOverriddenKeyEvents()}. 204 * 205 * It is considered a double tap if two {@link KeyEvent}s with the same 206 * {@link KeyEvent#getKeyCode()} are dispatched within 207 * {@link ViewConfiguration#getMultiPressTimeout()} milliseconds of each other. Change the 208 * {@link android.provider.Settings.Secure#MULTI_PRESS_TIMEOUT} value to adjust the interval. 209 * 210 * Note: This will only be called once with the {@link KeyEvent#ACTION_UP} KeyEvent. 211 * 212 * @param keyEvent 213 */ onDoubleTap(KeyEvent keyEvent)214 void onDoubleTap(KeyEvent keyEvent) { 215 } 216 217 /** 218 * Customized implementation for triple tap event. Will be run if 219 * {@link #KEY_EVENT_TRIPLE_TAP} flag is on for the corresponding key code from 220 * {@link #getOverriddenKeyEvents()}. 221 * 222 * It is considered a triple tap if three {@link KeyEvent}s with the same 223 * {@link KeyEvent#getKeyCode()} are dispatched within 224 * {@link ViewConfiguration#getMultiPressTimeout()} milliseconds of each other. Change the 225 * {@link android.provider.Settings.Secure#MULTI_PRESS_TIMEOUT} value to adjust the interval. 226 * 227 * Note: This will only be called once with the {@link KeyEvent#ACTION_UP} KeyEvent. 228 * 229 * @param keyEvent 230 */ onTripleTap(KeyEvent keyEvent)231 void onTripleTap(KeyEvent keyEvent) { 232 } 233 234 /** 235 * Customized implementation for long press event. Will be run if 236 * {@link #KEY_EVENT_LONG_PRESS} flag is on for the corresponding key code from 237 * {@link #getOverriddenKeyEvents()}. 238 * 239 * It is considered a long press if an {@link KeyEvent#ACTION_DOWN} key event is followed by 240 * another {@link KeyEvent#ACTION_DOWN} key event with {@link KeyEvent#FLAG_LONG_PRESS} 241 * enabled, and an {@link KeyEvent#getRepeatCount()} that is equal to 1. 242 * 243 * Note: This will be called for the following key events: 244 * <ul> 245 * <li>A {@link KeyEvent#ACTION_DOWN} KeyEvent with {@link KeyEvent#FLAG_LONG_PRESS} and 246 * {@link KeyEvent#getRepeatCount()} equal to 1</li> 247 * <li>Multiple {@link KeyEvent#ACTION_DOWN} KeyEvents with increasing 248 * {@link KeyEvent#getRepeatCount()}</li> 249 * <li>A {@link KeyEvent#ACTION_UP} KeyEvent</li> 250 * </ul> 251 * 252 * @param keyEvent 253 */ onLongPress(KeyEvent keyEvent)254 void onLongPress(KeyEvent keyEvent) { 255 } 256 } 257