AsyncRingtonePlayer.java revision d931a017a0abea32ad4485a91402b5f62b9ddb0e
11ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon/* 21ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Copyright 2014, The Android Open Source Project 31ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * 41ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 51ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * you may not use this file except in compliance with the License. 61ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * You may obtain a copy of the License at 71ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * 81ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 91ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * 101ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Unless required by applicable law or agreed to in writing, software 111ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 121ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * See the License for the specific language governing permissions and 141ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * limitations under the License. 151ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 161ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 181ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 191ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.media.Ringtone; 201ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.Handler; 211ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.HandlerThread; 221ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.Message; 231ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 24d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebingerimport com.android.internal.annotations.VisibleForTesting; 2591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport com.android.internal.util.Preconditions; 261ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 271ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon/** 281ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Plays the default ringtone. Uses {@link Ringtone} in a separate thread so that this class can be 291ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * used from the main thread. 301ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 31d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger@VisibleForTesting 32d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebingerpublic class AsyncRingtonePlayer { 331ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon // Message codes used with the ringtone thread. 34b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_PLAY = 1; 35b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_STOP = 2; 36b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_REPEAT = 3; 37b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 38b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // The interval in which to restart the ringer. 39b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int RESTART_RINGER_MILLIS = 3000; 401ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 411ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Handler running on the ringtone thread. */ 421ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Handler mHandler; 431ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 441ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** The current ringtone. Only used by the ringtone thread. */ 451ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Ringtone mRingtone; 461ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 471ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Plays the ringtone. */ 48d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger public void play(Ringtone ringtone) { 491ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Posting play."); 50d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger if (ringtone == null) { 51d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger Log.i(this, "null (silence -- not playing anything)"); 52f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang return; 53f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang } 545ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon postMessage(EVENT_PLAY, true /* shouldCreateHandler */, ringtone); 551ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 561ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 571ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Stops playing the ringtone. */ 58d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger public void stop() { 591ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Posting stop."); 605ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon postMessage(EVENT_STOP, false /* shouldCreateHandler */, null); 611ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 621ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 631ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 641ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Posts a message to the ringtone-thread handler. Creates the handler if specified by the 651ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * parameter shouldCreateHandler. 661ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * 671ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * @param messageCode The message to post. 681ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * @param shouldCreateHandler True when a handler should be created to handle this message. 691ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 70d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger private void postMessage(int messageCode, boolean shouldCreateHandler, Ringtone ringtone) { 711ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon synchronized(this) { 721ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler == null && shouldCreateHandler) { 731ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler = getNewHandler(); 741ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 751ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 761ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler == null) { 771ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Message %d skipped because there is no handler.", messageCode); 781ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 795ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon mHandler.obtainMessage(messageCode, ringtone).sendToTarget(); 801ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 811ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 821ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 831ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 841ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 851ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Creates a new ringtone Handler running in its own thread. 861ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 871ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Handler getNewHandler() { 881ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Preconditions.checkState(mHandler == null); 891ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 901ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon HandlerThread thread = new HandlerThread("ringtone-player"); 911ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon thread.start(); 921ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 931ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon return new Handler(thread.getLooper()) { 941ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon @Override 951ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon public void handleMessage(Message msg) { 961ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon switch(msg.what) { 971ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon case EVENT_PLAY: 98d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger handlePlay((Ringtone) msg.obj); 991ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon break; 100b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon case EVENT_REPEAT: 101b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon handleRepeat(); 102b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon break; 1031ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon case EVENT_STOP: 1041ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon handleStop(); 1051ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon break; 1061ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1071ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1081ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon }; 1091ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1101ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1111ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 1121ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Starts the actual playback of the ringtone. Executes on ringtone-thread. 1131ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 114d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger private void handlePlay(Ringtone ringtone) { 115b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // don't bother with any of this if there is an EVENT_STOP waiting. 116b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (mHandler.hasMessages(EVENT_STOP)) { 117b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon return; 118b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 119b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1201ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon ThreadUtil.checkNotOnMainThread(); 1211ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.i(this, "Play ringtone."); 1221ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1231ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone == null) { 124d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger mRingtone = ringtone; 1251ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1261ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 127b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon handleRepeat(); 128b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 129b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 130b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private void handleRepeat() { 131b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (mRingtone == null) { 132b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon return; 133b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 134b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1351ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone.isPlaying()) { 1361ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Ringtone already playing."); 1371ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 1381ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone.play(); 139b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon Log.i(this, "Repeat ringtone."); 140b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 141b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 142b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // Repost event to restart ringer in {@link RESTART_RINGER_MILLIS}. 143b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon synchronized(this) { 144b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (!mHandler.hasMessages(EVENT_REPEAT)) { 145b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon mHandler.sendEmptyMessageDelayed(EVENT_REPEAT, RESTART_RINGER_MILLIS); 146b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 1471ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1481ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1491ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1501ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 1511ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Stops the playback of the ringtone. Executes on the ringtone-thread. 1521ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 1531ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private void handleStop() { 1541ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon ThreadUtil.checkNotOnMainThread(); 1551ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.i(this, "Stop ringtone."); 1561ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1571ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone != null) { 1581ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Ringtone.stop() invoked."); 1591ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone.stop(); 1601ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone = null; 1611ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1621ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1631ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon synchronized(this) { 164b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // At the time that STOP is handled, there should be no need for repeat messages in the 165b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // queue. 166b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon mHandler.removeMessages(EVENT_REPEAT); 167b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1681ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler.hasMessages(EVENT_PLAY)) { 169b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon Log.v(this, "Keeping alive ringtone thread for subsequent play request."); 1701ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 1711ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler.removeMessages(EVENT_STOP); 1721ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler.getLooper().quitSafely(); 1731ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler = null; 1741ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.v(this, "Handler cleared."); 1751ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1761ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1771ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1781ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon} 179