1/*
2 * Copyright (C) 2013 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.incallui;
18
19import android.content.Context;
20import android.net.Uri;
21import android.telecom.PhoneCapabilities;
22import android.text.TextUtils;
23
24import com.android.incallui.ContactInfoCache.ContactCacheEntry;
25import com.android.incallui.InCallPresenter.InCallState;
26import com.android.incallui.InCallPresenter.InCallStateListener;
27
28import com.google.common.base.Preconditions;
29
30/**
31 * Logic for call buttons.
32 */
33public class ConferenceManagerPresenter
34        extends Presenter<ConferenceManagerPresenter.ConferenceManagerUi>
35        implements InCallStateListener {
36
37    private static final int MAX_CALLERS_IN_CONFERENCE = 5;
38
39    private String[] mCallerIds;
40    private Context mContext;
41
42    @Override
43    public void onUiReady(ConferenceManagerUi ui) {
44        super.onUiReady(ui);
45
46        // register for call state changes last
47        InCallPresenter.getInstance().addListener(this);
48    }
49
50    @Override
51    public void onUiUnready(ConferenceManagerUi ui) {
52        super.onUiUnready(ui);
53
54        InCallPresenter.getInstance().removeListener(this);
55    }
56
57    @Override
58    public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
59        if (getUi().isFragmentVisible()) {
60            Log.v(this, "onStateChange" + newState);
61            if (newState == InCallState.INCALL) {
62                final Call call = callList.getActiveOrBackgroundCall();
63                if (call != null && call.isConferenceCall()) {
64                    Log.v(this, "Number of existing calls is " +
65                            String.valueOf(call.getChildCallIds().size()));
66                    update(callList);
67                } else {
68                    getUi().setVisible(false);
69                }
70            } else {
71                getUi().setVisible(false);
72            }
73        }
74    }
75
76    public void init(Context context, CallList callList) {
77        mContext = Preconditions.checkNotNull(context);
78        mContext = context;
79        update(callList);
80    }
81
82    private void update(CallList callList) {
83        // callList is non null, but getActiveOrBackgroundCall() may return null
84        final Call currentCall = callList.getActiveOrBackgroundCall();
85        if (currentCall != null) {
86            // getChildCallIds() always returns a valid Set
87            mCallerIds = currentCall.getChildCallIds().toArray(new String[0]);
88        } else {
89            mCallerIds = new String[0];
90        }
91        Log.d(this, "Number of calls is " + String.valueOf(mCallerIds.length));
92
93        // Users can split out a call from the conference call if there either the active call
94        // or the holding call is empty. If both are filled at the moment, users can not split out
95        // another call.
96        final boolean hasActiveCall = (callList.getActiveCall() != null);
97        final boolean hasHoldingCall = (callList.getBackgroundCall() != null);
98        boolean canSeparate = !(hasActiveCall && hasHoldingCall);
99
100        for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) {
101            if (i < mCallerIds.length) {
102                int callCapabilities =
103                        callList.getCallById(currentCall.getChildCallIds().get(i))
104                        .getTelecommCall().getDetails().getCallCapabilities();
105                boolean thisRowCanSeparate = canSeparate &&
106                        ((callCapabilities & PhoneCapabilities.SEPARATE_FROM_CONFERENCE) != 0);
107                boolean thisRowCanDisconnect =
108                        ((callCapabilities & PhoneCapabilities.DISCONNECT_FROM_CONFERENCE) != 0);
109                // Fill in the row in the UI for this caller.
110                final ContactCacheEntry contactCache = ContactInfoCache.getInstance(mContext).
111                        getInfo(mCallerIds[i]);
112                updateManageConferenceRow(
113                        i,
114                        contactCache,
115                        thisRowCanSeparate,
116                        thisRowCanDisconnect);
117            } else {
118                // Blank out this row in the UI
119                updateManageConferenceRow(i, null, false, false);
120            }
121        }
122    }
123
124    /**
125      * Updates a single row of the "Manage conference" UI.  (One row in this
126      * UI represents a single caller in the conference.)
127      *
128      * @param i the row to update
129      * @param contactCacheEntry the contact details corresponding to this caller.
130      *        If null, that means this is an "empty slot" in the conference,
131      *        so hide this row in the UI.
132      * @param canSeparate if true, show a "Separate" (i.e. "Private") button
133      *        on this row in the UI.
134      * @param canDisconnect if true, show a "Disconnect" button on this row in the UI.
135      */
136    public void updateManageConferenceRow(final int i,
137                                          final ContactCacheEntry contactCacheEntry,
138                                          boolean canSeparate,
139                                          boolean canDisconnect) {
140
141        if (contactCacheEntry != null) {
142            // Activate this row of the Manage conference panel:
143            getUi().setRowVisible(i, true);
144
145            String name = contactCacheEntry.name;
146            String number = contactCacheEntry.number;
147
148            if (TextUtils.isEmpty(name)) {
149                name = number;
150                number = null;
151            }
152
153            getUi().setupSeparateButtonForRow(i, canSeparate);
154            getUi().setupEndButtonForRow(i, canDisconnect);
155            getUi().displayCallerInfoForConferenceRow(i, name, number, contactCacheEntry.label,
156                    contactCacheEntry.lookupKey, contactCacheEntry.displayPhotoUri);
157        } else {
158            // Disable this row of the Manage conference panel:
159            getUi().setRowVisible(i, false);
160        }
161    }
162
163    public int getMaxCallersInConference() {
164        return MAX_CALLERS_IN_CONFERENCE;
165    }
166
167    public void separateConferenceConnection(int rowId) {
168        if (rowId < mCallerIds.length) {
169            TelecomAdapter.getInstance().separateCall(mCallerIds[rowId]);
170        }
171    }
172
173    public void endConferenceConnection(int rowId) {
174        if (rowId < mCallerIds.length) {
175            TelecomAdapter.getInstance().disconnectCall(mCallerIds[rowId]);
176        }
177    }
178
179    public interface ConferenceManagerUi extends Ui {
180        void setVisible(boolean on);
181        boolean isFragmentVisible();
182        void setRowVisible(int rowId, boolean on);
183        void displayCallerInfoForConferenceRow(int rowId, String callerName, String callerNumber,
184                String callerNumberType, String lookupKey, Uri photoUri);
185        void setupSeparateButtonForRow(int rowId, boolean canSeparate);
186        void setupEndButtonForRow(int rowId, boolean canDisconnect);
187    }
188}
189