mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
1869 lines
73 KiB
Java
1869 lines
73 KiB
Java
package org.linphone;
|
|
|
|
/*
|
|
LinphoneManager.java
|
|
Copyright (C) 2018 Belledonne Communications, Grenoble, France
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
import static android.media.AudioManager.MODE_RINGTONE;
|
|
import static android.media.AudioManager.STREAM_RING;
|
|
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.AlertDialog;
|
|
import android.app.Dialog;
|
|
import android.app.ProgressDialog;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ClipData;
|
|
import android.content.ClipboardManager;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.res.Resources;
|
|
import android.hardware.Sensor;
|
|
import android.hardware.SensorEvent;
|
|
import android.hardware.SensorEventListener;
|
|
import android.hardware.SensorManager;
|
|
import android.media.AudioManager;
|
|
import android.media.MediaPlayer;
|
|
import android.net.ConnectivityManager;
|
|
import android.net.NetworkInfo;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import android.os.Handler;
|
|
import android.os.PowerManager;
|
|
import android.os.PowerManager.WakeLock;
|
|
import android.os.Vibrator;
|
|
import android.provider.Settings;
|
|
import android.provider.Settings.SettingNotFoundException;
|
|
import android.telephony.TelephonyManager;
|
|
import android.view.View;
|
|
import android.widget.Button;
|
|
import android.widget.CheckBox;
|
|
import android.widget.Toast;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.sql.Timestamp;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
import org.linphone.assistant.AssistantActivity;
|
|
import org.linphone.call.CallActivity;
|
|
import org.linphone.call.CallIncomingActivity;
|
|
import org.linphone.call.CallManager;
|
|
import org.linphone.contacts.ContactsManager;
|
|
import org.linphone.contacts.LinphoneContact;
|
|
import org.linphone.core.AccountCreator;
|
|
import org.linphone.core.AccountCreatorListener;
|
|
import org.linphone.core.Address;
|
|
import org.linphone.core.AuthInfo;
|
|
import org.linphone.core.AuthMethod;
|
|
import org.linphone.core.Call;
|
|
import org.linphone.core.Call.State;
|
|
import org.linphone.core.CallLog;
|
|
import org.linphone.core.CallParams;
|
|
import org.linphone.core.CallStats;
|
|
import org.linphone.core.ChatMessage;
|
|
import org.linphone.core.ChatRoom;
|
|
import org.linphone.core.ChatRoomCapabilities;
|
|
import org.linphone.core.ConfiguringState;
|
|
import org.linphone.core.Content;
|
|
import org.linphone.core.Core;
|
|
import org.linphone.core.Core.LogCollectionUploadState;
|
|
import org.linphone.core.CoreListener;
|
|
import org.linphone.core.EcCalibratorStatus;
|
|
import org.linphone.core.Event;
|
|
import org.linphone.core.Factory;
|
|
import org.linphone.core.Friend;
|
|
import org.linphone.core.FriendList;
|
|
import org.linphone.core.GlobalState;
|
|
import org.linphone.core.InfoMessage;
|
|
import org.linphone.core.PresenceActivity;
|
|
import org.linphone.core.PresenceBasicStatus;
|
|
import org.linphone.core.PresenceModel;
|
|
import org.linphone.core.ProxyConfig;
|
|
import org.linphone.core.PublishState;
|
|
import org.linphone.core.Reason;
|
|
import org.linphone.core.RegistrationState;
|
|
import org.linphone.core.SubscriptionState;
|
|
import org.linphone.core.Tunnel;
|
|
import org.linphone.core.TunnelConfig;
|
|
import org.linphone.core.VersionUpdateCheckResult;
|
|
import org.linphone.core.tools.H264Helper;
|
|
import org.linphone.core.tools.Log;
|
|
import org.linphone.core.tools.OpenH264DownloadHelper;
|
|
import org.linphone.core.tools.OpenH264DownloadHelperListener;
|
|
import org.linphone.mediastream.Version;
|
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
|
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
|
import org.linphone.receivers.BluetoothManager;
|
|
import org.linphone.receivers.HookReceiver;
|
|
import org.linphone.receivers.OutgoingCallReceiver;
|
|
import org.linphone.settings.LinphonePreferences;
|
|
import org.linphone.utils.FileUtils;
|
|
import org.linphone.utils.LinphoneUtils;
|
|
import org.linphone.utils.MediaScanner;
|
|
import org.linphone.utils.MediaScannerListener;
|
|
import org.linphone.utils.PushNotificationUtils;
|
|
|
|
/**
|
|
* Manager of the low level LibLinphone stuff.<br>
|
|
* Including:
|
|
*
|
|
* <ul>
|
|
* <li>Starting C liblinphone
|
|
* <li>Reacting to C liblinphone state changes
|
|
* <li>Calling Linphone android service listener methods
|
|
* <li>Interacting from Android GUI/service with low level SIP stuff/
|
|
* </ul>
|
|
*
|
|
* <p>Add Service Listener to react to Linphone state changes.
|
|
*/
|
|
public class LinphoneManager implements CoreListener, SensorEventListener, AccountCreatorListener {
|
|
|
|
private static final int LINPHONE_VOLUME_STREAM = STREAM_VOICE_CALL;
|
|
|
|
private static LinphoneManager sInstance;
|
|
private static boolean sExited;
|
|
|
|
public final String configFile;
|
|
public String wizardLoginViewDomain = null;
|
|
|
|
/** Called when the activity is first created. */
|
|
private final String mLPConfigXsd;
|
|
|
|
private final String mLinphoneFactoryConfigFile;
|
|
private final String mLinphoneDynamicConfigFile, mDefaultDynamicConfigFile;
|
|
private final String mChatDatabaseFile;
|
|
private final String mRingSoundFile;
|
|
private final String mCallLogDatabaseFile;
|
|
private final String mFriendsDatabaseFile;
|
|
private final String mUserCertsPath;
|
|
private final Context mServiceContext;
|
|
private final AudioManager mAudioManager;
|
|
private final PowerManager mPowerManager;
|
|
private final Resources mRessources;
|
|
private final LinphonePreferences mPrefs;
|
|
private Core mCore;
|
|
private OpenH264DownloadHelper mCodecDownloader;
|
|
private OpenH264DownloadHelperListener mCodecListener;
|
|
private final String mBasePath;
|
|
private boolean mAudioFocused;
|
|
private boolean mEchoTesterIsRunning;
|
|
private boolean mCallGsmON;
|
|
private final ConnectivityManager mConnectivityManager;
|
|
private BroadcastReceiver mHookReceiver;
|
|
private BroadcastReceiver mCallReceiver;
|
|
private IntentFilter mHookIntentFilter;
|
|
private IntentFilter mCallIntentFilter;
|
|
private final Handler mHandler = new Handler();
|
|
private WakeLock mProximityWakelock;
|
|
private AccountCreator mAccountCreator;
|
|
private final SensorManager mSensorManager;
|
|
private final Sensor mProximity;
|
|
private boolean mProximitySensingEnabled;
|
|
private boolean mHandsetON = false;
|
|
private Address mCurrentChatRoomAddress;
|
|
private Timer mTimer;
|
|
private final Map<String, Integer> mUnreadChatsPerRoom;
|
|
private final MediaScanner mMediaScanner;
|
|
private Call mRingingCall;
|
|
private MediaPlayer mRingerPlayer;
|
|
private final Vibrator mVibrator;
|
|
private boolean mIsRinging;
|
|
|
|
private LinphoneManager(Context c) {
|
|
mUnreadChatsPerRoom = new HashMap();
|
|
sExited = false;
|
|
mEchoTesterIsRunning = false;
|
|
mServiceContext = c;
|
|
mBasePath = c.getFilesDir().getAbsolutePath();
|
|
mLPConfigXsd = mBasePath + "/lpconfig.xsd";
|
|
mLinphoneFactoryConfigFile = mBasePath + "/linphonerc";
|
|
configFile = mBasePath + "/.linphonerc";
|
|
mLinphoneDynamicConfigFile = mBasePath + "/linphone_assistant_create.rc";
|
|
mDefaultDynamicConfigFile = mBasePath + "/default_assistant_create.rc";
|
|
mChatDatabaseFile = mBasePath + "/linphone-history.db";
|
|
mCallLogDatabaseFile = mBasePath + "/linphone-log-history.db";
|
|
mFriendsDatabaseFile = mBasePath + "/linphone-friends.db";
|
|
mRingSoundFile = mBasePath + "/share/sounds/linphone/rings/notes_of_the_optimistic.mkv";
|
|
mUserCertsPath = mBasePath + "/user-certs";
|
|
|
|
mPrefs = LinphonePreferences.instance();
|
|
mAudioManager = ((AudioManager) c.getSystemService(Context.AUDIO_SERVICE));
|
|
mVibrator = (Vibrator) c.getSystemService(Context.VIBRATOR_SERVICE);
|
|
mPowerManager = (PowerManager) c.getSystemService(Context.POWER_SERVICE);
|
|
mConnectivityManager =
|
|
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
|
|
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
|
mRessources = c.getResources();
|
|
|
|
File f = new File(mUserCertsPath);
|
|
if (!f.exists()) {
|
|
if (!f.mkdir()) {
|
|
Log.e("[Manager] " + mUserCertsPath + " can't be created.");
|
|
}
|
|
}
|
|
|
|
mMediaScanner = new MediaScanner(c);
|
|
}
|
|
|
|
public static synchronized void createAndStart(Context c, boolean isPush) {
|
|
if (sInstance != null) {
|
|
Log.e(
|
|
"[Manager] Linphone Manager is already initialized ! Destroying it and creating a new one...");
|
|
destroy();
|
|
}
|
|
|
|
sInstance = new LinphoneManager(c);
|
|
sInstance.startLibLinphone(c, isPush);
|
|
sInstance.initOpenH264DownloadHelper();
|
|
|
|
// H264 codec Management - set to auto mode -> MediaCodec >= android 5.0 >= OpenH264
|
|
H264Helper.setH264Mode(H264Helper.MODE_AUTO, getLc());
|
|
}
|
|
|
|
public static synchronized LinphoneManager getInstance() {
|
|
if (sInstance != null) return sInstance;
|
|
|
|
if (sExited) {
|
|
throw new RuntimeException(
|
|
"[Manager] Linphone Manager was already destroyed. "
|
|
+ "Better use getLcIfManagerNotDestroyedOrNull and check returned value");
|
|
}
|
|
|
|
throw new RuntimeException("[Manager] Linphone Manager should be created before accessed");
|
|
}
|
|
|
|
public static synchronized Core getLc() {
|
|
return getInstance().mCore;
|
|
}
|
|
|
|
private static Boolean isProximitySensorNearby(final SensorEvent event) {
|
|
float threshold = 4.001f; // <= 4 cm is near
|
|
|
|
final float distanceInCm = event.values[0];
|
|
final float maxDistance = event.sensor.getMaximumRange();
|
|
Log.d(
|
|
"[Manager] Proximity sensor report ["
|
|
+ distanceInCm
|
|
+ "] , for max range ["
|
|
+ maxDistance
|
|
+ "]");
|
|
|
|
if (maxDistance <= threshold) {
|
|
// Case binary 0/1 and short sensors
|
|
threshold = maxDistance;
|
|
}
|
|
return distanceInCm < threshold;
|
|
}
|
|
|
|
private static void ContactsManagerDestroy() {
|
|
if (LinphoneManager.sInstance != null && LinphoneManager.sInstance.mServiceContext != null)
|
|
LinphoneManager.sInstance
|
|
.mServiceContext
|
|
.getContentResolver()
|
|
.unregisterContentObserver(ContactsManager.getInstance());
|
|
ContactsManager.getInstance().destroy();
|
|
}
|
|
|
|
private static void BluetoothManagerDestroy() {
|
|
BluetoothManager.getInstance().destroy();
|
|
}
|
|
|
|
public static synchronized void destroy() {
|
|
if (sInstance == null) return;
|
|
sInstance.changeStatusToOffline();
|
|
sInstance.mMediaScanner.destroy();
|
|
sExited = true;
|
|
sInstance.destroyCore();
|
|
sInstance = null;
|
|
}
|
|
|
|
private static boolean reinviteWithVideo() {
|
|
return CallManager.getInstance().reinviteWithVideo();
|
|
}
|
|
|
|
public static synchronized Core getLcIfManagerNotDestroyedOrNull() {
|
|
if (sExited || sInstance == null) {
|
|
// Can occur if the UI thread play a posted event but in the meantime the
|
|
// LinphoneManager was destroyed
|
|
// Ex: stop call and quickly terminate application.
|
|
return null;
|
|
}
|
|
return getLc();
|
|
}
|
|
|
|
public static boolean isInstanciated() {
|
|
return sInstance != null;
|
|
}
|
|
|
|
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
|
Log.w(
|
|
"[Manager] Routing audio to "
|
|
+ (speakerOn ? "speaker" : "earpiece")
|
|
+ ", disabling bluetooth audio route");
|
|
BluetoothManager.getInstance().disableBluetoothSCO();
|
|
|
|
enableSpeaker(speakerOn);
|
|
}
|
|
|
|
public boolean isSpeakerEnabled() {
|
|
return mAudioManager != null && mAudioManager.isSpeakerphoneOn();
|
|
}
|
|
|
|
public void enableSpeaker(boolean enable) {
|
|
mAudioManager.setSpeakerphoneOn(enable);
|
|
}
|
|
|
|
private void initOpenH264DownloadHelper() {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
Log.i("[Manager] Android >= 5.1 we disable the download of OpenH264");
|
|
OpenH264DownloadHelper.setOpenH264DownloadEnabled(false);
|
|
return;
|
|
}
|
|
|
|
mCodecDownloader = Factory.instance().createOpenH264DownloadHelper(getContext());
|
|
mCodecListener =
|
|
new OpenH264DownloadHelperListener() {
|
|
ProgressDialog progress;
|
|
final int ctxt = 0;
|
|
|
|
@Override
|
|
public void OnProgress(final int current, final int max) {
|
|
mHandler.post(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
OpenH264DownloadHelper ohcodec =
|
|
LinphoneManager.getInstance()
|
|
.getOpenH264DownloadHelper();
|
|
if (progress == null) {
|
|
progress =
|
|
new ProgressDialog(
|
|
(Context) ohcodec.getUserData(ctxt));
|
|
progress.setCanceledOnTouchOutside(false);
|
|
progress.setCancelable(false);
|
|
progress.setProgressStyle(
|
|
ProgressDialog.STYLE_HORIZONTAL);
|
|
} else if (current <= max) {
|
|
progress.setMessage(
|
|
getString(
|
|
R.string
|
|
.assistant_openh264_downloading));
|
|
progress.setMax(max);
|
|
progress.setProgress(current);
|
|
progress.show();
|
|
} else {
|
|
progress.dismiss();
|
|
progress = null;
|
|
if (Build.VERSION.SDK_INT
|
|
>= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
LinphoneManager.getLc()
|
|
.reloadMsPlugins(
|
|
AssistantActivity.instance()
|
|
.getApplicationInfo()
|
|
.nativeLibraryDir);
|
|
AssistantActivity.instance().endDownloadCodec();
|
|
} else {
|
|
// We need to restart due to bad android linker
|
|
AssistantActivity.instance().restartApplication();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void OnError(final String error) {
|
|
mHandler.post(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (progress != null) progress.dismiss();
|
|
AlertDialog.Builder builder =
|
|
new AlertDialog.Builder(
|
|
(Context)
|
|
LinphoneManager.getInstance()
|
|
.getOpenH264DownloadHelper()
|
|
.getUserData(ctxt));
|
|
builder.setMessage(
|
|
getString(R.string.assistant_openh264_error));
|
|
builder.setCancelable(false);
|
|
builder.setNeutralButton(getString(R.string.ok), null);
|
|
builder.show();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
mCodecDownloader.setOpenH264HelperListener(mCodecListener);
|
|
}
|
|
|
|
public OpenH264DownloadHelperListener getOpenH264HelperListener() {
|
|
return mCodecListener;
|
|
}
|
|
|
|
public OpenH264DownloadHelper getOpenH264DownloadHelper() {
|
|
return mCodecDownloader;
|
|
}
|
|
|
|
public void routeAudioToSpeaker() {
|
|
routeAudioToSpeakerHelper(true);
|
|
}
|
|
|
|
public void routeAudioToReceiver() {
|
|
routeAudioToSpeakerHelper(false);
|
|
}
|
|
|
|
private boolean isPresenceModelActivitySet() {
|
|
Core lc = getLcIfManagerNotDestroyedOrNull();
|
|
if (isInstanciated() && lc != null) {
|
|
return lc.getPresenceModel() != null && lc.getPresenceModel().getActivity() != null;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void changeStatusToOnline() {
|
|
Core lc = getLcIfManagerNotDestroyedOrNull();
|
|
if (lc == null) return;
|
|
PresenceModel model = lc.createPresenceModel();
|
|
model.setBasicStatus(PresenceBasicStatus.Open);
|
|
lc.setPresenceModel(model);
|
|
}
|
|
|
|
public void changeStatusToOnThePhone() {
|
|
Core lc = getLcIfManagerNotDestroyedOrNull();
|
|
if (lc == null) return;
|
|
|
|
if (isInstanciated()
|
|
&& isPresenceModelActivitySet()
|
|
&& lc.getPresenceModel().getActivity().getType()
|
|
!= PresenceActivity.Type.OnThePhone) {
|
|
lc.getPresenceModel().getActivity().setType(PresenceActivity.Type.OnThePhone);
|
|
} else if (isInstanciated() && !isPresenceModelActivitySet()) {
|
|
PresenceModel model =
|
|
lc.createPresenceModelWithActivity(PresenceActivity.Type.OnThePhone, null);
|
|
lc.setPresenceModel(model);
|
|
}
|
|
}
|
|
|
|
private void changeStatusToOffline() {
|
|
Core lc = getLcIfManagerNotDestroyedOrNull();
|
|
if (isInstanciated() && lc != null) {
|
|
PresenceModel model = lc.getPresenceModel();
|
|
model.setBasicStatus(PresenceBasicStatus.Closed);
|
|
lc.setPresenceModel(model);
|
|
}
|
|
}
|
|
|
|
public void subscribeFriendList(boolean enabled) {
|
|
Core lc = getLcIfManagerNotDestroyedOrNull();
|
|
if (lc != null && lc.getFriendsLists() != null && lc.getFriendsLists().length > 0) {
|
|
FriendList friendList = (lc.getFriendsLists())[0];
|
|
Log.i("[Manager] Presence list subscription is " + (enabled ? "enabled" : "disabled"));
|
|
friendList.enableSubscriptions(enabled);
|
|
}
|
|
}
|
|
|
|
public void newOutgoingCall(AddressType address) {
|
|
String to = address.getText().toString();
|
|
newOutgoingCall(to, address.getDisplayedName());
|
|
}
|
|
|
|
public void newOutgoingCall(String to, String displayName) {
|
|
// if (mCore.inCall()) {
|
|
// listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
|
|
// return;
|
|
// }
|
|
if (to == null) return;
|
|
|
|
// If to is only a username, try to find the contact to get an alias if existing
|
|
if (!to.startsWith("sip:") || !to.contains("@")) {
|
|
LinphoneContact contact = ContactsManager.getInstance().findContactFromPhoneNumber(to);
|
|
if (contact != null) {
|
|
String alias = contact.getContactFromPresenceModelForUriOrTel(to);
|
|
if (alias != null) {
|
|
to = alias;
|
|
}
|
|
}
|
|
}
|
|
|
|
Address lAddress;
|
|
lAddress = mCore.interpretUrl(to); // InterpretUrl does normalizePhoneNumber
|
|
if (lAddress == null) {
|
|
Log.e("[Manager] Couldn't convert to String to Address : " + to);
|
|
return;
|
|
}
|
|
|
|
ProxyConfig lpc = mCore.getDefaultProxyConfig();
|
|
if (mRessources.getBoolean(R.bool.forbid_self_call)
|
|
&& lpc != null
|
|
&& lAddress.weakEqual(lpc.getIdentityAddress())) {
|
|
return;
|
|
}
|
|
lAddress.setDisplayName(displayName);
|
|
|
|
boolean isLowBandwidthConnection =
|
|
!LinphoneUtils.isHighBandwidthConnection(
|
|
LinphoneService.instance().getApplicationContext());
|
|
|
|
if (mCore.isNetworkReachable()) {
|
|
if (Version.isVideoCapable()) {
|
|
boolean prefVideoEnable = mPrefs.isVideoEnabled();
|
|
boolean prefInitiateWithVideo = mPrefs.shouldInitiateVideoCall();
|
|
CallManager.getInstance()
|
|
.inviteAddress(
|
|
lAddress,
|
|
prefVideoEnable && prefInitiateWithVideo,
|
|
isLowBandwidthConnection);
|
|
} else {
|
|
CallManager.getInstance().inviteAddress(lAddress, false, isLowBandwidthConnection);
|
|
}
|
|
} else if (LinphoneActivity.isInstanciated()) {
|
|
LinphoneActivity.instance()
|
|
.displayCustomToast(
|
|
getString(R.string.error_network_unreachable), Toast.LENGTH_LONG);
|
|
} else {
|
|
Log.e("[Manager] Error: " + getString(R.string.error_network_unreachable));
|
|
}
|
|
}
|
|
|
|
private void resetCameraFromPreferences() {
|
|
boolean useFrontCam = mPrefs.useFrontCam();
|
|
int camId = 0;
|
|
AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras();
|
|
for (AndroidCamera androidCamera : cameras) {
|
|
if (androidCamera.frontFacing == useFrontCam) {
|
|
camId = androidCamera.id;
|
|
break;
|
|
}
|
|
}
|
|
String[] devices = getLc().getVideoDevicesList();
|
|
if (camId >= devices.length) {
|
|
Log.e(
|
|
"[Manager] Trying to use a camera id that's higher than the linphone's devices list, using 0 to prevent crash...");
|
|
camId = 0;
|
|
}
|
|
String newDevice = devices[camId];
|
|
LinphoneManager.getLc().setVideoDevice(newDevice);
|
|
}
|
|
|
|
private void enableCamera(Call call, boolean enable) {
|
|
if (call != null) {
|
|
call.enableCamera(enable);
|
|
if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification))
|
|
LinphoneService.instance()
|
|
.getNotificationManager()
|
|
.displayCallNotification(mCore.getCurrentCall());
|
|
}
|
|
}
|
|
|
|
public void playDtmf(ContentResolver r, char dtmf) {
|
|
try {
|
|
if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) {
|
|
// audible touch disabled: don't play on speaker, only send in outgoing stream
|
|
return;
|
|
}
|
|
} catch (SettingNotFoundException e) {
|
|
Log.e("[Manager] playDtmf exception: " + e);
|
|
}
|
|
|
|
getLc().playDtmf(dtmf, -1);
|
|
}
|
|
|
|
private void terminateCall() {
|
|
if (mCore.inCall()) {
|
|
mCore.terminateCall(mCore.getCurrentCall());
|
|
}
|
|
}
|
|
|
|
public void initTunnelFromConf() {
|
|
if (!mCore.tunnelAvailable()) return;
|
|
|
|
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
|
Tunnel tunnel = mCore.getTunnel();
|
|
tunnel.cleanServers();
|
|
TunnelConfig config = mPrefs.getTunnelConfig();
|
|
if (config.getHost() != null) {
|
|
tunnel.addServer(config);
|
|
manageTunnelServer(info);
|
|
}
|
|
}
|
|
|
|
private boolean isTunnelNeeded(NetworkInfo info) {
|
|
if (info == null) {
|
|
Log.i("[Manager] No connectivity: tunnel should be disabled");
|
|
return false;
|
|
}
|
|
|
|
String pref = mPrefs.getTunnelMode();
|
|
|
|
if (getString(R.string.tunnel_mode_entry_value_always).equals(pref)) {
|
|
return true;
|
|
}
|
|
|
|
if (info.getType() != ConnectivityManager.TYPE_WIFI
|
|
&& getString(R.string.tunnel_mode_entry_value_3G_only).equals(pref)) {
|
|
Log.i("[Manager] Need tunnel: 'no wifi' connection");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void manageTunnelServer(NetworkInfo info) {
|
|
if (mCore == null) return;
|
|
if (!mCore.tunnelAvailable()) return;
|
|
Tunnel tunnel = mCore.getTunnel();
|
|
|
|
Log.i("[Manager] Managing tunnel");
|
|
if (isTunnelNeeded(info)) {
|
|
Log.i("[Manager] Tunnel need to be activated");
|
|
tunnel.setMode(Tunnel.Mode.Enable);
|
|
} else {
|
|
Log.i("[Manager] Tunnel should not be used");
|
|
String pref = mPrefs.getTunnelMode();
|
|
tunnel.setMode(Tunnel.Mode.Disable);
|
|
if (getString(R.string.tunnel_mode_entry_value_auto).equals(pref)) {
|
|
tunnel.setMode(Tunnel.Mode.Auto);
|
|
}
|
|
}
|
|
}
|
|
|
|
private synchronized void destroyCore() {
|
|
Log.w("[Manager] Destroying Core");
|
|
sExited = true;
|
|
ContactsManagerDestroy();
|
|
BluetoothManagerDestroy();
|
|
try {
|
|
mTimer.cancel();
|
|
destroyLinphoneCore();
|
|
} catch (RuntimeException e) {
|
|
Log.e("[Manager] Destroy Core Runtime Exception: " + e);
|
|
} finally {
|
|
try {
|
|
mServiceContext.unregisterReceiver(mHookReceiver);
|
|
} catch (Exception e) {
|
|
Log.e("[Manager] unregister receiver exception: " + e);
|
|
}
|
|
try {
|
|
mServiceContext.unregisterReceiver(mCallReceiver);
|
|
} catch (Exception e) {
|
|
Log.e("[Manager] unregister receiver exception: " + e);
|
|
}
|
|
mCore = null;
|
|
}
|
|
}
|
|
|
|
public void restartCore() {
|
|
mCore.stop();
|
|
mCore.start();
|
|
}
|
|
|
|
private synchronized void startLibLinphone(Context c, boolean isPush) {
|
|
try {
|
|
copyAssetsFromPackage();
|
|
// traces alway start with traces enable to not missed first initialization
|
|
mCore = Factory.instance().createCore(configFile, mLinphoneFactoryConfigFile, c);
|
|
mCore.addListener(this);
|
|
if (isPush) {
|
|
Log.w(
|
|
"[Manager] We are here because of a received push notification, enter background mode before starting the Core");
|
|
mCore.enterBackground();
|
|
}
|
|
mCore.start();
|
|
TimerTask lTask =
|
|
new TimerTask() {
|
|
@Override
|
|
public void run() {
|
|
LinphoneUtils.dispatchOnUIThread(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (mCore != null) {
|
|
mCore.iterate();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
/*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
|
|
mTimer = new Timer("Linphone scheduler");
|
|
mTimer.schedule(lTask, 0, 20);
|
|
} catch (Exception e) {
|
|
Log.e(e, "[Manager] Cannot start linphone");
|
|
}
|
|
}
|
|
|
|
private void initPushNotificationsService() {
|
|
PushNotificationUtils.init(mServiceContext);
|
|
}
|
|
|
|
private synchronized void initLiblinphone(Core lc) {
|
|
mCore = lc;
|
|
|
|
mCore.setZrtpSecretsFile(mBasePath + "/zrtp_secrets");
|
|
|
|
String deviceName = mPrefs.getDeviceName(mServiceContext);
|
|
String appName = mServiceContext.getResources().getString(R.string.user_agent);
|
|
String androidVersion = BuildConfig.VERSION_NAME;
|
|
String userAgent = appName + "/" + androidVersion + " (" + deviceName + ") LinphoneSDK";
|
|
|
|
mCore.setUserAgent(
|
|
userAgent,
|
|
getString(R.string.linphone_sdk_version)
|
|
+ " ("
|
|
+ getString(R.string.linphone_sdk_branch)
|
|
+ ")");
|
|
|
|
// mCore.setChatDatabasePath(mChatDatabaseFile);
|
|
mCore.setCallLogsDatabasePath(mCallLogDatabaseFile);
|
|
mCore.setFriendsDatabasePath(mFriendsDatabaseFile);
|
|
mCore.setUserCertificatesPath(mUserCertsPath);
|
|
// mCore.setCallErrorTone(Reason.NotFound, mErrorToneFile);
|
|
enableDeviceRingtone(mPrefs.isDeviceRingtoneEnabled());
|
|
|
|
int availableCores = Runtime.getRuntime().availableProcessors();
|
|
Log.w("[Manager] MediaStreamer : " + availableCores + " cores detected and configured");
|
|
|
|
mCore.migrateLogsFromRcToDb();
|
|
|
|
// Migrate existing linphone accounts to have conference factory uri and LIME X3Dh url set
|
|
String uri = getString(R.string.default_conference_factory_uri);
|
|
for (ProxyConfig lpc : mCore.getProxyConfigList()) {
|
|
if (lpc.getIdentityAddress().getDomain().equals(getString(R.string.default_domain))) {
|
|
if (lpc.getConferenceFactoryUri() == null) {
|
|
lpc.edit();
|
|
Log.i(
|
|
"[Manager] Setting conference factory on proxy config "
|
|
+ lpc.getIdentityAddress().asString()
|
|
+ " to default value: "
|
|
+ uri);
|
|
lpc.setConferenceFactoryUri(uri);
|
|
lpc.done();
|
|
}
|
|
|
|
if (mCore.limeX3DhAvailable()) {
|
|
String url = mCore.getLimeX3DhServerUrl();
|
|
if (url == null || url.length() == 0) {
|
|
url = getString(R.string.default_lime_x3dh_server_url);
|
|
Log.i("[Manager] Setting LIME X3Dh server url to default value: " + url);
|
|
mCore.setLimeX3DhServerUrl(url);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
|
|
initPushNotificationsService();
|
|
}
|
|
|
|
mCallIntentFilter = new IntentFilter("android.intent.action.ACTION_NEW_OUTGOING_CALL");
|
|
mCallIntentFilter.setPriority(99999999);
|
|
mCallReceiver = new OutgoingCallReceiver();
|
|
try {
|
|
mServiceContext.registerReceiver(mCallReceiver, mCallIntentFilter);
|
|
} catch (IllegalArgumentException e) {
|
|
e.printStackTrace();
|
|
}
|
|
mProximityWakelock =
|
|
mPowerManager.newWakeLock(
|
|
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
|
mServiceContext.getPackageName() + ";manager_proximity_sensor");
|
|
|
|
mHookIntentFilter = new IntentFilter("com.base.module.phone.HOOKEVENT");
|
|
mHookIntentFilter.setPriority(999);
|
|
mHookReceiver = new HookReceiver();
|
|
mServiceContext.registerReceiver(mHookReceiver, mHookIntentFilter);
|
|
|
|
resetCameraFromPreferences();
|
|
|
|
mAccountCreator =
|
|
LinphoneManager.getLc()
|
|
.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl());
|
|
mAccountCreator.setListener(this);
|
|
mCallGsmON = false;
|
|
|
|
updateMissedChatCount();
|
|
}
|
|
|
|
public void setHandsetMode(Boolean on) {
|
|
if (mCore.isIncomingInvitePending() && on) {
|
|
mHandsetON = true;
|
|
acceptCall(mCore.getCurrentCall());
|
|
LinphoneActivity.instance().startIncallActivity();
|
|
} else if (on && CallActivity.isInstanciated()) {
|
|
mHandsetON = true;
|
|
CallActivity.instance().setSpeakerEnabled(true);
|
|
CallActivity.instance().refreshInCallActions();
|
|
} else if (!on) {
|
|
mHandsetON = false;
|
|
LinphoneManager.getInstance().terminateCall();
|
|
}
|
|
}
|
|
|
|
public boolean isHansetModeOn() {
|
|
return mHandsetON;
|
|
}
|
|
|
|
private void copyAssetsFromPackage() throws IOException {
|
|
copyIfNotExist(R.raw.linphonerc_default, configFile);
|
|
copyFromPackage(R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName());
|
|
copyIfNotExist(R.raw.lpconfig, mLPConfigXsd);
|
|
copyFromPackage(
|
|
R.raw.default_assistant_create, new File(mDefaultDynamicConfigFile).getName());
|
|
copyFromPackage(
|
|
R.raw.linphone_assistant_create, new File(mLinphoneDynamicConfigFile).getName());
|
|
}
|
|
|
|
private void copyIfNotExist(int ressourceId, String target) throws IOException {
|
|
File lFileToCopy = new File(target);
|
|
if (!lFileToCopy.exists()) {
|
|
copyFromPackage(ressourceId, lFileToCopy.getName());
|
|
}
|
|
}
|
|
|
|
private void copyFromPackage(int ressourceId, String target) throws IOException {
|
|
FileOutputStream lOutputStream = mServiceContext.openFileOutput(target, 0);
|
|
InputStream lInputStream = mRessources.openRawResource(ressourceId);
|
|
int readByte;
|
|
byte[] buff = new byte[8048];
|
|
while ((readByte = lInputStream.read(buff)) != -1) {
|
|
lOutputStream.write(buff, 0, readByte);
|
|
}
|
|
lOutputStream.flush();
|
|
lOutputStream.close();
|
|
lInputStream.close();
|
|
}
|
|
|
|
private void destroyLinphoneCore() {
|
|
if (LinphonePreferences.instance() != null) {
|
|
// We set network reachable at false before destroy LC to not send register with expires
|
|
// at 0
|
|
if (LinphonePreferences.instance().isPushNotificationEnabled()) {
|
|
Log.w(
|
|
"[Manager] Setting network reachability to False to prevent unregister and allow incoming push notifications");
|
|
mCore.setNetworkReachable(false);
|
|
}
|
|
}
|
|
mCore.stop();
|
|
}
|
|
|
|
public void enableProximitySensing(boolean enable) {
|
|
if (enable) {
|
|
if (!mProximitySensingEnabled) {
|
|
mSensorManager.registerListener(
|
|
this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
|
mProximitySensingEnabled = true;
|
|
}
|
|
} else {
|
|
if (mProximitySensingEnabled) {
|
|
mSensorManager.unregisterListener(this);
|
|
mProximitySensingEnabled = false;
|
|
// Don't forgeting to release wakelock if held
|
|
if (mProximityWakelock.isHeld()) {
|
|
mProximityWakelock.release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSensorChanged(SensorEvent event) {
|
|
if (event.timestamp == 0) return;
|
|
if (isProximitySensorNearby(event)) {
|
|
if (!mProximityWakelock.isHeld()) {
|
|
mProximityWakelock.acquire();
|
|
}
|
|
} else {
|
|
if (mProximityWakelock.isHeld()) {
|
|
mProximityWakelock.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
|
|
|
public MediaScanner getMediaScanner() {
|
|
return mMediaScanner;
|
|
}
|
|
|
|
private String getString(int key) {
|
|
return mRessources.getString(key);
|
|
}
|
|
|
|
public void onNewSubscriptionRequested(Core lc, Friend lf, String url) {}
|
|
|
|
public void onNotifyPresenceReceived(Core lc, Friend lf) {}
|
|
|
|
@Override
|
|
public void onEcCalibrationAudioInit(Core lc) {}
|
|
|
|
@Override
|
|
public void onDtmfReceived(Core lc, Call call, int dtmf) {
|
|
Log.d("[Manager] DTMF received: " + dtmf);
|
|
}
|
|
|
|
@Override
|
|
public void onMessageReceived(Core lc, final ChatRoom cr, final ChatMessage message) {
|
|
if (mServiceContext.getResources().getBoolean(R.bool.disable_chat)) {
|
|
return;
|
|
}
|
|
|
|
if (mCurrentChatRoomAddress != null
|
|
&& cr.getPeerAddress()
|
|
.asStringUriOnly()
|
|
.equals(mCurrentChatRoomAddress.asStringUriOnly())) {
|
|
Log.i(
|
|
"[Manager] Message received for currently displayed chat room, do not make a notification");
|
|
return;
|
|
}
|
|
|
|
if (message.getErrorInfo() != null
|
|
&& message.getErrorInfo().getReason() == Reason.UnsupportedContent) {
|
|
Log.w("[Manager] Message received but content is unsupported, do not notify it");
|
|
return;
|
|
}
|
|
|
|
if (!message.hasTextContent() && message.getFileTransferInformation() == null) {
|
|
Log.w(
|
|
"[Manager] Message has no text or file transfer information to display, ignoring it...");
|
|
return;
|
|
}
|
|
|
|
increaseUnreadCountForChatRoom(cr);
|
|
|
|
if (mServiceContext.getResources().getBoolean(R.bool.disable_chat_message_notification)
|
|
|| message.isOutgoing()) {
|
|
return;
|
|
}
|
|
|
|
final Address from = message.getFromAddress();
|
|
final LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(from);
|
|
final String textMessage =
|
|
(message.hasTextContent())
|
|
? message.getTextContent()
|
|
: getString(R.string.content_description_incoming_file);
|
|
|
|
String file = null;
|
|
for (Content c : message.getContents()) {
|
|
if (c.isFile()) {
|
|
file = c.getFilePath();
|
|
getMediaScanner()
|
|
.scanFile(
|
|
new File(file),
|
|
new MediaScannerListener() {
|
|
@Override
|
|
public void onMediaScanned(String path, Uri uri) {
|
|
createNotification(
|
|
cr,
|
|
contact,
|
|
from,
|
|
textMessage,
|
|
message.getTime(),
|
|
uri,
|
|
FileUtils.getMimeFromFile(path));
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (file == null) {
|
|
createNotification(cr, contact, from, textMessage, message.getTime(), null, null);
|
|
}
|
|
}
|
|
|
|
private void createNotification(
|
|
ChatRoom cr,
|
|
LinphoneContact contact,
|
|
Address from,
|
|
String textMessage,
|
|
long time,
|
|
Uri file,
|
|
String mime) {
|
|
if (cr.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
|
|
if (contact != null) {
|
|
LinphoneService.instance()
|
|
.getNotificationManager()
|
|
.displayMessageNotification(
|
|
cr.getPeerAddress().asStringUriOnly(),
|
|
contact.getFullName(),
|
|
contact.getThumbnailUri(),
|
|
textMessage,
|
|
cr.getLocalAddress(),
|
|
time,
|
|
file,
|
|
mime);
|
|
} else {
|
|
LinphoneService.instance()
|
|
.getNotificationManager()
|
|
.displayMessageNotification(
|
|
cr.getPeerAddress().asStringUriOnly(),
|
|
from.getUsername(),
|
|
null,
|
|
textMessage,
|
|
cr.getLocalAddress(),
|
|
time,
|
|
file,
|
|
mime);
|
|
}
|
|
} else {
|
|
String subject = cr.getSubject();
|
|
if (contact != null) {
|
|
LinphoneService.instance()
|
|
.getNotificationManager()
|
|
.displayGroupChatMessageNotification(
|
|
subject,
|
|
cr.getPeerAddress().asStringUriOnly(),
|
|
contact.getFullName(),
|
|
contact.getThumbnailUri(),
|
|
textMessage,
|
|
cr.getLocalAddress(),
|
|
time,
|
|
file,
|
|
mime);
|
|
} else {
|
|
LinphoneService.instance()
|
|
.getNotificationManager()
|
|
.displayGroupChatMessageNotification(
|
|
subject,
|
|
cr.getPeerAddress().asStringUriOnly(),
|
|
from.getUsername(),
|
|
null,
|
|
textMessage,
|
|
cr.getLocalAddress(),
|
|
time,
|
|
file,
|
|
mime);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setCurrentChatRoomAddress(Address address) {
|
|
mCurrentChatRoomAddress = address;
|
|
LinphoneService.instance()
|
|
.setCurrentlyDisplayedChatRoom(address != null ? address.asStringUriOnly() : null);
|
|
}
|
|
|
|
@Override
|
|
public void onEcCalibrationResult(Core lc, EcCalibratorStatus status, int delay_ms) {
|
|
((AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE))
|
|
.setMode(AudioManager.MODE_NORMAL);
|
|
mAudioManager.abandonAudioFocus(null);
|
|
Log.i("[Manager] Set audio mode on 'Normal'");
|
|
}
|
|
|
|
public void onGlobalStateChanged(final Core lc, final GlobalState state, final String message) {
|
|
Log.i("New global state [", state, "]");
|
|
if (state == GlobalState.On) {
|
|
try {
|
|
initLiblinphone(lc);
|
|
} catch (IllegalArgumentException iae) {
|
|
Log.e("[Manager] Global State Changed Illegal Argument Exception: " + iae);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void onRegistrationStateChanged(
|
|
final Core lc,
|
|
final ProxyConfig proxy,
|
|
final RegistrationState state,
|
|
final String message) {
|
|
Log.i("[Manager] New registration state [" + state + "]");
|
|
|
|
if (state == RegistrationState.Failed) {
|
|
ConnectivityManager connectivityManager =
|
|
(ConnectivityManager)
|
|
mServiceContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
|
|
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
|
Log.i("[Manager] Active network type: " + activeNetworkInfo.getTypeName());
|
|
if (activeNetworkInfo.isAvailable() && activeNetworkInfo.isConnected()) {
|
|
Log.i("[Manager] Active network is available");
|
|
}
|
|
Log.i(
|
|
"[Manager] Active network reason and extra info: "
|
|
+ activeNetworkInfo.getReason()
|
|
+ " / "
|
|
+ activeNetworkInfo.getExtraInfo());
|
|
Log.i(
|
|
"[Manager] Active network state "
|
|
+ activeNetworkInfo.getState()
|
|
+ " / "
|
|
+ activeNetworkInfo.getDetailedState());
|
|
}
|
|
}
|
|
|
|
public Context getContext() {
|
|
try {
|
|
if (LinphoneActivity.isInstanciated()) return LinphoneActivity.instance();
|
|
else if (CallActivity.isInstanciated()) return CallActivity.instance();
|
|
else if (CallIncomingActivity.isInstanciated()) return CallIncomingActivity.instance();
|
|
else if (mServiceContext != null) return mServiceContext;
|
|
else if (LinphoneService.isReady())
|
|
return LinphoneService.instance().getApplicationContext();
|
|
} catch (Exception e) {
|
|
Log.e(e);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void setAudioManagerModeNormal() {
|
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
|
}
|
|
|
|
private void setAudioManagerInCallMode() {
|
|
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
|
|
Log.w("[Manager][AudioManager] already in MODE_IN_COMMUNICATION, skipping...");
|
|
return;
|
|
}
|
|
Log.d("[Manager][AudioManager] Mode: MODE_IN_COMMUNICATION");
|
|
|
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
|
}
|
|
|
|
@SuppressLint("Wakelock")
|
|
public void onCallStateChanged(
|
|
final Core lc, final Call call, final State state, final String message) {
|
|
Log.i("[Manager] New call state [", state, "]");
|
|
if (state == State.IncomingReceived && !call.equals(lc.getCurrentCall())) {
|
|
if (call.getReplacedCall() != null) {
|
|
// attended transfer
|
|
// it will be accepted automatically.
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((state == State.IncomingReceived || state == State.IncomingEarlyMedia)
|
|
&& getCallGsmON()) {
|
|
if (mCore != null) {
|
|
mCore.declineCall(call, Reason.Busy);
|
|
}
|
|
} else if (state == State.IncomingReceived
|
|
&& (LinphonePreferences.instance().isAutoAnswerEnabled())
|
|
&& !getCallGsmON()) {
|
|
TimerTask lTask =
|
|
new TimerTask() {
|
|
@Override
|
|
public void run() {
|
|
if (mCore != null) {
|
|
if (mCore.getCallsNb() > 0) {
|
|
acceptCall(call);
|
|
if (LinphoneManager.getInstance() != null) {
|
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
|
if (LinphoneActivity.instance() != null)
|
|
LinphoneActivity.instance().startIncallActivity();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
mTimer = new Timer("Auto answer");
|
|
mTimer.schedule(lTask, mPrefs.getAutoAnswerTime());
|
|
} else if (state == State.IncomingReceived
|
|
|| (state == State.IncomingEarlyMedia
|
|
&& mRessources.getBoolean(R.bool.allow_ringing_while_early_media))) {
|
|
// Brighten screen for at least 10 seconds
|
|
if (mCore.getCallsNb() == 1) {
|
|
requestAudioFocus(STREAM_RING);
|
|
|
|
mRingingCall = call;
|
|
startRinging();
|
|
// otherwise there is the beep
|
|
}
|
|
} else if (call == mRingingCall && mIsRinging) {
|
|
// previous state was ringing, so stop ringing
|
|
stopRinging();
|
|
}
|
|
|
|
if (state == State.Connected) {
|
|
if (mCore.getCallsNb() == 1) {
|
|
// It is for incoming calls, because outgoing calls enter MODE_IN_COMMUNICATION
|
|
// immediately when they start.
|
|
// However, incoming call first use the MODE_RINGING to play the local ring.
|
|
if (call.getDir() == Call.Dir.Incoming) {
|
|
setAudioManagerInCallMode();
|
|
// mAudioManager.abandonAudioFocus(null);
|
|
requestAudioFocus(STREAM_VOICE_CALL);
|
|
}
|
|
}
|
|
|
|
if (Hacks.needSoftvolume()) {
|
|
Log.w("[Manager] Using soft volume audio hack");
|
|
adjustVolume(0); // Synchronize
|
|
}
|
|
}
|
|
|
|
if (state == State.End || state == State.Error) {
|
|
if (mCore.getCallsNb() == 0) {
|
|
// Disabling proximity sensor
|
|
enableProximitySensing(false);
|
|
Context activity = getContext();
|
|
if (mAudioFocused) {
|
|
int res = mAudioManager.abandonAudioFocus(null);
|
|
Log.d(
|
|
"[Manager] Audio focus released a bit later: "
|
|
+ (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
|
? "Granted"
|
|
: "Denied"));
|
|
mAudioFocused = false;
|
|
}
|
|
if (activity != null) {
|
|
TelephonyManager tm =
|
|
(TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
|
|
if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
|
Log.d("[Manager] ---AudioManager: back to MODE_NORMAL");
|
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
|
Log.d("[Manager] All call terminated, routing back to earpiece");
|
|
routeAudioToReceiver();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (state == State.UpdatedByRemote) {
|
|
// If the correspondent proposes video while audio call
|
|
boolean remoteVideo = call.getRemoteParams().videoEnabled();
|
|
boolean localVideo = call.getCurrentParams().videoEnabled();
|
|
boolean autoAcceptCameraPolicy =
|
|
LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests();
|
|
if (remoteVideo
|
|
&& !localVideo
|
|
&& !autoAcceptCameraPolicy
|
|
&& LinphoneManager.getLc().getConference() == null) {
|
|
LinphoneManager.getLc().deferCallUpdate(call);
|
|
}
|
|
}
|
|
if (state == State.OutgoingInit) {
|
|
// Enter the MODE_IN_COMMUNICATION mode as soon as possible, so that ringback
|
|
// is heard normally in earpiece or bluetooth receiver.
|
|
setAudioManagerInCallMode();
|
|
requestAudioFocus(STREAM_VOICE_CALL);
|
|
startBluetooth();
|
|
}
|
|
|
|
if (state == State.StreamsRunning) {
|
|
startBluetooth();
|
|
setAudioManagerInCallMode();
|
|
}
|
|
}
|
|
|
|
private void startBluetooth() {
|
|
if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
|
BluetoothManager.getInstance().routeAudioToBluetooth();
|
|
}
|
|
}
|
|
|
|
public void onCallStatsUpdated(final Core lc, final Call call, final CallStats stats) {}
|
|
|
|
@Override
|
|
public void onChatRoomStateChanged(Core lc, ChatRoom cr, ChatRoom.State state) {}
|
|
|
|
@Override
|
|
public void onQrcodeFound(Core lc, String result) {}
|
|
|
|
public void onCallEncryptionChanged(
|
|
Core lc, Call call, boolean encrypted, String authenticationToken) {}
|
|
|
|
public void startEcCalibration() {
|
|
routeAudioToSpeaker();
|
|
setAudioManagerInCallMode();
|
|
Log.i("[Manager] Set audio mode on 'Voice Communication'");
|
|
requestAudioFocus(STREAM_VOICE_CALL);
|
|
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
|
mCore.startEchoCancellerCalibration();
|
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
|
}
|
|
|
|
public int startEchoTester() {
|
|
routeAudioToSpeaker();
|
|
setAudioManagerInCallMode();
|
|
Log.i("[Manager] Set audio mode on 'Voice Communication'");
|
|
requestAudioFocus(STREAM_VOICE_CALL);
|
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
|
int sampleRate;
|
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
|
String sampleRateProperty =
|
|
mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
|
sampleRate = Integer.parseInt(sampleRateProperty);
|
|
mCore.startEchoTester(sampleRate);
|
|
mEchoTesterIsRunning = true;
|
|
return 1;
|
|
}
|
|
|
|
public int stopEchoTester() {
|
|
mEchoTesterIsRunning = false;
|
|
mCore.stopEchoTester();
|
|
routeAudioToReceiver();
|
|
((AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE))
|
|
.setMode(AudioManager.MODE_NORMAL);
|
|
Log.i("[Manager] Set audio mode on 'Normal'");
|
|
return 1; // status;
|
|
}
|
|
|
|
public boolean getEchoTesterStatus() {
|
|
return mEchoTesterIsRunning;
|
|
}
|
|
|
|
private void requestAudioFocus(int stream) {
|
|
if (!mAudioFocused) {
|
|
int res =
|
|
mAudioManager.requestAudioFocus(
|
|
null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
|
|
Log.d(
|
|
"[Manager] Audio focus requested: "
|
|
+ (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
|
? "Granted"
|
|
: "Denied"));
|
|
if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused = true;
|
|
}
|
|
}
|
|
|
|
public void enableDeviceRingtone(boolean use) {
|
|
if (use) {
|
|
mCore.setRing(null);
|
|
} else {
|
|
mCore.setRing(mRingSoundFile);
|
|
}
|
|
}
|
|
|
|
private synchronized void startRinging() {
|
|
if (!LinphonePreferences.instance().isDeviceRingtoneEnabled()) {
|
|
// Enable speaker audio route, linphone library will do the ringing itself automatically
|
|
routeAudioToSpeaker();
|
|
return;
|
|
}
|
|
|
|
if (mRessources.getBoolean(R.bool.allow_ringing_while_early_media)) {
|
|
routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media
|
|
}
|
|
|
|
// if (Hacks.needGalaxySAudioHack())
|
|
mAudioManager.setMode(MODE_RINGTONE);
|
|
|
|
try {
|
|
if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
|
|
|| mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL)
|
|
&& mVibrator != null
|
|
&& LinphonePreferences.instance().isIncomingCallVibrationEnabled()) {
|
|
long[] patern = {0, 1000, 1000};
|
|
mVibrator.vibrate(patern, 1);
|
|
}
|
|
if (mRingerPlayer == null) {
|
|
requestAudioFocus(STREAM_RING);
|
|
mRingerPlayer = new MediaPlayer();
|
|
mRingerPlayer.setAudioStreamType(STREAM_RING);
|
|
|
|
String ringtone =
|
|
LinphonePreferences.instance()
|
|
.getRingtone(Settings.System.DEFAULT_RINGTONE_URI.toString());
|
|
try {
|
|
if (ringtone.startsWith("content://")) {
|
|
mRingerPlayer.setDataSource(mServiceContext, Uri.parse(ringtone));
|
|
} else {
|
|
FileInputStream fis = new FileInputStream(ringtone);
|
|
mRingerPlayer.setDataSource(fis.getFD());
|
|
fis.close();
|
|
}
|
|
} catch (IOException e) {
|
|
Log.e(e, "[Manager] Cannot set ringtone");
|
|
}
|
|
|
|
mRingerPlayer.prepare();
|
|
mRingerPlayer.setLooping(true);
|
|
mRingerPlayer.start();
|
|
} else {
|
|
Log.w("[Manager] Already ringing");
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e(e, "[Manager] Cannot handle incoming call");
|
|
}
|
|
mIsRinging = true;
|
|
}
|
|
|
|
private synchronized void stopRinging() {
|
|
if (mRingerPlayer != null) {
|
|
mRingerPlayer.stop();
|
|
mRingerPlayer.release();
|
|
mRingerPlayer = null;
|
|
}
|
|
if (mVibrator != null) {
|
|
mVibrator.cancel();
|
|
}
|
|
|
|
if (Hacks.needGalaxySAudioHack()) mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
|
|
|
mIsRinging = false;
|
|
// You may need to call galaxys audio hack after this method
|
|
if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
|
if (mServiceContext.getResources().getBoolean(R.bool.isTablet)) {
|
|
Log.d("[Manager] Stopped ringing, routing back to speaker");
|
|
routeAudioToSpeaker();
|
|
} else {
|
|
Log.d("[Manager] Stopped ringing, routing back to earpiece");
|
|
routeAudioToReceiver();
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @return false if already in video call. */
|
|
public boolean addVideo() {
|
|
Call call = mCore.getCurrentCall();
|
|
enableCamera(call, true);
|
|
return reinviteWithVideo();
|
|
}
|
|
|
|
public boolean acceptCall(Call call) {
|
|
if (call == null) return false;
|
|
|
|
CallParams params = LinphoneManager.getLc().createCallParams(call);
|
|
|
|
boolean isLowBandwidthConnection =
|
|
!LinphoneUtils.isHighBandwidthConnection(
|
|
LinphoneService.instance().getApplicationContext());
|
|
|
|
if (params != null) {
|
|
params.enableLowBandwidth(isLowBandwidthConnection);
|
|
params.setRecordFile(
|
|
FileUtils.getCallRecordingFilename(getContext(), call.getRemoteAddress()));
|
|
} else {
|
|
Log.e("[Manager] Could not create call params for call");
|
|
return false;
|
|
}
|
|
|
|
mCore.acceptCallWithParams(call, params);
|
|
return true;
|
|
}
|
|
|
|
public void adjustVolume(int i) {
|
|
// starting from ICS, volume must be adjusted by the application, at least for
|
|
// STREAM_VOICE_CALL volume stream
|
|
mAudioManager.adjustStreamVolume(
|
|
LINPHONE_VOLUME_STREAM,
|
|
i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE,
|
|
AudioManager.FLAG_SHOW_UI);
|
|
}
|
|
|
|
public void isAccountWithAlias() {
|
|
if (LinphoneManager.getLc().getDefaultProxyConfig() != null) {
|
|
long now = new Timestamp(new Date().getTime()).getTime();
|
|
if (mAccountCreator != null && LinphonePreferences.instance().getLinkPopupTime() == null
|
|
|| Long.parseLong(LinphonePreferences.instance().getLinkPopupTime()) < now) {
|
|
mAccountCreator.setUsername(
|
|
LinphonePreferences.instance()
|
|
.getAccountUsername(
|
|
LinphonePreferences.instance().getDefaultAccountIndex()));
|
|
mAccountCreator.isAccountExist();
|
|
}
|
|
} else {
|
|
LinphonePreferences.instance().setLinkPopupTime(null);
|
|
}
|
|
}
|
|
|
|
private void askLinkWithPhoneNumber() {
|
|
if (!LinphonePreferences.instance().isLinkPopupEnabled()) return;
|
|
|
|
long now = new Timestamp(new Date().getTime()).getTime();
|
|
if (LinphonePreferences.instance().getLinkPopupTime() != null
|
|
&& Long.parseLong(LinphonePreferences.instance().getLinkPopupTime()) >= now) return;
|
|
|
|
long future =
|
|
new Timestamp(
|
|
LinphoneActivity.instance()
|
|
.getResources()
|
|
.getInteger(R.integer.popup_time_interval))
|
|
.getTime();
|
|
long newDate = now + future;
|
|
|
|
LinphonePreferences.instance().setLinkPopupTime(String.valueOf(newDate));
|
|
|
|
final Dialog dialog =
|
|
LinphoneActivity.instance()
|
|
.displayDialog(
|
|
String.format(
|
|
getString(R.string.link_account_popup),
|
|
LinphoneManager.getLc()
|
|
.getDefaultProxyConfig()
|
|
.getIdentityAddress()
|
|
.asStringUriOnly()));
|
|
Button delete = dialog.findViewById(R.id.dialog_delete_button);
|
|
delete.setVisibility(View.GONE);
|
|
Button ok = dialog.findViewById(R.id.dialog_ok_button);
|
|
ok.setText(getString(R.string.link));
|
|
ok.setVisibility(View.VISIBLE);
|
|
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
|
|
cancel.setText(getString(R.string.maybe_later));
|
|
|
|
dialog.findViewById(R.id.dialog_do_not_ask_again_layout).setVisibility(View.VISIBLE);
|
|
final CheckBox doNotAskAgain = dialog.findViewById(R.id.doNotAskAgain);
|
|
dialog.findViewById(R.id.doNotAskAgainLabel)
|
|
.setOnClickListener(
|
|
new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
doNotAskAgain.setChecked(!doNotAskAgain.isChecked());
|
|
}
|
|
});
|
|
|
|
ok.setOnClickListener(
|
|
new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View view) {
|
|
Intent assistant = new Intent();
|
|
assistant.setClass(LinphoneActivity.instance(), AssistantActivity.class);
|
|
assistant.putExtra("LinkPhoneNumber", true);
|
|
assistant.putExtra("LinkPhoneNumberAsk", true);
|
|
mServiceContext.startActivity(assistant);
|
|
dialog.dismiss();
|
|
}
|
|
});
|
|
|
|
cancel.setOnClickListener(
|
|
new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View view) {
|
|
if (doNotAskAgain.isChecked()) {
|
|
LinphonePreferences.instance().enableLinkPopup(false);
|
|
}
|
|
dialog.dismiss();
|
|
}
|
|
});
|
|
dialog.show();
|
|
}
|
|
|
|
public String getDefaultDynamicConfigFile() {
|
|
return mDefaultDynamicConfigFile;
|
|
}
|
|
|
|
public String getLinphoneDynamicConfigFile() {
|
|
return mLinphoneDynamicConfigFile;
|
|
}
|
|
|
|
public boolean getCallGsmON() {
|
|
return mCallGsmON;
|
|
}
|
|
|
|
public void setCallGsmON(boolean on) {
|
|
mCallGsmON = on;
|
|
}
|
|
|
|
@Override
|
|
public void onTransferStateChanged(Core lc, Call call, State new_call_state) {}
|
|
|
|
@Override
|
|
public void onInfoReceived(Core lc, Call call, InfoMessage info) {
|
|
Log.d("[Manager] Info message received from " + call.getRemoteAddress().asString());
|
|
Content ct = info.getContent();
|
|
if (ct != null) {
|
|
Log.d(
|
|
"[Manager] Info received with body with mime type "
|
|
+ ct.getType()
|
|
+ "/"
|
|
+ ct.getSubtype()
|
|
+ " and data ["
|
|
+ ct.getStringBuffer()
|
|
+ "]");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSubscriptionStateChanged(Core lc, Event ev, SubscriptionState state) {
|
|
Log.d(
|
|
"[Manager] Subscription state changed to "
|
|
+ state
|
|
+ " event name is "
|
|
+ ev.getName());
|
|
}
|
|
|
|
@Override
|
|
public void onCallLogUpdated(Core lc, CallLog newcl) {}
|
|
|
|
@Override
|
|
public void onNotifyReceived(Core lc, Event ev, String eventName, Content content) {
|
|
Log.d("[Manager] Notify received for event " + eventName);
|
|
if (content != null)
|
|
Log.d(
|
|
"[Manager] With content "
|
|
+ content.getType()
|
|
+ "/"
|
|
+ content.getSubtype()
|
|
+ " data:"
|
|
+ content.getStringBuffer());
|
|
}
|
|
|
|
@Override
|
|
public void onSubscribeReceived(Core lc, Event lev, String subscribeEvent, Content body) {}
|
|
|
|
@Override
|
|
public void onPublishStateChanged(Core lc, Event ev, PublishState state) {
|
|
Log.d("[Manager] Publish state changed to " + state + " for event name " + ev.getName());
|
|
}
|
|
|
|
@Override
|
|
public void onIsComposingReceived(Core lc, ChatRoom cr) {
|
|
Log.d("[Manager] Composing received for chatroom " + cr.getPeerAddress().asStringUriOnly());
|
|
}
|
|
|
|
@Override
|
|
public void onMessageReceivedUnableDecrypt(Core lc, ChatRoom room, ChatMessage message) {}
|
|
|
|
@Override
|
|
public void onConfiguringStatus(Core lc, ConfiguringState state, String message) {
|
|
Log.d("[Manager] Remote provisioning status = " + state.toString() + " (" + message + ")");
|
|
|
|
LinphonePreferences prefs = LinphonePreferences.instance();
|
|
if (state == ConfiguringState.Successful) {
|
|
if (prefs.isProvisioningLoginViewEnabled()) {
|
|
ProxyConfig proxyConfig = lc.createProxyConfig();
|
|
Address addr = proxyConfig.getIdentityAddress();
|
|
wizardLoginViewDomain = addr.getDomain();
|
|
}
|
|
prefs.setPushNotificationEnabled(prefs.isPushNotificationEnabled());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onCallCreated(Core lc, Call call) {}
|
|
|
|
@Override
|
|
public void onLogCollectionUploadProgressIndication(Core linphoneCore, int offset, int total) {
|
|
if (total > 0)
|
|
Log.d(
|
|
"[Manager] Log upload progress: currently uploaded = "
|
|
+ offset
|
|
+ " , total = "
|
|
+ total
|
|
+ ", % = "
|
|
+ String.valueOf((offset * 100) / total));
|
|
}
|
|
|
|
@Override
|
|
public void onVersionUpdateCheckResultReceived(
|
|
Core lc, VersionUpdateCheckResult result, String version, String url) {
|
|
if (result == VersionUpdateCheckResult.NewVersionAvailable) {
|
|
final String urlToUse = url;
|
|
final String versionAv = version;
|
|
mHandler.postDelayed(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
|
builder.setMessage(
|
|
getString(R.string.update_available) + ": " + versionAv);
|
|
builder.setCancelable(false);
|
|
builder.setNeutralButton(
|
|
getString(R.string.ok),
|
|
new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(
|
|
DialogInterface dialogInterface, int i) {
|
|
if (urlToUse != null) {
|
|
Intent urlIntent = new Intent(Intent.ACTION_VIEW);
|
|
urlIntent.setData(Uri.parse(urlToUse));
|
|
getContext().startActivity(urlIntent);
|
|
}
|
|
}
|
|
});
|
|
builder.show();
|
|
}
|
|
},
|
|
1000);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEcCalibrationAudioUninit(Core lc) {}
|
|
|
|
private void sendLogs(String info) {
|
|
Context context = LinphoneActivity.instance();
|
|
final String appName = context.getString(R.string.app_name);
|
|
|
|
Intent i = new Intent(Intent.ACTION_SEND);
|
|
i.putExtra(
|
|
Intent.EXTRA_EMAIL,
|
|
new String[] {context.getString(R.string.about_bugreport_email)});
|
|
i.putExtra(Intent.EXTRA_SUBJECT, appName + " Logs");
|
|
i.putExtra(Intent.EXTRA_TEXT, info);
|
|
i.setType("application/zip");
|
|
|
|
try {
|
|
context.startActivity(Intent.createChooser(i, "Send mail..."));
|
|
} catch (android.content.ActivityNotFoundException ex) {
|
|
Log.e(ex);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onLogCollectionUploadStateChanged(
|
|
Core linphoneCore, LogCollectionUploadState state, String info) {
|
|
Log.d("[Manager] Log upload state: " + state.toString() + ", info = " + info);
|
|
if (state == LogCollectionUploadState.Delivered) {
|
|
ClipboardManager clipboard =
|
|
(ClipboardManager) mServiceContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
ClipData clip = ClipData.newPlainText("Logs url", info);
|
|
clipboard.setPrimaryClip(clip);
|
|
Toast.makeText(
|
|
LinphoneActivity.instance(),
|
|
getString(R.string.logs_url_copied_to_clipboard),
|
|
Toast.LENGTH_SHORT)
|
|
.show();
|
|
sendLogs(info);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onFriendListCreated(Core lc, FriendList list) {
|
|
if (LinphoneService.isReady()) {
|
|
list.addListener(ContactsManager.getInstance());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onFriendListRemoved(Core lc, FriendList list) {
|
|
list.removeListener(ContactsManager.getInstance());
|
|
}
|
|
|
|
@Override
|
|
public void onReferReceived(Core lc, String refer_to) {}
|
|
|
|
@Override
|
|
public void onNetworkReachable(Core lc, boolean enable) {}
|
|
|
|
@Override
|
|
public void onAuthenticationRequested(Core lc, AuthInfo authInfo, AuthMethod method) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onNotifyPresenceReceivedForUriOrTel(
|
|
Core lc, Friend lf, String uri_or_tel, PresenceModel presence_model) {}
|
|
|
|
@Override
|
|
public void onBuddyInfoUpdated(Core lc, Friend lf) {}
|
|
|
|
@Override
|
|
public void onIsAccountExist(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {
|
|
if (status.equals(AccountCreator.Status.AccountExist)) {
|
|
accountCreator.isAccountLinked();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onCreateAccount(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onActivateAccount(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onLinkAccount(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {
|
|
if (status.equals(AccountCreator.Status.AccountNotLinked)) {
|
|
askLinkWithPhoneNumber();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onActivateAlias(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onIsAccountActivated(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onRecoverAccount(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onIsAccountLinked(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {
|
|
if (status.equals(AccountCreator.Status.AccountNotLinked)) {
|
|
askLinkWithPhoneNumber();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onIsAliasUsed(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
@Override
|
|
public void onUpdateAccount(
|
|
AccountCreator accountCreator, AccountCreator.Status status, String resp) {}
|
|
|
|
private void updateMissedChatCount() {
|
|
for (ChatRoom cr : LinphoneManager.getLc().getChatRooms()) {
|
|
updateUnreadCountForChatRoom(cr, cr.getUnreadMessagesCount());
|
|
}
|
|
}
|
|
|
|
public int getUnreadMessageCount() {
|
|
int count = 0;
|
|
for (ChatRoom room : mCore.getChatRooms()) {
|
|
count += room.getUnreadMessagesCount();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
public void updateUnreadCountForChatRoom(
|
|
String localSipUri, String remoteSipUri, Integer value) {
|
|
String key = localSipUri + "//" + remoteSipUri;
|
|
mUnreadChatsPerRoom.put(key, value);
|
|
}
|
|
|
|
public void updateUnreadCountForChatRoom(ChatRoom cr, Integer value) {
|
|
String localSipUri = cr.getLocalAddress().asStringUriOnly();
|
|
String remoteSipUri = cr.getPeerAddress().asStringUriOnly();
|
|
updateUnreadCountForChatRoom(localSipUri, remoteSipUri, value);
|
|
}
|
|
|
|
private void increaseUnreadCountForChatRoom(ChatRoom cr) {
|
|
String localSipUri = cr.getLocalAddress().asStringUriOnly();
|
|
String remoteSipUri = cr.getPeerAddress().asStringUriOnly();
|
|
String key = localSipUri + "//" + remoteSipUri;
|
|
if (mUnreadChatsPerRoom.containsKey(key)) {
|
|
mUnreadChatsPerRoom.put(key, mUnreadChatsPerRoom.get(key) + 1);
|
|
} else {
|
|
mUnreadChatsPerRoom.put(key, 1);
|
|
}
|
|
}
|
|
|
|
public interface AddressType {
|
|
CharSequence getText();
|
|
|
|
void setText(CharSequence s);
|
|
|
|
String getDisplayedName();
|
|
|
|
void setDisplayedName(String s);
|
|
}
|
|
}
|