alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (SimulatedGsmCallState.java)

This example Android source code file (SimulatedGsmCallState.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

android, arraylist, atparseex, callinfo, connecting_pause_msec, drivercall, event_progress_call_state, gsm, invalidstateex, modelinterpreter, mt, os, sc, simulatedgsmcallstate, string, telephony, toa, util, utilities, utils

The SimulatedGsmCallState.java Android example source code

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.test;

import android.os.Looper;
import android.os.Message;
import android.os.Handler;
import android.telephony.PhoneNumberUtils;
import com.android.internal.telephony.ATParseEx;
import com.android.internal.telephony.DriverCall;
import java.util.List;
import java.util.ArrayList;

import android.util.Log;

class CallInfo {
    enum State {
        ACTIVE(0),
        HOLDING(1),
        DIALING(2),    // MO call only
        ALERTING(3),   // MO call only
        INCOMING(4),   // MT call only
        WAITING(5);    // MT call only

        State (int value) {this.value = value;}

        private final int value;
        public int value() {return value;};
    };

    boolean isMT;
    State state;
    boolean isMpty;
    String number;
    int TOA;

    CallInfo (boolean isMT, State state, boolean isMpty, String number) {
        this.isMT = isMT;
        this.state = state;
        this.isMpty = isMpty;
        this.number = number;

        if (number.length() > 0 && number.charAt(0) == '+') {
            TOA = PhoneNumberUtils.TOA_International;
        } else {
            TOA = PhoneNumberUtils.TOA_Unknown;
        }
    }

    static CallInfo
    createOutgoingCall(String number) {
        return new CallInfo (false, State.DIALING, false, number);
    }

    static CallInfo
    createIncomingCall(String number) {
        return new CallInfo (true, State.INCOMING, false, number);
    }

    String
    toCLCCLine(int index) {
        return
            "+CLCC: "
            + index + "," + (isMT ? "1" : "0") +","
            + state.value() + ",0," + (isMpty ? "1" : "0")
            + ",\"" + number + "\"," + TOA;
    }

    DriverCall
    toDriverCall(int index) {
        DriverCall ret;

        ret = new DriverCall();

        ret.index = index;
        ret.isMT = isMT;

        try {
            ret.state = DriverCall.stateFromCLCC(state.value());
        } catch (ATParseEx ex) {
            throw new RuntimeException("should never happen", ex);
        }

        ret.isMpty = isMpty;
        ret.number = number;
        ret.TOA = TOA;
        ret.isVoice = true;
        ret.als = 0;

        return ret;
    }


    boolean
    isActiveOrHeld() {
        return state == State.ACTIVE || state == State.HOLDING;
    }

    boolean
    isConnecting() {
        return state == State.DIALING || state == State.ALERTING;
    }

    boolean
    isRinging() {
        return state == State.INCOMING || state == State.WAITING;
    }

}

class InvalidStateEx extends Exception {
    InvalidStateEx() {

    }
}


class SimulatedGsmCallState extends Handler {
    //***** Instance Variables

    CallInfo calls[] = new CallInfo[MAX_CALLS];

    private boolean autoProgressConnecting = true;
    private boolean nextDialFailImmediately;


    //***** Event Constants

    static final int EVENT_PROGRESS_CALL_STATE = 1;

    //***** Constants

    static final int MAX_CALLS = 7;
    /** number of msec between dialing -> alerting and alerting->active */
    static final int CONNECTING_PAUSE_MSEC = 5 * 100;


    //***** Overridden from Handler

    public SimulatedGsmCallState(Looper looper) {
        super(looper);
    }

    public void
    handleMessage(Message msg) {
        synchronized(this) { switch (msg.what) {
            // PLEASE REMEMBER
            // calls may have hung up by the time delayed events happen

            case EVENT_PROGRESS_CALL_STATE:
                progressConnectingCallState();
            break;
        }}
    }

    //***** Public Methods

    /**
     * Start the simulated phone ringing
     * true if succeeded, false if failed
     */
    public boolean
    triggerRing(String number) {
        synchronized (this) {
            int empty = -1;
            boolean isCallWaiting = false;

            // ensure there aren't already calls INCOMING or WAITING
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call == null && empty < 0) {
                    empty = i;
                } else if (call != null
                    && (call.state == CallInfo.State.INCOMING
                        || call.state == CallInfo.State.WAITING)
                ) {
                    Log.w("ModelInterpreter",
                        "triggerRing failed; phone already ringing");
                    return false;
                } else if (call != null) {
                    isCallWaiting = true;
                }
            }

            if (empty < 0 ) {
                Log.w("ModelInterpreter", "triggerRing failed; all full");
                return false;
            }

            calls[empty] = CallInfo.createIncomingCall(
                PhoneNumberUtils.extractNetworkPortion(number));

            if (isCallWaiting) {
                calls[empty].state = CallInfo.State.WAITING;
            }

        }
        return true;
    }

    /** If a call is DIALING or ALERTING, progress it to the next state */
    public void
    progressConnectingCallState() {
        synchronized (this)  {
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null && call.state == CallInfo.State.DIALING) {
                    call.state = CallInfo.State.ALERTING;

                    if (autoProgressConnecting) {
                        sendMessageDelayed(
                                obtainMessage(EVENT_PROGRESS_CALL_STATE, call),
                                CONNECTING_PAUSE_MSEC);
                    }
                    break;
                } else if (call != null
                        && call.state == CallInfo.State.ALERTING
                ) {
                    call.state = CallInfo.State.ACTIVE;
                    break;
                }
            }
        }
    }

    /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */
    public void
    progressConnectingToActive() {
        synchronized (this)  {
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null && (call.state == CallInfo.State.DIALING
                    || call.state == CallInfo.State.ALERTING)
                ) {
                    call.state = CallInfo.State.ACTIVE;
                    break;
                }
            }
        }
    }

    /** automatically progress mobile originated calls to ACTIVE.
     *  default to true
     */
    public void
    setAutoProgressConnectingCall(boolean b) {
        autoProgressConnecting = b;
    }

    public void
    setNextDialFailImmediately(boolean b) {
        nextDialFailImmediately = b;
    }

    /**
     * hangup ringing, dialing, or active calls
     * returns true if call was hung up, false if not
     */
    public boolean
    triggerHangupForeground() {
        synchronized (this) {
            boolean found;

            found = false;

            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null
                    && (call.state == CallInfo.State.INCOMING
                        || call.state == CallInfo.State.WAITING)
                ) {
                    calls[i] = null;
                    found = true;
                }
            }

            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null
                    && (call.state == CallInfo.State.DIALING
                        || call.state == CallInfo.State.ACTIVE
                        || call.state == CallInfo.State.ALERTING)
                ) {
                    calls[i] = null;
                    found = true;
                }
            }
            return found;
        }
    }

    /**
     * hangup holding calls
     * returns true if call was hung up, false if not
     */
    public boolean
    triggerHangupBackground() {
        synchronized (this) {
            boolean found = false;

            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null && call.state == CallInfo.State.HOLDING) {
                    calls[i] = null;
                    found = true;
                }
            }

            return found;
        }
    }

    /**
     * hangup all
     * returns true if call was hung up, false if not
     */
    public boolean
    triggerHangupAll() {
        synchronized(this) {
            boolean found = false;

            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (calls[i] != null) {
                    found = true;
                }

                calls[i] = null;
            }

            return found;
        }
    }

    public boolean
    onAnswer() {
        synchronized (this) {
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo call = calls[i];

                if (call != null
                    && (call.state == CallInfo.State.INCOMING
                        || call.state == CallInfo.State.WAITING)
                ) {
                    return switchActiveAndHeldOrWaiting();
                }
            }
        }

        return false;
    }

    public boolean
    onHangup() {
        boolean found = false;

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo call = calls[i];

            if (call != null && call.state != CallInfo.State.WAITING) {
                calls[i] = null;
                found = true;
            }
        }

        return found;
    }

    public boolean
    onChld(char c0, char c1) {
        boolean ret;
        int callIndex = 0;

        if (c1 != 0) {
            callIndex = c1 - '1';

            if (callIndex < 0 || callIndex >= calls.length) {
                return false;
            }
        }

        switch (c0) {
            case '0':
                ret = releaseHeldOrUDUB();
            break;
            case '1':
                if (c1 <= 0) {
                    ret = releaseActiveAcceptHeldOrWaiting();
                } else {
                    if (calls[callIndex] == null) {
                        ret = false;
                    } else {
                        calls[callIndex] = null;
                        ret = true;
                    }
                }
            break;
            case '2':
                if (c1 <= 0) {
                    ret = switchActiveAndHeldOrWaiting();
                } else {
                    ret = separateCall(callIndex);
                }
            break;
            case '3':
                ret = conference();
            break;
            case '4':
                ret = explicitCallTransfer();
            break;
            case '5':
                if (true) { //just so javac doesnt complain about break
                    //CCBS not impled
                    ret = false;
                }
            break;
            default:
                ret = false;

        }

        return ret;
    }

    public boolean
    releaseHeldOrUDUB() {
        boolean found = false;

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null && c.isRinging()) {
                found = true;
                calls[i] = null;
                break;
            }
        }

        if (!found) {
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo c = calls[i];

                if (c != null && c.state == CallInfo.State.HOLDING) {
                    found = true;
                    calls[i] = null;
                    // don't stop...there may be more than one
                }
            }
        }

        return true;
    }


    public boolean
    releaseActiveAcceptHeldOrWaiting() {
        boolean foundHeld = false;
        boolean foundActive = false;

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null && c.state == CallInfo.State.ACTIVE) {
                calls[i] = null;
                foundActive = true;
            }
        }

        if (!foundActive) {
            // FIXME this may not actually be how most basebands react
            // CHLD=1 may not hang up dialing/alerting calls
            for (int i = 0 ; i < calls.length ; i++) {
                CallInfo c = calls[i];

                if (c != null
                        && (c.state == CallInfo.State.DIALING
                            || c.state == CallInfo.State.ALERTING)
                ) {
                    calls[i] = null;
                    foundActive = true;
                }
            }
        }

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null && c.state == CallInfo.State.HOLDING) {
                c.state = CallInfo.State.ACTIVE;
                foundHeld = true;
            }
        }

        if (foundHeld) {
            return true;
        }

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null && c.isRinging()) {
                c.state = CallInfo.State.ACTIVE;
                return true;
            }
        }

        return true;
    }

    public boolean
    switchActiveAndHeldOrWaiting() {
        boolean hasHeld = false;

        // first, are there held calls?
        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null && c.state == CallInfo.State.HOLDING) {
                hasHeld = true;
                break;
            }
        }

        // Now, switch
        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                if (c.state == CallInfo.State.ACTIVE) {
                    c.state = CallInfo.State.HOLDING;
                } else if (c.state == CallInfo.State.HOLDING) {
                    c.state = CallInfo.State.ACTIVE;
                } else if (!hasHeld && c.isRinging())  {
                    c.state = CallInfo.State.ACTIVE;
                }
            }
        }

        return true;
    }


    public boolean
    separateCall(int index) {
        try {
            CallInfo c;

            c = calls[index];

            if (c == null || c.isConnecting() || countActiveLines() != 1) {
                return false;
            }

            c.state = CallInfo.State.ACTIVE;
            c.isMpty = false;

            for (int i = 0 ; i < calls.length ; i++) {
                int countHeld=0, lastHeld=0;

                if (i != index) {
                    CallInfo cb = calls[i];

                    if (cb != null && cb.state == CallInfo.State.ACTIVE) {
                        cb.state = CallInfo.State.HOLDING;
                        countHeld++;
                        lastHeld = i;
                    }
                }

                if (countHeld == 1) {
                    // if there's only one left, clear the MPTY flag
                    calls[lastHeld].isMpty = false;
                }
            }

            return true;
        } catch (InvalidStateEx ex) {
            return false;
        }
    }



    public boolean
    conference() {
        int countCalls = 0;

        // if there's connecting calls, we can't do this yet
        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                countCalls++;

                if (c.isConnecting()) {
                    return false;
                }
            }
        }
        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                c.state = CallInfo.State.ACTIVE;
                if (countCalls > 0) {
                    c.isMpty = true;
                }
            }
        }

        return true;
    }

    public boolean
    explicitCallTransfer() {
        int countCalls = 0;

        // if there's connecting calls, we can't do this yet
        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                countCalls++;

                if (c.isConnecting()) {
                    return false;
                }
            }
        }

        // disconnect the subscriber from both calls
        return triggerHangupAll();
    }

    public boolean
    onDial(String address) {
        CallInfo call;
        int freeSlot = -1;

        Log.d("GSM", "SC> dial '" + address + "'");

        if (nextDialFailImmediately) {
            nextDialFailImmediately = false;

            Log.d("GSM", "SC< dial fail (per request)");
            return false;
        }

        String phNum = PhoneNumberUtils.extractNetworkPortion(address);

        if (phNum.length() == 0) {
            Log.d("GSM", "SC< dial fail (invalid ph num)");
            return false;
        }

        // Ignore setting up GPRS
        if (phNum.startsWith("*99") && phNum.endsWith("#")) {
            Log.d("GSM", "SC< dial ignored (gprs)");
            return true;
        }

        // There can be at most 1 active "line" when we initiate
        // a new call
        try {
            if (countActiveLines() > 1) {
                Log.d("GSM", "SC< dial fail (invalid call state)");
                return false;
            }
        } catch (InvalidStateEx ex) {
            Log.d("GSM", "SC< dial fail (invalid call state)");
            return false;
        }

        for (int i = 0 ; i < calls.length ; i++) {
            if (freeSlot < 0 && calls[i] == null) {
                freeSlot = i;
            }

            if (calls[i] != null && !calls[i].isActiveOrHeld()) {
                // Can't make outgoing calls when there is a ringing or
                // connecting outgoing call
                Log.d("GSM", "SC< dial fail (invalid call state)");
                return false;
            } else if (calls[i] != null && calls[i].state == CallInfo.State.ACTIVE) {
                // All active calls behome held
                calls[i].state = CallInfo.State.HOLDING;
            }
        }

        if (freeSlot < 0) {
            Log.d("GSM", "SC< dial fail (invalid call state)");
            return false;
        }

        calls[freeSlot] = CallInfo.createOutgoingCall(phNum);

        if (autoProgressConnecting) {
            sendMessageDelayed(
                    obtainMessage(EVENT_PROGRESS_CALL_STATE, calls[freeSlot]),
                    CONNECTING_PAUSE_MSEC);
        }

        Log.d("GSM", "SC< dial (slot = " + freeSlot + ")");

        return true;
    }

    public List<DriverCall>
    getDriverCalls() {
        ArrayList<DriverCall> ret = new ArrayList(calls.length);

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                DriverCall dc;

                dc = c.toDriverCall(i + 1);
                ret.add(dc);
            }
        }

        Log.d("GSM", "SC< getDriverCalls " + ret);

        return ret;
    }

    public List<String>
    getClccLines() {
        ArrayList<String> ret = new ArrayList(calls.length);

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo c = calls[i];

            if (c != null) {
                ret.add((c.toCLCCLine(i + 1)));
            }
        }

        return ret;
    }

    private int
    countActiveLines() throws InvalidStateEx {
        boolean hasMpty = false;
        boolean hasHeld = false;
        boolean hasActive = false;
        boolean hasConnecting = false;
        boolean hasRinging = false;
        boolean mptyIsHeld = false;

        for (int i = 0 ; i < calls.length ; i++) {
            CallInfo call = calls[i];

            if (call != null) {
                if (!hasMpty && call.isMpty) {
                    mptyIsHeld = call.state == CallInfo.State.HOLDING;
                } else if (call.isMpty && mptyIsHeld
                    && call.state == CallInfo.State.ACTIVE
                ) {
                    Log.e("ModelInterpreter", "Invalid state");
                    throw new InvalidStateEx();
                } else if (!call.isMpty && hasMpty && mptyIsHeld
                    && call.state == CallInfo.State.HOLDING
                ) {
                    Log.e("ModelInterpreter", "Invalid state");
                    throw new InvalidStateEx();
                }

                hasMpty |= call.isMpty;
                hasHeld |= call.state == CallInfo.State.HOLDING;
                hasActive |= call.state == CallInfo.State.ACTIVE;
                hasConnecting |= call.isConnecting();
                hasRinging |= call.isRinging();
            }
        }

        int ret = 0;

        if (hasHeld) ret++;
        if (hasActive) ret++;
        if (hasConnecting) ret++;
        if (hasRinging) ret++;

        return ret;
    }

}

Other Android examples (source code examples)

Here is a short list of links related to this Android SimulatedGsmCallState.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.