package org.linphone; /* LinphoneContext.java Copyright (C) 2019 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 android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Handler; import android.provider.ContactsContract; import org.linphone.call.CallActivity; import org.linphone.call.CallIncomingActivity; import org.linphone.call.CallOutgoingActivity; import org.linphone.compatibility.Compatibility; import org.linphone.contacts.ContactsManager; import org.linphone.core.Call; import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; import org.linphone.core.Factory; import org.linphone.core.LogLevel; import org.linphone.core.LoggingService; import org.linphone.core.LoggingServiceListener; import org.linphone.core.tools.Log; import org.linphone.mediastream.Version; import org.linphone.notifications.NotificationsManager; import org.linphone.settings.LinphonePreferences; import org.linphone.utils.LinphoneUtils; public class LinphoneContext { private static LinphoneContext sInstance = null; private Context mContext; public final Handler handler = new Handler(); private final LoggingServiceListener mJavaLoggingService = new LoggingServiceListener() { @Override public void onLogMessageWritten( LoggingService logService, String domain, LogLevel lev, String message) { switch (lev) { case Debug: android.util.Log.d(domain, message); break; case Message: android.util.Log.i(domain, message); break; case Warning: android.util.Log.w(domain, message); break; case Error: android.util.Log.e(domain, message); break; case Fatal: default: android.util.Log.wtf(domain, message); break; } } }; private CoreListenerStub mListener; private NotificationsManager mNotificationManager; private LinphoneManager mLinphoneManager; private ContactsManager mContactsManager; private Class mIncomingReceivedActivity = CallIncomingActivity.class; public static boolean isReady() { return sInstance != null; } public static LinphoneContext instance() { return sInstance; } public LinphoneContext(Context context) { mContext = context; LinphonePreferences.instance().setContext(context); Factory.instance().setLogCollectionPath(context.getFilesDir().getAbsolutePath()); boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); LinphoneUtils.configureLoggingService(isDebugEnabled, context.getString(R.string.app_name)); // Dump some debugging information to the logs dumpDeviceInformation(); dumpLinphoneInformation(); String incomingReceivedActivityName = LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived(); try { mIncomingReceivedActivity = (Class) Class.forName(incomingReceivedActivityName); } catch (ClassNotFoundException e) { Log.e(e); } sInstance = this; Log.i("[Context] Ready"); mListener = new CoreListenerStub() { @Override public void onCallStateChanged( Core core, Call call, Call.State state, String message) { if (mContext.getResources().getBoolean(R.bool.enable_call_notification)) { mNotificationManager.displayCallNotification(call); } if (state == Call.State.IncomingReceived || state == Call.State.IncomingEarlyMedia) { // Starting SDK 24 (Android 7.0) we rely on the fullscreen intent of the // call incoming notification if (Version.sdkStrictlyBelow(Version.API24_NOUGAT_70)) { if (!mLinphoneManager.getCallGsmON()) onIncomingReceived(); } } else if (state == Call.State.OutgoingInit) { onOutgoingStarted(); } else if (state == Call.State.Connected) { onCallStarted(); } else if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) { if (LinphoneService.isReady()) { LinphoneService.instance().destroyOverlay(); } if (state == Call.State.Released && call.getCallLog().getStatus() == Call.Status.Missed) { mNotificationManager.displayMissedCallNotification(call); } } } }; mLinphoneManager = new LinphoneManager(context); mNotificationManager = new NotificationsManager(context); } public void start(boolean isPush) { Log.i("[Context] Starting"); mLinphoneManager.startLibLinphone(isPush); LinphoneManager.getCore().addListener(mListener); mNotificationManager.onCoreReady(); mContactsManager = new ContactsManager(mContext, handler); if (!Version.sdkAboveOrEqual(Version.API26_O_80) || (mContactsManager.hasReadContactsAccess())) { mContext.getContentResolver() .registerContentObserver( ContactsContract.Contacts.CONTENT_URI, true, mContactsManager); } if (mContactsManager.hasReadContactsAccess()) { mContactsManager.enableContactsAccess(); } mContactsManager.initializeContactManager(); } public void destroy() { Log.i("[Context] Destroying"); Core core = LinphoneManager.getCore(); if (core != null) { core.removeListener(mListener); core = null; // To allow the gc calls below to free the Core } // Make sure our notification is gone. if (mNotificationManager != null) { mNotificationManager.destroy(); } if (mContactsManager != null) { mContactsManager.destroy(); } // Destroy the LinphoneManager second to last to ensure any getCore() call will work if (mLinphoneManager != null) { mLinphoneManager.destroy(); } // Wait for every other object to be destroyed to make LinphoneService.instance() invalid sInstance = null; if (LinphonePreferences.instance().useJavaLogger()) { Factory.instance().getLoggingService().removeListener(mJavaLoggingService); } LinphonePreferences.instance().destroy(); } public void updateContext(Context context) { mContext = context; } public Context getApplicationContext() { return mContext; } /* Managers accessors */ public LoggingServiceListener getJavaLoggingService() { return mJavaLoggingService; } public NotificationsManager getNotificationManager() { return mNotificationManager; } public LinphoneManager getLinphoneManager() { return mLinphoneManager; } public ContactsManager getContactsManager() { return mContactsManager; } /* Log device related information */ private void dumpDeviceInformation() { Log.i("==== Phone information dump ===="); Log.i("DISPLAY NAME=" + Compatibility.getDeviceName(mContext)); Log.i("DEVICE=" + Build.DEVICE); Log.i("MODEL=" + Build.MODEL); Log.i("MANUFACTURER=" + Build.MANUFACTURER); Log.i("ANDROID SDK=" + Build.VERSION.SDK_INT); StringBuilder sb = new StringBuilder(); sb.append("ABIs="); for (String abi : Version.getCpuAbis()) { sb.append(abi).append(", "); } Log.i(sb.substring(0, sb.length() - 2)); } private void dumpLinphoneInformation() { Log.i("==== Linphone information dump ===="); Log.i("VERSION NAME=" + BuildConfig.VERSION_NAME); Log.i("VERSION CODE=" + BuildConfig.VERSION_CODE); Log.i("PACKAGE=" + BuildConfig.APPLICATION_ID); Log.i("BUILD TYPE=" + BuildConfig.BUILD_TYPE); Log.i("SDK VERSION=" + mContext.getString(R.string.linphone_sdk_version)); Log.i("SDK BRANCH=" + mContext.getString(R.string.linphone_sdk_branch)); } /* Call activities */ private void onIncomingReceived() { Intent intent = new Intent().setClass(mContext, mIncomingReceivedActivity); // This flag is required to start an Activity from a Service context intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } private void onOutgoingStarted() { Intent intent = new Intent(mContext, CallOutgoingActivity.class); // This flag is required to start an Activity from a Service context intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } private void onCallStarted() { Intent intent = new Intent(mContext, CallActivity.class); // This flag is required to start an Activity from a Service context intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } }