Home | History | Annotate | Download | only in imsphone
      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 
     17 package com.android.internal.telephony.imsphone;
     18 
     19 import android.telephony.Rlog;
     20 import android.telephony.DisconnectCause;
     21 
     22 import com.android.internal.telephony.Call;
     23 import com.android.internal.telephony.CallStateException;
     24 import com.android.internal.telephony.Connection;
     25 import com.android.internal.telephony.Phone;
     26 import com.android.ims.ImsCall;
     27 import com.android.ims.ImsException;
     28 import com.android.ims.ImsStreamMediaProfile;
     29 
     30 import java.util.List;
     31 
     32 /**
     33  * {@hide}
     34  */
     35 public class ImsPhoneCall extends Call {
     36     /*************************** Instance Variables **************************/
     37 
     38     private static final String LOG_TAG = "ImsPhoneCall";
     39 
     40     /*package*/ ImsPhoneCallTracker mOwner;
     41 
     42     private boolean mRingbackTonePlayed = false;
     43 
     44     /****************************** Constructors *****************************/
     45     /*package*/
     46     ImsPhoneCall() {
     47     }
     48 
     49     /*package*/
     50     ImsPhoneCall(ImsPhoneCallTracker owner) {
     51         mOwner = owner;
     52     }
     53 
     54     public void dispose() {
     55         try {
     56             mOwner.hangup(this);
     57         } catch (CallStateException ex) {
     58             //Rlog.e(LOG_TAG, "dispose: unexpected error on hangup", ex);
     59             //while disposing, ignore the exception and clean the connections
     60         } finally {
     61             for(int i = 0, s = mConnections.size(); i < s; i++) {
     62                 ImsPhoneConnection c = (ImsPhoneConnection) mConnections.get(i);
     63                 c.onDisconnect(DisconnectCause.LOST_SIGNAL);
     64             }
     65         }
     66     }
     67 
     68     /************************** Overridden from Call *************************/
     69 
     70     @Override
     71     public List<Connection>
     72     getConnections() {
     73         return mConnections;
     74     }
     75 
     76     @Override
     77     public Phone
     78     getPhone() {
     79         return mOwner.mPhone;
     80     }
     81 
     82     @Override
     83     public boolean
     84     isMultiparty() {
     85         return mConnections.size() > 1;
     86     }
     87 
     88     /** Please note: if this is the foreground call and a
     89      *  background call exists, the background call will be resumed.
     90      */
     91     @Override
     92     public void
     93     hangup() throws CallStateException {
     94         mOwner.hangup(this);
     95     }
     96 
     97     @Override
     98     public String
     99     toString() {
    100         return mState.toString();
    101     }
    102 
    103     //***** Called from ImsPhoneConnection
    104 
    105     /*package*/ void
    106     attach(Connection conn) {
    107         clearDisconnected();
    108         mConnections.add(conn);
    109     }
    110 
    111     /*package*/ void
    112     attach(Connection conn, State state) {
    113         this.attach(conn);
    114         mState = state;
    115     }
    116 
    117     /*package*/ void
    118     attachFake(Connection conn, State state) {
    119         attach(conn, state);
    120     }
    121 
    122     /**
    123      * Called by ImsPhoneConnection when it has disconnected
    124      */
    125     boolean
    126     connectionDisconnected(ImsPhoneConnection conn) {
    127         if (mState != State.DISCONNECTED) {
    128             /* If only disconnected connections remain, we are disconnected*/
    129 
    130             boolean hasOnlyDisconnectedConnections = true;
    131 
    132             for (int i = 0, s = mConnections.size()  ; i < s; i ++) {
    133                 if (mConnections.get(i).getState() != State.DISCONNECTED) {
    134                     hasOnlyDisconnectedConnections = false;
    135                     break;
    136                 }
    137             }
    138 
    139             if (hasOnlyDisconnectedConnections) {
    140                 mState = State.DISCONNECTED;
    141                 return true;
    142             }
    143         }
    144 
    145         return false;
    146     }
    147 
    148     /*package*/ void
    149     detach(ImsPhoneConnection conn) {
    150         mConnections.remove(conn);
    151 
    152         if (mConnections.size() == 0) {
    153             mState = State.IDLE;
    154         }
    155     }
    156 
    157     /**
    158      * @return true if there's no space in this call for additional
    159      * connections to be added via "conference"
    160      */
    161     /*package*/ boolean
    162     isFull() {
    163         return mConnections.size() == ImsPhoneCallTracker.MAX_CONNECTIONS_PER_CALL;
    164     }
    165 
    166     //***** Called from ImsPhoneCallTracker
    167     /**
    168      * Called when this Call is being hung up locally (eg, user pressed "end")
    169      */
    170     void
    171     onHangupLocal() {
    172         for (int i = 0, s = mConnections.size(); i < s; i++) {
    173             ImsPhoneConnection cn = (ImsPhoneConnection)mConnections.get(i);
    174             cn.onHangupLocal();
    175         }
    176         mState = State.DISCONNECTING;
    177     }
    178 
    179     /**
    180      * Called when it's time to clean up disconnected Connection objects
    181      */
    182     void
    183     clearDisconnected() {
    184         for (int i = mConnections.size() - 1 ; i >= 0 ; i--) {
    185             ImsPhoneConnection cn = (ImsPhoneConnection)mConnections.get(i);
    186 
    187             if (cn.getState() == State.DISCONNECTED) {
    188                 mConnections.remove(i);
    189             }
    190         }
    191 
    192         if (mConnections.size() == 0) {
    193             mState = State.IDLE;
    194         }
    195     }
    196 
    197     /*package*/ ImsPhoneConnection
    198     getFirstConnection() {
    199         if (mConnections.size() == 0) return null;
    200 
    201         return (ImsPhoneConnection) mConnections.get(0);
    202     }
    203 
    204     /*package*/ void
    205     setMute(boolean mute) {
    206         ImsCall imsCall = getFirstConnection() == null ?
    207                 null : getFirstConnection().getImsCall();
    208         if (imsCall != null) {
    209             try {
    210                 imsCall.setMute(mute);
    211             } catch (ImsException e) {
    212                 Rlog.e(LOG_TAG, "setMute failed : " + e.getMessage());
    213             }
    214         }
    215     }
    216 
    217     /* package */ void
    218     merge(ImsPhoneCall that, State state) {
    219         ImsPhoneConnection[] cc = that.mConnections.toArray(
    220                 new ImsPhoneConnection[that.mConnections.size()]);
    221         for (ImsPhoneConnection c : cc) {
    222             c.update(null, state);
    223         }
    224     }
    225 
    226     /*package*/ ImsCall
    227     getImsCall() {
    228         return (getFirstConnection() == null) ? null : getFirstConnection().getImsCall();
    229     }
    230 
    231     /*package*/ static boolean isLocalTone(ImsCall imsCall) {
    232         if ((imsCall == null) || (imsCall.getCallProfile() == null)
    233                 || (imsCall.getCallProfile().mMediaProfile == null)) {
    234             return false;
    235         }
    236 
    237         ImsStreamMediaProfile mediaProfile = imsCall.getCallProfile().mMediaProfile;
    238 
    239         return (mediaProfile.mAudioDirection == ImsStreamMediaProfile.DIRECTION_INACTIVE)
    240                 ? true : false;
    241     }
    242 
    243     /*package*/ boolean
    244     update (ImsPhoneConnection conn, ImsCall imsCall, State state) {
    245         State newState = state;
    246         boolean changed = false;
    247 
    248         //ImsCall.Listener.onCallProgressing can be invoked several times
    249         //and ringback tone mode can be changed during the call setup procedure
    250         if (state == State.ALERTING) {
    251             if (mRingbackTonePlayed && !isLocalTone(imsCall)) {
    252                 mOwner.mPhone.stopRingbackTone();
    253                 mRingbackTonePlayed = false;
    254             } else if (!mRingbackTonePlayed && isLocalTone(imsCall)) {
    255                 mOwner.mPhone.startRingbackTone();
    256                 mRingbackTonePlayed = true;
    257             }
    258         } else {
    259             if (mRingbackTonePlayed) {
    260                 mOwner.mPhone.stopRingbackTone();
    261                 mRingbackTonePlayed = false;
    262             }
    263         }
    264 
    265         if ((newState != mState) && (state != State.DISCONNECTED)) {
    266             mState = newState;
    267             changed = true;
    268         } else if (state == State.DISCONNECTED) {
    269             changed = true;
    270         }
    271 
    272         return changed;
    273     }
    274 
    275     /* package */ ImsPhoneConnection
    276     getHandoverConnection() {
    277         ImsPhoneConnection conn = (ImsPhoneConnection) getEarliestConnection();
    278         if (conn != null) {
    279             conn.setMultiparty(isMultiparty());
    280         }
    281         return conn;
    282     }
    283 
    284     void switchWith(ImsPhoneCall that) {
    285         synchronized (ImsPhoneCall.class) {
    286             ImsPhoneCall tmp = new ImsPhoneCall();
    287             tmp.takeOver(this);
    288             this.takeOver(that);
    289             that.takeOver(tmp);
    290         }
    291     }
    292 
    293     private void takeOver(ImsPhoneCall that) {
    294         mConnections = that.mConnections;
    295         mState = that.mState;
    296         for (Connection c : mConnections) {
    297             ((ImsPhoneConnection) c).changeParent(this);
    298         }
    299     }
    300 }
    301