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