PstnIncomingCallNotifier.java revision da120f4e3d32ca97c5b4c21d6c505d834a29ab8d
1/* 2 * Copyright (C) 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.services.telephony; 18 19import android.content.BroadcastReceiver; 20 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.os.AsyncResult; 25import android.os.Handler; 26import android.os.Message; 27import android.os.UserHandle; 28import android.telecomm.TelecommManager; 29 30import com.android.internal.telephony.Call; 31import com.android.internal.telephony.Connection; 32import com.android.internal.telephony.Phone; 33import com.android.internal.telephony.PhoneConstants; 34import com.android.internal.telephony.PhoneProxy; 35import com.android.internal.telephony.TelephonyIntents; 36import com.google.common.base.Preconditions; 37 38/** 39 * Listens to incoming-call events from the associated phone object and notifies Telecomm upon each 40 * occurence. One instance of these exists for each of the telephony-based call services. 41 */ 42final class PstnIncomingCallNotifier { 43 /** New ringing connection event code. */ 44 private static final int EVENT_NEW_RINGING_CONNECTION = 100; 45 46 /** The phone proxy object to listen to. */ 47 private final PhoneProxy mPhoneProxy; 48 49 /** 50 * The base phone implementation behind phone proxy. The underlying phone implementation can 51 * change underneath when the radio technology changes. We listen for these events and update 52 * the base phone in this variable. We save it so that when the change happens, we can 53 * unregister from the events we were listening to. 54 */ 55 private Phone mPhoneBase; 56 57 /** 58 * Used to listen to events from {@link #mPhoneBase}. 59 */ 60 private final Handler mHandler = new Handler() { 61 @Override 62 public void handleMessage(Message msg) { 63 switch(msg.what) { 64 case EVENT_NEW_RINGING_CONNECTION: 65 handleNewRingingConnection((AsyncResult) msg.obj); 66 break; 67 default: 68 break; 69 } 70 } 71 }; 72 73 /** 74 * Receiver to listen for radio technology change events. 75 */ 76 private final BroadcastReceiver mRATReceiver = new BroadcastReceiver() { 77 @Override 78 public void onReceive(Context context, Intent intent) { 79 String action = intent.getAction(); 80 if (TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED.equals(action)) { 81 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY); 82 Log.d(this, "Radio technology switched. Now %s is active.", newPhone); 83 84 registerForNotifications(); 85 } 86 } 87 }; 88 89 /** 90 * Persists the specified parameters and starts listening to phone events. 91 * 92 * @param phoneProxy The phone object for listening to incoming calls. 93 */ 94 PstnIncomingCallNotifier(PhoneProxy phoneProxy) { 95 Preconditions.checkNotNull(phoneProxy); 96 97 mPhoneProxy = phoneProxy; 98 99 registerForNotifications(); 100 101 IntentFilter intentFilter = 102 new IntentFilter(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 103 mPhoneProxy.getContext().registerReceiver(mRATReceiver, intentFilter); 104 } 105 106 void teardown() { 107 unregisterForNotifications(); 108 mPhoneProxy.getContext().unregisterReceiver(mRATReceiver); 109 } 110 111 /** 112 * Register for notifications from the base phone. 113 * TODO: We should only need to interact with the phoneproxy directly. However, 114 * since the phoneproxy only interacts directly with CallManager we either listen to callmanager 115 * or we have to poke into the proxy like this. Neither is desirable. It would be better if 116 * this class and callManager could register generically with the phone proxy instead and get 117 * radio techonology changes directly. Or better yet, just register for the notifications 118 * directly with phone proxy and never worry about the technology changes. This requires a 119 * change in opt/telephony code. 120 */ 121 private void registerForNotifications() { 122 Phone newPhone = mPhoneProxy.getActivePhone(); 123 if (newPhone != mPhoneBase) { 124 if (mPhoneBase != null) { 125 Log.i(this, "Unregistering: %s", mPhoneBase); 126 mPhoneBase.unregisterForNewRingingConnection(mHandler); 127 } 128 129 if (newPhone != null) { 130 Log.i(this, "Registering: %s", newPhone); 131 mPhoneBase = newPhone; 132 mPhoneBase.registerForNewRingingConnection( 133 mHandler, EVENT_NEW_RINGING_CONNECTION, null); 134 } 135 } 136 } 137 138 private void unregisterForNotifications() { 139 if (mPhoneBase != null) { 140 mPhoneBase.unregisterForNewRingingConnection(mHandler); 141 } 142 } 143 144 /** 145 * Verifies the incoming call and triggers sending the incoming-call intent to Telecomm. 146 * 147 * @param asyncResult The result object from the new ringing event. 148 */ 149 private void handleNewRingingConnection(AsyncResult asyncResult) { 150 Log.d(this, "handleNewRingingConnection"); 151 Connection connection = (Connection) asyncResult.result; 152 if (connection != null) { 153 Call call = connection.getCall(); 154 155 // Final verification of the ringing state before sending the intent to Telecomm. 156 if (call != null && call.getState().isRinging()) { 157 sendIncomingCallIntent(connection); 158 } 159 } 160 } 161 162 /** 163 * Sends the incoming call intent to telecomm. 164 */ 165 private void sendIncomingCallIntent(Connection connection) { 166 TelecommManager.from(mPhoneProxy.getContext()).addNewIncomingCall( 167 TelecommAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), null); 168 } 169} 170