blob: fce29dac914da09f14e96397f012002917202912 [file] [log] [blame]
Santos Cordon4e9fffe2014-03-04 18:13:41 -08001/*
2 * Copyright 2014, 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
17package com.android.telecomm;
18
Santos Cordon57a680f2014-03-07 14:48:11 -080019import android.media.Ringtone;
20import android.media.RingtoneManager;
21import android.os.Handler;
22import android.os.HandlerThread;
23import android.os.Message;
24import android.provider.Settings;
25import android.util.Log;
26
Santos Cordon4e9fffe2014-03-04 18:13:41 -080027/**
28 * Controls ringing and vibration for incoming calls.
29 *
30 * TODO(santoscordon): Consider moving all ringing responsibility to InCall app as an implementation
31 * within InCallServiceBase.
32 */
33final class Ringer {
34
Santos Cordon57a680f2014-03-07 14:48:11 -080035 private static final String TAG = Ringer.class.getSimpleName();
36
37 // Message codes used with {@link #mRingtoneHandler}.
38 private static final int EVENT_PLAY_RING = 1;
39 private static final int EVENT_STOP_RING = 2;
40
41 /**
42 * Handler used to send messages to the ringtone-playing thread.
43 */
44 private Handler mRingtoneHandler;
45
46 /**
47 * The active ringtone. Accessed only from the thread looping {@link #mRingtoneHandler}.
48 */
49 private Ringtone mRingtone;
50
Santos Cordon4e9fffe2014-03-04 18:13:41 -080051 /**
52 * Starts the vibration, ringer, and/or call-waiting tone.
53 */
54 void startRinging() {
Santos Cordon57a680f2014-03-07 14:48:11 -080055 // TODO(santoscordon): Double-check that we want to play the ringtone. e.g., don't play if
56 // the volume is currently set to 0.
57
58 ThreadUtil.checkOnMainThread();
59 Handler handler = getRingtoneHandler();
60
61 Log.d(TAG, "Posting play");
62 handler.obtainMessage(EVENT_PLAY_RING, getCurrentRingtone()).sendToTarget();
Santos Cordon4e9fffe2014-03-04 18:13:41 -080063 }
64
65 /**
66 * Stops the vibration, ringer, and/or call-waiting tone.
67 */
68 void stopRinging() {
Santos Cordon57a680f2014-03-07 14:48:11 -080069 ThreadUtil.checkOnMainThread();
70 if (mRingtoneHandler != null) {
71 Log.d(TAG, "Posting stop");
72 mRingtoneHandler.sendEmptyMessage(EVENT_STOP_RING);
73 mRingtoneHandler = null;
74 }
75 }
76
77 /**
78 * Returns the handler to use for playing ringtones.
79 */
80 private Handler getRingtoneHandler() {
81 if (mRingtoneHandler == null) {
82 // TODO(santoscordon): Clean this up. Needs more investigation for multi-incoming calls
83 // and this multiple thread approach.
84 HandlerThread thread = new HandlerThread("ringer");
85 thread.start();
86
87 mRingtoneHandler = new Handler(thread.getLooper()) {
88 @Override
89 public void handleMessage(Message msg) {
90 switch(msg.what) {
91 case EVENT_PLAY_RING:
92 handlePlayRingtone(this, (Ringtone) msg.obj);
93 break;
94 case EVENT_STOP_RING:
95 handleStopRingtone(this);
96 break;
97 }
98 }
99 };
100 }
101 return mRingtoneHandler;
102 }
103
104 /**
105 * @return The user's currently-selected ringtone.
106 */
107 private Ringtone getCurrentRingtone() {
108 // TODO(santoscordon): Needs support for custom ringtones.
109 return RingtoneManager.getRingtone(
110 TelecommApp.getInstance(), Settings.System.DEFAULT_RINGTONE_URI);
111 }
112
113 /**
114 * Plays the ringtone. Processed by {@link #mRingtoneHandler}.
115 *
116 * @param handler The handler that invoked this method.
117 */
118 private void handlePlayRingtone(Handler handler, Ringtone ringtone) {
119 ThreadUtil.checkNotOnMainThread();
120 // Verify that we haven't been asked to stop the ringtone before we start playing it.
121 if (!handler.hasMessages(EVENT_STOP_RING)) {
122
123 // Check to see if a ringtone already exists and is playing.
124 if (mRingtone != null && mRingtone.isPlaying()) {
125 mRingtone.stop();
126 }
127 mRingtone = ringtone;
128 mRingtone.play();
129 }
130
131 // TODO(santoscordon): Requires reposting EVENT_PLAY_RINGTONE in the case where the ringtone
132 // ends. This method only plays one loop of the ringtone.
133 }
134
135 /**
136 * Stops the ringtone and cleans up references.
137 *
138 * @param handler The handler that invoked this method.
139 */
140 private void handleStopRingtone(Handler handler) {
141 ThreadUtil.checkNotOnMainThread();
142 if (mRingtone != null) {
143 mRingtone.stop();
144 mRingtone = null;
145 }
146
147 handler.getLooper().quitSafely();
Santos Cordon4e9fffe2014-03-04 18:13:41 -0800148 }
149}