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 
17 package com.android.incallui;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.IBinder;
22 import android.os.Trace;
23 import android.telecom.Call;
24 import android.telecom.CallAudioState;
25 import android.telecom.InCallService;
26 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
27 import com.android.dialer.feedback.FeedbackComponent;
28 import com.android.incallui.audiomode.AudioModeProvider;
29 import com.android.incallui.call.CallList;
30 import com.android.incallui.call.ExternalCallList;
31 import com.android.incallui.call.TelecomAdapter;
32 import com.android.incallui.speakeasy.SpeakEasyCallManager;
33 import com.android.incallui.speakeasy.SpeakEasyComponent;
34 
35 /**
36  * Used to receive updates about calls from the Telecom component. This service is bound to Telecom
37  * while there exist calls which potentially require UI. This includes ringing (incoming), dialing
38  * (outgoing), and active calls. When the last call is disconnected, Telecom will unbind to the
39  * service triggering InCallActivity (via CallList) to finish soon after.
40  */
41 public class InCallServiceImpl extends InCallService {
42 
43   private ReturnToCallController returnToCallController;
44   private CallList.Listener feedbackListener;
45   // We only expect there to be one speakEasyCallManager to be instantiated at a time.
46   // We did not use a singleton SpeakEasyCallManager to avoid holding on to state beyond the
47   // lifecycle of this service, because the singleton is associated with the state of the
48   // Application, not this service.
49   private SpeakEasyCallManager speakEasyCallManager;
50 
51   @Override
onCallAudioStateChanged(CallAudioState audioState)52   public void onCallAudioStateChanged(CallAudioState audioState) {
53     Trace.beginSection("InCallServiceImpl.onCallAudioStateChanged");
54     AudioModeProvider.getInstance().onAudioStateChanged(audioState);
55     Trace.endSection();
56   }
57 
58   @Override
onBringToForeground(boolean showDialpad)59   public void onBringToForeground(boolean showDialpad) {
60     Trace.beginSection("InCallServiceImpl.onBringToForeground");
61     InCallPresenter.getInstance().onBringToForeground(showDialpad);
62     Trace.endSection();
63   }
64 
65   @Override
onCallAdded(Call call)66   public void onCallAdded(Call call) {
67     Trace.beginSection("InCallServiceImpl.onCallAdded");
68     InCallPresenter.getInstance().onCallAdded(call);
69     Trace.endSection();
70   }
71 
72   @Override
onCallRemoved(Call call)73   public void onCallRemoved(Call call) {
74     Trace.beginSection("InCallServiceImpl.onCallRemoved");
75     speakEasyCallManager.onCallRemoved(CallList.getInstance().getDialerCallFromTelecomCall(call));
76 
77     InCallPresenter.getInstance().onCallRemoved(call);
78     Trace.endSection();
79   }
80 
81   @Override
onCanAddCallChanged(boolean canAddCall)82   public void onCanAddCallChanged(boolean canAddCall) {
83     Trace.beginSection("InCallServiceImpl.onCanAddCallChanged");
84     InCallPresenter.getInstance().onCanAddCallChanged(canAddCall);
85     Trace.endSection();
86   }
87 
88   @Override
onCreate()89   public void onCreate() {
90     super.onCreate();
91     this.speakEasyCallManager = SpeakEasyComponent.get(this).speakEasyCallManager();
92   }
93 
94   @Override
onBind(Intent intent)95   public IBinder onBind(Intent intent) {
96     Trace.beginSection("InCallServiceImpl.onBind");
97     final Context context = getApplicationContext();
98     final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context);
99     AudioModeProvider.getInstance().initializeAudioState(this);
100     InCallPresenter.getInstance()
101         .setUp(
102             context,
103             CallList.getInstance(),
104             new ExternalCallList(),
105             new StatusBarNotifier(context, contactInfoCache),
106             new ExternalCallNotifier(context, contactInfoCache),
107             contactInfoCache,
108             new ProximitySensor(
109                 context, AudioModeProvider.getInstance(), new AccelerometerListener(context)),
110             new FilteredNumberAsyncQueryHandler(context),
111             speakEasyCallManager);
112     InCallPresenter.getInstance().onServiceBind();
113     InCallPresenter.getInstance().maybeStartRevealAnimation(intent);
114     TelecomAdapter.getInstance().setInCallService(this);
115     returnToCallController =
116         new ReturnToCallController(this, ContactInfoCache.getInstance(context));
117     feedbackListener = FeedbackComponent.get(context).getCallFeedbackListener();
118     CallList.getInstance().addListener(feedbackListener);
119 
120     IBinder iBinder = super.onBind(intent);
121     Trace.endSection();
122     return iBinder;
123   }
124 
125   @Override
onUnbind(Intent intent)126   public boolean onUnbind(Intent intent) {
127     Trace.beginSection("InCallServiceImpl.onUnbind");
128     super.onUnbind(intent);
129 
130     InCallPresenter.getInstance().onServiceUnbind();
131     tearDown();
132 
133     Trace.endSection();
134     return false;
135   }
136 
tearDown()137   private void tearDown() {
138     Trace.beginSection("InCallServiceImpl.tearDown");
139     Log.v(this, "tearDown");
140     // Tear down the InCall system
141     InCallPresenter.getInstance().tearDown();
142     TelecomAdapter.getInstance().clearInCallService();
143     if (returnToCallController != null) {
144       returnToCallController.tearDown();
145       returnToCallController = null;
146     }
147     if (feedbackListener != null) {
148       CallList.getInstance().removeListener(feedbackListener);
149       feedbackListener = null;
150     }
151     Trace.endSection();
152   }
153 }
154