1deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon/* 2deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * Copyright 2014, The Android Open Source Project 3deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * 4deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 5deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * you may not use this file except in compliance with the License. 6deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * You may obtain a copy of the License at 7deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * 8deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 9deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * 10deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * Unless required by applicable law or agreed to in writing, software 11deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 12deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * See the License for the specific language governing permissions and 14deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * limitations under the License. 15deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon */ 16deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 18deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 19deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordonimport android.content.Context; 20deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordonimport android.content.Intent; 2107920f67c86e80fc78086e21fd446b2531c2defdRoboErikimport android.media.AudioAttributes; 22deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordonimport android.media.session.MediaSession; 23731369c3983628e700f161138fe2ea3230033a1aIhab Awadimport android.os.Handler; 24731369c3983628e700f161138fe2ea3230033a1aIhab Awadimport android.os.Looper; 25731369c3983628e700f161138fe2ea3230033a1aIhab Awadimport android.os.Message; 26deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordonimport android.view.KeyEvent; 27deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 28deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon/** 29deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * Static class to handle listening to the headset media buttons. 30deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon */ 318de76915ea2772faeb41705aaaeb65f5b3478ac4Ihab Awadpublic class HeadsetMediaButton extends CallsManagerListenerBase { 32deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 33deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon // Types of media button presses 34deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon static final int SHORT_PRESS = 1; 35deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon static final int LONG_PRESS = 2; 36deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 3707920f67c86e80fc78086e21fd446b2531c2defdRoboErik private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder() 3807920f67c86e80fc78086e21fd446b2531c2defdRoboErik .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 3907920f67c86e80fc78086e21fd446b2531c2defdRoboErik .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build(); 4007920f67c86e80fc78086e21fd446b2531c2defdRoboErik 41731369c3983628e700f161138fe2ea3230033a1aIhab Awad private static final int MSG_MEDIA_SESSION_INITIALIZE = 0; 42731369c3983628e700f161138fe2ea3230033a1aIhab Awad private static final int MSG_MEDIA_SESSION_SET_ACTIVE = 1; 43731369c3983628e700f161138fe2ea3230033a1aIhab Awad 44deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon private final MediaSession.Callback mSessionCallback = new MediaSession.Callback() { 45deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon @Override 46a6e9d758f02ec0654f489725e9b9442796d0b03fRoboErik public boolean onMediaButtonEvent(Intent intent) { 47deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 48deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon Log.v(this, "SessionCallback.onMediaButton()... event = %s.", event); 49deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) { 50731369c3983628e700f161138fe2ea3230033a1aIhab Awad synchronized (mLock) { 51731369c3983628e700f161138fe2ea3230033a1aIhab Awad Log.v(this, "SessionCallback: HEADSETHOOK"); 52731369c3983628e700f161138fe2ea3230033a1aIhab Awad boolean consumed = handleHeadsetHook(event); 53731369c3983628e700f161138fe2ea3230033a1aIhab Awad Log.v(this, "==> handleHeadsetHook(): consumed = %b.", consumed); 54731369c3983628e700f161138fe2ea3230033a1aIhab Awad return consumed; 55731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 56deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } 57a6e9d758f02ec0654f489725e9b9442796d0b03fRoboErik return true; 58deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } 59deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon }; 60deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 61731369c3983628e700f161138fe2ea3230033a1aIhab Awad private final Handler mMediaSessionHandler = new Handler(Looper.getMainLooper()) { 62731369c3983628e700f161138fe2ea3230033a1aIhab Awad @Override 63731369c3983628e700f161138fe2ea3230033a1aIhab Awad public void handleMessage(Message msg) { 64731369c3983628e700f161138fe2ea3230033a1aIhab Awad switch (msg.what) { 65731369c3983628e700f161138fe2ea3230033a1aIhab Awad case MSG_MEDIA_SESSION_INITIALIZE: { 66731369c3983628e700f161138fe2ea3230033a1aIhab Awad MediaSession session = new MediaSession( 67731369c3983628e700f161138fe2ea3230033a1aIhab Awad mContext, 68731369c3983628e700f161138fe2ea3230033a1aIhab Awad HeadsetMediaButton.class.getSimpleName()); 69731369c3983628e700f161138fe2ea3230033a1aIhab Awad session.setCallback(mSessionCallback); 70731369c3983628e700f161138fe2ea3230033a1aIhab Awad session.setFlags(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY 71731369c3983628e700f161138fe2ea3230033a1aIhab Awad | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); 72731369c3983628e700f161138fe2ea3230033a1aIhab Awad session.setPlaybackToLocal(AUDIO_ATTRIBUTES); 73731369c3983628e700f161138fe2ea3230033a1aIhab Awad mSession = session; 74731369c3983628e700f161138fe2ea3230033a1aIhab Awad break; 75731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 76731369c3983628e700f161138fe2ea3230033a1aIhab Awad case MSG_MEDIA_SESSION_SET_ACTIVE: { 77731369c3983628e700f161138fe2ea3230033a1aIhab Awad if (mSession != null) { 78731369c3983628e700f161138fe2ea3230033a1aIhab Awad boolean activate = msg.arg1 != 0; 79731369c3983628e700f161138fe2ea3230033a1aIhab Awad if (activate != mSession.isActive()) { 80731369c3983628e700f161138fe2ea3230033a1aIhab Awad mSession.setActive(activate); 81731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 82731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 83731369c3983628e700f161138fe2ea3230033a1aIhab Awad break; 84731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 85731369c3983628e700f161138fe2ea3230033a1aIhab Awad default: 86731369c3983628e700f161138fe2ea3230033a1aIhab Awad break; 87731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 88731369c3983628e700f161138fe2ea3230033a1aIhab Awad } 89731369c3983628e700f161138fe2ea3230033a1aIhab Awad }; 90deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 91731369c3983628e700f161138fe2ea3230033a1aIhab Awad private final Context mContext; 92731369c3983628e700f161138fe2ea3230033a1aIhab Awad private final CallsManager mCallsManager; 93731369c3983628e700f161138fe2ea3230033a1aIhab Awad private final TelecomSystem.SyncRoot mLock; 94731369c3983628e700f161138fe2ea3230033a1aIhab Awad private MediaSession mSession; 95deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 96731369c3983628e700f161138fe2ea3230033a1aIhab Awad public HeadsetMediaButton( 97731369c3983628e700f161138fe2ea3230033a1aIhab Awad Context context, 98731369c3983628e700f161138fe2ea3230033a1aIhab Awad CallsManager callsManager, 99731369c3983628e700f161138fe2ea3230033a1aIhab Awad TelecomSystem.SyncRoot lock) { 100731369c3983628e700f161138fe2ea3230033a1aIhab Awad mContext = context; 101deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon mCallsManager = callsManager; 102731369c3983628e700f161138fe2ea3230033a1aIhab Awad mLock = lock; 103deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 104b771c432c5526ed54e5f07949ace2b99008bc341RoboErik // Create a MediaSession but don't enable it yet. This is a 105deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon // replacement for MediaButtonReceiver 106731369c3983628e700f161138fe2ea3230033a1aIhab Awad mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_INITIALIZE).sendToTarget(); 107deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } 108deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 109deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon /** 110deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * Handles the wired headset button while in-call. 111deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * 112deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon * @return true if we consumed the event. 113deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon */ 114deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon private boolean handleHeadsetHook(KeyEvent event) { 115deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon Log.d(this, "handleHeadsetHook()...%s %s", event.getAction(), event.getRepeatCount()); 116deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 117deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon if (event.isLongPress()) { 118deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon return mCallsManager.onMediaButton(LONG_PRESS); 119deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } else if (event.getAction() == KeyEvent.ACTION_UP && event.getRepeatCount() == 0) { 120deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon return mCallsManager.onMediaButton(SHORT_PRESS); 121deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } 122deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon 123deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon return true; 124deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon } 1258128998af91646bae7ae858f60e05075776e0a5cSantos Cordon 1268128998af91646bae7ae858f60e05075776e0a5cSantos Cordon /** ${inheritDoc} */ 1278128998af91646bae7ae858f60e05075776e0a5cSantos Cordon @Override 1288128998af91646bae7ae858f60e05075776e0a5cSantos Cordon public void onCallAdded(Call call) { 1291a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn if (call.isExternalCall()) { 1301a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn return; 1311a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn } 132731369c3983628e700f161138fe2ea3230033a1aIhab Awad mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 1, 0).sendToTarget(); 1338128998af91646bae7ae858f60e05075776e0a5cSantos Cordon } 1348128998af91646bae7ae858f60e05075776e0a5cSantos Cordon 1358128998af91646bae7ae858f60e05075776e0a5cSantos Cordon /** ${inheritDoc} */ 1368128998af91646bae7ae858f60e05075776e0a5cSantos Cordon @Override 1378128998af91646bae7ae858f60e05075776e0a5cSantos Cordon public void onCallRemoved(Call call) { 138f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn if (call.isExternalCall()) { 139f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn return; 140f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn } 1418128998af91646bae7ae858f60e05075776e0a5cSantos Cordon if (!mCallsManager.hasAnyCalls()) { 142731369c3983628e700f161138fe2ea3230033a1aIhab Awad mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget(); 1438128998af91646bae7ae858f60e05075776e0a5cSantos Cordon } 1448128998af91646bae7ae858f60e05075776e0a5cSantos Cordon } 1451a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn 1461a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn /** ${inheritDoc} */ 1471a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn @Override 1481a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn public void onExternalCallChanged(Call call, boolean isExternalCall) { 1491a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn if (isExternalCall) { 1501a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn onCallRemoved(call); 1511a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn } else { 1521a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn onCallAdded(call); 1531a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn } 1541a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn } 155deb8c89707c604d4f9f32e476a58bd10a68293ffSantos Cordon} 156