AsyncRingtonePlayer.java revision f43ff474988d4b35c77e0834506d0e15111a4cf1
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 1991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport android.content.Context; 20b64c150bde86ae22787aec4eaa16b9e3b3420f9dSantos Cordonimport android.media.AudioManager; 211ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.media.Ringtone; 221ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.media.RingtoneManager; 235ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordonimport android.net.Uri; 241ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.Handler; 251ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.HandlerThread; 261ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.os.Message; 271ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonimport android.provider.Settings; 281ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 2991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport com.android.internal.util.Preconditions; 301ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 311ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon/** 321ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Plays the default ringtone. Uses {@link Ringtone} in a separate thread so that this class can be 331ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * used from the main thread. 341ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 351ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordonclass AsyncRingtonePlayer { 361ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon // Message codes used with the ringtone thread. 37b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_PLAY = 1; 38b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_STOP = 2; 39b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int EVENT_REPEAT = 3; 40b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 41b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // The interval in which to restart the ringer. 42b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private static final int RESTART_RINGER_MILLIS = 3000; 431ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 441ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Handler running on the ringtone thread. */ 451ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Handler mHandler; 461ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 471ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** The current ringtone. Only used by the ringtone thread. */ 481ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Ringtone mRingtone; 491ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 5091d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn /** 5191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn * The context. 5291d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn */ 5391d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn private final Context mContext; 5491d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn 5591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn AsyncRingtonePlayer(Context context) { 5691d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext = context; 5791d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn } 5891d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn 591ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Plays the ringtone. */ 605ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon void play(Uri ringtone) { 611ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Posting play."); 62f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang if (ringtone == Uri.EMPTY) { 63f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang Log.i(this, "Uri.EMPTY (silence -- not playing anything)"); 64f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang return; 65f43ff474988d4b35c77e0834506d0e15111a4cf1Wenyi Wang } 665ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon postMessage(EVENT_PLAY, true /* shouldCreateHandler */, ringtone); 671ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 681ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 691ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** Stops playing the ringtone. */ 701ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon void stop() { 711ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Posting stop."); 725ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon postMessage(EVENT_STOP, false /* shouldCreateHandler */, null); 731ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 741ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 751ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 761ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Posts a message to the ringtone-thread handler. Creates the handler if specified by the 771ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * parameter shouldCreateHandler. 781ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * 791ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * @param messageCode The message to post. 801ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * @param shouldCreateHandler True when a handler should be created to handle this message. 811ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 825ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon private void postMessage(int messageCode, boolean shouldCreateHandler, Uri ringtone) { 831ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon synchronized(this) { 841ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler == null && shouldCreateHandler) { 851ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler = getNewHandler(); 861ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 871ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 881ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler == null) { 891ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Message %d skipped because there is no handler.", messageCode); 901ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 915ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon mHandler.obtainMessage(messageCode, ringtone).sendToTarget(); 921ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 931ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 941ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 951ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 961ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 971ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Creates a new ringtone Handler running in its own thread. 981ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 991ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private Handler getNewHandler() { 1001ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Preconditions.checkState(mHandler == null); 1011ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1021ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon HandlerThread thread = new HandlerThread("ringtone-player"); 1031ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon thread.start(); 1041ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1051ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon return new Handler(thread.getLooper()) { 1061ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon @Override 1071ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon public void handleMessage(Message msg) { 1081ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon switch(msg.what) { 1091ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon case EVENT_PLAY: 1105ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon handlePlay((Uri) msg.obj); 1111ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon break; 112b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon case EVENT_REPEAT: 113b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon handleRepeat(); 114b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon break; 1151ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon case EVENT_STOP: 1161ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon handleStop(); 1171ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon break; 1181ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1191ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1201ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon }; 1211ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1221ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1231ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 1241ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Starts the actual playback of the ringtone. Executes on ringtone-thread. 1251ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 1265ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon private void handlePlay(Uri ringtoneUri) { 127b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // don't bother with any of this if there is an EVENT_STOP waiting. 128b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (mHandler.hasMessages(EVENT_STOP)) { 129b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon return; 130b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 131b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1321ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon ThreadUtil.checkNotOnMainThread(); 1331ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.i(this, "Play ringtone."); 1341ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1351ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone == null) { 1365ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon mRingtone = getRingtone(ringtoneUri); 1371ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1381ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon // Cancel everything if there is no ringtone. 1391ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone == null) { 1401ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon handleStop(); 1411ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon return; 1421ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1431ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1441ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 145b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon handleRepeat(); 146b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 147b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 148b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon private void handleRepeat() { 149b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (mRingtone == null) { 150b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon return; 151b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 152b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1531ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone.isPlaying()) { 1541ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Ringtone already playing."); 1551ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 1561ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone.play(); 157b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon Log.i(this, "Repeat ringtone."); 158b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 159b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 160b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // Repost event to restart ringer in {@link RESTART_RINGER_MILLIS}. 161b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon synchronized(this) { 162b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon if (!mHandler.hasMessages(EVENT_REPEAT)) { 163b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon mHandler.sendEmptyMessageDelayed(EVENT_REPEAT, RESTART_RINGER_MILLIS); 164b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon } 1651ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1661ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1671ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1681ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon /** 1691ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon * Stops the playback of the ringtone. Executes on the ringtone-thread. 1701ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon */ 1711ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon private void handleStop() { 1721ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon ThreadUtil.checkNotOnMainThread(); 1731ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.i(this, "Stop ringtone."); 1741ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1751ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mRingtone != null) { 1761ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.d(this, "Ringtone.stop() invoked."); 1771ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone.stop(); 1781ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mRingtone = null; 1791ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1801ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1811ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon synchronized(this) { 182b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // At the time that STOP is handled, there should be no need for repeat messages in the 183b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon // queue. 184b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon mHandler.removeMessages(EVENT_REPEAT); 185b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon 1861ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon if (mHandler.hasMessages(EVENT_PLAY)) { 187b21c5daa6ce683d7f6a1605a50a7ae05c520309fSantos Cordon Log.v(this, "Keeping alive ringtone thread for subsequent play request."); 1881ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } else { 1891ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler.removeMessages(EVENT_STOP); 1901ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler.getLooper().quitSafely(); 1911ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon mHandler = null; 1921ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon Log.v(this, "Handler cleared."); 1931ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1941ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1951ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 1961ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon 1975ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon private Ringtone getRingtone(Uri ringtoneUri) { 1985ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon if (ringtoneUri == null) { 1995ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon ringtoneUri = Settings.System.DEFAULT_RINGTONE_URI; 2005ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon } 2015ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon 20291d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn Ringtone ringtone = RingtoneManager.getRingtone(mContext, ringtoneUri); 203dcf7b1f6cdbf597f4e1da766eeb995a9cf9bc949Yorke Lee if (ringtone != null) { 204dcf7b1f6cdbf597f4e1da766eeb995a9cf9bc949Yorke Lee ringtone.setStreamType(AudioManager.STREAM_RING); 205dcf7b1f6cdbf597f4e1da766eeb995a9cf9bc949Yorke Lee } 206b64c150bde86ae22787aec4eaa16b9e3b3420f9dSantos Cordon return ringtone; 2071ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon } 2081ae2b855daecb6829cf50690b1dfa2d55f62cf6dSantos Cordon} 209