/* * Copyright (C) 2006 The Android Open Source Project * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * 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.phone; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.gsm.TDPhone; import android.content.Context; import android.os.Message; import android.os.SystemProperties; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Log; /** * Phone app module that listens for phone state changes and various other * events from the telephony layer, and triggers any resulting UI behavior * (like starting the Ringer and Incoming Call UI, playing in-call tones, * updating notifications, writing call log entries, etc.) */ public class MsmsCallNotifier extends CallNotifier { private static final String LOG_TAG = "MsmsCallNotifier"; private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2); //for call forward protected boolean needQueryCfuSub1 = true; protected boolean needQueryCfuSub2 = true; protected boolean needUpdateCfiSub1 = true; protected boolean needUpdateCfiSub2 = true; protected boolean mVoice1CfuVisible = false; protected boolean mVoice2CfuVisible = false; protected boolean mVideo1CfuVisible = false; protected boolean mVideo2CfuVisible = false; /** * Initialize the singleton CallNotifier instance. * This is only done once, at startup, from PhoneApp.onCreate(). */ /* package */ static MsmsCallNotifier init(PhoneApp app, Phone phone, Ringer ringer, BluetoothHandsfree btMgr, CallLogAsync callLog) { synchronized (MsmsCallNotifier.class) { if (sInstance == null) { sInstance = new MsmsCallNotifier(app, phone, ringer, btMgr, callLog); } else { Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); } return (MsmsCallNotifier) sInstance; } } /** Private constructor; @see init() */ private MsmsCallNotifier(PhoneApp app, Phone phone, Ringer ringer, BluetoothHandsfree btMgr, CallLogAsync callLog) { super(app, phone, ringer, btMgr, callLog); } @Override public void handleMessage(Message msg) { switch (msg.what) { case PHONE_MWI_CHANGED: Phone phone = (Phone)msg.obj; onMwiChanged(mApplication.phone.getMessageWaitingIndicator(), phone); break; default: super.handleMessage(msg); } } protected void listenPhoneStateListerner() { for (int i = 0; i < TelephonyManager.getPhoneCount(); i++) { TelephonyManager telephonyManager = (TelephonyManager) mApplication.mContext .getSystemService(PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, i)); telephonyManager.listen(getPhoneStateListener(i), PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_SERVICE_STATE); } } private void onMwiChanged(boolean visible, Phone phone) { if (VDBG) log("onMwiChanged(): " + visible); // "Voicemail" is meaningless on non-voice-capable devices, // so ignore MWI events. // if (!PhoneApp.sVoiceCapable) { // ...but still log a warning, since we shouldn't have gotten this // event in the first place! // (PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR events // *should* be blocked at the telephony layer on non-voice-capable // capable devices.) // Log.w(LOG_TAG, "Got onMwiChanged() on non-voice-capable device! Ignoring..."); // return; // } ((MsmsNotificationMgr)mApplication.notificationMgr).updateMwi(visible, phone); } /** * Posts a delayed PHONE_MWI_CHANGED event, to schedule a "retry" for a * failed NotificationMgr.updateMwi() call. */ /* package */ void sendMwiChangedDelayed(long delayMillis, Phone phone) { Message message = Message.obtain(this, PHONE_MWI_CHANGED, phone); sendMessageDelayed(message, delayMillis); } protected void onCfiChanged(boolean visible, int subscription) { if (VDBG) log("onCfiChanged(): " + visible); ((MsmsNotificationMgr)mApplication.notificationMgr).updateCfi(visible, subscription); } protected void onCfiChanged(boolean visible, int serviceClass, int subscription) { if (VDBG) log("onCfiChanged(): " + visible + "serviceClass:" + serviceClass); if (0 == subscription) { if (CommandsInterface.SERVICE_CLASS_VOICE == serviceClass) { mVoice1CfuVisible = visible; } if (TDPhone.SERVICE_CLASS_VIDEO == serviceClass) { mVideo1CfuVisible = visible; } } if (1 == subscription) { if (CommandsInterface.SERVICE_CLASS_VOICE == serviceClass) { mVoice2CfuVisible = visible; } if (TDPhone.SERVICE_CLASS_VIDEO == serviceClass) { mVideo2CfuVisible = visible; } } ((MsmsNotificationMgr) mApplication.notificationMgr).updateCfi(visible, serviceClass, subscription); } private PhoneStateListener getPhoneStateListener(final int sub) { Log.d(LOG_TAG, "getPhoneStateListener: SUBSCRIPTION == " + sub); PhoneStateListener phoneStateListener = new PhoneStateListener() { @Override public void onMessageWaitingIndicatorChanged(boolean mwi) { // mSubscription is a data member of PhoneStateListener class. // Each subscription is associated with one PhoneStateListener. onMwiChanged(mwi, MsmsPhoneApp.getInstance().getPhone(sub)); } @Override public void onCallForwardingIndicatorChangedByServiceClass(boolean cfi, int serviceClass) { onCfiChanged(cfi, serviceClass, sub); } @Override public void onServiceStateChanged(ServiceState serviceState) { if (!PhoneFactory.isCardExist(sub)) { return; } switch (serviceState.getState()) { case ServiceState.STATE_OUT_OF_SERVICE: case ServiceState.STATE_POWER_OFF: ((MsmsNotificationMgr) mApplication.notificationMgr).updateCfi(false, CommandsInterface.SERVICE_CLASS_VOICE, sub); if (SystemProperties.getBoolean("ro.device.support.vt", true)) { ((MsmsNotificationMgr) mApplication.notificationMgr).updateCfi(false, TDPhone.SERVICE_CLASS_VIDEO, sub); } needUpdateCfiSub1 = ((0 == sub) ? true :needQueryCfuSub1); needUpdateCfiSub2 = ((1 == sub) ? true :needQueryCfuSub2); break; case ServiceState.STATE_IN_SERVICE: if (SystemProperties.getInt("persist.sys.callforwarding", 1) == 1) { if (0 == sub) { if (needQueryCfuSub1) { log("(sub0) query call forward only this once"); mApplication.getPhone(sub).getCallForwardingOption( CommandsInterface.CF_REASON_UNCONDITIONAL, CommandsInterface.SERVICE_CLASS_VOICE, null); // only sub0 need query video cfu. if (SystemProperties.getBoolean("ro.device.support.vt", true)) { mApplication.getPhone(sub).getCallForwardingOption( CommandsInterface.CF_REASON_UNCONDITIONAL, TDPhone.SERVICE_CLASS_VIDEO, null); } needQueryCfuSub1 = false; } else if (needUpdateCfiSub1) { ((MsmsNotificationMgr) mApplication.notificationMgr).updateCfi( mVoice1CfuVisible, CommandsInterface.SERVICE_CLASS_VOICE, sub); if (SystemProperties.getBoolean("ro.device.support.vt", true)) { ((MsmsNotificationMgr) mApplication.notificationMgr) .updateCfi(mVideo1CfuVisible, TDPhone.SERVICE_CLASS_VIDEO, sub); } needUpdateCfiSub1 = false; } } if (1 == sub) { if (needQueryCfuSub2) { log("(sub1) query call forward only this once"); mApplication.getPhone(sub).getCallForwardingOption( CommandsInterface.CF_REASON_UNCONDITIONAL, CommandsInterface.SERVICE_CLASS_VOICE, null); if (SystemProperties.getBoolean("ro.device.support.vt", true)) { mApplication.getPhone(sub).getCallForwardingOption( CommandsInterface.CF_REASON_UNCONDITIONAL, TDPhone.SERVICE_CLASS_VIDEO, null); } needQueryCfuSub2 = false; } else if (needUpdateCfiSub2) { ((MsmsNotificationMgr) mApplication.notificationMgr).updateCfi( mVoice2CfuVisible, CommandsInterface.SERVICE_CLASS_VOICE, sub); if (SystemProperties.getBoolean("ro.device.support.vt", true)) { ((MsmsNotificationMgr) mApplication.notificationMgr) .updateCfi(mVideo2CfuVisible, TDPhone.SERVICE_CLASS_VIDEO, sub); } needUpdateCfiSub2 = false; } } } break; default: break; } } }; return phoneStateListener; } private void log(String msg) { Log.d(LOG_TAG, msg); } }