Started to split LinphoneActivity in multiple activities

Added new activities that will replace LinphoneActivity

Added About & Dialer activities

Fixed back key press

Transformed Recordings fragment into activity

Started Settings activity

Small improvement for Recordings

Finished dialer

Permission shenanigans

Added back History

Small history improvements

Fixed issue with rotation in History

Started contacts

More changes & fixes for Chat

Improved performances when switching between activities

Prevent keyboard from opening automatically on some views

Added back workaround for infinite loop if screen off

Fixes & improvements

Some cleanup but a lot of work still left

Switching back to classic fragment fixed issues

Lots of fixes & improvements over History & Contacts

More work on chat

Small refactoring of license header

Settings & Chat fixes/improvements

More TODO FIXES removal

Tablet fixes

Fixes & improvements

Fixed back button on tablets

Got rid of LinphoneActivity

Fixed TODO FIXME related to permissions

Started chat room group info

Lot of fixes & improvements over Chat

Fixed sharing feature if LinphoneService isn't running

Lifecycle improvements

Sharing from outside app finished

Fixed quit button

Fixed display of missed chat/calls

Clean old code for chat rooms unread message count

Improved unread message count on tablets

This isn't useful anymore

Fixed last issue with unread count not updating in chat rooms list using new callbacks

Fixed latest TODO FIXME due to CallAcitvity singleton removal

Updated remaining TODOs

Fixed issue with outgoing call not going to call activity once answered

Fixed back key press go home feature

Removed dead code

Code cleanup thanks to Android Studio inspector

Added back device power saver dialog + update registration state changed in menu

More auto rework by Android Studio + added back checkForUpdate & isAccountWithAlias method calls

More improvements, most of them on layout files

Fixed secured group chat rooms creation

Improved launch screen by using logo on gray background instead of default white screen

Added workaround for faster display of splashscreen

Removed noHistory flag on Settings, will be weird when going back from Android native settings

Fixed display of call logs list in history details in landscape on smartphone depending on screen size

Reorganized activities + fixed dark theme switch

Manager & Service cleanup

Simplified notification process

More manager simplifications

Moved audio manager related code from LinphoneManager to dedicated class

Core accessor cleanup

Exclude XmlRpc & InApp related code from standard APK + moved call related methods from LinphoneManager to CallManager

Fixed click on chat bottom bar button doing nothing after going into chatroom through notification or shortcut

Fixed chat message fragment update if presence is received while view has already been displayed

Improved second to last commit

Fixed navigation issue in chat

More code improvements
This commit is contained in:
Sylvain Berfini 2019-04-24 11:18:47 +02:00
parent df27d9bed5
commit 4b846bcca8
216 changed files with 7888 additions and 10814 deletions

View file

@ -30,6 +30,9 @@ if (!firebaseEnabled()) {
excludeFiles.add('**/Firebase*')
println '[Push Notification] Firebase disabled'
}
// Remove or comment if you want to use those
excludeFiles.add('**/XmlRpc*')
excludeFiles.add('**/InAppPurchase*')
def excludePackage = []

View file

@ -62,13 +62,9 @@
android:roundIcon="@mipmap/ic_launcher_round">
<activity
android:name=".LinphoneLauncherActivity"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:name=".activities.SplashScreenActivity"
android:noHistory="true"
android:theme="@style/LinphoneStyleLight"
android:windowSoftInputMode="adjustPan|stateHidden">
android:theme="@style/LinphoneLauncherStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -77,12 +73,21 @@
</activity>
<activity
android:name=".LinphoneActivity"
android:launchMode="singleTask"
android:name=".activities.LinphoneLauncherActivity"
android:noHistory="true"
android:theme="@style/LinphoneLauncherStyle">
</activity>
<service
android:name=".LinphoneService"
android:label="@string/service_name" />
<!-- Main activities -->
<activity
android:name=".activities.DialerActivity"
android:launchMode="singleTop"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<action android:name="android.intent.action.CALL_PRIVILEGED" />
@ -101,11 +106,32 @@
<data android:scheme="imto" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<action android:name="org.linphone.intent.action.CallLaunched" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="${linphone_address_mime_type}" />
</intent-filter>
</activity>
<activity
android:name=".activities.AboutActivity"
android:noHistory="true"
android:theme="@style/LinphoneStyleLight">
</activity>
<activity
android:name=".recording.RecordingsActivity"
android:noHistory="true"
android:theme="@style/LinphoneStyleLight">
</activity>
<activity
android:name=".settings.SettingsActivity"
android:theme="@style/LinphoneStyleLight">
</activity>
<activity
android:name=".chat.ChatActivity"
android:launchMode="singleTop"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.SEND" />
@ -126,12 +152,28 @@
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<activity
android:name=".contacts.ContactsActivity"
android:launchMode="singleTop"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="org.linphone.intent.action.CallLaunched" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="${linphone_address_mime_type}" />
</intent-filter>
</activity>
<activity
android:name=".history.HistoryActivity"
android:launchMode="singleTop"
android:theme="@style/LinphoneStyleLight">
</activity>
<!-- Call activities -->
<activity
android:name=".call.CallIncomingActivity"
android:launchMode="singleTop"
@ -139,127 +181,82 @@
android:showWhenLocked="true"
android:turnScreenOn="true"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".call.CallOutgoingActivity"
android:launchMode="singleTop"
android:noHistory="true"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".call.CallActivity"
android:launchMode="singleTop"
android:noHistory="true"
android:showWhenLocked="true"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<!-- Assistant activities -->
<activity
android:name=".assistant.MenuAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.AccountConnectionAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.EmailAccountCreationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.EmailAccountValidationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.PhoneAccountCreationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.PhoneAccountValidationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.PhoneAccountLinkingAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.GenericConnectionAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.QrCodeConfigurationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.RemoteConfigurationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.EchoCancellerCalibrationAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".assistant.OpenH264DownloadAssistantActivity"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<!-- Other stuff -->
<activity
android:name=".purchase.InAppPurchaseActivity"
android:screenOrientation="nosensor"
android:theme="@style/LinphoneStyleLight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service
android:name=".LinphoneService"
android:label="@string/service_name" />
<service
android:name=".sync.SyncService"
android:exported="true">
@ -274,6 +271,7 @@
android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
<service android:name=".sync.AuthenticationService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
@ -287,6 +285,7 @@
<receiver
android:name=".receivers.BluetoothManager"
android:enabled="false"/>
<receiver android:name=".receivers.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
@ -295,6 +294,7 @@
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.PhoneStateChangedReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PHONE_STATE" />
@ -331,8 +331,6 @@
android:resource="@xml/provider_paths" />
</provider>
<activity android:name=".utils.LinphoneGenericActivity" />
<receiver
android:name=".notifications.NotificationBroadcastReceiver"
android:enabled="true"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -26,13 +26,12 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.provider.ContactsContract;
import android.view.WindowManager;
import java.util.ArrayList;
import org.linphone.call.CallIncomingActivity;
import org.linphone.call.CallOutgoingActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.core.Call;
import org.linphone.core.Call.State;
@ -50,6 +49,7 @@ import org.linphone.mediastream.Version;
import org.linphone.notifications.NotificationsManager;
import org.linphone.receivers.BluetoothManager;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.ActivityMonitor;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.LinphoneGL2JNIViewOverlay;
import org.linphone.views.LinphoneOverlay;
@ -67,25 +67,15 @@ import org.linphone.views.LinphoneTextureViewOverlay;
* <li>Delegating GUI state change actions to GUI listener
*/
public final class LinphoneService extends Service {
/* Listener needs to be implemented in the Service as it calls
* setLatestEventInfo and startActivity() which needs a context.
*/
private static final String START_LINPHONE_LOGS = " ==== Phone information dump ====";
private static LinphoneService sInstance;
public final Handler handler = new Handler();
private boolean mTestDelayElapsed = true;
private CoreListenerStub mListener;
private WindowManager mWindowManager;
private LinphoneOverlay mOverlay;
private WindowManager mWindowManager;
private Application.ActivityLifecycleCallbacks mActivityCallbacks;
private NotificationsManager mNotificationManager;
private String mIncomingReceivedActivityName;
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
private LoggingServiceListener mJavaLoggingService =
private final LoggingServiceListener mJavaLoggingService =
new LoggingServiceListener() {
@Override
public void onLogMessageWritten(
@ -110,57 +100,88 @@ public final class LinphoneService extends Service {
}
}
};
private CoreListenerStub mListener;
private NotificationsManager mNotificationManager;
private LinphoneManager mLinphoneManager;
private ContactsManager mContactsManager;
private BluetoothManager mBluetoothManager;
public LoggingServiceListener getJavaLoggingService() {
return mJavaLoggingService;
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
@SuppressWarnings("unchecked")
@Override
public void onCreate() {
super.onCreate();
setupActivityMonitor();
// Needed in order for the two next calls to succeed, libraries must have been loaded first
LinphonePreferences.instance().setContext(this);
Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath());
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneUtils.configureLoggingService(isDebugEnabled, getString(R.string.app_name));
// LinphoneService isn't ready yet so we have to manually set up the Java logging service
if (LinphonePreferences.instance().useJavaLogger()) {
Factory.instance().getLoggingService().addListener(mJavaLoggingService);
}
public static boolean isReady() {
return sInstance != null && sInstance.mTestDelayElapsed;
// Dump some debugging information to the logs
Log.i(START_LINPHONE_LOGS);
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
String incomingReceivedActivityName =
LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived();
try {
mIncomingReceivedActivity =
(Class<? extends Activity>) Class.forName(incomingReceivedActivityName);
} catch (ClassNotFoundException e) {
Log.e(e);
}
public static LinphoneService instance() {
if (isReady()) return sInstance;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
throw new RuntimeException("LinphoneService not instantiated yet");
mListener =
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core core, Call call, Call.State state, String message) {
if (sInstance == null) {
Log.i(
"[Service] Service not ready, discarding call state change to ",
state.toString());
return;
}
public NotificationsManager getNotificationManager() {
return mNotificationManager;
if (getResources().getBoolean(R.bool.enable_call_notification)) {
mNotificationManager.displayCallNotification(call);
}
public void removeForegroundServiceNotificationIfPossible() {
mNotificationManager.removeForegroundServiceNotificationIfPossible();
}
if (state == Call.State.IncomingReceived
|| state == State.IncomingEarlyMedia) {
if (!mLinphoneManager.getCallGsmON()) onIncomingReceived();
} else if (state == State.OutgoingInit) {
onOutgoingStarted();
} else if (state == State.End
|| state == State.Released
|| state == State.Error) {
destroyOverlay();
public Class<? extends Activity> getIncomingReceivedActivity() {
return mIncomingReceivedActivity;
if (state == State.Released
&& call.getCallLog().getStatus() == Call.Status.Missed) {
mNotificationManager.displayMissedCallNotification(call);
}
public void setCurrentlyDisplayedChatRoom(String address) {
if (address != null) {
mNotificationManager.resetMessageNotifCount(address);
}
}
private void onBackgroundMode() {
Log.i("[Service] App has entered background mode");
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterBackground();
}
}
@Override
public void onGlobalStateChanged(
Core core, GlobalState state, String message) {}
private void onForegroundMode() {
Log.i("[Service] App has left background mode");
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterForeground();
}
}
private void setupActivityMonitor() {
if (mActivityCallbacks != null) return;
getApplication()
.registerActivityLifecycleCallbacks(mActivityCallbacks = new ActivityMonitor());
@Override
public void onRegistrationStateChanged(
Core core, ProxyConfig cfg, RegistrationState state, String smessage) {}
};
}
@Override
@ -178,64 +199,12 @@ public final class LinphoneService extends Service {
return START_STICKY;
}
LinphoneManager.createAndStart(this, isPush);
mLinphoneManager = new LinphoneManager(this);
sInstance = this; // sInstance is ready once linphone manager has been created
mLinphoneManager.startLibLinphone(isPush);
LinphoneManager.getCore().addListener(mListener);
mNotificationManager = new NotificationsManager(this);
LinphoneManager.getLc()
.addListener(
mListener =
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core lc, Call call, Call.State state, String message) {
if (sInstance == null) {
Log.i(
"[Service] Service not ready, discarding call state change to ",
state.toString());
return;
}
if (getResources()
.getBoolean(R.bool.enable_call_notification)) {
mNotificationManager.displayCallNotification(call);
}
if (state == Call.State.IncomingReceived
|| state == State.IncomingEarlyMedia) {
if (!LinphoneManager.getInstance().getCallGsmON())
onIncomingReceived();
}
if (state == State.End
|| state == State.Released
|| state == State.Error) {
destroyOverlay();
}
if (state == State.Released
&& call.getCallLog().getStatus()
== Call.Status.Missed) {
mNotificationManager.displayMissedCallNotification(
call);
}
}
@Override
public void onGlobalStateChanged(
Core lc, GlobalState state, String message) {
// TODO global state if ON
}
@Override
public void onRegistrationStateChanged(
Core lc,
ProxyConfig cfg,
RegistrationState state,
String smessage) {
// TODO registration status
}
});
if (Version.sdkAboveOrEqual(Version.API26_O_80)
&& intent != null
@ -243,71 +212,114 @@ public final class LinphoneService extends Service {
mNotificationManager.startForeground();
}
mContactsManager = new ContactsManager(this, handler);
if (!Version.sdkAboveOrEqual(Version.API26_O_80)
|| (ContactsManager.getInstance() != null
&& ContactsManager.getInstance().hasReadContactsAccess())) {
|| (mContactsManager.hasReadContactsAccess())) {
getContentResolver()
.registerContentObserver(
ContactsContract.Contacts.CONTENT_URI,
true,
ContactsManager.getInstance());
ContactsContract.Contacts.CONTENT_URI, true, mContactsManager);
}
if (!mTestDelayElapsed) {
// Only used when testing. Simulates a 5 seconds delay for launching service
handler.postDelayed(
new Runnable() {
@Override
public void run() {
mTestDelayElapsed = true;
}
},
5000);
}
BluetoothManager.getInstance().initBluetooth();
mBluetoothManager = new BluetoothManager();
return START_STICKY;
}
@SuppressWarnings("unchecked")
@Override
public void onCreate() {
super.onCreate();
public void onTaskRemoved(Intent rootIntent) {
boolean serviceNotif = LinphonePreferences.instance().getServiceNotificationVisibility();
if (serviceNotif) {
Log.i("[Service] Service is running in foreground, don't stop it");
} else if (getResources().getBoolean(R.bool.kill_service_with_task_manager)) {
Log.i("[Service] Task removed, stop service");
Core core = LinphoneManager.getCore();
if (core != null) {
core.terminateAllCalls();
}
setupActivityMonitor();
// If push is enabled, don't unregister account, otherwise do unregister
if (LinphonePreferences.instance().isPushNotificationEnabled()) {
if (core != null) core.setNetworkReachable(false);
}
stopSelf();
}
super.onTaskRemoved(rootIntent);
}
@SuppressWarnings("UnusedAssignment")
@Override
public synchronized void onDestroy() {
if (mActivityCallbacks != null) {
getApplication().unregisterActivityLifecycleCallbacks(mActivityCallbacks);
mActivityCallbacks = null;
}
destroyOverlay();
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
core = null; // To allow the gc calls below to free the Core
}
mLinphoneManager.destroy();
sInstance = null;
// Make sure our notification is gone.
if (mNotificationManager != null) {
mNotificationManager.destroy();
}
mContactsManager.destroy();
mBluetoothManager.destroy();
// Needed in order for the two next calls to succeed, libraries must have been loaded first
LinphonePreferences.instance().setContext(getBaseContext());
Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath());
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneUtils.configureLoggingService(isDebugEnabled, getString(R.string.app_name));
// LinphoneService isn't ready yet so we have to manually set up the Java logging service
if (LinphonePreferences.instance().useJavaLogger()) {
Factory.instance().getLoggingService().addListener(mJavaLoggingService);
Factory.instance().getLoggingService().removeListener(mJavaLoggingService);
}
LinphonePreferences.instance().destroy();
super.onDestroy();
}
// Dump some debugging information to the logs
Log.i(START_LINPHONE_LOGS);
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
mIncomingReceivedActivityName =
LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived();
try {
mIncomingReceivedActivity =
(Class<? extends Activity>) Class.forName(mIncomingReceivedActivityName);
} catch (ClassNotFoundException e) {
Log.e(e);
@Override
public IBinder onBind(Intent intent) {
return null;
}
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
public static boolean isReady() {
return sInstance != null;
}
public static LinphoneService instance() {
if (isReady()) return sInstance;
throw new RuntimeException("LinphoneService not instantiated yet");
}
/* Managers accessors */
public LoggingServiceListener getJavaLoggingService() {
return mJavaLoggingService;
}
public NotificationsManager getNotificationManager() {
return mNotificationManager;
}
public LinphoneManager getLinphoneManager() {
return mLinphoneManager;
}
public ContactsManager getContactsManager() {
return mContactsManager;
}
public BluetoothManager getBluetoothManager() {
return mBluetoothManager;
}
public void createOverlay() {
if (mOverlay != null) destroyOverlay();
Core core = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
Call call = core.getCurrentCall();
if (call == null || !call.getCurrentParams().videoEnabled()) return;
@ -330,6 +342,12 @@ public final class LinphoneService extends Service {
mOverlay = null;
}
private void setupActivityMonitor() {
if (mActivityCallbacks != null) return;
getApplication()
.registerActivityLifecycleCallbacks(mActivityCallbacks = new ActivityMonitor());
}
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
@ -361,183 +379,17 @@ public final class LinphoneService extends Service {
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onTaskRemoved(Intent rootIntent) {
boolean serviceNotif = LinphonePreferences.instance().getServiceNotificationVisibility();
if (serviceNotif) {
Log.i("[Service] Service is running in foreground, don't stop it");
} else if (getResources().getBoolean(R.bool.kill_service_with_task_manager)) {
Log.i("[Service] Task removed, stop service");
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.terminateAllCalls();
}
// If push is enabled, don't unregister account, otherwise do unregister
if (LinphonePreferences.instance().isPushNotificationEnabled()) {
if (lc != null) lc.setNetworkReachable(false);
}
stopSelf();
}
super.onTaskRemoved(rootIntent);
}
@Override
public synchronized void onDestroy() {
if (mActivityCallbacks != null) {
getApplication().unregisterActivityLifecycleCallbacks(mActivityCallbacks);
mActivityCallbacks = null;
}
destroyOverlay();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
lc = null; // To allow the gc calls below to free the Core
}
sInstance = null;
LinphoneManager.destroy();
// Make sure our notification is gone.
if (mNotificationManager != null) {
mNotificationManager.destroy();
}
// This will prevent the app from crashing if the service gets killed in background mode
if (LinphoneActivity.isInstanciated()) {
Log.w("[Service] Service is getting destroyed, finish LinphoneActivity");
LinphoneActivity.instance().finish();
}
if (LinphonePreferences.instance().useJavaLogger()) {
Factory.instance().getLoggingService().removeListener(mJavaLoggingService);
}
super.onDestroy();
}
@SuppressWarnings("unchecked")
public void setActivityToLaunchOnIncomingReceived(String activityName) {
try {
mIncomingReceivedActivity = (Class<? extends Activity>) Class.forName(activityName);
mIncomingReceivedActivityName = activityName;
LinphonePreferences.instance()
.setActivityToLaunchOnIncomingReceived(mIncomingReceivedActivityName);
} catch (ClassNotFoundException e) {
Log.e(e);
}
}
private void onIncomingReceived() {
Intent intent = new Intent().setClass(this, mIncomingReceivedActivity);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().startActivity(intent);
} else {
// This flag is required to start an Activity from a Service context
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
/*Believe me or not, but knowing the application visibility state on Android is a nightmare.
After two days of hard work I ended with the following class, that does the job more or less reliabily.
*/
class ActivityMonitor implements Application.ActivityLifecycleCallbacks {
private final ArrayList<Activity> activities = new ArrayList<>();
private boolean mActive = false;
private int mRunningActivities = 0;
private InactivityChecker mLastChecker;
@Override
public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("[Service] Activity created:" + activity);
if (!activities.contains(activity)) activities.add(activity);
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Activity started:" + activity);
}
@Override
public synchronized void onActivityResumed(Activity activity) {
Log.i("[Service] Activity resumed:" + activity);
if (activities.contains(activity)) {
mRunningActivities++;
Log.i("[Service] runningActivities=" + mRunningActivities);
checkActivity();
}
}
@Override
public synchronized void onActivityPaused(Activity activity) {
Log.i("[Service] Activity paused:" + activity);
if (activities.contains(activity)) {
mRunningActivities--;
Log.i("[Service] runningActivities=" + mRunningActivities);
checkActivity();
}
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("[Service] Activity stopped:" + activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
@Override
public synchronized void onActivityDestroyed(Activity activity) {
Log.i("[Service] Activity destroyed:" + activity);
activities.remove(activity);
}
void startInactivityChecker() {
if (mLastChecker != null) mLastChecker.cancel();
LinphoneService.this.handler.postDelayed(
(mLastChecker = new InactivityChecker()), 2000);
}
void checkActivity() {
if (mRunningActivities == 0) {
if (mActive) startInactivityChecker();
} else if (mRunningActivities > 0) {
if (!mActive) {
mActive = true;
LinphoneService.this.onForegroundMode();
}
if (mLastChecker != null) {
mLastChecker.cancel();
mLastChecker = null;
}
}
}
class InactivityChecker implements Runnable {
private boolean isCanceled;
void cancel() {
isCanceled = true;
}
@Override
public void run() {
synchronized (LinphoneService.this) {
if (!isCanceled) {
if (ActivityMonitor.this.mRunningActivities == 0 && mActive) {
mActive = false;
LinphoneService.this.onBackgroundMode();
}
}
}
}
}
private void onOutgoingStarted() {
Intent intent = new Intent(LinphoneService.this, CallOutgoingActivity.class);
// This flag is required to start an Activity from a Service context
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}

View file

@ -1,7 +1,8 @@
package org.linphone.fragments;
package org.linphone.activities;
/*
AboutFragment.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
AboutActivity.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
@ -18,7 +19,6 @@ 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.Fragment;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
@ -27,34 +27,43 @@ import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import org.linphone.BuildConfig;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.Core.LogCollectionUploadState;
import org.linphone.core.CoreListenerStub;
import org.linphone.settings.LinphonePreferences;
public class AboutFragment extends Fragment implements OnClickListener {
private View mSendLogButton = null;
private View mResetLogButton = null;
public class AboutActivity extends MainActivity {
private CoreListenerStub mListener;
private ProgressDialog mProgress;
private boolean mUploadInProgress;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.about, container, false);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOnBackPressGoHome = false;
TextView aboutVersion = view.findViewById(R.id.about_android_version);
TextView aboutLiblinphoneVersion = view.findViewById(R.id.about_liblinphone_sdk_version);
// Uses the fragment container layout to inflate the about view instead of using a fragment
View aboutView = LayoutInflater.from(this).inflate(R.layout.about, null, false);
LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
fragmentContainer.addView(aboutView, params);
if (isTablet()) {
findViewById(R.id.fragmentContainer2).setVisibility(View.GONE);
}
TextView aboutVersion = findViewById(R.id.about_android_version);
TextView aboutLiblinphoneVersion = findViewById(R.id.about_liblinphone_sdk_version);
aboutLiblinphoneVersion.setText(
String.format(
getString(R.string.about_liblinphone_sdk_version),
@ -68,9 +77,9 @@ public class AboutFragment extends Fragment implements OnClickListener {
getString(R.string.about_version),
BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")"));
TextView privacyPolicy = view.findViewById(R.id.privacy_policy_link);
TextView privacyPolicy = findViewById(R.id.privacy_policy_link);
privacyPolicy.setOnClickListener(
new OnClickListener() {
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent browserIntent =
@ -81,9 +90,9 @@ public class AboutFragment extends Fragment implements OnClickListener {
}
});
TextView license = view.findViewById(R.id.about_text);
TextView license = findViewById(R.id.about_text);
license.setOnClickListener(
new OnClickListener() {
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent browserIntent =
@ -94,36 +103,77 @@ public class AboutFragment extends Fragment implements OnClickListener {
}
});
mSendLogButton = view.findViewById(R.id.send_log);
mSendLogButton.setOnClickListener(this);
mSendLogButton.setVisibility(
Button sendLogs = findViewById(R.id.send_log);
sendLogs.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Core core = LinphoneManager.getCore();
if (core != null) {
core.uploadLogCollection();
}
}
});
sendLogs.setVisibility(
LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
mResetLogButton = view.findViewById(R.id.reset_log);
mResetLogButton.setOnClickListener(this);
mResetLogButton.setVisibility(
Button resetLogs = findViewById(R.id.reset_log);
resetLogs.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Core core = LinphoneManager.getCore();
if (core != null) {
core.resetLogCollection();
}
}
});
resetLogs.setVisibility(
LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
mListener =
new CoreListenerStub() {
@Override
public void onLogCollectionUploadProgressIndication(
Core lc, int offset, int total) {}
Core core, int offset, int total) {}
@Override
public void onLogCollectionUploadStateChanged(
Core lc, LogCollectionUploadState state, String info) {
if (state == LogCollectionUploadState.InProgress) {
Core core, Core.LogCollectionUploadState state, String info) {
if (state == Core.LogCollectionUploadState.InProgress) {
displayUploadLogsInProgress();
} else if (state == LogCollectionUploadState.Delivered
|| state == LogCollectionUploadState.NotDelivered) {
} else if (state == Core.LogCollectionUploadState.Delivered
|| state == Core.LogCollectionUploadState.NotDelivered) {
mUploadInProgress = false;
if (mProgress != null) mProgress.dismiss();
}
}
};
}
return view;
@Override
public void onPause() {
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
super.onPause();
}
@Override
public void onResume() {
super.onResume();
showTopBarWithTitle(getString(R.string.about));
if (getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views)) {
hideTabBar();
}
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
}
private void displayUploadLogsInProgress() {
@ -132,9 +182,8 @@ public class AboutFragment extends Fragment implements OnClickListener {
}
mUploadInProgress = true;
mProgress = ProgressDialog.show(LinphoneActivity.instance(), null, null);
Drawable d =
new ColorDrawable(ContextCompat.getColor(getActivity(), R.color.light_grey_color));
mProgress = ProgressDialog.show(this, null, null);
Drawable d = new ColorDrawable(ContextCompat.getColor(this, R.color.light_grey_color));
d.setAlpha(200);
mProgress
.getWindow()
@ -145,44 +194,4 @@ public class AboutFragment extends Fragment implements OnClickListener {
mProgress.setContentView(R.layout.wait_layout);
mProgress.show();
}
@Override
public void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
}
super.onPause();
}
@Override
public void onResume() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
}
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT);
}
super.onResume();
}
@Override
public void onClick(View v) {
if (LinphoneActivity.isInstanciated()) {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (v == mSendLogButton) {
if (lc != null) {
lc.uploadLogCollection();
}
} else if (v == mResetLogButton) {
if (lc != null) {
lc.resetLogCollection();
}
}
}
}
}

View file

@ -0,0 +1,282 @@
package org.linphone.activities;
/*
DialerActivity.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.Manifest;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.call.CallActivity;
import org.linphone.contacts.ContactsActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.core.Call;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.tools.Log;
import org.linphone.views.AddressAware;
import org.linphone.views.AddressText;
import org.linphone.views.CallButton;
import org.linphone.views.EraseButton;
public class DialerActivity extends MainActivity implements AddressText.AddressChangedListener {
private static final String ACTION_CALL_LINPHONE = "org.linphone.intent.action.CallLaunched";
private AddressAware mNumpad;
private AddressText mAddress;
private CallButton mStartCall, mAddCall, mTransferCall;
private ImageView mAddContact, mBackToCall;
private boolean mIsTransfer;
private CoreListenerStub mListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Uses the fragment container layout to inflate the dialer view instead of using a fragment
View dialerView = LayoutInflater.from(this).inflate(R.layout.dialer, null, false);
LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
fragmentContainer.addView(dialerView, params);
if (isTablet()) {
findViewById(R.id.fragmentContainer2).setVisibility(View.GONE);
}
mAddress = findViewById(R.id.address);
mAddress.setAddressListener(this);
EraseButton erase = findViewById(R.id.erase);
erase.setAddressWidget(mAddress);
mStartCall = findViewById(R.id.start_call);
mStartCall.setAddressWidget(mAddress);
mStartCall.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
LinphoneManager.getCallManager().newOutgoingCall(mAddress);
}
});
mAddCall = findViewById(R.id.add_call);
mAddCall.setAddressWidget(mAddress);
mAddCall.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
LinphoneManager.getCallManager().newOutgoingCall(mAddress);
}
});
mTransferCall = findViewById(R.id.transfer_call);
mTransferCall.setAddressWidget(mAddress);
mTransferCall.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Core core = LinphoneManager.getCore();
if (core.getCurrentCall() == null) {
return;
}
core.transferCall(core.getCurrentCall(), mAddress.getText().toString());
}
});
mNumpad = findViewById(R.id.numpad);
if (mNumpad != null) {
mNumpad.setAddressWidget(mAddress);
}
mAddContact = findViewById(R.id.add_contact);
mAddContact.setEnabled(false);
mAddContact.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(DialerActivity.this, ContactsActivity.class);
intent.putExtra("EditOnClick", true);
intent.putExtra("SipAddress", mAddress.getText().toString());
startActivity(intent);
}
});
mBackToCall = findViewById(R.id.back_to_call);
mBackToCall.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(DialerActivity.this, CallActivity.class));
}
});
mIsTransfer = false;
if (getIntent() != null) {
mIsTransfer = getIntent().getBooleanExtra("Transfer", false);
mAddress.setText(getIntent().getStringExtra("SipUri"));
}
mListener =
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core core, Call call, Call.State state, String message) {
updateLayout();
}
};
// On dialer we ask for all permissions
mPermissionsToHave =
new String[] {
// This one is to allow floating notifications
Manifest.permission.SYSTEM_ALERT_WINDOW,
// Required starting Android 9 to be able to start a foreground service
"android.permission.FOREGROUND_SERVICE",
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.READ_CONTACTS
};
handleIntentParams(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntentParams(intent);
}
@Override
protected void onResume() {
super.onResume();
mDialerSelected.setVisibility(View.VISIBLE);
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
boolean isOrientationLandscape =
getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
if (isOrientationLandscape && !isTablet()) {
((LinearLayout) mNumpad).setVisibility(View.GONE);
} else {
((LinearLayout) mNumpad).setVisibility(View.VISIBLE);
}
updateLayout();
}
@Override
protected void onPause() {
super.onPause();
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("isTransfer", mIsTransfer);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mIsTransfer = savedInstanceState.getBoolean("isTransfer");
}
@Override
public void onAddressChanged() {
Core core = LinphoneManager.getCore();
mAddContact.setEnabled(
core != null && core.getCallsNb() > 0 || !mAddress.getText().toString().equals(""));
}
private void updateLayout() {
Core core = LinphoneManager.getCore();
if (core == null) {
return;
}
boolean atLeastOneCall = core.getCallsNb() > 0;
mStartCall.setVisibility(atLeastOneCall ? View.GONE : View.VISIBLE);
mAddContact.setVisibility(atLeastOneCall ? View.GONE : View.VISIBLE);
if (!atLeastOneCall) {
if (core.getVideoActivationPolicy().getAutomaticallyInitiate()) {
mStartCall.setImageResource(R.drawable.call_video_start);
} else {
mStartCall.setImageResource(R.drawable.call_audio_start);
}
}
mBackToCall.setVisibility(atLeastOneCall ? View.VISIBLE : View.GONE);
mAddCall.setVisibility(atLeastOneCall && !mIsTransfer ? View.VISIBLE : View.GONE);
mTransferCall.setVisibility(atLeastOneCall && mIsTransfer ? View.VISIBLE : View.GONE);
}
private void handleIntentParams(Intent intent) {
if (intent == null) return;
String action = intent.getAction();
String addressToCall = null;
if (ACTION_CALL_LINPHONE.equals(action)
&& (intent.getStringExtra("NumberToCall") != null)) {
String numberToCall = intent.getStringExtra("NumberToCall");
Log.i("[Dialer] ACTION_CALL_LINPHONE with number: " + numberToCall);
LinphoneManager.getCallManager().newOutgoingCall(numberToCall, null);
} else if (Intent.ACTION_CALL.equals(action)) {
if (intent.getData() != null) {
addressToCall = intent.getData().toString();
addressToCall = addressToCall.replace("%40", "@");
addressToCall = addressToCall.replace("%3A", ":");
if (addressToCall.startsWith("sip:")) {
addressToCall = addressToCall.substring("sip:".length());
} else if (addressToCall.startsWith("tel:")) {
addressToCall = addressToCall.substring("tel:".length());
}
Log.i("[Dialer] ACTION_CALL with number: " + addressToCall);
}
} else if (Intent.ACTION_VIEW.equals(action)) {
addressToCall =
ContactsManager.getInstance()
.getAddressOrNumberForAndroidContact(
getContentResolver(), intent.getData());
Log.i("[Dialer] ACTION_VIEW with number: " + addressToCall);
}
if (addressToCall != null) {
mAddress.setText(addressToCall);
}
}
}

View file

@ -1,4 +1,4 @@
package org.linphone.utils;
package org.linphone.activities;
/*
LinphoneGenericActivity.java
@ -20,22 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.os.Bundle;
import org.linphone.LinphoneLauncherActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
public class LinphoneGenericActivity extends ThemableActivity {
public abstract class LinphoneGenericActivity extends ThemableActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*After a crash, Android restart the last Activity so we need to check
* if all dependencies are load
*/
if (!LinphoneService.isReady() || !LinphoneManager.isInstanciated()) {
finish();
// After a crash, Android restart the last Activity so we need to check
// if all dependencies are loaded
if (!LinphoneService.isReady()) {
startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class));
finish();
}
}
}

View file

@ -1,4 +1,4 @@
package org.linphone;
package org.linphone.activities;
/*
LinphoneLauncherActivity.java
@ -19,44 +19,42 @@ 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.content.Intent.ACTION_MAIN;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.assistant.MenuAssistantActivity;
import org.linphone.chat.ChatActivity;
import org.linphone.settings.LinphonePreferences;
/** Launch Linphone main activity when Service is ready. */
/** Creates LinphoneService and wait until Core is ready to start main Activity */
public class LinphoneLauncherActivity extends Activity {
private Handler mHandler;
private ServiceWaitThread mServiceThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hack to avoid to draw twice LinphoneActivity on tablets
if (getResources().getBoolean(R.bool.orientation_portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
if (getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) {
setContentView(R.layout.launch_screen_full_image);
} else {
if (!getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) {
setContentView(R.layout.launch_screen);
}
} // Otherwise use drawable/launch_screen layer list up until first activity starts
mHandler = new Handler();
}
@Override
protected void onStart() {
super.onStart();
if (LinphoneService.isReady()) {
onServiceReady();
} else {
// start linphone as background
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
mServiceThread = new ServiceWaitThread();
mServiceThread.start();
startService(
new Intent().setClass(LinphoneLauncherActivity.this, LinphoneService.class));
new ServiceWaitThread().start();
}
}
@ -68,7 +66,16 @@ public class LinphoneLauncherActivity extends Activity {
if (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch()) {
classToStart = MenuAssistantActivity.class;
} else {
classToStart = LinphoneActivity.class;
if (getIntent().getExtras() != null
&& "Chat".equals(getIntent().getExtras().getString("Activity", null))) {
classToStart = ChatActivity.class;
} else {
classToStart = DialerActivity.class;
}
}
if (getResources().getBoolean(R.bool.check_for_update_when_app_starts)) {
LinphoneManager.getInstance().checkForUpdate();
}
mHandler.postDelayed(
@ -80,10 +87,16 @@ public class LinphoneLauncherActivity extends Activity {
if (getIntent() != null && getIntent().getExtras() != null) {
intent.putExtras(getIntent().getExtras());
}
intent.setAction(getIntent().getAction());
intent.setType(getIntent().getType());
startActivity(intent);
LinphoneService.instance()
.getNotificationManager()
.removeForegroundServiceNotificationIfPossible();
}
},
500);
100);
LinphoneManager.getInstance().changeStatusToOnline();
}
@ -104,7 +117,6 @@ public class LinphoneLauncherActivity extends Activity {
onServiceReady();
}
});
mServiceThread = null;
}
}
}

View file

@ -0,0 +1,687 @@
package org.linphone.activities;
/*
MainActivity.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.Manifest;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.KeyguardManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import java.util.ArrayList;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.chat.ChatActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.AuthInfo;
import org.linphone.core.Call;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.ProxyConfig;
import org.linphone.core.RegistrationState;
import org.linphone.core.tools.Log;
import org.linphone.fragments.EmptyFragment;
import org.linphone.fragments.StatusFragment;
import org.linphone.history.HistoryActivity;
import org.linphone.menu.SideMenuFragment;
import org.linphone.settings.LinphonePreferences;
import org.linphone.settings.SettingsActivity;
import org.linphone.utils.DeviceUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.utils.PushNotificationUtils;
public abstract class MainActivity extends LinphoneGenericActivity
implements StatusFragment.MenuClikedListener, SideMenuFragment.QuitClikedListener {
private static final int MAIN_PERMISSIONS = 1;
private static final int FRAGMENT_SPECIFIC_PERMISSION = 2;
private TextView mMissedCalls;
private TextView mMissedMessages;
protected View mContactsSelected;
protected View mHistorySelected;
View mDialerSelected;
protected View mChatSelected;
private LinearLayout mTopBar;
private TextView mTopBarTitle;
private LinearLayout mTabBar;
private SideMenuFragment mSideMenuFragment;
private StatusFragment mStatusFragment;
protected boolean mOnBackPressGoHome;
protected String[] mPermissionsToHave;
private CoreListenerStub mListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mOnBackPressGoHome = true;
RelativeLayout history = findViewById(R.id.history);
history.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, HistoryActivity.class);
addFlagsToIntent(intent);
startActivity(intent);
}
});
RelativeLayout contacts = findViewById(R.id.contacts);
contacts.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ContactsActivity.class);
addFlagsToIntent(intent);
startActivity(intent);
}
});
RelativeLayout dialer = findViewById(R.id.dialer);
dialer.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, DialerActivity.class);
addFlagsToIntent(intent);
startActivity(intent);
}
});
RelativeLayout chat = findViewById(R.id.chat);
chat.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ChatActivity.class);
addFlagsToIntent(intent);
startActivity(intent);
}
});
mMissedCalls = findViewById(R.id.missed_calls);
mMissedMessages = findViewById(R.id.missed_chats);
mHistorySelected = findViewById(R.id.history_select);
mContactsSelected = findViewById(R.id.contacts_select);
mDialerSelected = findViewById(R.id.dialer_select);
mChatSelected = findViewById(R.id.chat_select);
mTabBar = findViewById(R.id.footer);
mTopBar = findViewById(R.id.top_bar);
mTopBarTitle = findViewById(R.id.top_bar_title);
ImageView back = findViewById(R.id.cancel);
back.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
goBack();
}
});
mStatusFragment =
(StatusFragment) getFragmentManager().findFragmentById(R.id.status_fragment);
DrawerLayout mSideMenu = findViewById(R.id.side_menu);
RelativeLayout mSideMenuContent = findViewById(R.id.side_menu_content);
mSideMenuFragment =
(SideMenuFragment)
getSupportFragmentManager().findFragmentById(R.id.side_menu_fragment);
mSideMenuFragment.setDrawer(mSideMenu, mSideMenuContent);
if (getResources().getBoolean(R.bool.disable_chat)) {
chat.setVisibility(View.GONE);
}
mListener =
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core core, Call call, Call.State state, String message) {
if (state == Call.State.End || state == Call.State.Released) {
displayMissedCalls();
}
}
@Override
public void onMessageReceived(Core core, ChatRoom room, ChatMessage message) {
displayMissedChats();
}
@Override
public void onChatRoomRead(Core core, ChatRoom room) {
displayMissedChats();
}
@Override
public void onMessageReceivedUnableDecrypt(
Core core, ChatRoom room, ChatMessage message) {
displayMissedChats();
}
@Override
public void onRegistrationStateChanged(
Core core,
ProxyConfig proxyConfig,
RegistrationState state,
String message) {
mSideMenuFragment.displayAccountsInSideMenu();
if (state == RegistrationState.Ok) {
// For push notifications to work on some devices,
// app must be in "protected mode" in battery settings...
// https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it
DeviceUtils
.displayDialogIfDeviceHasPowerManagerThatCouldPreventPushNotifications(
MainActivity.this);
if (getResources().getBoolean(R.bool.use_phone_number_validation)) {
AuthInfo authInfo =
core.findAuthInfo(
proxyConfig.getRealm(),
proxyConfig.getIdentityAddress().getUsername(),
proxyConfig.getDomain());
if (authInfo != null
&& authInfo.getDomain()
.equals(getString(R.string.default_domain))) {
LinphoneManager.getInstance().isAccountWithAlias();
}
}
}
}
@Override
public void onLogCollectionUploadStateChanged(
Core core, Core.LogCollectionUploadState state, String info) {
Log.d(
"[Main Activity] Log upload state: "
+ state.toString()
+ ", info = "
+ info);
if (state == Core.LogCollectionUploadState.Delivered) {
ClipboardManager clipboard =
(ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Logs url", info);
clipboard.setPrimaryClip(clip);
Toast.makeText(
MainActivity.this,
getString(R.string.logs_url_copied_to_clipboard),
Toast.LENGTH_SHORT)
.show();
shareUploadedLogsUrl(info);
}
}
};
}
@Override
protected void onStart() {
super.onStart();
requestRequiredPermissions();
if (checkPermission(Manifest.permission.READ_CONTACTS)) {
ContactsManager.getInstance().enableContactsAccess();
}
ContactsManager.getInstance().initializeContactManager();
if (DeviceUtils.isAppUserRestricted(this)) {
Log.w(
"[Main Activity] Device has been restricted by user (Android 9+), push notifications won't work !");
}
int bucket = DeviceUtils.getAppStandbyBucket(this);
if (bucket > 0) {
Log.w(
"[Main Activity] Device is in bucket "
+ Compatibility.getAppStandbyBucketNameFromValue(bucket));
}
if (!PushNotificationUtils.isAvailable(this)) {
Log.w("[Main Activity] Push notifications won't work !");
}
}
@Override
protected void onResume() {
super.onResume();
hideTopBar();
showTabBar();
mHistorySelected.setVisibility(View.GONE);
mContactsSelected.setVisibility(View.GONE);
mDialerSelected.setVisibility(View.GONE);
mChatSelected.setVisibility(View.GONE);
mStatusFragment.setMenuListener(this);
mSideMenuFragment.setQuitListener(this);
mSideMenuFragment.displayAccountsInSideMenu();
if (mSideMenuFragment.isOpened()) {
mSideMenuFragment.closeDrawer();
}
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
displayMissedChats();
displayMissedCalls();
}
}
@Override
protected void onPause() {
mStatusFragment.setMenuListener(null);
mSideMenuFragment.setQuitListener(null);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
super.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
try {
super.onSaveInstanceState(outState);
} catch (IllegalStateException ise) {
// Do not log this exception
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
try {
super.onRestoreInstanceState(savedInstanceState);
} catch (IllegalStateException ise) {
// Do not log this exception
}
}
@Override
public void onMenuCliked() {
if (mSideMenuFragment.isOpened()) {
mSideMenuFragment.openOrCloseSideMenu(false, true);
} else {
mSideMenuFragment.openOrCloseSideMenu(true, true);
}
}
@Override
public void onQuitClicked() {
quit();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mOnBackPressGoHome) {
if (getFragmentManager().getBackStackEntryCount() == 0) {
goHomeAndClearStack();
return true;
}
}
goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
public boolean popBackStack() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
return true;
}
return false;
}
public void goBack() {
finish();
}
protected boolean isTablet() {
return getResources().getBoolean(R.bool.isTablet);
}
private void goHomeAndClearStack() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
private void quit() {
goHomeAndClearStack();
stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
am.killBackgroundProcesses(getString(R.string.sync_account_type));
android.os.Process.killProcess(android.os.Process.myPid());
}
// Tab, Top and Status bars
public void hideStatusBar() {
findViewById(R.id.status_fragment).setVisibility(View.GONE);
}
public void showStatusBar() {
findViewById(R.id.status_fragment).setVisibility(View.VISIBLE);
}
public void hideTabBar() {
if (!isTablet()) { // do not hide if tablet, otherwise won't be able to navigate...
mTabBar.setVisibility(View.GONE);
}
}
public void showTabBar() {
mTabBar.setVisibility(View.VISIBLE);
}
protected void hideTopBar() {
mTopBar.setVisibility(View.GONE);
mTopBarTitle.setText("");
}
private void showTopBar() {
mTopBar.setVisibility(View.VISIBLE);
}
protected void showTopBarWithTitle(String title) {
showTopBar();
mTopBarTitle.setText(title);
}
// Permissions
private boolean checkPermission(String permission) {
int granted = getPackageManager().checkPermission(permission, getPackageName());
Log.i(
"[Permission] "
+ permission
+ " permission is "
+ (granted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
return granted == PackageManager.PERMISSION_GRANTED;
}
public void requestPermissionIfNotGranted(String permission) {
if (!checkPermission(permission)) {
Log.i("[Permission] Requesting " + permission + " permission");
String[] permissions = new String[] {permission};
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean locked = km.inKeyguardRestrictedInputMode();
if (!locked) {
// This is to workaround an infinite loop of pause/start in Activity issue
// if incoming call ends while screen if off and locked
ActivityCompat.requestPermissions(this, permissions, FRAGMENT_SPECIFIC_PERMISSION);
}
}
}
public void requestPermissionsIfNotGranted(String[] perms) {
requestPermissionsIfNotGranted(perms, FRAGMENT_SPECIFIC_PERMISSION);
}
private void requestPermissionsIfNotGranted(String[] perms, int resultCode) {
ArrayList<String> permissionsToAskFor = new ArrayList<>();
if (perms != null) { // This is created (or not) by the child activity
for (String permissionToHave : perms) {
if (!checkPermission(permissionToHave)) {
permissionsToAskFor.add(permissionToHave);
}
}
}
if (permissionsToAskFor.size() > 0) {
for (String permission : permissionsToAskFor) {
Log.i("[Permission] Requesting " + permission + " permission");
}
String[] permissions = new String[permissionsToAskFor.size()];
permissions = permissionsToAskFor.toArray(permissions);
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean locked = km.inKeyguardRestrictedInputMode();
if (!locked) {
// This is to workaround an infinite loop of pause/start in Activity issue
// if incoming call ends while screen if off and locked
ActivityCompat.requestPermissions(this, permissions, resultCode);
}
}
}
private void requestRequiredPermissions() {
requestPermissionsIfNotGranted(mPermissionsToHave, MAIN_PERMISSIONS);
}
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
if (permissions.length <= 0) return;
for (int i = 0; i < permissions.length; i++) {
Log.i(
"[Permission] "
+ permissions[i]
+ " is "
+ (grantResults[i] == PackageManager.PERMISSION_GRANTED
? "granted"
: "denied"));
if (permissions[i].equals(Manifest.permission.READ_CONTACTS)
|| permissions[i].equals(Manifest.permission.WRITE_CONTACTS)) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().enableContactsAccess();
}
} else if (permissions[i].equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {
boolean enableRingtone = grantResults[i] == PackageManager.PERMISSION_GRANTED;
LinphonePreferences.instance().enableDeviceRingtone(enableRingtone);
LinphoneManager.getInstance().enableDeviceRingtone(enableRingtone);
}
}
}
// Missed calls & chat indicators
protected void displayMissedCalls() {
int count = 0;
Core core = LinphoneManager.getCore();
if (core != null) {
count = core.getMissedCallsCount();
}
if (count > 0) {
mMissedCalls.setText(String.valueOf(count));
mMissedCalls.setVisibility(View.VISIBLE);
} else {
mMissedCalls.clearAnimation();
mMissedCalls.setVisibility(View.GONE);
}
}
public void displayMissedChats() {
int count = 0;
Core core = LinphoneManager.getCore();
if (core != null) {
count = core.getUnreadChatMessageCountFromActiveLocals();
}
if (count > 0) {
mMissedMessages.setText(String.valueOf(count));
mMissedMessages.setVisibility(View.VISIBLE);
} else {
mMissedMessages.clearAnimation();
mMissedMessages.setVisibility(View.GONE);
}
}
// Navigation between actvities
private void addFlagsToIntent(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
}
protected void changeFragment(Fragment fragment, String name, boolean isChild) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (transaction.isAddToBackStackAllowed()) {
int count = fragmentManager.getBackStackEntryCount();
if (count > 0) {
FragmentManager.BackStackEntry entry =
fragmentManager.getBackStackEntryAt(count - 1);
if (entry != null && name.equals(entry.getName())) {
fragmentManager.popBackStack();
if (!isChild) {
// We just removed it's duplicate from the back stack
// And we want at least one in it
transaction.addToBackStack(name);
}
}
}
if (isChild) {
transaction.addToBackStack(name);
}
}
Compatibility.setFragmentTransactionReorderingAllowed(transaction, false);
if (isChild && isTablet()) {
transaction.replace(R.id.fragmentContainer2, fragment, name);
findViewById(R.id.fragmentContainer2).setVisibility(View.VISIBLE);
} else {
transaction.replace(R.id.fragmentContainer, fragment, name);
}
transaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
public void showEmptyChildFragment() {
changeFragment(new EmptyFragment(), "Empty", true);
}
public void showAccountSettings(int accountIndex) {
Intent intent = new Intent(this, SettingsActivity.class);
addFlagsToIntent(intent);
intent.putExtra("Account", accountIndex);
startActivity(intent);
}
public void showContactDetails(LinphoneContact contact) {
Intent intent = new Intent(this, ContactsActivity.class);
addFlagsToIntent(intent);
intent.putExtra("Contact", contact);
startActivity(intent);
}
public void showContactsListForCreationOrEdition(Address address) {
if (address == null) return;
Intent intent = new Intent(this, ContactsActivity.class);
addFlagsToIntent(intent);
intent.putExtra("CreateOrEdit", true);
intent.putExtra("SipUri", address.asStringUriOnly());
if (address.getDisplayName() != null) {
intent.putExtra("DisplayName", address.getDisplayName());
}
startActivity(intent);
}
public void showChatRoom(Address localAddress, Address peerAddress) {
Intent intent = new Intent(this, ChatActivity.class);
addFlagsToIntent(intent);
if (localAddress != null) {
intent.putExtra("LocalSipUri", localAddress.asStringUriOnly());
}
if (peerAddress != null) {
intent.putExtra("RemoteSipUri", peerAddress.asStringUriOnly());
}
startActivity(intent);
}
// Dialogs
public Dialog displayDialog(String text) {
return LinphoneUtils.getDialog(this, text);
}
public void displayChatRoomError() {
final Dialog dialog = displayDialog(getString(R.string.chat_room_creation_failed));
dialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE);
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
cancel.setText(getString(R.string.ok));
cancel.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
// Logs
private void shareUploadedLogsUrl(String info) {
final String appName = getString(R.string.app_name);
Intent i = new Intent(Intent.ACTION_SEND);
i.putExtra(Intent.EXTRA_EMAIL, new String[] {getString(R.string.about_bugreport_email)});
i.putExtra(Intent.EXTRA_SUBJECT, appName + " Logs");
i.putExtra(Intent.EXTRA_TEXT, info);
i.setType("application/zip");
try {
startActivity(Intent.createChooser(i, "Send mail..."));
} catch (android.content.ActivityNotFoundException ex) {
Log.e(ex);
}
}
}

View file

@ -0,0 +1,72 @@
package org.linphone.activities;
/*
SplashScreenActivity.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.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import org.linphone.R;
/**
* This activity does pretty much nothing except starting the linphone launcher that will be
* starting the Service which takes time and will delay the splashscreen UI creation to later, and
* until that time it will display the default windowBackground. This activity will load faster,
* thus showing the splashscreen sooner.
*/
public class SplashScreenActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getBoolean(R.bool.orientation_portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
if (!getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) {
setContentView(R.layout.launch_screen);
} // Otherwise use drawable/launch_screen layer list up until first activity starts
}
@Override
protected void onResume() {
super.onResume();
// Start the linphone launcher asynchronously otherwise it will wait for launcher to be
// loaded which will render this workaround useless.
new Handler()
.postDelayed(
new Runnable() {
@Override
public void run() {
Intent intent = new Intent();
intent.setClass(
SplashScreenActivity.this, LinphoneLauncherActivity.class);
if (getIntent() != null && getIntent().getExtras() != null) {
intent.putExtras(getIntent().getExtras());
}
intent.setAction(getIntent().getAction());
intent.setType(getIntent().getType());
startActivity(intent);
}
},
100);
}
}

View file

@ -1,4 +1,4 @@
package org.linphone.utils;
package org.linphone.activities;
/*
ThemableActivity.java
@ -25,11 +25,14 @@ import androidx.appcompat.app.AppCompatActivity;
import org.linphone.R;
import org.linphone.settings.LinphonePreferences;
public class ThemableActivity extends AppCompatActivity {
public abstract class ThemableActivity extends AppCompatActivity {
private int mTheme;
@Override
protected void onCreate(Bundle savedInstanceState) {
mTheme = R.style.LinphoneStyleLight;
if (LinphonePreferences.instance().isDarkModeEnabled()) {
mTheme = R.style.LinphoneStyleDark;
setTheme(R.style.LinphoneStyleDark);
}
@ -39,4 +42,19 @@ public class ThemableActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
if (LinphonePreferences.instance().isDarkModeEnabled()) {
if (mTheme != R.style.LinphoneStyleDark) {
recreate();
}
} else {
if (mTheme != R.style.LinphoneStyleLight) {
recreate();
}
}
}
}

View file

@ -42,7 +42,6 @@ public class AccountConnectionAssistantActivity extends AssistantActivity {
private Switch mUsernameConnectionSwitch;
private EditText mPrefix, mPhoneNumber, mUsername, mPassword;
private TextView mCountryPicker, mError, mConnect;
private ImageView mPhoneNumberInfos;
private AccountCreatorListenerStub mListener;
@ -157,8 +156,8 @@ public class AccountConnectionAssistantActivity extends AssistantActivity {
}
});
mPhoneNumberInfos = findViewById(R.id.info_phone_number);
mPhoneNumberInfos.setOnClickListener(
ImageView phoneNumberInfos = findViewById(R.id.info_phone_number);
phoneNumberInfos.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {

View file

@ -27,9 +27,10 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.activities.DialerActivity;
import org.linphone.activities.ThemableActivity;
import org.linphone.core.AccountCreator;
import org.linphone.core.Core;
import org.linphone.core.DialPlan;
@ -37,17 +38,15 @@ import org.linphone.core.Factory;
import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.ThemableActivity;
public abstract class AssistantActivity extends ThemableActivity
implements CountryPicker.CountryPickedListener {
protected static AccountCreator mAccountCreator;
static AccountCreator mAccountCreator;
protected View mTopBar, mStatusBar;
protected ImageView mBack;
protected AlertDialog mCountryPickerDialog;
ImageView mBack;
private AlertDialog mCountryPickerDialog;
protected CountryPicker mCountryPicker;
private CountryPicker mCountryPicker;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -55,7 +54,7 @@ public abstract class AssistantActivity extends ThemableActivity
if (mAccountCreator == null) {
String url = LinphonePreferences.instance().getXmlrpcUrl();
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
core.loadConfigFromXml(LinphoneManager.getInstance().getDefaultDynamicConfigFile());
mAccountCreator = core.createAccountCreator(url);
}
@ -67,14 +66,14 @@ public abstract class AssistantActivity extends ThemableActivity
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
mStatusBar = findViewById(R.id.status);
View statusBar = findViewById(R.id.status);
if (getResources().getBoolean(R.bool.assistant_hide_status_bar)) {
mStatusBar.setVisibility(View.GONE);
statusBar.setVisibility(View.GONE);
}
mTopBar = findViewById(R.id.top_bar);
View topBar = findViewById(R.id.top_bar);
if (getResources().getBoolean(R.bool.assistant_hide_top_bar)) {
mTopBar.setVisibility(View.GONE);
topBar.setVisibility(View.GONE);
}
mBack = findViewById(R.id.back);
@ -95,8 +94,8 @@ public abstract class AssistantActivity extends ThemableActivity
}
}
protected void createProxyConfigAndLeaveAssistant() {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
void createProxyConfigAndLeaveAssistant() {
Core core = LinphoneManager.getCore();
boolean useLinphoneDefaultValues =
getString(R.string.default_domain).equals(mAccountCreator.getDomain());
if (useLinphoneDefaultValues) {
@ -119,8 +118,9 @@ public abstract class AssistantActivity extends ThemableActivity
}
}
protected void goToLinphoneActivity() {
boolean needsEchoCalibration = LinphoneManager.getLc().isEchoCancellerCalibrationRequired();
void goToLinphoneActivity() {
boolean needsEchoCalibration =
LinphoneManager.getCore().isEchoCancellerCalibrationRequired();
boolean echoCalibrationDone =
LinphonePreferences.instance().isEchoCancellationCalibrationDone();
Log.i(
@ -144,14 +144,13 @@ public abstract class AssistantActivity extends ThemableActivity
if (openH264 && abiSupported && androidVersionOk && !codecFound) {
intent = new Intent(this, OpenH264DownloadAssistantActivity.class);
} else {*/
intent = new Intent(this, LinphoneActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent = new Intent(this, DialerActivity.class);
// }
}
startActivity(intent);
}
protected void showPhoneNumberDialog() {
void showPhoneNumberDialog() {
new AlertDialog.Builder(this)
.setTitle(getString(R.string.phone_number_info_title))
.setMessage(
@ -162,18 +161,18 @@ public abstract class AssistantActivity extends ThemableActivity
.show();
}
protected void showAccountAlreadyExistsDialog() {
void showAccountAlreadyExistsDialog() {
new AlertDialog.Builder(this)
.setTitle(getString(R.string.account_already_exist))
.setMessage(getString(R.string.assistant_phone_number_unavailable))
.show();
}
protected void showGenericErrorDialog(AccountCreator.Status status) {
void showGenericErrorDialog(AccountCreator.Status status) {
String message;
switch (status) {
// TODO
// TODO handle other possible status
case PhoneNumberInvalid:
message = getString(R.string.phone_number_invalid);
break;
@ -194,7 +193,7 @@ public abstract class AssistantActivity extends ThemableActivity
.show();
}
protected void showCountryPickerDialog() {
void showCountryPickerDialog() {
if (mCountryPicker == null) {
mCountryPicker = new CountryPicker(this, this);
}
@ -202,7 +201,7 @@ public abstract class AssistantActivity extends ThemableActivity
new AlertDialog.Builder(this).setView(mCountryPicker.getView()).show();
}
protected DialPlan getDialPlanForCurrentCountry() {
DialPlan getDialPlanForCurrentCountry() {
try {
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String countryIso = tm.getNetworkCountryIso();
@ -213,7 +212,7 @@ public abstract class AssistantActivity extends ThemableActivity
return null;
}
protected String getDevicePhoneNumber() {
String getDevicePhoneNumber() {
try {
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
return tm.getLine1Number();
@ -223,7 +222,7 @@ public abstract class AssistantActivity extends ThemableActivity
return null;
}
protected DialPlan getDialPlanFromPrefix(String prefix) {
DialPlan getDialPlanFromPrefix(String prefix) {
if (prefix == null || prefix.isEmpty()) return null;
for (DialPlan c : Factory.instance().getDialPlans()) {
@ -232,7 +231,7 @@ public abstract class AssistantActivity extends ThemableActivity
return null;
}
protected DialPlan getDialPlanFromCountryCode(String countryCode) {
private DialPlan getDialPlanFromCountryCode(String countryCode) {
if (countryCode == null || countryCode.isEmpty()) return null;
for (DialPlan c : Factory.instance().getDialPlans()) {
@ -241,7 +240,7 @@ public abstract class AssistantActivity extends ThemableActivity
return null;
}
protected int arePhoneNumberAndPrefixOk(EditText prefixEditText, EditText phoneNumberEditText) {
int arePhoneNumberAndPrefixOk(EditText prefixEditText, EditText phoneNumberEditText) {
String prefix = prefixEditText.getText().toString();
if (prefix.startsWith("+")) {
prefix = prefix.substring(1);
@ -251,7 +250,7 @@ public abstract class AssistantActivity extends ThemableActivity
return mAccountCreator.setPhoneNumber(phoneNumber, prefix);
}
protected String getErrorFromPhoneNumberStatus(int status) {
String getErrorFromPhoneNumberStatus(int status) {
AccountCreator.PhoneNumberStatus phoneNumberStatus =
AccountCreator.PhoneNumberStatus.fromInt(status);
switch (phoneNumberStatus) {

View file

@ -34,9 +34,9 @@ import org.linphone.R;
import org.linphone.core.DialPlan;
import org.linphone.core.Factory;
public class CountryAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private LayoutInflater mInflater;
class CountryAdapter extends BaseAdapter implements Filterable {
private final Context mContext;
private final LayoutInflater mInflater;
private final DialPlan[] mAllCountries;
private List<DialPlan> mFilteredCountries;

View file

@ -31,28 +31,24 @@ import android.widget.ListView;
import org.linphone.R;
import org.linphone.core.DialPlan;
public class CountryPicker {
private Context mContext;
private LayoutInflater mInflater;
private CountryAdapter mAdapter;
private ListView mList;
class CountryPicker {
private final LayoutInflater mInflater;
private final CountryAdapter mAdapter;
private EditText mSearch;
private ImageView mClear;
private CountryPickedListener mListener;
private final CountryPickedListener mListener;
public CountryPicker(Context context, CountryPickedListener listener) {
mContext = context;
mListener = listener;
mInflater = LayoutInflater.from(mContext);
mAdapter = new CountryAdapter(mContext, mInflater);
mInflater = LayoutInflater.from(context);
mAdapter = new CountryAdapter(context, mInflater);
}
private View createView() {
View view = mInflater.inflate(R.layout.assistant_country_list, null, false);
mList = view.findViewById(R.id.countryList);
mList.setAdapter(mAdapter);
mList.setOnItemClickListener(
ListView list = view.findViewById(R.id.countryList);
list.setAdapter(mAdapter);
list.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(
@ -85,8 +81,8 @@ public class CountryPicker {
});
mSearch.setText("");
mClear = view.findViewById(R.id.clear_field);
mClear.setOnClickListener(
ImageView clear = view.findViewById(R.id.clear_field);
clear.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -98,8 +94,7 @@ public class CountryPicker {
}
public View getView() {
View view = createView();
return view;
return createView();
}
public interface CountryPickedListener {

View file

@ -76,14 +76,12 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity
: "denied"));
}
switch (requestCode) {
case RECORD_AUDIO_PERMISSION_RESULT:
if (requestCode == RECORD_AUDIO_PERMISSION_RESULT) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startEchoCancellerCalibration();
} else {
// TODO: permission denied, display something to the user
}
break;
}
}
@ -111,7 +109,7 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity
}
private void startEchoCancellerCalibration() {
LinphoneManager.getLc()
LinphoneManager.getCore()
.addListener(
new CoreListenerStub() {
@Override
@ -119,13 +117,13 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity
Core core, EcCalibratorStatus status, int delayMs) {
if (status == EcCalibratorStatus.InProgress) return;
core.removeListener(this);
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
goToLinphoneActivity();
((AudioManager) getSystemService(Context.AUDIO_SERVICE))
.setMode(AudioManager.MODE_NORMAL);
}
});
LinphoneManager.getInstance().startEcCalibration();
LinphoneManager.getAudioManager().startEcCalibration();
}
}

View file

@ -30,7 +30,7 @@ import org.linphone.core.AccountCreatorListenerStub;
import org.linphone.core.tools.Log;
public class EmailAccountValidationAssistantActivity extends AssistantActivity {
private TextView mEmail, mFinishCreation;
private TextView mFinishCreation;
private AccountCreatorListenerStub mListener;
@ -40,8 +40,8 @@ public class EmailAccountValidationAssistantActivity extends AssistantActivity {
setContentView(R.layout.assistant_email_account_validation);
mEmail = findViewById(R.id.send_email);
mEmail.setText(mAccountCreator.getEmail());
TextView email = findViewById(R.id.send_email);
email.setText(mAccountCreator.getEmail());
mFinishCreation = findViewById(R.id.assistant_check);
mFinishCreation.setOnClickListener(

View file

@ -67,7 +67,7 @@ public class GenericConnectionAssistantActivity extends AssistantActivity implem
mTransport = findViewById(R.id.assistant_transports);
mAccountCreator =
LinphoneManager.getLcIfManagerNotDestroyedOrNull()
LinphoneManager.getCore()
.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl());
}
@ -76,7 +76,7 @@ public class GenericConnectionAssistantActivity extends AssistantActivity implem
mAccountCreator.setDomain(mDomain.getText().toString());
mAccountCreator.setPassword(mPassword.getText().toString());
mAccountCreator.setDisplayName(mDisplayName.getText().toString());
// TODO: mUserId
// TODO: add support for user-id in account creator
switch (mTransport.getCheckedRadioButtonId()) {
case R.id.transport_udp:

View file

@ -26,11 +26,9 @@ import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import org.linphone.R;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
public class MenuAssistantActivity extends AssistantActivity {
private TextView mAccountCreation, mAccountConnection, mGenericConnection, mRemoteConfiguration;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -38,10 +36,8 @@ public class MenuAssistantActivity extends AssistantActivity {
setContentView(R.layout.assistant_menu);
Log.e("###");
mAccountCreation = findViewById(R.id.account_creation);
mAccountCreation.setOnClickListener(
TextView accountCreation = findViewById(R.id.account_creation);
accountCreation.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -62,8 +58,8 @@ public class MenuAssistantActivity extends AssistantActivity {
}
});
mAccountConnection = findViewById(R.id.account_connection);
mAccountConnection.setOnClickListener(
TextView accountConnection = findViewById(R.id.account_connection);
accountConnection.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -74,11 +70,11 @@ public class MenuAssistantActivity extends AssistantActivity {
}
});
if (getResources().getBoolean(R.bool.hide_linphone_accounts_in_assistant)) {
mAccountConnection.setVisibility(View.GONE);
accountConnection.setVisibility(View.GONE);
}
mGenericConnection = findViewById(R.id.generic_connection);
mGenericConnection.setOnClickListener(
TextView genericConnection = findViewById(R.id.generic_connection);
genericConnection.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -89,11 +85,11 @@ public class MenuAssistantActivity extends AssistantActivity {
}
});
if (getResources().getBoolean(R.bool.hide_generic_accounts_in_assistant)) {
mGenericConnection.setVisibility(View.GONE);
genericConnection.setVisibility(View.GONE);
}
mRemoteConfiguration = findViewById(R.id.remote_configuration);
mRemoteConfiguration.setOnClickListener(
TextView remoteConfiguration = findViewById(R.id.remote_configuration);
remoteConfiguration.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -104,7 +100,7 @@ public class MenuAssistantActivity extends AssistantActivity {
}
});
if (getResources().getBoolean(R.bool.hide_remote_provisioning_in_assistant)) {
mRemoteConfiguration.setVisibility(View.GONE);
remoteConfiguration.setVisibility(View.GONE);
}
if (getResources().getBoolean(R.bool.assistant_use_linphone_login_as_first_fragment)) {

View file

@ -27,6 +27,7 @@ import androidx.annotation.Nullable;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.Factory;
import org.linphone.core.PayloadType;
import org.linphone.core.tools.Log;
import org.linphone.core.tools.OpenH264DownloadHelper;
@ -45,7 +46,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.assistant_openh264_codec_download);
mHelper = LinphoneManager.getInstance().getOpenH264DownloadHelper();
mHelper = Factory.instance().createOpenH264DownloadHelper(this);
LinphonePreferences.instance().setOpenH264CodecDownloadEnabled(false);
mProgress = findViewById(R.id.progress_bar);
@ -83,7 +84,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity {
mProgress.setMax(max);
mProgress.setProgress(current);
} else {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
core.reloadMsPlugins(getApplicationInfo().nativeLibraryDir);
enableH264();
@ -115,7 +116,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity {
}
private void enableH264() {
for (PayloadType pt : LinphoneManager.getLc().getVideoPayloadTypes()) {
for (PayloadType pt : LinphoneManager.getCore().getVideoPayloadTypes()) {
if (pt.getMimeType().equals("H264")) {
pt.enable(true);
break;

View file

@ -37,7 +37,6 @@ import org.linphone.core.tools.Log;
public class PhoneAccountCreationAssistantActivity extends AssistantActivity {
private TextView mCountryPicker, mError, mSipUri, mCreate;
private EditText mPrefix, mPhoneNumber;
private ImageView mPhoneNumberInfos;
private AccountCreatorListenerStub mListener;
@ -122,8 +121,8 @@ public class PhoneAccountCreationAssistantActivity extends AssistantActivity {
}
});
mPhoneNumberInfos = findViewById(R.id.info_phone_number);
mPhoneNumberInfos.setOnClickListener(
ImageView phoneNumberInfos = findViewById(R.id.info_phone_number);
phoneNumberInfos.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {

View file

@ -43,10 +43,8 @@ import org.linphone.core.tools.Log;
public class PhoneAccountLinkingAssistantActivity extends AssistantActivity {
private TextView mCountryPicker, mError, mLink;
private EditText mPrefix, mPhoneNumber;
private ImageView mPhoneNumberInfos;
private AccountCreatorListenerStub mListener;
private ProxyConfig mProxyConfig;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -56,7 +54,7 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity {
if (getIntent() != null && getIntent().hasExtra("AccountNumber")) {
int proxyConfigIndex = getIntent().getExtras().getInt("AccountNumber");
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core == null) {
Log.e("[Account Linking] Core not available");
unexpectedError();
@ -64,7 +62,7 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity {
ProxyConfig[] proxyConfigs = core.getProxyConfigList();
if (proxyConfigIndex >= 0 && proxyConfigIndex < proxyConfigs.length) {
mProxyConfig = proxyConfigs[proxyConfigIndex];
ProxyConfig mProxyConfig = proxyConfigs[proxyConfigIndex];
Address identity = mProxyConfig.getIdentityAddress();
if (identity == null) {
@ -160,8 +158,8 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity {
}
});
mPhoneNumberInfos = findViewById(R.id.info_phone_number);
mPhoneNumberInfos.setOnClickListener(
ImageView phoneNumberInfos = findViewById(R.id.info_phone_number);
phoneNumberInfos.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {

View file

@ -35,12 +35,12 @@ import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
public class PhoneAccountValidationAssistantActivity extends AssistantActivity {
private TextView mPhoneNumber, mFinishCreation;
private TextView mFinishCreation;
private EditText mSmsCode;
private ClipboardManager mClipboard;
private int mActivationCodeLength;
private boolean mIsLogin, mIsLinking;
private boolean mIsLinking;
private AccountCreatorListenerStub mListener;
@Override
@ -49,10 +49,8 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity {
setContentView(R.layout.assistant_phone_account_validation);
mIsLogin = mIsLinking = false;
if (getIntent() != null && getIntent().getBooleanExtra("isLoginVerification", false)) {
findViewById(R.id.title_account_creation).setVisibility(View.VISIBLE);
mIsLogin = true;
} else if (getIntent() != null
&& getIntent().getBooleanExtra("isLinkingVerification", false)) {
mIsLinking = true;
@ -64,8 +62,8 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity {
mActivationCodeLength =
getResources().getInteger(R.integer.phone_number_validation_code_length);
mPhoneNumber = findViewById(R.id.phone_number);
mPhoneNumber.setText(mAccountCreator.getPhoneNumber());
TextView phoneNumber = findViewById(R.id.phone_number);
phoneNumber.setText(mAccountCreator.getPhoneNumber());
mSmsCode = findViewById(R.id.sms_code);
mSmsCode.addTextChangedListener(
@ -124,7 +122,7 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity {
showGenericErrorDialog(status);
if (status.equals(AccountCreator.Status.WrongActivationCode)) {
// TODO
// TODO do something so the server re-send a SMS
}
}
}
@ -141,7 +139,7 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity {
showGenericErrorDialog(status);
if (status.equals(AccountCreator.Status.WrongActivationCode)) {
// TODO
// TODO do something so the server re-send a SMS
}
}
}

View file

@ -46,7 +46,7 @@ public class QrCodeConfigurationAssistantActivity extends AssistantActivity {
mListener =
new CoreListenerStub() {
@Override
public void onQrcodeFound(Core lc, String result) {
public void onQrcodeFound(Core core, String result) {
Intent resultIntent = new Intent();
resultIntent.putExtra("URL", result);
setResult(Activity.RESULT_OK, resultIntent);
@ -56,32 +56,40 @@ public class QrCodeConfigurationAssistantActivity extends AssistantActivity {
}
private void enableQrcodeReader(boolean enable) {
LinphoneManager.getLc().enableQrcodeVideoPreview(enable);
LinphoneManager.getLc().enableVideoPreview(enable);
Core core = LinphoneManager.getCore();
if (core == null) return;
core.enableQrcodeVideoPreview(enable);
core.enableVideoPreview(enable);
if (enable) {
LinphoneManager.getLc().addListener(mListener);
core.addListener(mListener);
} else {
LinphoneManager.getLc().removeListener(mListener);
core.removeListener(mListener);
}
}
private void setBackCamera() {
Core core = LinphoneManager.getCore();
if (core == null) return;
int camId = 0;
AndroidCameraConfiguration.AndroidCamera[] cameras =
AndroidCameraConfiguration.retrieveCameras();
for (AndroidCameraConfiguration.AndroidCamera androidCamera : cameras) {
if (!androidCamera.frontFacing) camId = androidCamera.id;
}
String[] devices = LinphoneManager.getLc().getVideoDevicesList();
String[] devices = core.getVideoDevicesList();
String newDevice = devices[camId];
LinphoneManager.getLc().setVideoDevice(newDevice);
core.setVideoDevice(newDevice);
}
private void launchQrcodeReader() {
LinphoneManager.getLc().setNativePreviewWindowId(mQrcodeView);
setBackCamera();
Core core = LinphoneManager.getCore();
if (core == null) return;
core.setNativePreviewWindowId(mQrcodeView);
setBackCamera();
enableQrcodeReader(true);
}

View file

@ -46,7 +46,7 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity {
private static final int QR_CODE_ACTIVITY_RESULT = 1;
private static final int CAMERA_PERMISSION_RESULT = 2;
private TextView mFetchAndApply, mQrCode;
private TextView mFetchAndApply;
private EditText mRemoteConfigurationUrl;
private RelativeLayout mWaitLayout;
@ -72,9 +72,9 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity {
mWaitLayout.setVisibility(View.VISIBLE);
mFetchAndApply.setEnabled(false);
LinphonePreferences.instance().setRemoteProvisioningUrl(url);
LinphoneManager.getLc().getConfig().sync();
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
core.getConfig().sync();
core.addListener(mListener);
}
LinphoneManager.getInstance().restartCore();
@ -106,8 +106,8 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity {
});
mRemoteConfigurationUrl.setText(LinphonePreferences.instance().getRemoteProvisioningUrl());
mQrCode = findViewById(R.id.qr_code);
mQrCode.setOnClickListener(
TextView qrCode = findViewById(R.id.qr_code);
qrCode.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -186,8 +186,7 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity {
: "denied"));
}
switch (requestCode) {
case CAMERA_PERMISSION_RESULT:
if (requestCode == CAMERA_PERMISSION_RESULT) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startActivityForResult(
new Intent(
@ -197,7 +196,6 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity {
} else {
// TODO: permission denied, display something to the user
}
break;
}
}
}

View file

@ -22,26 +22,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import org.linphone.core.CallParams;
public class BandwidthManager {
private static final int HIGH_RESOLUTION = 0;
private static final int LOW_RESOLUTION = 1;
private static final int LOW_BANDWIDTH = 2;
private static BandwidthManager sInstance;
private static final int currentProfile = HIGH_RESOLUTION;
private final int currentProfile = HIGH_RESOLUTION;
private BandwidthManager() {
public BandwidthManager() {
// FIXME register a listener on NetworkManager to get notified of network state
// FIXME register a listener on Preference to get notified of change in video enable value
// FIXME initially get those values
}
public static synchronized BandwidthManager getInstance() {
if (sInstance == null) sInstance = new BandwidthManager();
return sInstance;
}
public void destroy() {}
public void updateWithProfileSettings(CallParams callParams) {
if (callParams != null) { // in call

View file

@ -61,9 +61,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.activities.DialerActivity;
import org.linphone.activities.LinphoneGenericActivity;
import org.linphone.chat.ChatActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
@ -87,7 +89,6 @@ import org.linphone.fragments.StatusFragment;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.receivers.BluetoothManager;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.LinphoneGenericActivity;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
import org.linphone.views.Numpad;
@ -101,27 +102,28 @@ public class CallActivity extends LinphoneGenericActivity
private static final int PERMISSIONS_ENABLED_MIC = 204;
private static final int PERMISSIONS_EXTERNAL_STORAGE = 205;
private static CallActivity sInstance;
private static long sTimeRemind = 0;
private Handler mControlsHandler = new Handler();
private Runnable mControls;
private ImageView mSwitchCamera;
private TextView mMissedChats;
private RelativeLayout mActiveCallHeader, mSideMenuContent, mAvatarLayout;
private ImageView mPause,
mHangUp,
mDialer,
mVideo,
mMicro,
mSpeaker,
mOptions,
mAddCall,
mTransfer,
mConference,
mConferenceStatus,
mRecordCall,
mRecording;
private ImageView mAudioRoute, mRouteSpeaker, mRouteEarpiece, mRouteBluetooth, mMenu, mChat;
private ImageView mPause;
private ImageView mDialer;
private ImageView mVideo;
private ImageView mMicro;
private ImageView mSpeaker;
private ImageView mOptions;
private ImageView mAddCall;
private ImageView mTransfer;
private ImageView mConference;
private ImageView mConferenceStatus;
private ImageView mRecordCall;
private ImageView mRecording;
private ImageView mAudioRoute;
private ImageView mRouteSpeaker;
private ImageView mRouteEarpiece;
private ImageView mRouteBluetooth;
private LinearLayout mNoCurrentCall, mCallInfo, mCallPaused;
private ProgressBar mVideoProgress;
private StatusFragment mStatus;
@ -152,23 +154,15 @@ public class CallActivity extends LinphoneGenericActivity
private TimerTask mTask;
private HashMap<String, String> mEncoderTexts;
private HashMap<String, String> mDecoderTexts;
private CallListenerStub mCallListener;
private Call mCallDisplayedInStats;
private boolean mOldIsSpeakerEnabled = false;
public static CallActivity instance() {
return sInstance;
}
public static boolean isInstanciated() {
return sInstance != null;
}
private CallActivityInterface mCallInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sInstance = this;
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Compatibility.setShowWhenLocked(this, true);
@ -192,14 +186,14 @@ public class CallActivity extends LinphoneGenericActivity
mListener =
new CoreListenerStub() {
@Override
public void onMessageReceived(Core lc, ChatRoom cr, ChatMessage message) {
public void onMessageReceived(Core core, ChatRoom cr, ChatMessage message) {
displayMissedChats();
}
@Override
public void onCallStateChanged(
Core lc, final Call call, Call.State state, String message) {
if (LinphoneManager.getLc().getCallsNb() == 0) {
Core core, final Call call, Call.State state, String message) {
if (core.getCallsNb() == 0) {
finish();
return;
}
@ -210,7 +204,7 @@ public class CallActivity extends LinphoneGenericActivity
} else if (state == State.Paused
|| state == State.PausedByRemote
|| state == State.Pausing) {
if (LinphoneManager.getLc().getCurrentCall() != null) {
if (core.getCurrentCall() != null) {
mVideo.setEnabled(false);
}
if (isVideoEnabled(call)) {
@ -223,7 +217,7 @@ public class CallActivity extends LinphoneGenericActivity
showVideoView();
}
}
if (LinphoneManager.getLc().getCurrentCall() != null) {
if (core.getCurrentCall() != null) {
mVideo.setEnabled(true);
}
} else if (state == State.StreamsRunning) {
@ -250,19 +244,19 @@ public class CallActivity extends LinphoneGenericActivity
if (remoteVideo
&& !localVideo
&& !autoAcceptCameraPolicy
&& !LinphoneManager.getLc().isInConference()) {
&& !core.isInConference()) {
showAcceptCallUpdateDialog();
createTimerForDialog(SECONDS_BEFORE_DENYING_CALL_UPDATE);
}
}
refreshIncallUi();
mTransfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null);
mTransfer.setEnabled(core.getCurrentCall() != null);
}
@Override
public void onCallEncryptionChanged(
Core lc,
Core core,
final Call call,
boolean encrypted,
String authenticationToken) {
@ -281,8 +275,9 @@ public class CallActivity extends LinphoneGenericActivity
if (findViewById(R.id.fragmentContainer) != null) {
initUI();
if (LinphoneManager.getLc().getCallsNb() > 0) {
Call call = LinphoneManager.getLc().getCalls()[0];
Core core = LinphoneManager.getCore();
if (core.getCallsNb() > 0) {
Call call = core.getCalls()[0];
if (LinphoneUtils.isCallEstablished(call)) {
enableAndRefreshInCallActions();
@ -302,16 +297,16 @@ public class CallActivity extends LinphoneGenericActivity
refreshInCallActions();
return;
} else {
mIsSpeakerEnabled = LinphoneManager.getInstance().isSpeakerEnabled();
mIsMicMuted = !LinphoneManager.getLc().micEnabled();
mIsSpeakerEnabled = LinphoneManager.getAudioManager().isAudioRoutedToSpeaker();
mIsMicMuted = !core.micEnabled();
}
Fragment callFragment;
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
if (isVideoEnabled(core.getCurrentCall())) {
callFragment = new CallVideoFragment();
mVideoCallFragment = (CallVideoFragment) callFragment;
displayVideoCall(false);
LinphoneManager.getInstance().routeAudioToSpeaker();
LinphoneManager.getAudioManager().routeAudioToSpeaker();
mIsSpeakerEnabled = true;
} else {
callFragment = new CallAudioFragment();
@ -328,6 +323,24 @@ public class CallActivity extends LinphoneGenericActivity
.add(R.id.fragmentContainer, callFragment)
.commitAllowingStateLoss();
}
mCallInterface =
new CallActivityInterface() {
@Override
public void setSpeakerEnabled(boolean enable) {
CallActivity.this.setSpeakerEnabled(enable);
}
@Override
public void refreshInCallActions() {
CallActivity.this.refreshInCallActions();
}
@Override
public void resetCallControlsHidingTimer() {
CallActivity.this.resetCallControlsHidingTimer();
}
};
}
private void createTimerForDialog(long time) {
@ -356,13 +369,13 @@ public class CallActivity extends LinphoneGenericActivity
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("Speaker", LinphoneManager.getInstance().isSpeakerEnabled());
outState.putBoolean("Mic", !LinphoneManager.getLc().micEnabled());
super.onSaveInstanceState(outState);
outState.putBoolean("Speaker", LinphoneManager.getAudioManager().isAudioRoutedToSpeaker());
outState.putBoolean("Mic", !LinphoneManager.getCore().micEnabled());
outState.putBoolean("VideoCallPaused", mIsVideoCallPaused);
outState.putBoolean("AskingVideo", mIsVideoAsk);
outState.putLong("sTimeRemind", sTimeRemind);
if (mDialog != null) mDialog.dismiss();
super.onSaveInstanceState(outState);
}
private boolean isTablet() {
@ -394,7 +407,7 @@ public class CallActivity extends LinphoneGenericActivity
mOptions.setEnabled(false);
// BottonBar
mHangUp = findViewById(R.id.hang_up);
ImageView mHangUp = findViewById(R.id.hang_up);
mHangUp.setOnClickListener(this);
mDialer = findViewById(R.id.dialer);
@ -403,7 +416,7 @@ public class CallActivity extends LinphoneGenericActivity
mNumpad = findViewById(R.id.numpad);
mNumpad.getBackground().setAlpha(240);
mChat = findViewById(R.id.chat);
ImageView mChat = findViewById(R.id.chat);
mChat.setOnClickListener(this);
mMissedChats = findViewById(R.id.missed_chats);
@ -561,7 +574,7 @@ public class CallActivity extends LinphoneGenericActivity
private void createInCallStats() {
mSideMenu = findViewById(R.id.side_menu);
mMenu = findViewById(R.id.call_quality);
ImageView mMenu = findViewById(R.id.call_quality);
mSideMenuContent = findViewById(R.id.side_menu_content);
@ -577,9 +590,9 @@ public class CallActivity extends LinphoneGenericActivity
}
});
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
initCallStatsRefresher(lc.getCurrentCall(), findViewById(R.id.incall_stats));
Core core = LinphoneManager.getCore();
if (core != null) {
initCallStatsRefresher(core.getCurrentCall(), findViewById(R.id.incall_stats));
}
}
@ -590,16 +603,16 @@ public class CallActivity extends LinphoneGenericActivity
displayMissedChats();
}
public void setSpeakerEnabled(boolean enabled) {
private void setSpeakerEnabled(boolean enabled) {
mIsSpeakerEnabled = enabled;
}
public void refreshInCallActions() {
private void refreshInCallActions() {
if (!LinphonePreferences.instance().isVideoEnabled() || mIsConferenceRunning) {
mVideo.setEnabled(false);
} else {
if (mVideo.isEnabled()) {
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
if (isVideoEnabled(LinphoneManager.getCore().getCurrentCall())) {
mVideo.setSelected(true);
mVideoProgress.setVisibility(View.INVISIBLE);
} else {
@ -647,32 +660,29 @@ public class CallActivity extends LinphoneGenericActivity
private void enableAndRefreshInCallActions() {
int confsize = 0;
if (LinphoneManager.getLc().isInConference()) {
confsize =
LinphoneManager.getLc().getConferenceSize()
- (LinphoneManager.getLc().getConference() != null ? 1 : 0);
Core core = LinphoneManager.getCore();
if (core.isInConference()) {
confsize = core.getConferenceSize() - (core.getConference() != null ? 1 : 0);
}
// Enabled mTransfer button
mTransfer.setEnabled(mIsTransferAllowed && !LinphoneManager.getLc().soundResourcesLocked());
mTransfer.setEnabled(mIsTransferAllowed && !core.soundResourcesLocked());
// Enable mConference button
mConference.setEnabled(
LinphoneManager.getLc().getCallsNb() > 1
&& LinphoneManager.getLc().getCallsNb() > confsize
&& !LinphoneManager.getLc().soundResourcesLocked());
core.getCallsNb() > 1
&& core.getCallsNb() > confsize
&& !core.soundResourcesLocked());
mAddCall.setEnabled(
LinphoneManager.getLc().getCallsNb() < LinphoneManager.getLc().getMaxCalls()
&& !LinphoneManager.getLc().soundResourcesLocked());
mAddCall.setEnabled(core.getCallsNb() < core.getMaxCalls() && !core.soundResourcesLocked());
mOptions.setEnabled(
!getResources().getBoolean(R.bool.disable_options_in_call)
&& (mAddCall.isEnabled() || mTransfer.isEnabled()));
Call currentCall = LinphoneManager.getLc().getCurrentCall();
Call currentCall = core.getCurrentCall();
mRecordCall.setEnabled(
!LinphoneManager.getLc().soundResourcesLocked()
!core.soundResourcesLocked()
&& currentCall != null
&& currentCall.getCurrentParams().getRecordFile() != null);
mRecordCall.setSelected(mIsRecording);
@ -711,7 +721,7 @@ public class CallActivity extends LinphoneGenericActivity
+ (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (camera == PackageManager.PERMISSION_GRANTED) {
disableVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall()));
disableVideo(isVideoEnabled(LinphoneManager.getCore().getCurrentCall()));
} else {
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA);
}
@ -755,7 +765,7 @@ public class CallActivity extends LinphoneGenericActivity
} else if (id == R.id.recording) {
toggleCallRecording(false);
} else if (id == R.id.pause) {
pauseOrResumeCall(LinphoneManager.getLc().getCurrentCall());
pauseOrResumeCall(LinphoneManager.getCore().getCurrentCall());
} else if (id == R.id.hang_up) {
hangUp();
} else if (id == R.id.dialer) {
@ -784,14 +794,14 @@ public class CallActivity extends LinphoneGenericActivity
}
hideOrDisplayAudioRoutes();
} else if (id == R.id.route_earpiece) {
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
mIsSpeakerEnabled = false;
mRouteBluetooth.setSelected(false);
mRouteSpeaker.setSelected(false);
mRouteEarpiece.setSelected(true);
hideOrDisplayAudioRoutes();
} else if (id == R.id.route_speaker) {
LinphoneManager.getInstance().routeAudioToSpeaker();
LinphoneManager.getAudioManager().routeAudioToSpeaker();
mIsSpeakerEnabled = true;
mRouteBluetooth.setSelected(false);
mRouteSpeaker.setSelected(true);
@ -806,7 +816,7 @@ public class CallActivity extends LinphoneGenericActivity
}
private void toggleCallRecording(boolean enable) {
Call call = LinphoneManager.getLc().getCurrentCall();
Call call = LinphoneManager.getCore().getCurrentCall();
if (call == null) return;
@ -832,19 +842,20 @@ public class CallActivity extends LinphoneGenericActivity
}
private void disableVideo(final boolean videoDisabled) {
final Call call = LinphoneManager.getLc().getCurrentCall();
Core core = LinphoneManager.getCore();
final Call call = core.getCurrentCall();
if (call == null) {
return;
}
if (videoDisabled) {
CallParams params = LinphoneManager.getLc().createCallParams(call);
CallParams params = core.createCallParams(call);
params.enableVideo(false);
LinphoneManager.getLc().updateCall(call, params);
core.updateCall(call, params);
} else {
mVideoProgress.setVisibility(View.VISIBLE);
if (call.getRemoteParams() != null && !call.getRemoteParams().lowBandwidthEnabled()) {
LinphoneManager.getInstance().addVideo();
LinphoneManager.getCallManager().addVideo();
} else {
displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG);
}
@ -866,7 +877,7 @@ public class CallActivity extends LinphoneGenericActivity
}
private void switchVideo(final boolean displayVideo) {
final Call call = LinphoneManager.getLc().getCurrentCall();
final Call call = LinphoneManager.getCore().getCurrentCall();
if (call == null) {
return;
}
@ -878,7 +889,7 @@ public class CallActivity extends LinphoneGenericActivity
showAudioView();
} else {
if (!call.getRemoteParams().lowBandwidthEnabled()) {
LinphoneManager.getInstance().addVideo();
LinphoneManager.getCallManager().addVideo();
if (mVideoCallFragment == null || !mVideoCallFragment.isVisible()) showVideoView();
} else {
displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG);
@ -887,7 +898,7 @@ public class CallActivity extends LinphoneGenericActivity
}
private void showAudioView() {
if (LinphoneManager.getLc().getCurrentCall() != null) {
if (LinphoneManager.getCore().getCurrentCall() != null) {
if (!mIsSpeakerEnabled) {
LinphoneManager.getInstance().enableProximitySensing(true);
}
@ -901,7 +912,7 @@ public class CallActivity extends LinphoneGenericActivity
private void showVideoView() {
if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
Log.w("Bluetooth not available, using mSpeaker");
LinphoneManager.getInstance().routeAudioToSpeaker();
LinphoneManager.getAudioManager().routeAudioToSpeaker();
mIsSpeakerEnabled = true;
}
refreshInCallActions();
@ -963,40 +974,40 @@ public class CallActivity extends LinphoneGenericActivity
}
private void toggleMicro() {
Core lc = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
mIsMicMuted = !mIsMicMuted;
lc.enableMic(!mIsMicMuted);
core.enableMic(!mIsMicMuted);
mMicro.setSelected(mIsMicMuted);
}
private void toggleSpeaker() {
mIsSpeakerEnabled = !mIsSpeakerEnabled;
if (LinphoneManager.getLc().getCurrentCall() != null) {
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()))
Core core = LinphoneManager.getCore();
if (core.getCurrentCall() != null) {
if (isVideoEnabled(core.getCurrentCall()))
LinphoneManager.getInstance().enableProximitySensing(false);
else LinphoneManager.getInstance().enableProximitySensing(!mIsSpeakerEnabled);
}
mSpeaker.setSelected(mIsSpeakerEnabled);
if (mIsSpeakerEnabled) {
LinphoneManager.getInstance().routeAudioToSpeaker();
LinphoneManager.getInstance().enableSpeaker(mIsSpeakerEnabled);
LinphoneManager.getAudioManager().routeAudioToSpeaker();
} else {
Log.d("Toggle mSpeaker off, routing back to earpiece");
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
}
}
private void pauseOrResumeCall(Call call) {
Core lc = LinphoneManager.getLc();
if (call != null && LinphoneManager.getLc().getCurrentCall() == call) {
lc.pauseCall(call);
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
Core core = LinphoneManager.getCore();
if (call != null && core.getCurrentCall() == call) {
core.pauseCall(call);
if (isVideoEnabled(core.getCurrentCall())) {
mIsVideoCallPaused = true;
}
mPause.setSelected(true);
} else if (call != null) {
if (call.getState() == State.Paused) {
lc.resumeCall(call);
core.resumeCall(call);
if (mIsVideoCallPaused) {
mIsVideoCallPaused = false;
}
@ -1006,19 +1017,19 @@ public class CallActivity extends LinphoneGenericActivity
}
private void hangUp() {
Core lc = LinphoneManager.getLc();
Call currentCall = lc.getCurrentCall();
Core core = LinphoneManager.getCore();
Call currentCall = core.getCurrentCall();
if (mIsRecording) {
toggleCallRecording(false);
}
if (currentCall != null) {
lc.terminateCall(currentCall);
} else if (lc.isInConference()) {
lc.terminateConference();
core.terminateCall(currentCall);
} else if (core.isInConference()) {
core.terminateConference();
} else {
lc.terminateAllCalls();
core.terminateAllCalls();
}
}
@ -1047,17 +1058,18 @@ public class CallActivity extends LinphoneGenericActivity
if (mControlsLayout.getVisibility() != View.VISIBLE) {
displayVideoCall(true);
}
resetControlsHidingCallBack();
resetCallControlsHidingTimer();
}
}
public void resetControlsHidingCallBack() {
private void resetCallControlsHidingTimer() {
if (mControlsHandler != null && mControls != null) {
mControlsHandler.removeCallbacks(mControls);
}
mControls = null;
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()) && mControlsHandler != null) {
if (isVideoEnabled(LinphoneManager.getCore().getCurrentCall())
&& mControlsHandler != null) {
mControlsHandler.postDelayed(
mControls =
new Runnable() {
@ -1138,28 +1150,27 @@ public class CallActivity extends LinphoneGenericActivity
mConference.setVisibility(View.VISIBLE);
mRecordCall.setVisibility(View.VISIBLE);
mOptions.setSelected(true);
mTransfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null);
mTransfer.setEnabled(LinphoneManager.getCore().getCurrentCall() != null);
}
}
private void goBackToDialer() {
Intent intent = new Intent();
intent.setClass(this, LinphoneActivity.class);
intent.putExtra("AddCall", true);
intent.setClass(this, DialerActivity.class);
intent.putExtra("Transfer", false);
startActivity(intent);
}
private void goBackToDialerAndDisplayTransferButton() {
Intent intent = new Intent();
intent.setClass(this, LinphoneActivity.class);
intent.setClass(this, DialerActivity.class);
intent.putExtra("Transfer", true);
startActivity(intent);
}
private void goToChatList() {
Intent intent = new Intent();
intent.setClass(this, LinphoneActivity.class);
intent.putExtra("GoToChat", true);
intent.setClass(this, ChatActivity.class);
startActivity(intent);
}
@ -1168,19 +1179,20 @@ public class CallActivity extends LinphoneGenericActivity
mCountDownTimer.cancel();
}
Call call = LinphoneManager.getLc().getCurrentCall();
Core core = LinphoneManager.getCore();
Call call = core.getCurrentCall();
if (call == null) {
return;
}
CallParams params = LinphoneManager.getLc().createCallParams(call);
CallParams params = core.createCallParams(call);
if (accept) {
params.enableVideo(true);
LinphoneManager.getLc().enableVideoCapture(true);
LinphoneManager.getLc().enableVideoDisplay(true);
core.enableVideoCapture(true);
core.enableVideoDisplay(true);
}
LinphoneManager.getLc().acceptCallUpdate(call, params);
core.acceptCallUpdate(call, params);
}
private void hideStatusBar() {
@ -1273,27 +1285,26 @@ public class CallActivity extends LinphoneGenericActivity
@Override
protected void onResume() {
sInstance = this;
super.onResume();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
LinphoneManager.getCallManager().setCallInterface(mCallInterface);
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
mIsSpeakerEnabled = LinphoneManager.getInstance().isSpeakerEnabled();
mIsSpeakerEnabled = LinphoneManager.getAudioManager().isAudioRoutedToSpeaker();
refreshIncallUi();
handleViewIntent();
if (mStatus != null && lc != null) {
Call currentCall = lc.getCurrentCall();
if (mStatus != null && core != null) {
Call currentCall = core.getCurrentCall();
if (currentCall != null && !currentCall.getAuthenticationTokenVerified()) {
mStatus.showZRTPDialog(currentCall);
}
}
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
if (!isVideoEnabled(LinphoneManager.getCore().getCurrentCall())) {
if (!mIsSpeakerEnabled) {
LinphoneManager.getInstance().enableProximitySensing(true);
removeCallbacks();
@ -1304,7 +1315,7 @@ public class CallActivity extends LinphoneGenericActivity
private void handleViewIntent() {
Intent intent = getIntent();
if (intent != null && "android.intent.action.VIEW".equals(intent.getAction())) {
Call call = LinphoneManager.getLc().getCurrentCall();
Call call = LinphoneManager.getCore().getCurrentCall();
if (call != null && isVideoEnabled(call)) {
Player player = call.getPlayer();
String path = intent.getData().getPath();
@ -1330,10 +1341,11 @@ public class CallActivity extends LinphoneGenericActivity
@Override
protected void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
LinphoneManager.getCallManager().setCallInterface(null);
super.onPause();
@ -1360,9 +1372,8 @@ public class CallActivity extends LinphoneGenericActivity
if (mTimer != null) {
mTimer.cancel();
}
sInstance = null;
super.onDestroy();
System.gc();
}
private void unbindDrawables(View view) {
@ -1382,7 +1393,7 @@ public class CallActivity extends LinphoneGenericActivity
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (LinphoneUtils.onKeyVolumeAdjust(keyCode)) return true;
if (LinphoneManager.getAudioManager().onKeyVolumeAdjust(keyCode)) return true;
if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) return true;
return super.onKeyDown(keyCode, event);
}
@ -1475,9 +1486,6 @@ public class CallActivity extends LinphoneGenericActivity
|| call.getState() == State.PausedByRemote
|| call.getState() == State.Pausing) {
onCallStateChanged.setSelected(false);
} else if (call.getState() == State.OutgoingInit
|| call.getState() == State.OutgoingProgress
|| call.getState() == State.OutgoingRinging) {
}
}
@ -1503,20 +1511,21 @@ public class CallActivity extends LinphoneGenericActivity
}
private void refreshCallList() {
mIsConferenceRunning = LinphoneManager.getLc().isInConference();
Core core = LinphoneManager.getCore();
mIsConferenceRunning = core.isInConference();
List<Call> pausedCalls =
LinphoneUtils.getCallsInState(
LinphoneManager.getLc(), Collections.singletonList(State.PausedByRemote));
core, Collections.singletonList(State.PausedByRemote));
// MultiCalls
if (LinphoneManager.getLc().getCallsNb() > 1) {
if (core.getCallsNb() > 1) {
mCallsList.setVisibility(View.VISIBLE);
}
// Active call
if (LinphoneManager.getLc().getCurrentCall() != null) {
if (core.getCurrentCall() != null) {
displayNoCurrentCall(false);
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())
if (isVideoEnabled(core.getCurrentCall())
&& !mIsConferenceRunning
&& pausedCalls.size() == 0) {
displayVideoCall(false);
@ -1526,7 +1535,7 @@ public class CallActivity extends LinphoneGenericActivity
} else {
showAudioView();
displayNoCurrentCall(true);
if (LinphoneManager.getLc().getCallsNb() == 1) {
if (core.getCallsNb() == 1) {
mCallsList.setVisibility(View.VISIBLE);
}
}
@ -1542,19 +1551,18 @@ public class CallActivity extends LinphoneGenericActivity
mCallsList.removeAllViews();
int index = 0;
if (LinphoneManager.getLc().getCallsNb() == 0) {
if (core.getCallsNb() == 0) {
goBackToDialer();
return;
}
boolean isConfPaused = false;
for (Call call : LinphoneManager.getLc().getCalls()) {
for (Call call : core.getCalls()) {
if (call.getConference() != null && !mIsConferenceRunning) {
isConfPaused = true;
index++;
} else {
if (call != LinphoneManager.getLc().getCurrentCall()
&& call.getConference() == null) {
if (call != core.getCurrentCall() && call.getConference() == null) {
displayPausedCalls(call, index);
index++;
} else {
@ -1581,31 +1589,31 @@ public class CallActivity extends LinphoneGenericActivity
// Conference
private void exitConference(final Call call) {
Core lc = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
if (lc.isInConference()) {
lc.removeFromConference(call);
if (lc.getConferenceSize() <= 1) {
lc.leaveConference();
if (core.isInConference()) {
core.removeFromConference(call);
if (core.getConferenceSize() <= 1) {
core.leaveConference();
}
}
refreshIncallUi();
}
private void enterConference() {
LinphoneManager.getLc().addAllToConference();
LinphoneManager.getCore().addAllToConference();
}
private void pauseOrResumeConference() {
Core lc = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
mConferenceStatus = findViewById(R.id.conference_pause);
if (mConferenceStatus != null) {
if (lc.isInConference()) {
if (core.isInConference()) {
mConferenceStatus.setSelected(true);
lc.leaveConference();
core.leaveConference();
} else {
mConferenceStatus.setSelected(false);
lc.enterConference();
core.enterConference();
}
}
refreshCallList();
@ -1659,7 +1667,7 @@ public class CallActivity extends LinphoneGenericActivity
// Conference participant
int index = 1;
for (Call call : LinphoneManager.getLc().getCalls()) {
for (Call call : LinphoneManager.getCore().getCalls()) {
if (call.getConference() != null) {
displayConferenceParticipant(index, call);
index++;
@ -1672,7 +1680,11 @@ public class CallActivity extends LinphoneGenericActivity
}
private void displayMissedChats() {
int count = LinphoneManager.getInstance().getUnreadMessageCount();
int count = 0;
Core core = LinphoneManager.getCore();
if (core != null) {
count = core.getUnreadChatMessageCountFromActiveLocals();
}
if (count > 0) {
mMissedChats.setText(String.valueOf(count));
@ -1683,7 +1695,6 @@ public class CallActivity extends LinphoneGenericActivity
}
}
@SuppressWarnings("deprecation")
private void formatText(TextView tv, String name, String value) {
tv.setText(Html.fromHtml("<b>" + name + " </b>" + value));
}
@ -1692,7 +1703,7 @@ public class CallActivity extends LinphoneGenericActivity
String ret = mEncoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getLc().getMediastreamerFactory();
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getEncoderText(mime);
mEncoderTexts.put(mime, ret);
}
@ -1703,7 +1714,7 @@ public class CallActivity extends LinphoneGenericActivity
String ret = mDecoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getLc().getMediastreamerFactory();
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getDecoderText(mime);
mDecoderTexts.put(mime, ret);
}
@ -1751,16 +1762,16 @@ public class CallActivity extends LinphoneGenericActivity
formatText(
dl,
getString(R.string.call_stats_download),
String.valueOf((int) stats.getDownloadBandwidth()) + " kbits/s");
(int) stats.getDownloadBandwidth() + " kbits/s");
formatText(
ul,
getString(R.string.call_stats_upload),
String.valueOf((int) stats.getUploadBandwidth()) + " kbits/s");
(int) stats.getUploadBandwidth() + " kbits/s");
if (isVideo) {
formatText(
edl,
getString(R.string.call_stats_estimated_download),
String.valueOf(stats.getEstimatedDownloadBandwidth()) + " kbits/s");
stats.getEstimatedDownloadBandwidth() + " kbits/s");
}
formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString());
formatText(
@ -1854,10 +1865,10 @@ public class CallActivity extends LinphoneGenericActivity
final View videoLayout = view.findViewById(R.id.callStatsVideo);
final View audioLayout = view.findViewById(R.id.callStatsAudio);
mCallListener =
CallListenerStub mCallListener =
new CallListenerStub() {
public void onStateChanged(Call call, Call.State cstate, String message) {
if (cstate == Call.State.End || cstate == Call.State.Error) {
public void onStateChanged(Call call, State cstate, String message) {
if (cstate == State.End || cstate == State.Error) {
if (mTimer != null) {
Log.i(
"Call is terminated, stopping mCountDownTimer in charge of stats refreshing.");
@ -1901,11 +1912,9 @@ public class CallActivity extends LinphoneGenericActivity
new Runnable() {
@Override
public void run() {
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull()
== null) return;
synchronized (LinphoneManager.getLc()) {
if (LinphoneActivity.isInstanciated()
&& call.getState() != Call.State.Released) {
if (LinphoneManager.getCore() == null) return;
synchronized (LinphoneManager.getCore()) {
if (call.getState() != Call.State.Released) {
CallParams params = call.getCurrentParams();
if (params != null) {
CallStats audioStats =
@ -1984,6 +1993,14 @@ public class CallActivity extends LinphoneGenericActivity
mTimer.scheduleAtFixedRate(mTask, 0, 1000);
}
public interface CallActivityInterface {
void setSpeakerEnabled(boolean enable);
void refreshInCallActions();
void resetCallControlsHidingTimer();
}
//// Earset Connectivity Broadcast innerClass
public class HeadsetReceiver extends BroadcastReceiver {
@Override
@ -1993,13 +2010,13 @@ public class CallActivity extends LinphoneGenericActivity
switch (intent.getIntExtra("state", 0)) {
case 0:
if (mOldIsSpeakerEnabled) {
LinphoneManager.getInstance().routeAudioToSpeaker();
LinphoneManager.getAudioManager().routeAudioToSpeaker();
mIsSpeakerEnabled = true;
mSpeaker.setEnabled(true);
}
break;
case 1:
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
mOldIsSpeakerEnabled = mIsSpeakerEnabled;
mIsSpeakerEnabled = false;
mSpeaker.setEnabled(false);

View file

@ -33,9 +33,10 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.activities.LinphoneGenericActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
@ -46,7 +47,6 @@ import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.LinphoneGenericActivity;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.CallIncomingAnswerButton;
import org.linphone.views.CallIncomingButtonListener;
@ -54,26 +54,12 @@ import org.linphone.views.CallIncomingDeclineButton;
import org.linphone.views.ContactAvatar;
public class CallIncomingActivity extends LinphoneGenericActivity {
private static CallIncomingActivity sInstance;
private TextView mName, mNumber;
private ImageView mAcceptIcon;
private CallIncomingAnswerButton mAccept;
private CallIncomingDeclineButton mDecline;
private Call mCall;
private CoreListenerStub mListener;
private boolean mAlreadyAcceptedOrDeniedCall;
private KeyguardManager mKeyguardManager;
private TextureView mVideoDisplay;
public static CallIncomingActivity instance() {
return sInstance;
}
public static boolean isInstanciated() {
return sInstance != null;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -87,9 +73,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
mNumber = findViewById(R.id.contact_number);
mVideoDisplay = findViewById(R.id.videoSurface);
mAccept = findViewById(R.id.answer_button);
mDecline = findViewById(R.id.decline_button);
mAcceptIcon = findViewById(R.id.acceptIcon);
CallIncomingAnswerButton mAccept = findViewById(R.id.answer_button);
CallIncomingDeclineButton mDecline = findViewById(R.id.decline_button);
ImageView mAcceptIcon = findViewById(R.id.acceptIcon);
lookupCurrentCall();
if (LinphonePreferences.instance() != null
@ -100,7 +86,8 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
mAcceptIcon.setImageResource(R.drawable.call_video_start);
}
mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager mKeyguardManager =
(KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean doNotUseSliders =
getResources()
.getBoolean(
@ -133,35 +120,23 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core lc, Call call, State state, String message) {
Core core, Call call, State state, String message) {
if (call == mCall && State.End == state) {
finish();
} else if (state == State.Connected) {
startActivity(
new Intent(CallIncomingActivity.this, CallActivity.class));
} else if (state == State.StreamsRunning) {
Log.e(
"CallIncommingActivity - onCreate - State.StreamsRunning - speaker = "
+ LinphoneManager.getInstance().isSpeakerEnabled());
// The following should not be needed except some devices need it (e.g.
// Galaxy S).
LinphoneManager.getInstance()
.enableSpeaker(
LinphoneManager.getInstance().isSpeakerEnabled());
}
}
};
sInstance = this;
}
@Override
protected void onResume() {
super.onResume();
sInstance = this;
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
mAlreadyAcceptedOrDeniedCall = false;
@ -204,32 +179,26 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
@Override
protected void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
sInstance = null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (LinphoneManager.isInstanciated()
if (LinphoneService.isReady()
&& (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)) {
LinphoneManager.getLc().terminateCall(mCall);
LinphoneManager.getCore().terminateCall(mCall);
finish();
}
return super.onKeyDown(keyCode, event);
}
private void lookupCurrentCall() {
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
for (Call call : LinphoneManager.getLc().getCalls()) {
if (LinphoneManager.getCore() != null) {
for (Call call : LinphoneManager.getCore().getCalls()) {
if (State.IncomingReceived == call.getState()
|| State.IncomingEarlyMedia == call.getState()) {
mCall = call;
@ -245,7 +214,7 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
}
mAlreadyAcceptedOrDeniedCall = true;
LinphoneManager.getLc().terminateCall(mCall);
LinphoneManager.getCore().terminateCall(mCall);
finish();
}
@ -255,15 +224,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
}
mAlreadyAcceptedOrDeniedCall = true;
if (!LinphoneManager.getInstance().acceptCall(mCall)) {
if (!LinphoneManager.getCallManager().acceptCall(mCall)) {
// the above method takes care of Samsung Galaxy S
Toast.makeText(this, R.string.couldnt_accept_call, Toast.LENGTH_LONG).show();
} else {
if (!LinphoneActivity.isInstanciated()) {
return;
}
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneActivity.instance().startIncallActivity();
}
}
@ -284,10 +247,21 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
"[Permission] Camera permission is "
+ (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int readPhoneState =
getPackageManager()
.checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName());
Log.i(
"[Permission] Read phone state permission is "
+ (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
Log.i("[Permission] Asking for record audio");
permissionsList.add(Manifest.permission.RECORD_AUDIO);
}
if (readPhoneState != PackageManager.PERMISSION_GRANTED) {
Log.i("[Permission] Asking for read phone state");
permissionsList.add(Manifest.permission.READ_PHONE_STATE);
}
if (LinphonePreferences.instance().shouldInitiateVideoCall()
|| LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) {
if (camera != PackageManager.PERMISSION_GRANTED) {

View file

@ -19,31 +19,42 @@ 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.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.widget.Toast;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.CallParams;
import org.linphone.core.Core;
import org.linphone.core.MediaEncryption;
import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.mediastream.Version;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.FileUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.AddressType;
/** Handle call updating, reinvites. */
public class CallManager {
private Context mContext;
private boolean mHandsetON = false;
private CallActivity.CallActivityInterface mCallInterface;
private BandwidthManager mBandwidthManager;
private static CallManager sInstance;
public static synchronized CallManager getInstance() {
if (sInstance == null) sInstance = new CallManager();
return sInstance;
public CallManager(Context context) {
mContext = context;
mBandwidthManager = new BandwidthManager();
}
private CallManager() {}
private BandwidthManager getBandwidthManager() {
return BandwidthManager.getInstance();
public void destroy() {
mBandwidthManager.destroy();
}
public void inviteAddress(Address lAddress, boolean forceZRTP) {
@ -54,16 +65,12 @@ public class CallManager {
inviteAddress(lAddress, false, isLowBandwidthConnection, forceZRTP);
}
public void inviteAddress(Address lAddress) {
inviteAddress(lAddress, false);
}
public void inviteAddress(
private void inviteAddress(
Address lAddress, boolean videoEnabled, boolean lowBandwidth, boolean forceZRTP) {
Core lc = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
CallParams params = lc.createCallParams(null);
getBandwidthManager().updateWithProfileSettings(params);
CallParams params = core.createCallParams(null);
mBandwidthManager.updateWithProfileSettings(params);
if (videoEnabled && params.videoEnabled()) {
params.enableVideo(true);
@ -73,7 +80,7 @@ public class CallManager {
if (lowBandwidth) {
params.enableLowBandwidth(true);
Log.d("Low bandwidth enabled in call params");
Log.d("[Call Manager] Low bandwidth enabled in call params");
}
if (forceZRTP) {
@ -81,11 +88,10 @@ public class CallManager {
}
String recordFile =
FileUtils.getCallRecordingFilename(
LinphoneManager.getInstance().getContext(), lAddress);
FileUtils.getCallRecordingFilename(LinphoneService.instance(), lAddress);
params.setRecordFile(recordFile);
lc.inviteAddressWithParams(lAddress, params);
core.inviteAddressWithParams(lAddress, params);
}
public void inviteAddress(Address lAddress, boolean videoEnabled, boolean lowBandwidth) {
@ -99,18 +105,18 @@ public class CallManager {
* @return if updateCall called
*/
public boolean reinviteWithVideo() {
Core lc = LinphoneManager.getLc();
Call lCall = lc.getCurrentCall();
if (lCall == null) {
Log.e("Trying to reinviteWithVideo while not in call: doing nothing");
Core core = LinphoneManager.getCore();
Call call = core.getCurrentCall();
if (call == null) {
Log.e("[Call Manager] Trying to reinviteWithVideo while not in call: doing nothing");
return false;
}
CallParams params = lc.createCallParams(lCall);
CallParams params = core.createCallParams(call);
if (params.videoEnabled()) return false;
// Check if video possible regarding bandwidth limitations
getBandwidthManager().updateWithProfileSettings(params);
mBandwidthManager.updateWithProfileSettings(params);
// Abort if not enough bandwidth...
if (!params.videoEnabled()) {
@ -118,7 +124,7 @@ public class CallManager {
}
// Not yet in video call: try to re-invite with video
lc.updateCall(lCall, params);
core.updateCall(call, params);
return true;
}
@ -128,14 +134,174 @@ public class CallManager {
* is recreated and setParameters is called.
*/
public void updateCall() {
Core lc = LinphoneManager.getLc();
Call lCall = lc.getCurrentCall();
if (lCall == null) {
Log.e("Trying to updateCall while not in call: doing nothing");
Core core = LinphoneManager.getCore();
Call call = core.getCurrentCall();
if (call == null) {
Log.e("[Call Manager] Trying to updateCall while not in call: doing nothing");
return;
}
CallParams params = lc.createCallParams(lCall);
getBandwidthManager().updateWithProfileSettings(params);
lc.updateCall(lCall, null);
CallParams params = core.createCallParams(call);
mBandwidthManager.updateWithProfileSettings(params);
core.updateCall(call, null);
}
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;
}
}
}
LinphonePreferences preferences = LinphonePreferences.instance();
Core core = LinphoneManager.getCore();
Address address;
address = core.interpretUrl(to); // InterpretUrl does normalizePhoneNumber
if (address == null) {
Log.e("[Call Manager] Couldn't convert to String to Address : " + to);
return;
}
ProxyConfig lpc = core.getDefaultProxyConfig();
if (mContext.getResources().getBoolean(R.bool.forbid_self_call)
&& lpc != null
&& address.weakEqual(lpc.getIdentityAddress())) {
return;
}
address.setDisplayName(displayName);
boolean isLowBandwidthConnection =
!LinphoneUtils.isHighBandwidthConnection(
LinphoneService.instance().getApplicationContext());
if (core.isNetworkReachable()) {
if (Version.isVideoCapable()) {
boolean prefVideoEnable = preferences.isVideoEnabled();
boolean prefInitiateWithVideo = preferences.shouldInitiateVideoCall();
inviteAddress(
address,
prefVideoEnable && prefInitiateWithVideo,
isLowBandwidthConnection);
} else {
inviteAddress(address, false, isLowBandwidthConnection);
}
} else {
Toast.makeText(
mContext,
mContext.getString(R.string.error_network_unreachable),
Toast.LENGTH_LONG)
.show();
Log.e(
"[Call Manager] Error: "
+ mContext.getString(R.string.error_network_unreachable));
}
}
private void enableCamera(Call call, boolean enable) {
if (call != null) {
call.enableCamera(enable);
if (mContext.getResources().getBoolean(R.bool.enable_call_notification))
LinphoneService.instance()
.getNotificationManager()
.displayCallNotification(LinphoneManager.getCore().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 (Settings.SettingNotFoundException e) {
Log.e("[Call Manager] playDtmf exception: " + e);
}
LinphoneManager.getCore().playDtmf(dtmf, -1);
}
private void terminateCall() {
Core core = LinphoneManager.getCore();
if (core.inCall()) {
core.terminateCall(core.getCurrentCall());
}
}
/** @return false if already in video call. */
public boolean addVideo() {
Call call = LinphoneManager.getCore().getCurrentCall();
enableCamera(call, true);
return reinviteWithVideo();
}
public boolean acceptCall(Call call) {
if (call == null) return false;
Core core = LinphoneManager.getCore();
CallParams params = core.createCallParams(call);
boolean isLowBandwidthConnection =
!LinphoneUtils.isHighBandwidthConnection(
LinphoneService.instance().getApplicationContext());
if (params != null) {
params.enableLowBandwidth(isLowBandwidthConnection);
params.setRecordFile(
FileUtils.getCallRecordingFilename(mContext, call.getRemoteAddress()));
} else {
Log.e("[Call Manager] Could not create call params for call");
return false;
}
core.acceptCallWithParams(call, params);
return true;
}
public void setCallInterface(CallActivity.CallActivityInterface callInterface) {
mCallInterface = callInterface;
}
public void resetCallControlsHidingTimer() {
if (mCallInterface != null) {
mCallInterface.resetCallControlsHidingTimer();
}
}
public void refreshInCallActions() {
if (mCallInterface != null) {
mCallInterface.refreshInCallActions();
}
}
public void setHandsetMode(Boolean on) {
if (mHandsetON == on) return;
Core core = LinphoneManager.getCore();
if (core.isIncomingInvitePending() && on) {
mHandsetON = true;
acceptCall(core.getCurrentCall());
} else if (on && mCallInterface != null) {
mHandsetON = true;
mCallInterface.setSpeakerEnabled(true);
mCallInterface.refreshInCallActions();
} else if (!on) {
mHandsetON = false;
terminateCall();
}
}
}

View file

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Gravity;
@ -34,9 +35,10 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.activities.LinphoneGenericActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
@ -47,13 +49,13 @@ import org.linphone.core.CoreListenerStub;
import org.linphone.core.Reason;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.LinphoneGenericActivity;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
public class CallOutgoingActivity extends LinphoneGenericActivity implements OnClickListener {
private TextView mName, mNumber;
private ImageView mMicro, mSpeaker, mHangUp;
private ImageView mMicro;
private ImageView mSpeaker;
private Call mCall;
private CoreListenerStub mListener;
private boolean mIsMicMuted, mIsSpeakerEnabled;
@ -76,21 +78,15 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
mSpeaker = findViewById(R.id.speaker);
mSpeaker.setOnClickListener(this);
mHangUp = findViewById(R.id.outgoing_hang_up);
mHangUp.setOnClickListener(this);
ImageView hangUp = findViewById(R.id.outgoing_hang_up);
hangUp.setOnClickListener(this);
mListener =
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core lc, Call call, Call.State state, String message) {
if (call == mCall && State.Connected == state) {
if (!LinphoneActivity.isInstanciated()) {
return;
}
LinphoneActivity.instance().startIncallActivity();
return;
} else if (state == State.Error) {
Core core, Call call, Call.State state, String message) {
if (state == State.Error) {
// Convert Core message for internalization
if (call.getErrorInfo().getReason() == Reason.Declined) {
displayCustomToast(
@ -125,9 +121,12 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
Toast.LENGTH_SHORT);
decline();
}
} else if (state == State.Connected) {
startActivity(
new Intent(CallOutgoingActivity.this, CallActivity.class));
}
if (LinphoneManager.getLc().getCallsNb() == 0) {
if (LinphoneManager.getCore().getCallsNb() == 0) {
finish();
}
}
@ -137,16 +136,16 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
@Override
protected void onResume() {
super.onResume();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
mCall = null;
// Only one call ringing at a time is allowed
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
for (Call call : LinphoneManager.getLc().getCalls()) {
if (LinphoneManager.getCore() != null) {
for (Call call : LinphoneManager.getCore().getCalls()) {
State cstate = call.getState();
if (State.OutgoingInit == cstate
|| State.OutgoingProgress == cstate
@ -155,13 +154,6 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
mCall = call;
break;
}
if (State.StreamsRunning == cstate) {
if (!LinphoneActivity.isInstanciated()) {
return;
}
LinphoneActivity.instance().startIncallActivity();
return;
}
}
}
if (mCall == null) {
@ -191,9 +183,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
@Override
protected void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
super.onPause();
}
@ -205,12 +197,16 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
if (id == R.id.micro) {
mIsMicMuted = !mIsMicMuted;
mMicro.setSelected(mIsMicMuted);
LinphoneManager.getLc().enableMic(!mIsMicMuted);
LinphoneManager.getCore().enableMic(!mIsMicMuted);
}
if (id == R.id.speaker) {
mIsSpeakerEnabled = !mIsSpeakerEnabled;
mSpeaker.setSelected(mIsSpeakerEnabled);
LinphoneManager.getInstance().enableSpeaker(mIsSpeakerEnabled);
if (mIsSpeakerEnabled) {
LinphoneManager.getAudioManager().routeAudioToSpeaker();
} else {
LinphoneManager.getAudioManager().routeAudioToEarPiece();
}
}
if (id == R.id.outgoing_hang_up) {
decline();
@ -219,9 +215,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (LinphoneManager.isInstanciated()
if (LinphoneService.isReady()
&& (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)) {
LinphoneManager.getLc().terminateCall(mCall);
LinphoneManager.getCore().terminateCall(mCall);
finish();
}
return super.onKeyDown(keyCode, event);
@ -242,7 +238,7 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
}
private void decline() {
LinphoneManager.getLc().terminateCall(mCall);
LinphoneManager.getCore().terminateCall(mCall);
finish();
}
@ -263,10 +259,21 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
"[Permission] Camera permission is "
+ (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int readPhoneState =
getPackageManager()
.checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName());
Log.i(
"[Permission] Read phone state permission is "
+ (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
Log.i("[Permission] Asking for record audio");
permissionsList.add(Manifest.permission.RECORD_AUDIO);
}
if (readPhoneState != PackageManager.PERMISSION_GRANTED) {
Log.i("[Permission] Asking for read phone state");
permissionsList.add(Manifest.permission.READ_PHONE_STATE);
}
if (LinphonePreferences.instance().shouldInitiateVideoCall()
|| LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) {
if (camera != PackageManager.PERMISSION_GRANTED) {

View file

@ -55,13 +55,12 @@ public class CallVideoFragment extends Fragment
private CallActivity mInCallActivity;
private int mPreviewX, mPreviewY;
@SuppressWarnings("deprecation")
// Warning useless because value is ignored and automatically set by new APIs.
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view;
if (LinphoneManager.getLc().hasCrappyOpengl()) {
Core core = LinphoneManager.getCore();
if (core.hasCrappyOpengl()) {
view = inflater.inflate(R.layout.video_no_opengl, container, false);
} else {
view = inflater.inflate(R.layout.video, container, false);
@ -70,8 +69,8 @@ public class CallVideoFragment extends Fragment
mVideoView = view.findViewById(R.id.videoSurface);
mCaptureView = view.findViewById(R.id.videoCaptureSurface);
LinphoneManager.getLc().setNativeVideoWindowId(mVideoView);
LinphoneManager.getLc().setNativePreviewWindowId(mCaptureView);
core.setNativeVideoWindowId(mVideoView);
core.setNativePreviewWindowId(mCaptureView);
mVideoView.setOnTouchListener(
new OnTouchListener() {
@ -131,11 +130,11 @@ public class CallVideoFragment extends Fragment
}
private void resizePreview() {
Core lc = LinphoneManager.getLc();
if (lc.getCallsNb() > 0) {
Call call = lc.getCurrentCall();
Core core = LinphoneManager.getCore();
if (core.getCallsNb() > 0) {
Call call = core.getCurrentCall();
if (call == null) {
call = lc.getCalls()[0];
call = core.getCalls()[0];
}
if (call == null) return;
@ -151,7 +150,7 @@ public class CallVideoFragment extends Fragment
if (videoSize.getWidth() == 0 || videoSize.getHeight() == 0) {
Log.w(
"[Video Fragment] Couldn't get sent video definition, using default video definition");
videoSize = lc.getPreferredVideoDefinition();
videoSize = core.getPreferredVideoDefinition();
}
int width = videoSize.getWidth();
int height = videoSize.getHeight();
@ -177,8 +176,9 @@ public class CallVideoFragment extends Fragment
public void switchCamera() {
try {
String currentDevice = LinphoneManager.getLc().getVideoDevice();
String[] devices = LinphoneManager.getLc().getVideoDevicesList();
Core core = LinphoneManager.getCore();
String currentDevice = core.getVideoDevice();
String[] devices = core.getVideoDevicesList();
int index = 0;
for (String d : devices) {
if (d.equals(currentDevice)) {
@ -191,9 +191,9 @@ public class CallVideoFragment extends Fragment
if (index == 1) newDevice = devices[0];
else if (devices.length > 1) newDevice = devices[1];
else newDevice = devices[index];
LinphoneManager.getLc().setVideoDevice(newDevice);
core.setVideoDevice(newDevice);
CallManager.getInstance().updateCall();
LinphoneManager.getCallManager().updateCall();
} catch (ArithmeticException ae) {
Log.e("[Video Fragment] Cannot swtich camera : no camera");
}
@ -216,11 +216,11 @@ public class CallVideoFragment extends Fragment
@Override
public void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (LinphonePreferences.instance().isOverlayEnabled()
&& lc != null
&& lc.getCurrentCall() != null) {
Call call = lc.getCurrentCall();
&& core != null
&& core.getCurrentCall() != null) {
Call call = core.getCurrentCall();
if (call.getState() == Call.State.StreamsRunning) {
// Prevent overlay creation if video call is paused by remote
LinphoneService.instance().createOverlay();
@ -244,7 +244,7 @@ public class CallVideoFragment extends Fragment
0.1f,
Math.min(mZoomFactor, Math.max(portraitZoomFactor, landscapeZoomFactor)));
Call currentCall = LinphoneManager.getLc().getCurrentCall();
Call currentCall = LinphoneManager.getCore().getCurrentCall();
if (currentCall != null) {
currentCall.zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
return true;
@ -254,7 +254,8 @@ public class CallVideoFragment extends Fragment
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (LinphoneUtils.isCallEstablished(LinphoneManager.getLc().getCurrentCall())) {
Core core = LinphoneManager.getCore();
if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) {
if (mZoomFactor > 1) {
// Video is zoomed, slide is used to change center of zoom
if (distanceX > 0 && mZoomCenterX < 1) {
@ -273,9 +274,7 @@ public class CallVideoFragment extends Fragment
if (mZoomCenterY > 1) mZoomCenterY = 1;
if (mZoomCenterY < 0) mZoomCenterY = 0;
LinphoneManager.getLc()
.getCurrentCall()
.zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
return true;
}
}
@ -285,7 +284,8 @@ public class CallVideoFragment extends Fragment
@Override
public boolean onDoubleTap(MotionEvent e) {
if (LinphoneUtils.isCallEstablished(LinphoneManager.getLc().getCurrentCall())) {
Core core = LinphoneManager.getCore();
if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) {
if (mZoomFactor == 1.f) {
// Zoom to make the video fill the screen vertically
float portraitZoomFactor =
@ -301,7 +301,7 @@ public class CallVideoFragment extends Fragment
resetZoom();
}
LinphoneManager.getLc().getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
return true;
}

View file

@ -0,0 +1,293 @@
package org.linphone.chat;
/*
ChatActivity.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.Fragment;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import org.linphone.R;
import org.linphone.activities.MainActivity;
import org.linphone.contacts.ContactAddress;
import org.linphone.core.Address;
import org.linphone.core.Factory;
import org.linphone.core.tools.Log;
import org.linphone.utils.FileUtils;
public class ChatActivity extends MainActivity {
private String mSharedText, mSharedFiles;
@Override
protected void onCreate(Bundle savedInstanceState) {
getIntent().putExtra("Activity", "Chat");
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
if (currentFragment == null) {
if (getIntent() != null && getIntent().getExtras() != null) {
Bundle extras = getIntent().getExtras();
if (isTablet() || !extras.containsKey("RemoteSipUri")) {
showChatRooms();
}
handleRemoteSipUriInIntentExtras(extras);
// Remove the SIP Uri from the intent so a click on chat button will go back to list
getIntent().removeExtra("RemoteSipUri");
} else {
showChatRooms();
if (isTablet()) {
showEmptyChildFragment();
}
}
}
handleIntentExtras(getIntent());
}
@Override
protected void onResume() {
super.onResume();
mChatSelected.setVisibility(View.VISIBLE);
}
@Override
protected void onPause() {
super.onPause();
getIntent().setAction("");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("SharedText", mSharedText);
outState.putString("SharedFiles", mSharedFiles);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mSharedText = savedInstanceState.getString("SharedText", null);
mSharedFiles = savedInstanceState.getString("SharedFiles", null);
}
@Override
public void goBack() {
// 1 is for the empty fragment on tablets
if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) {
if (popBackStack()) {
return;
}
}
super.goBack();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// Clean fragments stack upon return
while (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
}
handleIntentExtras(intent);
}
private void handleIntentExtras(Intent intent) {
if (intent == null) return;
String sharedText = null;
String sharedFiles = null;
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if (("text/plain").equals(type) && intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
Log.i("[Chat Activity] ACTION_SEND with text/plain data: " + sharedText);
} else {
Uri fileUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
sharedFiles = FileUtils.getFilePath(this, fileUri);
Log.i("[Chat Activity] ACTION_SEND with file: " + sharedFiles);
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
if (type.startsWith("image/")) {
ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
StringBuilder filePaths = new StringBuilder();
for (Uri uri : imageUris) {
filePaths.append(FileUtils.getFilePath(this, uri));
filePaths.append(":");
}
sharedFiles = filePaths.toString();
Log.i("[Chat Activity] ACTION_SEND_MULTIPLE with files: " + sharedFiles);
}
} else {
if (intent.getExtras() != null) {
Bundle extras = intent.getExtras();
handleRemoteSipUriInIntentExtras(extras);
} else {
// If there is no extras, make sure the chat rooms list fragment is displayed
Fragment currentFragment =
getFragmentManager().findFragmentById(R.id.fragmentContainer);
if (currentFragment == null || !(currentFragment instanceof ChatRoomsFragment)) {
showChatRooms();
}
}
}
if (sharedText != null || sharedFiles != null) {
mSharedText = sharedText;
mSharedFiles = sharedFiles;
Toast.makeText(this, R.string.toast_choose_chat_room_for_sharing, Toast.LENGTH_LONG)
.show();
Log.i("[Chat Activity] Sharing arguments found: " + mSharedText + " / " + mSharedFiles);
}
}
private void handleRemoteSipUriInIntentExtras(Bundle extras) {
if (extras == null) return;
if (extras.containsKey("RemoteSipUri")) {
String remoteSipUri = extras.getString("RemoteSipUri", null);
String localSipUri = extras.getString("LocalSipUri", null);
Address localAddress = null;
Address remoteAddress = null;
if (localSipUri != null) {
localAddress = Factory.instance().createAddress(localSipUri);
}
if (remoteSipUri != null) {
remoteAddress = Factory.instance().createAddress(remoteSipUri);
}
// Don't make it a child on smartphones to have a working back button
showChatRoom(localAddress, remoteAddress, isTablet());
}
}
private void showChatRooms() {
ChatRoomsFragment fragment = new ChatRoomsFragment();
changeFragment(fragment, "Chat rooms", false);
}
private void showChatRoom(Address localAddress, Address peerAddress, boolean isChild) {
Bundle extras = new Bundle();
if (localAddress != null) {
extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly());
}
if (peerAddress != null) {
extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly());
}
if (mSharedText != null) {
extras.putString("SharedText", mSharedText);
mSharedText = null;
}
if (mSharedFiles != null) {
extras.putString("SharedFiles", mSharedFiles);
mSharedFiles = null;
}
ChatMessagesFragment fragment = new ChatMessagesFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Chat room", isChild);
}
public void showChatRoom(Address localAddress, Address peerAddress) {
showChatRoom(localAddress, peerAddress, true);
}
public void showImdn(Address localAddress, Address peerAddress, String messageId) {
Bundle extras = new Bundle();
if (localAddress != null) {
extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly());
}
if (peerAddress != null) {
extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly());
}
extras.putString("MessageId", messageId);
ImdnFragment fragment = new ImdnFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Chat message IMDN", true);
}
public void showDevices(Address localAddress, Address peerAddress) {
showDevices(localAddress, peerAddress, true);
}
private void showDevices(Address localAddress, Address peerAddress, boolean isChild) {
Bundle extras = new Bundle();
if (localAddress != null) {
extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly());
}
if (peerAddress != null) {
extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly());
}
DevicesFragment fragment = new DevicesFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Chat room devices", isChild);
}
public void showChatRoomCreation(
Address peerAddress,
ArrayList<ContactAddress> participants,
String subject,
boolean encrypted,
boolean isGroupChatRoom) {
Bundle extras = new Bundle();
if (peerAddress != null) {
extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly());
}
extras.putSerializable("Participants", participants);
extras.putString("Subject", subject);
extras.putBoolean("Encrypted", encrypted);
extras.putBoolean("IsGroupChatRoom", isGroupChatRoom);
ChatRoomCreationFragment fragment = new ChatRoomCreationFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Chat room creation", true);
}
public void showChatRoomGroupInfo(
Address peerAddress,
ArrayList<ContactAddress> participants,
String subject,
boolean encrypted) {
Bundle extras = new Bundle();
if (peerAddress != null) {
extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly());
}
extras.putSerializable("Participants", participants);
extras.putString("Subject", subject);
extras.putBoolean("Encrypted", encrypted);
GroupInfoFragment fragment = new GroupInfoFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Chat room group info", true);
}
}

View file

@ -1,107 +0,0 @@
package org.linphone.chat;
/*
ChatMessageViewHolder.java
Copyright (C) 2017 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.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.linphone.R;
public class ChatMessageOldViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
public final LinearLayout eventLayout;
public final TextView eventMessage;
public final RelativeLayout bubbleLayout;
public final LinearLayout separatorLayout;
public final LinearLayout background;
public final RelativeLayout avatarLayout;
public final TextView contactName;
public final ImageView messageStatus;
public final ProgressBar messageSendingInProgress;
public final LinearLayout imdmLayout;
public final ImageView imdmIcon;
public final TextView imdmLabel;
public final TextView messageText;
public final ImageView messageImage;
public final RelativeLayout fileTransferLayout;
public final ProgressBar fileTransferProgressBar;
public final Button fileTransferAction;
public final TextView fileName;
public final Button openFileButton;
public final CheckBox delete;
private ChatMessageViewHolderClickListener mListener;
public ChatMessageOldViewHolder(View view, ChatMessageViewHolderClickListener listener) {
this(view);
mListener = listener;
view.setOnClickListener(this);
}
public ChatMessageOldViewHolder(View view) {
super(view);
eventLayout = view.findViewById(R.id.event);
// eventTime = view.findViewById(R.id.event_date);
eventMessage = view.findViewById(R.id.event_text);
bubbleLayout = view.findViewById(R.id.bubble);
background = view.findViewById(R.id.background);
avatarLayout = view.findViewById(R.id.avatar_layout);
contactName = view.findViewById(R.id.contact_header);
messageStatus = view.findViewById(R.id.status);
messageSendingInProgress = view.findViewById(R.id.inprogress);
imdmLayout = view.findViewById(R.id.imdmLayout);
imdmIcon = view.findViewById(R.id.imdmIcon);
imdmLabel = view.findViewById(R.id.imdmText);
messageText = view.findViewById(R.id.message);
messageImage = view.findViewById(R.id.image);
separatorLayout = view.findViewById(R.id.separator);
fileTransferLayout = view.findViewById(R.id.file_transfer_layout);
fileTransferProgressBar = view.findViewById(R.id.progress_bar);
fileTransferAction = view.findViewById(R.id.file_transfer_action);
fileName = view.findViewById(R.id.file_name);
openFileButton = view.findViewById(R.id.open_file);
delete = view.findViewById(R.id.delete_message);
}
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onItemClicked(getAdapterPosition());
}
}
}

View file

@ -45,7 +45,6 @@ import com.google.android.flexbox.FlexboxLayout;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
@ -71,13 +70,14 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi
public final LinearLayout background;
public final RelativeLayout avatarLayout;
public final ProgressBar downloadInProgress, sendInProgress;
private final ProgressBar downloadInProgress;
public final ProgressBar sendInProgress;
public final TextView timeText;
public final ImageView outgoingImdn;
public final TextView messageText;
private final ImageView outgoingImdn;
private final TextView messageText;
public final FlexboxLayout multiFileContents;
public final RelativeLayout singleFileContent;
private final FlexboxLayout multiFileContents;
private final RelativeLayout singleFileContent;
public final CheckBox delete;
@ -92,7 +92,7 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi
view.setOnClickListener(this);
}
public ChatMessageViewHolder(View view) {
private ChatMessageViewHolder(View view) {
super(view);
eventLayout = view.findViewById(R.id.event);
eventMessage = view.findViewById(R.id.event_text);
@ -174,8 +174,7 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi
background.setBackgroundResource(R.drawable.chat_bubble_incoming_full);
// Can't anchor incoming messages, setting this to align max width with LIME icon
bubbleLayout.setPadding(
0, 0, (int) ImageUtils.dpToPixels(LinphoneActivity.instance(), 18), 0);
bubbleLayout.setPadding(0, 0, (int) ImageUtils.dpToPixels(mContext, 18), 0);
if (status == ChatMessage.State.FileTransferInProgress) {
downloadInProgress.setVisibility(View.VISIBLE);
@ -325,7 +324,8 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi
} else {
Log.w(
"WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file");
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
((ChatActivity) mContext)
.requestPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
}
}

View file

@ -20,8 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import static android.content.Context.INPUT_METHOD_SERVICE;
import static org.linphone.fragments.FragmentsAvailable.CHAT;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
@ -61,11 +61,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.call.CallManager;
import org.linphone.call.CallActivity;
import org.linphone.contacts.ContactAddress;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.ContactsUpdatedListener;
@ -103,7 +102,9 @@ public class ChatMessagesFragment extends Fragment
private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS";
private final Handler mHandler = new Handler(Looper.getMainLooper());
private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton;
private ImageView mCallButton;
private ImageView mBackToCallButton;
private ImageView mGroupInfosButton;
private ImageView mAttachImageButton, mSendMessageButton;
private TextView mRoomLabel, mParticipantsLabel, mSipUriLabel, mRemoteComposing;
private RichEditText mMessageTextToSend;
@ -114,20 +115,15 @@ public class ChatMessagesFragment extends Fragment
private Context mContext;
private ViewTreeObserver.OnGlobalLayoutListener mKeyboardListener;
private Uri mImageToUploadUri;
private ChatMessagesAdapter mEventsAdapter;
private ChatMessagesOldAdapter mOldEventsAdapter;
private String mLocalSipUri, mRemoteSipUri;
private String mRemoteSipUri;
private Address mLocalSipAddress, mRemoteSipAddress, mRemoteParticipantAddress;
private ChatRoom mChatRoom;
private ArrayList<LinphoneContact> mParticipants;
private LinearLayoutManager layoutManager;
private int mContextMenuMessagePosition;
private ChatScrollListener mChatScrollListener;
private LinearLayout mTopBar;
private ImageView mChatRoomSecurityLevel;
private InputContentInfoCompat mCurrentInputContentInfo;
private int mCurrentFlags;
@Override
public View onCreateView(
@ -138,12 +134,12 @@ public class ChatMessagesFragment extends Fragment
if (getArguments() != null) {
if (getArguments().getString("LocalSipUri") != null) {
mLocalSipUri = getArguments().getString("LocalSipUri");
mLocalSipAddress = LinphoneManager.getLc().createAddress(mLocalSipUri);
String mLocalSipUri = getArguments().getString("LocalSipUri");
mLocalSipAddress = Factory.instance().createAddress(mLocalSipUri);
}
if (getArguments().getString("RemoteSipUri") != null) {
mRemoteSipUri = getArguments().getString("RemoteSipUri");
mRemoteSipAddress = LinphoneManager.getLc().createAddress(mRemoteSipUri);
mRemoteSipAddress = Factory.instance().createAddress(mRemoteSipUri);
}
}
@ -173,36 +169,34 @@ public class ChatMessagesFragment extends Fragment
if (oneParticipantOneDevice) {
ParticipantDevice device =
mChatRoom.getParticipants()[0].getDevices()[0];
CallManager.getInstance().inviteAddress(device.getAddress(), true);
LinphoneManager.getCallManager()
.inviteAddress(device.getAddress(), true);
} else {
LinphoneActivity.instance()
.goToContactDevicesInfos(mLocalSipUri, mRemoteSipUri);
((ChatActivity) getActivity())
.showDevices(mLocalSipAddress, mRemoteSipAddress);
}
}
}
});
mBackButton = view.findViewById(R.id.back);
if (getResources().getBoolean(R.bool.isTablet)) {
mBackButton.setVisibility(View.INVISIBLE);
} else {
mBackButton.setOnClickListener(
ImageView backButton = view.findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneActivity.instance().goToChatList();
((ChatActivity) getActivity()).goBack();
}
});
}
backButton.setVisibility(
getResources().getBoolean(R.bool.isTablet) ? View.INVISIBLE : View.VISIBLE);
mCallButton = view.findViewById(R.id.start_call);
mCallButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneActivity.instance()
.setAddresGoToDialerAndCall(
mRemoteParticipantAddress.asString(), null);
LinphoneManager.getCallManager()
.newOutgoingCall(mRemoteParticipantAddress.asString(), null);
}
});
@ -211,8 +205,7 @@ public class ChatMessagesFragment extends Fragment
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneActivity.instance()
.resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
startActivity(new Intent(getActivity(), CallActivity.class));
}
});
@ -233,20 +226,18 @@ public class ChatMessagesFragment extends Fragment
c.setFullName(displayName);
}
ContactAddress ca =
new ContactAddress(
c, a.asString(), "", c.isFriend(), p.isAdmin());
new ContactAddress(c, a.asString(), "", p.isAdmin());
participants.add(ca);
}
LinphoneActivity.instance()
.goToChatGroupInfos(
mRemoteSipAddress.asString(),
boolean encrypted =
mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt());
((ChatActivity) getActivity())
.showChatRoomGroupInfo(
mRemoteSipAddress,
participants,
mChatRoom.getSubject(),
mChatRoom.getMe() != null && mChatRoom.getMe().isAdmin(),
false,
null,
mChatRoom.hasCapability(
ChatRoomCapabilities.Encrypted.toInt()));
encrypted);
}
});
@ -261,7 +252,10 @@ public class ChatMessagesFragment extends Fragment
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneActivity.instance().checkAndRequestPermissionsToSendImage();
String[] permissions = {
Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE
};
((ChatActivity) getActivity()).requestPermissionsIfNotGranted(permissions);
pickFile();
}
});
@ -308,21 +302,21 @@ public class ChatMessagesFragment extends Fragment
mChatEventsList = view.findViewById(R.id.chat_message_list);
mSelectionHelper = new SelectableHelper(view, this);
layoutManager =
LinearLayoutManager layoutManager =
new LinphoneLinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, true);
mChatEventsList.setLayoutManager(layoutManager);
mChatScrollListener =
ChatScrollListener chatScrollListener =
new ChatScrollListener(layoutManager) {
@Override
public void onLoadMore(int totalItemsCount) {
loadMoreData(totalItemsCount);
}
};
mChatEventsList.addOnScrollListener(mChatScrollListener);
mChatEventsList.addOnScrollListener(chatScrollListener);
if (getArguments() != null) {
String fileSharedUri = getArguments().getString("fileSharedUri");
String fileSharedUri = getArguments().getString("SharedFiles");
if (fileSharedUri != null) {
Log.i("[ChatMessages] Found shared file(s): " + fileSharedUri);
if (fileSharedUri.contains(":")) {
@ -335,8 +329,8 @@ public class ChatMessagesFragment extends Fragment
}
}
if (getArguments().getString("messageDraft") != null) {
String sharedText = getArguments().getString("messageDraft");
if (getArguments().containsKey("SharedText")) {
String sharedText = getArguments().getString("SharedText");
mMessageTextToSend.setText(sharedText);
Log.i("[ChatMessages] Found shared text: " + sharedText);
}
@ -353,9 +347,6 @@ public class ChatMessagesFragment extends Fragment
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(CHAT);
}
ContactsManager.getInstance().addContactsListener(this);
addVirtualKeyboardVisiblityListener();
@ -375,32 +366,18 @@ public class ChatMessagesFragment extends Fragment
initChatRoom();
displayChatRoomHeader();
displayChatRoomHistory();
LinphoneManager.getInstance().setCurrentChatRoomAddress(mRemoteSipAddress);
if (LinphoneManager.getInstance().hasLastCallSasBeenRejected()) {
LinphoneManager.getInstance().lastCallSasRejected(false);
LinphoneUtils.showTrustDeniedDialog(getActivity());
}
}
public void changeDisplayedChat(String localSipUri, String remoteSipUri) {
mLocalSipUri = localSipUri;
mLocalSipAddress = LinphoneManager.getLc().createAddress(mLocalSipUri);
mRemoteSipUri = remoteSipUri;
mRemoteSipAddress = LinphoneManager.getLc().createAddress(mRemoteSipUri);
initChatRoom();
displayChatRoomHeader();
displayChatRoomHistory();
LinphoneManager.getInstance().setCurrentChatRoomAddress(mRemoteSipAddress);
LinphoneService.instance()
.getNotificationManager()
.setCurrentlyDisplayedChatRoom(
mRemoteSipAddress != null ? mRemoteSipAddress.asStringUriOnly() : null);
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
removeVirtualKeyboardVisiblityListener();
LinphoneManager.getInstance().setCurrentChatRoomAddress(null);
LinphoneService.instance().getNotificationManager().setCurrentlyDisplayedChatRoom(null);
if (mChatRoom != null) mChatRoom.removeListener(this);
if (mChatEventsList.getAdapter() != null)
((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).clear();
@ -466,16 +443,6 @@ public class ChatMessagesFragment extends Fragment
public void onDeleteSelection(Object[] objectsToDelete) {
for (Object obj : objectsToDelete) {
EventLog eventLog = (EventLog) obj;
if (eventLog.getType() == EventLog.Type.ConferenceChatMessage) {
ChatMessage message = eventLog.getChatMessage();
if (message.getAppdata() != null && !message.isOutgoing()) {
File file = new File(message.getAppdata());
if (file.exists()) {
// Delete downloaded file from incoming message that will be deleted
file.delete();
}
}
}
eventLog.deleteFromDatabase();
}
if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
@ -492,13 +459,8 @@ public class ChatMessagesFragment extends Fragment
ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (mContext.getResources().getBoolean(R.bool.use_new_chat_bubbles_layout)) {
ChatMessageViewHolder holder = (ChatMessageViewHolder) v.getTag();
mContextMenuMessagePosition = holder.getAdapterPosition();
} else {
ChatMessageOldViewHolder holder = (ChatMessageOldViewHolder) v.getTag();
mContextMenuMessagePosition = holder.getAdapterPosition();
}
EventLog event =
(EventLog)
@ -559,8 +521,7 @@ public class ChatMessagesFragment extends Fragment
return true;
}
if (item.getItemId() == R.id.imdn_infos) {
LinphoneActivity.instance()
.goToChatMessageImdnInfos(mLocalSipUri, mRemoteSipUri, messageId);
((ChatActivity) getActivity()).showImdn(mLocalSipAddress, mRemoteSipAddress, messageId);
return true;
}
if (item.getItemId() == R.id.copy_text) {
@ -582,13 +543,8 @@ public class ChatMessagesFragment extends Fragment
if (item.getItemId() == R.id.add_to_contacts) {
Address address = message.getFromAddress();
if (address == null) return true;
String uri = address.getUsername() + "@" + address.getDomain(); // Get a clean address
if (address.getDisplayName() != null) {
LinphoneActivity.instance()
.displayContactsForEdition(uri, address.getDisplayName());
} else {
LinphoneActivity.instance().displayContactsForEdition(uri);
}
address.clean();
((ChatActivity) getActivity()).showContactsListForCreationOrEdition(address);
return true;
}
return super.onContextItemSelected(item);
@ -682,16 +638,16 @@ public class ChatMessagesFragment extends Fragment
}
private void showKeyboardVisibleMode() {
LinphoneActivity.instance().hideTabBar(true);
LinphoneActivity.instance().hideStatusBar();
((ChatActivity) getActivity()).hideTabBar();
((ChatActivity) getActivity()).hideStatusBar();
mTopBar.setVisibility(View.GONE);
}
private void hideKeyboardVisibleMode() {
LinphoneActivity.instance()
.hideTabBar(
getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views));
LinphoneActivity.instance().showStatusBar();
if (getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views)) {
((ChatActivity) getActivity()).showTabBar();
}
((ChatActivity) getActivity()).showStatusBar();
mTopBar.setVisibility(View.VISIBLE);
}
@ -740,7 +696,7 @@ public class ChatMessagesFragment extends Fragment
mChatRoom.removeListener(this);
}
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (mRemoteSipAddress == null
|| mRemoteSipUri == null
|| mRemoteSipUri.length() == 0
@ -756,8 +712,8 @@ public class ChatMessagesFragment extends Fragment
}
mChatRoom.addListener(this);
mChatRoom.markAsRead();
LinphoneManager.getInstance().updateUnreadCountForChatRoom(mChatRoom, 0);
LinphoneActivity.instance().refreshMissedChatCountDisplay();
((ChatActivity) getActivity()).displayMissedChats();
mRemoteParticipantAddress = mRemoteSipAddress;
if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())
@ -771,7 +727,7 @@ public class ChatMessagesFragment extends Fragment
}
private void displayChatRoomHeader() {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core == null || mChatRoom == null) return;
if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
@ -846,6 +802,7 @@ public class ChatMessagesFragment extends Fragment
private void displayChatRoomHistory() {
if (mChatRoom == null) return;
ChatMessagesAdapter mEventsAdapter;
if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
mEventsAdapter =
new ChatMessagesAdapter(
@ -855,14 +812,6 @@ public class ChatMessagesFragment extends Fragment
mChatRoom.getHistoryMessageEvents(MESSAGES_PER_PAGE),
mParticipants,
this);
mOldEventsAdapter =
new ChatMessagesOldAdapter(
this,
mSelectionHelper,
R.layout.chat_bubble_old,
mChatRoom.getHistoryMessageEvents(MESSAGES_PER_PAGE),
mParticipants,
this);
} else {
mEventsAdapter =
new ChatMessagesAdapter(
@ -872,28 +821,16 @@ public class ChatMessagesFragment extends Fragment
mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE),
mParticipants,
this);
mOldEventsAdapter =
new ChatMessagesOldAdapter(
this,
mSelectionHelper,
R.layout.chat_bubble_old,
mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE),
mParticipants,
this);
}
if (mContext.getResources().getBoolean(R.bool.use_new_chat_bubbles_layout)) {
mSelectionHelper.setAdapter(mEventsAdapter);
mChatEventsList.setAdapter(mEventsAdapter);
} else {
mSelectionHelper.setAdapter(mOldEventsAdapter);
mChatEventsList.setAdapter(mOldEventsAdapter);
}
scrollToBottom();
}
private void showSecurityDialog(boolean oneParticipantOneDevice) {
final Dialog dialog =
LinphoneActivity.instance().displayDialog(getString(R.string.lime_security_popup));
((ChatActivity) getActivity())
.displayDialog(getString(R.string.lime_security_popup));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
delete.setVisibility(View.GONE);
Button ok = dialog.findViewById(R.id.dialog_ok_button);
@ -926,10 +863,11 @@ public class ChatMessagesFragment extends Fragment
if (oneParticipantOneDevice) {
ParticipantDevice device =
mChatRoom.getParticipants()[0].getDevices()[0];
CallManager.getInstance().inviteAddress(device.getAddress(), true);
LinphoneManager.getCallManager()
.inviteAddress(device.getAddress(), true);
} else {
LinphoneActivity.instance()
.goToContactDevicesInfos(mLocalSipUri, mRemoteSipUri);
((ChatActivity) getActivity())
.showDevices(mLocalSipAddress, mRemoteSipAddress);
}
dialog.dismiss();
@ -960,31 +898,8 @@ public class ChatMessagesFragment extends Fragment
}
}
/** File transfer related */
@Override
public void onSaveInstanceState(Bundle outState) {
if (mFilesUploadLayout != null) {
String files[] = new String[mFilesUploadLayout.getChildCount()];
for (int i = 0; i < mFilesUploadLayout.getChildCount(); i++) {
View child = mFilesUploadLayout.getChildAt(i);
String path = (String) child.getTag();
files[i] = path;
}
outState.putStringArray("Files", files);
}
if (mCurrentInputContentInfo != null) {
outState.putParcelable(
INPUT_CONTENT_INFO_KEY, (Parcelable) mCurrentInputContentInfo.unwrap());
outState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags);
}
mCurrentInputContentInfo = null;
mCurrentFlags = 0;
super.onSaveInstanceState(outState);
}
private void onRestoreInstanceState(Bundle savedInstanceState) {
String files[] = savedInstanceState.getStringArray("Files");
String[] files = savedInstanceState.getStringArray("Files");
if (files != null && files.length > 0) {
for (String file : files) {
if (FileUtils.isExtensionImage(file)) {
@ -1011,9 +926,7 @@ public class ChatMessagesFragment extends Fragment
new File(
FileUtils.getStorageDirectory(mContext),
getString(R.string.temp_photo_name_with_date)
.replace(
"%s",
String.valueOf(System.currentTimeMillis()) + ".jpeg"));
.replace("%s", System.currentTimeMillis() + ".jpeg"));
mImageToUploadUri = Uri.fromFile(file);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageToUploadUri);
cameraIntents.add(captureIntent);
@ -1202,37 +1115,9 @@ public class ChatMessagesFragment extends Fragment
final Address from = msg.getFromAddress();
final LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(from);
if (LinphoneActivity.instance().isOnBackground()) {
if (!getResources().getBoolean(R.bool.disable_chat_message_notification)) {
if (contact != null) {
LinphoneService.instance()
.getNotificationManager()
.displayMessageNotification(
from.asStringUriOnly(),
contact.getFullName(),
contact.getThumbnailUri(),
getString(R.string.message_cant_be_decrypted_notif),
cr.getLocalAddress(),
msg.getTime(),
null,
null);
} else {
LinphoneService.instance()
.getNotificationManager()
.displayMessageNotification(
from.asStringUriOnly(),
from.getUsername(),
null,
getString(R.string.message_cant_be_decrypted_notif),
cr.getLocalAddress(),
msg.getTime(),
null,
null);
}
}
} else if (LinphoneManager.getLc().limeEnabled() == LimeState.Mandatory) {
if (LinphoneManager.getCore().limeEnabled() == LimeState.Mandatory) {
final Dialog dialog =
LinphoneActivity.instance()
((ChatActivity) getActivity())
.displayDialog(
getString(R.string.message_cant_be_decrypted)
.replace(
@ -1248,7 +1133,7 @@ public class ChatMessagesFragment extends Fragment
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneManager.getInstance()
LinphoneManager.getCallManager()
.newOutgoingCall(
from.asStringUriOnly(),
(contact != null)
@ -1272,8 +1157,7 @@ public class ChatMessagesFragment extends Fragment
@Override
public void onChatMessageReceived(ChatRoom cr, EventLog event) {
cr.markAsRead();
LinphoneManager.getInstance().updateUnreadCountForChatRoom(mChatRoom, 0);
LinphoneActivity.instance().refreshMissedChatCountDisplay();
((ChatActivity) getActivity()).displayMissedChats();
ChatMessage msg = event.getChatMessage();
if (msg.getErrorInfo() != null
@ -1290,7 +1174,8 @@ public class ChatMessagesFragment extends Fragment
String externalBodyUrl = msg.getExternalBodyUrl();
Content fileTransferContent = msg.getFileTransferInformation();
if (externalBodyUrl != null || fileTransferContent != null) {
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
((ChatActivity) getActivity())
.requestPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).addToHistory(event);
@ -1433,6 +1318,8 @@ public class ChatMessagesFragment extends Fragment
@Override
public void onContactsUpdated() {
getContactsForParticipants();
displayChatRoomHeader();
mChatEventsList.getAdapter().notifyDataSetChanged();
}
@Override
@ -1481,7 +1368,6 @@ public class ChatMessagesFragment extends Fragment
}
mCurrentInputContentInfo = inputContentInfo;
mCurrentFlags = flags;
return true;
}

View file

@ -1,662 +0,0 @@
package org.linphone.chat;
/*
ChatMessagesAdapter.java
Copyright (C) 2017 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.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatMessageListenerStub;
import org.linphone.core.Content;
import org.linphone.core.EventLog;
import org.linphone.core.LimeState;
import org.linphone.core.tools.Log;
import org.linphone.utils.FileUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.utils.SelectableAdapter;
import org.linphone.utils.SelectableHelper;
import org.linphone.views.AsyncBitmap;
import org.linphone.views.BitmapWorkerTask;
import org.linphone.views.ContactAvatar;
public class ChatMessagesOldAdapter extends SelectableAdapter<ChatMessageOldViewHolder>
implements ChatMessagesGenericAdapter {
private static final int MARGIN_BETWEEN_MESSAGES = 10;
private static final int SIDE_MARGIN = 100;
private final Context mContext;
private List<EventLog> mHistory;
private List<LinphoneContact> mParticipants;
private final int mItemResource;
private Bitmap mDefaultBitmap;
private final ChatMessagesFragment mFragment;
private final ChatMessageListenerStub mListener;
private final ChatMessageViewHolderClickListener mClickListener;
public ChatMessagesOldAdapter(
ChatMessagesFragment fragment,
SelectableHelper helper,
int itemResource,
EventLog[] history,
ArrayList<LinphoneContact> participants,
ChatMessageViewHolderClickListener clickListener) {
super(helper);
mFragment = fragment;
mContext = mFragment.getActivity();
mItemResource = itemResource;
mHistory = new ArrayList<>(Arrays.asList(history));
Collections.reverse(mHistory);
mParticipants = participants;
mClickListener = clickListener;
mListener =
new ChatMessageListenerStub() {
@Override
public void onFileTransferProgressIndication(
ChatMessage message, Content content, int offset, int total) {
ChatMessageOldViewHolder holder =
(ChatMessageOldViewHolder) message.getUserData();
if (holder == null) return;
if (offset == total) {
holder.fileTransferProgressBar.setVisibility(View.GONE);
holder.fileTransferAction.setVisibility(View.GONE);
holder.fileTransferLayout.setVisibility(View.GONE);
displayAttachedFile(message, holder);
} else {
holder.fileTransferProgressBar.setVisibility(View.VISIBLE);
holder.fileTransferProgressBar.setProgress(offset * 100 / total);
}
}
@Override
public void onMsgStateChanged(ChatMessage message, ChatMessage.State state) {
if (state == ChatMessage.State.FileTransferDone) {
if (!message.isOutgoing()) {
message.setAppdata(message.getFileTransferFilepath());
}
message.setFileTransferFilepath(
null); // Not needed anymore, will help differenciate between
// InProgress states for file transfer / message sending
}
for (int i = 0; i < mHistory.size(); i++) {
EventLog log = mHistory.get(i);
if (log.getType() == EventLog.Type.ConferenceChatMessage
&& log.getChatMessage() == message) {
notifyItemChanged(i);
break;
}
}
}
};
}
@Override
public ChatMessageOldViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(mItemResource, parent, false);
ChatMessageOldViewHolder VH = new ChatMessageOldViewHolder(v, mClickListener);
// Allows onLongClick ContextMenu on bubbles
mFragment.registerForContextMenu(v);
v.setTag(VH);
return VH;
}
@Override
public void onBindViewHolder(@NonNull final ChatMessageOldViewHolder holder, int position) {
final EventLog event = mHistory.get(position);
holder.eventLayout.setVisibility(View.GONE);
holder.bubbleLayout.setVisibility(View.GONE);
holder.delete.setVisibility(isEditionEnabled() ? View.VISIBLE : View.GONE);
holder.messageText.setVisibility(View.GONE);
holder.messageImage.setVisibility(View.GONE);
holder.fileTransferLayout.setVisibility(View.GONE);
holder.fileTransferProgressBar.setProgress(0);
holder.fileTransferAction.setEnabled(true);
holder.fileName.setVisibility(View.GONE);
holder.openFileButton.setVisibility(View.GONE);
holder.messageStatus.setVisibility(View.INVISIBLE);
holder.messageSendingInProgress.setVisibility(View.GONE);
holder.imdmLayout.setVisibility(View.INVISIBLE);
if (isEditionEnabled()) {
holder.delete.setOnCheckedChangeListener(null);
holder.delete.setChecked(isSelected(position));
holder.delete.setTag(position);
}
if (event.getType() == EventLog.Type.ConferenceChatMessage) {
holder.bubbleLayout.setVisibility(View.VISIBLE);
final ChatMessage message = event.getChatMessage();
if (position > 0
&& mContext.getResources()
.getBoolean(R.bool.lower_space_between_chat_bubbles_if_same_person)) {
EventLog previousEvent = (EventLog) getItem(position - 1);
if (previousEvent.getType() == EventLog.Type.ConferenceChatMessage) {
ChatMessage previousMessage = previousEvent.getChatMessage();
if (previousMessage.getFromAddress().weakEqual(message.getFromAddress())) {
holder.separatorLayout.setVisibility(View.GONE);
}
} else {
// No separator if previous event is not a message
holder.separatorLayout.setVisibility(View.GONE);
}
}
message.setUserData(holder);
message.addListener(mListener);
RelativeLayout.LayoutParams layoutParams =
new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
ChatMessage.State status = message.getState();
Address remoteSender = message.getFromAddress();
String displayName;
LinphoneContact contact = null;
if (message.isOutgoing()) {
if (status == ChatMessage.State.InProgress) {
holder.messageSendingInProgress.setVisibility(View.VISIBLE);
}
if (!message.isSecured()
&& LinphoneManager.getLc().limeEnabled() == LimeState.Mandatory
&& status != ChatMessage.State.InProgress) {
holder.messageStatus.setVisibility(View.VISIBLE);
holder.messageStatus.setImageResource(R.drawable.chat_unsecure);
}
if (status == ChatMessage.State.DeliveredToUser) {
holder.imdmLayout.setVisibility(View.VISIBLE);
holder.imdmIcon.setImageResource(R.drawable.imdn_received);
holder.imdmLabel.setText(R.string.delivered);
holder.imdmLabel.setTextColor(
mContext.getResources().getColor(R.color.grey_color));
} else if (status == ChatMessage.State.Displayed) {
holder.imdmLayout.setVisibility(View.VISIBLE);
holder.imdmIcon.setImageResource(R.drawable.imdn_read);
holder.imdmLabel.setText(R.string.displayed);
holder.imdmLabel.setTextColor(
mContext.getResources().getColor(R.color.imdn_read_color));
} else if (status == ChatMessage.State.NotDelivered) {
holder.imdmLayout.setVisibility(View.VISIBLE);
holder.imdmIcon.setImageResource(R.drawable.imdn_error);
holder.imdmLabel.setText(R.string.error);
holder.imdmLabel.setTextColor(
mContext.getResources().getColor(R.color.red_color));
} else if (status == ChatMessage.State.FileTransferError) {
holder.imdmLayout.setVisibility(View.VISIBLE);
holder.imdmIcon.setImageResource(R.drawable.imdn_error);
holder.imdmLabel.setText(R.string.file_transfer_error);
holder.imdmLabel.setTextColor(
mContext.getResources().getColor(R.color.red_color));
}
// layoutParams allow bubbles alignment during selection mode
if (isEditionEnabled()) {
layoutParams.addRule(RelativeLayout.LEFT_OF, holder.delete.getId());
layoutParams.setMargins(
SIDE_MARGIN,
MARGIN_BETWEEN_MESSAGES / 2,
0,
MARGIN_BETWEEN_MESSAGES / 2);
} else {
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
layoutParams.setMargins(
SIDE_MARGIN,
MARGIN_BETWEEN_MESSAGES / 2,
0,
MARGIN_BETWEEN_MESSAGES / 2);
}
holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing);
Compatibility.setTextAppearance(holder.contactName, mContext, R.style.font3);
Compatibility.setTextAppearance(
holder.fileTransferAction, mContext, R.style.font15);
holder.fileTransferAction.setBackgroundResource(
R.drawable.resizable_confirm_delete_button);
} else {
for (LinphoneContact c : mParticipants) {
if (c != null && c.hasAddress(remoteSender.asStringUriOnly())) {
contact = c;
break;
}
}
if (isEditionEnabled()) {
layoutParams.addRule(RelativeLayout.LEFT_OF, holder.delete.getId());
layoutParams.setMargins(
SIDE_MARGIN,
MARGIN_BETWEEN_MESSAGES / 2,
0,
MARGIN_BETWEEN_MESSAGES / 2);
} else {
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
layoutParams.setMargins(
0,
MARGIN_BETWEEN_MESSAGES / 2,
SIDE_MARGIN,
MARGIN_BETWEEN_MESSAGES / 2);
}
holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming);
Compatibility.setTextAppearance(
holder.contactName, mContext, R.style.contact_organization_font);
Compatibility.setTextAppearance(
holder.fileTransferAction, mContext, R.style.button_font);
holder.fileTransferAction.setBackgroundResource(
R.drawable.resizable_assistant_button);
}
if (contact == null) {
contact = ContactsManager.getInstance().findContactFromAddress(remoteSender);
}
if (contact != null) {
if (contact.getFullName() != null) {
displayName = contact.getFullName();
} else {
displayName = LinphoneUtils.getAddressDisplayName(remoteSender);
}
ContactAvatar.displayAvatar(contact, holder.avatarLayout);
} else {
displayName = LinphoneUtils.getAddressDisplayName(remoteSender);
ContactAvatar.displayAvatar(displayName, holder.avatarLayout);
}
holder.contactName.setText(
LinphoneUtils.timestampToHumanDate(
mContext, message.getTime(), R.string.messages_date_format)
+ " - "
+ displayName);
if (message.hasTextContent()) {
String msg = message.getTextContent();
Spanned text = LinphoneUtils.getTextWithHttpLinks(msg);
holder.messageText.setText(text);
holder.messageText.setMovementMethod(LinkMovementMethod.getInstance());
holder.messageText.setVisibility(View.VISIBLE);
}
String externalBodyUrl = message.getExternalBodyUrl();
Content fileTransferContent = message.getFileTransferInformation();
boolean hasFile = message.getAppdata() != null;
boolean hasFileTransfer = externalBodyUrl != null;
for (Content c : message.getContents()) {
if (c.isFile()) {
hasFile = true;
} else if (c.isFileTransfer()) {
hasFileTransfer = true;
}
}
if (hasFile) { // Something to display
displayAttachedFile(message, holder);
}
if (hasFileTransfer) { // Incoming file transfer not yet downloaded
holder.fileName.setVisibility(View.VISIBLE);
holder.fileName.setText(fileTransferContent.getName());
holder.fileTransferLayout.setVisibility(View.VISIBLE);
holder.fileTransferProgressBar.setVisibility(View.GONE);
if (message.isFileTransferInProgress()) { // Incoming file transfer in progress
holder.fileTransferAction.setVisibility(View.GONE);
} else {
holder.fileTransferAction.setText(mContext.getString(R.string.accept));
holder.fileTransferAction.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mContext.getPackageManager()
.checkPermission(
Manifest.permission
.WRITE_EXTERNAL_STORAGE,
mContext.getPackageName())
== PackageManager.PERMISSION_GRANTED) {
v.setEnabled(false);
String filename =
message.getFileTransferInformation().getName();
File file =
new File(
FileUtils.getStorageDirectory(mContext),
filename);
int prefix = 1;
while (file.exists()) {
file =
new File(
FileUtils.getStorageDirectory(mContext),
prefix + "_" + filename);
Log.w(
"File with that name already exists, renamed to "
+ prefix
+ "_"
+ filename);
prefix += 1;
}
message.setFileTransferFilepath(file.getPath());
message.downloadFile();
} else {
Log.w(
"WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file");
LinphoneActivity.instance()
.checkAndRequestExternalStoragePermission();
}
}
});
}
} else if (message.isFileTransferInProgress()) { // Outgoing file transfer in progress
holder.messageSendingInProgress.setVisibility(View.GONE);
holder.fileTransferLayout.setVisibility(View.VISIBLE);
holder.fileTransferAction.setText(mContext.getString(R.string.cancel));
holder.fileTransferAction.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
message.cancelFileTransfer();
notifyItemChanged(holder.getAdapterPosition());
}
});
}
holder.bubbleLayout.setLayoutParams(layoutParams);
} else { // Event is not chat message
holder.eventLayout.setVisibility(View.VISIBLE);
holder.eventMessage.setTextColor(
mContext.getResources().getColor(R.color.light_grey_color));
holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_gray);
holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_gray);
Address address = event.getParticipantAddress();
if (address == null && event.getType() == EventLog.Type.ConferenceSecurityEvent) {
address = event.getSecurityEventFaultyDeviceAddress();
}
String displayName = "";
if (address != null) {
LinphoneContact contact =
ContactsManager.getInstance().findContactFromAddress(address);
if (contact != null) {
displayName = contact.getFullName();
} else {
displayName = LinphoneUtils.getAddressDisplayName(address);
}
}
switch (event.getType()) {
case ConferenceCreated:
holder.eventMessage.setText(mContext.getString(R.string.conference_created));
break;
case ConferenceTerminated:
holder.eventMessage.setText(mContext.getString(R.string.conference_destroyed));
break;
case ConferenceParticipantAdded:
holder.eventMessage.setText(
mContext.getString(R.string.participant_added)
.replace("%s", displayName));
break;
case ConferenceParticipantRemoved:
holder.eventMessage.setText(
mContext.getString(R.string.participant_removed)
.replace("%s", displayName));
break;
case ConferenceSubjectChanged:
holder.eventMessage.setText(
mContext.getString(R.string.subject_changed)
.replace("%s", event.getSubject()));
break;
case ConferenceParticipantSetAdmin:
holder.eventMessage.setText(
mContext.getString(R.string.admin_set).replace("%s", displayName));
break;
case ConferenceParticipantUnsetAdmin:
holder.eventMessage.setText(
mContext.getString(R.string.admin_unset).replace("%s", displayName));
break;
case ConferenceParticipantDeviceAdded:
holder.eventMessage.setText(
mContext.getString(R.string.device_added).replace("%s", displayName));
break;
case ConferenceParticipantDeviceRemoved:
holder.eventMessage.setText(
mContext.getString(R.string.device_removed).replace("%s", displayName));
break;
case ConferenceSecurityEvent:
holder.eventMessage.setTextColor(
mContext.getResources().getColor(R.color.red_color));
holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_red);
holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_red);
switch (event.getSecurityEventType()) {
case EncryptionIdentityKeyChanged:
holder.eventMessage.setText(
mContext.getString(R.string.lime_identity_key_changed)
.replace("%s", displayName));
break;
case ManInTheMiddleDetected:
holder.eventMessage.setText(
mContext.getString(R.string.man_in_the_middle_detected)
.replace("%s", displayName));
break;
case SecurityLevelDowngraded:
holder.eventMessage.setText(
mContext.getString(R.string.security_level_downgraded)
.replace("%s", displayName));
break;
case ParticipantMaxDeviceCountExceeded:
holder.eventMessage.setText(
mContext.getString(R.string.participant_max_count_exceeded)
.replace("%s", displayName));
break;
case None:
default:
break;
}
break;
case None:
default:
holder.eventMessage.setText(
mContext.getString(R.string.unexpected_event)
.replace("%s", displayName)
.replace("%i", String.valueOf(event.getType().toInt())));
break;
}
}
}
@Override
public int getItemCount() {
return mHistory.size();
}
public void addToHistory(EventLog log) {
mHistory.add(0, log);
notifyItemInserted(0);
}
public void addAllToHistory(ArrayList<EventLog> logs) {
int currentSize = mHistory.size() - 1;
Collections.reverse(logs);
mHistory.addAll(logs);
notifyItemRangeInserted(currentSize + 1, logs.size());
}
public void setContacts(ArrayList<LinphoneContact> participants) {
mParticipants = participants;
}
public void refresh(EventLog[] history) {
mHistory = new ArrayList<>(Arrays.asList(history));
Collections.reverse(mHistory);
notifyDataSetChanged();
}
public void clear() {
for (EventLog event : mHistory) {
if (event.getType() == EventLog.Type.ConferenceChatMessage) {
ChatMessage message = event.getChatMessage();
message.removeListener(mListener);
}
}
mHistory.clear();
}
public Object getItem(int i) {
return mHistory.get(i);
}
public void removeItem(int i) {
mHistory.remove(i);
notifyItemRemoved(i);
}
private void loadBitmap(String path, ImageView imageView) {
if (cancelPotentialWork(path, imageView)) {
mDefaultBitmap =
BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_file);
BitmapWorkerTask task = new BitmapWorkerTask(mContext, imageView, mDefaultBitmap);
final AsyncBitmap asyncBitmap =
new AsyncBitmap(mContext.getResources(), mDefaultBitmap, task);
imageView.setImageDrawable(asyncBitmap);
task.execute(path);
}
}
private void openFile(String path) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file;
Uri contentUri;
if (path.startsWith("file://")) {
path = path.substring("file://".length());
file = new File(path);
contentUri =
FileProvider.getUriForFile(
mContext,
mContext.getResources().getString(R.string.file_provider),
file);
} else if (path.startsWith("content://")) {
contentUri = Uri.parse(path);
} else {
file = new File(path);
try {
contentUri =
FileProvider.getUriForFile(
mContext,
mContext.getResources().getString(R.string.file_provider),
file);
} catch (Exception e) {
contentUri = Uri.parse(path);
}
}
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(contentUri.toString());
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
if (type != null) {
intent.setDataAndType(contentUri, type);
} else {
intent.setDataAndType(contentUri, "*/*");
}
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(intent);
}
private void displayAttachedFile(ChatMessage message, ChatMessageOldViewHolder holder) {
holder.fileName.setVisibility(View.VISIBLE);
String appData = message.getAppdata();
if (appData == null) {
for (Content c : message.getContents()) {
if (c.isFile()) {
appData = c.getFilePath();
}
}
}
if (appData != null) {
FileUtils.scanFile(message);
holder.fileName.setText(FileUtils.getNameFromFilePath(appData));
if (FileUtils.isExtensionImage(appData)) {
holder.messageImage.setVisibility(View.VISIBLE);
loadBitmap(appData, holder.messageImage);
holder.messageImage.setTag(appData);
} else {
holder.openFileButton.setVisibility(View.VISIBLE);
holder.openFileButton.setTag(appData);
holder.openFileButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
openFile((String) v.getTag());
}
});
}
}
}
private boolean cancelPotentialWork(String path, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = BitmapWorkerTask.getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final String bitmapData = bitmapWorkerTask.path;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == null || !bitmapData.equals(path)) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
}

View file

@ -1,3 +1,5 @@
package org.linphone.chat;
/*
ChatRoomCreationFragment.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import static android.content.Context.INPUT_METHOD_SERVICE;
import android.app.Fragment;
@ -41,7 +41,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactAddress;
@ -56,11 +55,11 @@ import org.linphone.core.ChatRoomBackend;
import org.linphone.core.ChatRoomListenerStub;
import org.linphone.core.ChatRoomParams;
import org.linphone.core.Core;
import org.linphone.core.Factory;
import org.linphone.core.FriendCapability;
import org.linphone.core.ProxyConfig;
import org.linphone.core.SearchResult;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.LinphonePreferences;
import org.linphone.views.ContactSelectView;
@ -71,19 +70,19 @@ public class ChatRoomCreationFragment extends Fragment
private RecyclerView mContactsList;
private LinearLayout mContactsSelectedLayout;
private HorizontalScrollView mContactsSelectLayout;
private ImageView mAllContactsButton, mLinphoneContactsButton, mBackButton, mNextButton;
private ImageView mAllContactsButton;
private ImageView mLinphoneContactsButton;
private ImageView mNextButton;
private boolean mOnlyDisplayLinphoneContacts;
private View mAllContactsSelected, mLinphoneContactsSelected;
private RelativeLayout mSearchLayout, mWaitLayout, mLinphoneContactsToggle, mAllContactsToggle;
private SearchView mSearchField;
private ProgressBar mContactsFetchInProgress;
private SearchContactsAdapter mSearchAdapter;
private String mChatRoomSubject, mChatRoomAddress;
private ChatRoom mChatRoom;
private ChatRoomListenerStub mChatRoomCreationListener;
private Bundle mShareInfos;
private ImageView mSecurityToggleOff, mSecurityToggleOn;
private Switch mSecurityToggle;
private ArrayList<ContactAddress> mParticipants;
private boolean mCreateGroupChatRoom;
private boolean mChatRoomEncrypted;
@ -92,22 +91,22 @@ public class ChatRoomCreationFragment extends Fragment
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.chat_create, container, false);
setRetainInstance(true);
ArrayList<ContactAddress> selectedContacts = new ArrayList<>();
mParticipants = new ArrayList<>();
mChatRoomSubject = null;
mChatRoomAddress = null;
mCreateGroupChatRoom = false;
if (getArguments() != null) {
if (getArguments().getSerializable("selectedContacts") != null) {
selectedContacts =
(ArrayList<ContactAddress>)
getArguments().getSerializable("selectedContacts");
if (getArguments().getSerializable("Participants") != null) {
mParticipants =
(ArrayList<ContactAddress>) getArguments().getSerializable("Participants");
}
mChatRoomSubject = getArguments().getString("subject");
mChatRoomAddress = getArguments().getString("groupChatRoomAddress");
mCreateGroupChatRoom = getArguments().getBoolean("createGroupChatRoom", false);
mChatRoomEncrypted = getArguments().getBoolean("encrypted", false);
mChatRoomSubject = getArguments().getString("Subject");
mChatRoomAddress = getArguments().getString("RemoteSipUri");
mCreateGroupChatRoom = getArguments().getBoolean("IsGroupChatRoom", false);
mChatRoomEncrypted = getArguments().getBoolean("Encrypted", false);
}
mWaitLayout = view.findViewById(R.id.waitScreen);
@ -126,16 +125,44 @@ public class ChatRoomCreationFragment extends Fragment
mAllContactsSelected = view.findViewById(R.id.all_contacts_select);
mLinphoneContactsSelected = view.findViewById(R.id.linphone_contacts_select);
mBackButton = view.findViewById(R.id.back);
mBackButton.setOnClickListener(this);
ImageView backButton = view.findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
((ChatActivity) getActivity()).goBack();
}
});
mNextButton = view.findViewById(R.id.next);
mNextButton.setOnClickListener(this);
mNextButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mChatRoomAddress == null && mChatRoomSubject == null) {
mContactsSelectedLayout.removeAllViews();
} else {
// Pop the back stack twice so we don't have in stack Group -> Creation
// -> Group
getFragmentManager().popBackStack();
getFragmentManager().popBackStack();
}
((ChatActivity) getActivity())
.showChatRoomGroupInfo(
mChatRoomAddress == null
? null
: Factory.instance()
.createAddress(mChatRoomAddress),
mSearchAdapter.getContactsSelectedList(),
mChatRoomSubject,
mSecurityToggle.isChecked());
}
});
mNextButton.setEnabled(false);
mSearchLayout = view.findViewById(R.id.layoutSearchField);
mContactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress);
mContactsFetchInProgress.setVisibility(View.GONE);
ProgressBar contactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress);
contactsFetchInProgress.setVisibility(View.GONE);
mSearchAdapter = new SearchContactsAdapter(this, !mCreateGroupChatRoom, mChatRoomEncrypted);
@ -165,16 +192,16 @@ public class ChatRoomCreationFragment extends Fragment
setSecurityEnabled(isChecked);
}
});
mSecurityToggleOn = view.findViewById(R.id.security_toogle_on);
mSecurityToggleOff = view.findViewById(R.id.security_toogle_off);
mSecurityToggleOn.setOnClickListener(
ImageView securityToggleOn = view.findViewById(R.id.security_toogle_on);
ImageView securityToggleOff = view.findViewById(R.id.security_toogle_off);
securityToggleOn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
setSecurityEnabled(true);
}
});
mSecurityToggleOff.setOnClickListener(
securityToggleOff.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -184,12 +211,12 @@ public class ChatRoomCreationFragment extends Fragment
mSecurityToggle.setChecked(mChatRoomEncrypted);
mSearchAdapter.setSecurityEnabled(mChatRoomEncrypted);
ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig();
ProxyConfig lpc = LinphoneManager.getCore().getDefaultProxyConfig();
if ((mChatRoomSubject != null && mChatRoomAddress != null)
|| (lpc == null || lpc.getConferenceFactoryUri() == null)) {
mSecurityToggle.setVisibility(View.GONE);
mSecurityToggleOn.setVisibility(View.GONE);
mSecurityToggleOff.setVisibility(View.GONE);
securityToggleOn.setVisibility(View.GONE);
securityToggleOff.setVisibility(View.GONE);
}
LinearLayoutManager layoutManager =
@ -209,32 +236,22 @@ public class ChatRoomCreationFragment extends Fragment
mContactsList.setLayoutManager(layoutManager);
if (savedInstanceState != null
&& savedInstanceState.getStringArrayList("selectedContacts") != null) {
mContactsSelectedLayout.removeAllViews();
// We need to get all contacts not only sip
selectedContacts =
(ArrayList<ContactAddress>)
savedInstanceState.getSerializable("selectedContacts");
}
if (selectedContacts.size() != 0) {
mSearchAdapter.setContactsSelectedList(selectedContacts);
updateList();
updateListSelected();
}
mOnlyDisplayLinphoneContacts =
ContactsManager.getInstance().isLinphoneContactsPrefered()
|| getResources().getBoolean(R.bool.hide_non_linphone_contacts);
if (savedInstanceState != null) {
if (mParticipants.isEmpty()
&& savedInstanceState.getStringArrayList("Participants") != null) {
mContactsSelectedLayout.removeAllViews();
// We need to get all contacts not only sip
mParticipants =
(ArrayList<ContactAddress>)
savedInstanceState.getSerializable("Participants");
}
mOnlyDisplayLinphoneContacts =
savedInstanceState.getBoolean("onlySipContact", mOnlyDisplayLinphoneContacts);
}
mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts);
updateList();
displayChatCreation();
mChatRoomCreationListener =
new ChatRoomListenerStub() {
@ -242,14 +259,15 @@ public class ChatRoomCreationFragment extends Fragment
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance()
.goToChat(
cr.getLocalAddress().asStringUriOnly(),
cr.getPeerAddress().asStringUriOnly(),
mShareInfos);
// Pop back stack so back button takes to the chat rooms list
getFragmentManager().popBackStack();
((ChatActivity) getActivity())
.showChatRoom(
mChatRoom.getLocalAddress(),
mChatRoom.getPeerAddress());
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
((ChatActivity) getActivity()).displayChatRoomError();
Log.e(
"[Chat Room Creation] Group chat room for address "
+ cr.getPeerAddress()
@ -258,34 +276,15 @@ public class ChatRoomCreationFragment extends Fragment
}
};
if (getArguments() != null) {
String fileSharedUri = getArguments().getString("fileSharedUri");
String messageDraft = getArguments().getString("messageDraft");
if (fileSharedUri != null || messageDraft != null) {
Log.i("[ChatRoomCreation] Forwarding arguments to new chat room");
mShareInfos = new Bundle();
}
if (fileSharedUri != null) {
LinphoneActivity.instance().checkAndRequestPermissionsToSendImage();
mShareInfos.putString("fileSharedUri", fileSharedUri);
}
if (messageDraft != null) mShareInfos.putString("messageDraft", messageDraft);
}
return view;
}
@Override
public void onResume() {
ContactsManager.getInstance().addContactsListener(this);
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CREATE_CHAT);
}
updateLayout();
InputMethodManager inputMethodManager =
(InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
@ -304,6 +303,191 @@ public class ChatRoomCreationFragment extends Fragment
super.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mSearchAdapter.getContactsSelectedList().size() > 0) {
outState.putSerializable("Participants", mSearchAdapter.getContactsSelectedList());
}
outState.putBoolean("onlySipContact", mOnlyDisplayLinphoneContacts);
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.all_contacts) {
mOnlyDisplayLinphoneContacts = false;
mSearchAdapter.setOnlySipContact(false);
mAllContactsSelected.setVisibility(View.VISIBLE);
mAllContactsButton.setEnabled(false);
mLinphoneContactsButton.setEnabled(true);
mLinphoneContactsSelected.setVisibility(View.INVISIBLE);
updateList();
resetAndResearch();
} else if (id == R.id.linphone_contacts) {
mSearchAdapter.setOnlySipContact(true);
mLinphoneContactsSelected.setVisibility(View.VISIBLE);
mLinphoneContactsButton.setEnabled(false);
mOnlyDisplayLinphoneContacts = true;
mAllContactsButton.setEnabled(true);
mAllContactsSelected.setVisibility(View.INVISIBLE);
updateList();
resetAndResearch();
} else if (id == R.id.contactChatDelete) {
ContactAddress ca = (ContactAddress) view.getTag();
addOrRemoveContactFromSelection(ca);
}
}
@Override
public void onItemClicked(int position) {
SearchResult searchResult = mSearchAdapter.getContacts().get(position);
Core core = LinphoneManager.getCore();
ProxyConfig lpc = core.getDefaultProxyConfig();
boolean createEncryptedChatRoom = mSecurityToggle.isChecked();
if (createEncryptedChatRoom && !searchResult.hasCapability(FriendCapability.LimeX3Dh)) {
Log.w(
"[Chat Room Creation] Contact "
+ searchResult.getFriend()
+ " doesn't have LIME X3DH capability !");
return;
} else if (mCreateGroupChatRoom
&& !searchResult.hasCapability(FriendCapability.GroupChat)) {
Log.w(
"[Chat Room Creation] Contact "
+ searchResult.getFriend()
+ " doesn't have group chat capability !");
return;
}
if (lpc == null || lpc.getConferenceFactoryUri() == null || !mCreateGroupChatRoom) {
Address address = searchResult.getAddress();
if (address == null) {
Log.w(
"[Chat Room Creation] Using search result without an address, trying with phone number...");
address = core.interpretUrl(searchResult.getPhoneNumber());
}
if (address == null) {
Log.e("[Chat Room Creation] Can't create a chat room without a valid address !");
return;
}
if (lpc != null && lpc.getIdentityAddress().weakEqual(address)) {
Log.e("[Chat Room Creation] Can't create a 1-to-1 chat room with myself !");
return;
}
if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) {
mChatRoom = core.findOneToOneChatRoom(lpc.getIdentityAddress(), address, true);
if (mChatRoom != null) {
((ChatActivity) getActivity())
.showChatRoom(mChatRoom.getLocalAddress(), mChatRoom.getPeerAddress());
} else {
ChatRoomParams params = core.createDefaultChatRoomParams();
// This will set the backend to FlexisipChat automatically
params.enableEncryption(true);
params.enableGroup(false);
Address[] participants = new Address[1];
participants[0] = address;
mChatRoom =
core.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Chat Room Creation Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
}
} else {
if (lpc != null
&& lpc.getConferenceFactoryUri() != null
&& !LinphonePreferences.instance().useBasicChatRoomFor1To1()) {
mChatRoom = core.findOneToOneChatRoom(lpc.getIdentityAddress(), address, false);
if (mChatRoom == null) {
mWaitLayout.setVisibility(View.VISIBLE);
ChatRoomParams params = core.createDefaultChatRoomParams();
params.enableEncryption(false);
params.enableGroup(false);
// We don't want a basic chat room
params.setBackend(ChatRoomBackend.FlexisipChat);
Address[] participants = new Address[1];
participants[0] = address;
mChatRoom =
core.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Chat Room Creation Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
} else {
// Pop back stack so back button takes to the chat rooms list
getFragmentManager().popBackStack();
((ChatActivity) getActivity())
.showChatRoom(
mChatRoom.getLocalAddress(), mChatRoom.getPeerAddress());
}
} else {
ChatRoom chatRoom = core.getChatRoom(address);
if (chatRoom != null) {
// Pop back stack so back button takes to the chat rooms list
getFragmentManager().popBackStack();
((ChatActivity) getActivity())
.showChatRoom(
chatRoom.getLocalAddress(), chatRoom.getPeerAddress());
}
}
}
} else {
LinphoneContact c =
searchResult.getFriend() != null
? (LinphoneContact) searchResult.getFriend().getUserData()
: null;
if (c == null) {
c = ContactsManager.getInstance().findContactFromAddress(searchResult.getAddress());
if (c == null) {
c =
ContactsManager.getInstance()
.findContactFromPhoneNumber(searchResult.getPhoneNumber());
}
}
addOrRemoveContactFromSelection(
new ContactAddress(
c,
searchResult.getAddress().asStringUriOnly(),
searchResult.getPhoneNumber()));
}
}
@Override
public void onContactsUpdated() {
updateList();
}
private void updateLayout() {
if (mParticipants.size() != 0) {
mSearchAdapter.setContactsSelectedList(mParticipants);
updateList();
updateListSelected();
}
mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts);
updateList();
displayChatCreation();
}
private void setSecurityEnabled(boolean enabled) {
mChatRoomEncrypted = enabled;
mSecurityToggle.setChecked(mChatRoomEncrypted);
@ -409,8 +593,7 @@ public class ChatRoomCreationFragment extends Fragment
private void addSelectedContactAddress(ContactAddress ca) {
View viewContact =
LayoutInflater.from(LinphoneActivity.instance())
.inflate(R.layout.contact_selected, null);
LayoutInflater.from(getActivity()).inflate(R.layout.contact_selected, null);
if (ca.getContact() != null) {
String name =
(ca.getContact().getFullName() != null
@ -436,7 +619,7 @@ public class ChatRoomCreationFragment extends Fragment
private void updateContactsClick(ContactAddress ca) {
boolean isSelected = mSearchAdapter.toggleContactSelection(ca);
if (isSelected) {
ContactSelectView csv = new ContactSelectView(LinphoneActivity.instance());
ContactSelectView csv = new ContactSelectView(getActivity());
csv.setListener(this);
csv.setContactName(ca);
addSelectedContactAddress(ca);
@ -455,208 +638,4 @@ public class ChatRoomCreationFragment extends Fragment
mSearchAdapter.notifyDataSetChanged();
updateListSelected();
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (mSearchAdapter.getContactsSelectedList().size() > 0) {
outState.putSerializable("selectedContacts", mSearchAdapter.getContactsSelectedList());
}
outState.putBoolean("onlySipContact", mOnlyDisplayLinphoneContacts);
super.onSaveInstanceState(outState);
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.all_contacts) {
mOnlyDisplayLinphoneContacts = false;
mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts);
mAllContactsSelected.setVisibility(View.VISIBLE);
mAllContactsButton.setEnabled(false);
mLinphoneContactsButton.setEnabled(true);
mLinphoneContactsSelected.setVisibility(View.INVISIBLE);
updateList();
resetAndResearch();
} else if (id == R.id.linphone_contacts) {
mSearchAdapter.setOnlySipContact(true);
mLinphoneContactsSelected.setVisibility(View.VISIBLE);
mLinphoneContactsButton.setEnabled(false);
mOnlyDisplayLinphoneContacts = true;
mAllContactsButton.setEnabled(mOnlyDisplayLinphoneContacts);
mAllContactsSelected.setVisibility(View.INVISIBLE);
updateList();
resetAndResearch();
} else if (id == R.id.back) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChatList();
} else {
mContactsSelectedLayout.removeAllViews();
LinphoneActivity.instance().popBackStack();
}
} else if (id == R.id.next) {
if (mChatRoomAddress == null && mChatRoomSubject == null) {
mContactsSelectedLayout.removeAllViews();
LinphoneActivity.instance()
.goToChatGroupInfos(
null,
mSearchAdapter.getContactsSelectedList(),
null,
true,
false,
mShareInfos,
mSecurityToggle.isChecked());
} else {
LinphoneActivity.instance()
.goToChatGroupInfos(
mChatRoomAddress,
mSearchAdapter.getContactsSelectedList(),
mChatRoomSubject,
true,
true,
mShareInfos,
mSecurityToggle.isChecked());
}
} else if (id == R.id.contactChatDelete) {
ContactAddress ca = (ContactAddress) view.getTag();
addOrRemoveContactFromSelection(ca);
}
}
@Override
public void onItemClicked(int position) {
SearchResult searchResult = mSearchAdapter.getContacts().get(position);
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
ProxyConfig lpc = lc.getDefaultProxyConfig();
boolean createEncryptedChatRoom = mSecurityToggle.isChecked();
if (createEncryptedChatRoom && !searchResult.hasCapability(FriendCapability.LimeX3Dh)) {
Log.w(
"[Chat Room Creation] Contact "
+ searchResult.getFriend()
+ " doesn't have LIME X3DH capability !");
return;
} else if (mCreateGroupChatRoom
&& !searchResult.hasCapability(FriendCapability.GroupChat)) {
Log.w(
"[Chat Room Creation] Contact "
+ searchResult.getFriend()
+ " doesn't have group chat capability !");
return;
}
if (lpc == null || lpc.getConferenceFactoryUri() == null || !mCreateGroupChatRoom) {
Address address = searchResult.getAddress();
if (address == null) {
Log.w(
"[Chat Room Creation] Using search result without an address, trying with phone number...");
address = lc.interpretUrl(searchResult.getPhoneNumber());
}
if (address == null) {
Log.e("[Chat Room Creation] Can't create a chat room without a valid address !");
return;
}
if (lpc != null && lpc.getIdentityAddress().weakEqual(address)) {
Log.e("[Chat Room Creation] Can't create a 1-to-1 chat room with myself !");
return;
}
if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) {
mChatRoom = lc.findOneToOneChatRoom(lpc.getIdentityAddress(), address, true);
if (mChatRoom != null) {
LinphoneActivity.instance()
.goToChat(
mChatRoom.getLocalAddress().asStringUriOnly(),
mChatRoom.getPeerAddress().asStringUriOnly(),
mShareInfos);
} else {
ChatRoomParams params = lc.createDefaultChatRoomParams();
// This will set the backend to FlexisipChat automatically
params.enableEncryption(true);
params.enableGroup(false);
Address participants[] = new Address[1];
participants[0] = address;
mChatRoom =
lc.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Chat Room Creation Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
}
} else {
if (lpc != null
&& lpc.getConferenceFactoryUri() != null
&& !LinphonePreferences.instance().useBasicChatRoomFor1To1()) {
mChatRoom = lc.findOneToOneChatRoom(lpc.getIdentityAddress(), address, false);
if (mChatRoom == null) {
mWaitLayout.setVisibility(View.VISIBLE);
ChatRoomParams params = lc.createDefaultChatRoomParams();
params.enableEncryption(false);
params.enableGroup(false);
// We don't want a basic chat room
params.setBackend(ChatRoomBackend.FlexisipChat);
Address participants[] = new Address[1];
participants[0] = address;
mChatRoom =
lc.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Chat Room Creation Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
} else {
LinphoneActivity.instance()
.goToChat(
mChatRoom.getLocalAddress().asStringUriOnly(),
mChatRoom.getPeerAddress().asStringUriOnly(),
mShareInfos);
}
} else {
ChatRoom chatRoom = lc.getChatRoom(address);
LinphoneActivity.instance()
.goToChat(
chatRoom.getLocalAddress().asStringUriOnly(),
chatRoom.getPeerAddress().asStringUriOnly(),
mShareInfos);
}
}
} else {
LinphoneContact c =
searchResult.getFriend() != null
? (LinphoneContact) searchResult.getFriend().getUserData()
: null;
if (c == null) {
c = ContactsManager.getInstance().findContactFromAddress(searchResult.getAddress());
if (c == null) {
c =
ContactsManager.getInstance()
.findContactFromPhoneNumber(searchResult.getPhoneNumber());
}
}
addOrRemoveContactFromSelection(
new ContactAddress(
c,
searchResult.getAddress().asStringUriOnly(),
searchResult.getPhoneNumber(),
searchResult.getFriend() != null));
}
}
@Override
public void onContactsUpdated() {
updateList();
}
}

View file

@ -1,3 +1,5 @@
package org.linphone.chat;
/*
ChatRoomViewHolder.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import android.content.Context;
import android.view.View;
import android.widget.CheckBox;
@ -39,12 +39,12 @@ import org.linphone.views.ContactAvatar;
public class ChatRoomViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener {
public final TextView lastMessageView;
public final TextView date;
public final TextView displayName;
private final TextView lastMessageView;
private final TextView date;
private final TextView displayName;
public final TextView unreadMessages;
public final CheckBox delete;
public final RelativeLayout avatarLayout;
private final RelativeLayout avatarLayout;
private final Context mContext;
private final ClickListener mListener;
@ -77,7 +77,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder
messageContent.insert(0, c.getStringBuffer() + " ");
}
}
lastMessageView.setText(getSender(room) + messageContent);
lastMessageView.setText(getSender(lastMessage) + messageContent);
date.setText(
LinphoneUtils.timestampToHumanDate(
mContext,
@ -106,23 +106,21 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder
return false;
}
public String getSender(ChatRoom mRoom) {
if (mRoom.getLastMessageInHistory() != null) {
private String getSender(ChatMessage lastMessage) {
if (lastMessage != null) {
LinphoneContact contact =
ContactsManager.getInstance()
.findContactFromAddress(
mRoom.getLastMessageInHistory().getFromAddress());
.findContactFromAddress(lastMessage.getFromAddress());
if (contact != null) {
return (contact.getFullName() + mContext.getString(R.string.separator));
}
return (LinphoneUtils.getAddressDisplayName(
mRoom.getLastMessageInHistory().getFromAddress())
return (LinphoneUtils.getAddressDisplayName(lastMessage.getFromAddress())
+ mContext.getString(R.string.separator));
}
return null;
}
public String getContact(ChatRoom mRoom) {
private String getContact(ChatRoom mRoom) {
Address contactAddress = mRoom.getPeerAddress();
if (mRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())
&& mRoom.getParticipants().length > 0) {
@ -140,7 +138,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder
return mRoom.getSubject();
}
public void getAvatar(ChatRoom mRoom) {
private void getAvatar(ChatRoom mRoom) {
if (mRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
LinphoneContact contact = null;
if (mRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) {

View file

@ -1,3 +1,5 @@
package org.linphone.chat;
/*
ChatRoomsAdapter.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@ -68,11 +68,12 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomViewHolder> {
? View.INVISIBLE
: (room.getUnreadMessagesCount() > 0 ? View.VISIBLE : View.INVISIBLE));
holder.delete.setChecked(isSelected(position));
room.setUserData(holder);
holder.bindChatRoom(room);
}
public void refresh() {
ChatRoom[] rooms = LinphoneManager.getLc().getChatRooms();
ChatRoom[] rooms = LinphoneManager.getCore().getChatRooms();
if (mContext.getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) {
mRooms = LinphoneUtils.removeEmptyOneToOneChatRooms(rooms);
} else {
@ -95,7 +96,7 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomViewHolder> {
public void clear() {
mRooms.clear();
notifyDataSetChanged();
// Do not notify data set changed, we don't want the list to empty when fragment is paused
}
/** Adapter's methods */

View file

@ -1,3 +1,5 @@
package org.linphone.chat;
/*
ChatRoomsFragment.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
@ -17,12 +19,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import static org.linphone.fragments.FragmentsAvailable.CHAT_LIST;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -30,16 +28,14 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.call.CallActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.ContactsUpdatedListener;
import org.linphone.core.ChatMessage;
@ -47,10 +43,7 @@ import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomListenerStub;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.EventLog;
import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.LinphoneUtils;
import org.linphone.utils.SelectableHelper;
@ -60,14 +53,13 @@ public class ChatRoomsFragment extends Fragment
SelectableHelper.DeleteListener {
private RecyclerView mChatRoomsList;
private ImageView mNewDiscussionButton, mNewGroupDiscussionButton, mBackToCallButton;
private ImageView mNewGroupDiscussionButton;
private ImageView mBackToCallButton;
private ChatRoomsAdapter mChatRoomsAdapter;
private CoreListenerStub mListener;
private RelativeLayout mWaitLayout;
private int mChatRoomDeletionPendingCount;
private ChatRoomListenerStub mChatRoomListener;
private Context mContext;
private List<ChatRoom> mRooms;
private SelectableHelper mSelectionHelper;
private TextView mNoChatHistory;
@ -76,18 +68,18 @@ public class ChatRoomsFragment extends Fragment
final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity().getApplicationContext();
View view = inflater.inflate(R.layout.chatlist, container, false);
mChatRoomsList = view.findViewById(R.id.chatList);
mWaitLayout = view.findViewById(R.id.waitScreen);
mNewDiscussionButton = view.findViewById(R.id.new_discussion);
ImageView newDiscussionButton = view.findViewById(R.id.new_discussion);
mNewGroupDiscussionButton = view.findViewById(R.id.new_group_discussion);
mBackToCallButton = view.findViewById(R.id.back_in_call);
mNoChatHistory = view.findViewById(R.id.noChatHistory);
ChatRoom[] rooms = LinphoneManager.getLc().getChatRooms();
if (mContext.getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) {
ChatRoom[] rooms = LinphoneManager.getCore().getChatRooms();
List<ChatRoom> mRooms;
if (getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) {
mRooms = LinphoneUtils.removeEmptyOneToOneChatRooms(rooms);
} else {
mRooms = Arrays.asList(rooms);
@ -96,19 +88,18 @@ public class ChatRoomsFragment extends Fragment
mSelectionHelper = new SelectableHelper(view, this);
mChatRoomsAdapter =
new ChatRoomsAdapter(
mContext, R.layout.chatlist_cell, mRooms, this, mSelectionHelper);
getActivity(), R.layout.chatlist_cell, mRooms, this, mSelectionHelper);
mChatRoomsList.setAdapter(mChatRoomsAdapter);
mSelectionHelper.setAdapter(mChatRoomsAdapter);
mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mChatRoomsList.setLayoutManager(layoutManager);
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(
mChatRoomsList.getContext(),
((LinearLayoutManager) layoutManager).getOrientation());
mChatRoomsList.getContext(), layoutManager.getOrientation());
dividerItemDecoration.setDrawable(
getActivity()
.getApplicationContext()
@ -118,18 +109,12 @@ public class ChatRoomsFragment extends Fragment
mWaitLayout.setVisibility(View.GONE);
mNewDiscussionButton.setOnClickListener(
newDiscussionButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle extras = null;
if (getArguments() != null) {
Log.i("[ChatRooms] Forwarding arguments to new chat room");
extras = (Bundle) getArguments().clone();
getArguments().clear();
}
LinphoneActivity.instance()
.goToChatCreator(null, null, null, false, extras, false, false);
((ChatActivity) getActivity())
.showChatRoomCreation(null, null, null, false, false);
}
});
@ -137,14 +122,8 @@ public class ChatRoomsFragment extends Fragment
new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle extras = null;
if (getArguments() != null) {
Log.i("[ChatRooms] Forwarding arguments to new group chat room");
extras = (Bundle) getArguments().clone();
getArguments().clear();
}
LinphoneActivity.instance()
.goToChatCreator(null, null, null, false, extras, true, false);
((ChatActivity) getActivity())
.showChatRoomCreation(null, null, null, false, true);
}
});
@ -152,22 +131,38 @@ public class ChatRoomsFragment extends Fragment
new View.OnClickListener() {
@Override
public void onClick(View v) {
LinphoneActivity.instance()
.resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
startActivity(new Intent(getActivity(), CallActivity.class));
}
});
mListener =
new CoreListenerStub() {
@Override
public void onMessageReceived(Core lc, ChatRoom cr, ChatMessage message) {
refreshChatRoomsList();
public void onMessageSent(Core core, ChatRoom room, ChatMessage message) {
refreshChatRoom(room);
}
@Override
public void onChatRoomStateChanged(Core lc, ChatRoom cr, ChatRoom.State state) {
public void onMessageReceived(Core core, ChatRoom cr, ChatMessage message) {
refreshChatRoom(cr);
}
@Override
public void onMessageReceivedUnableDecrypt(
Core core, ChatRoom room, ChatMessage message) {
refreshChatRoom(room);
}
@Override
public void onChatRoomRead(Core core, ChatRoom room) {
refreshChatRoom(room);
}
@Override
public void onChatRoomStateChanged(
Core core, ChatRoom cr, ChatRoom.State state) {
if (state == ChatRoom.State.Created) {
refreshChatRoomsList();
refreshChatRoom(cr);
}
}
};
@ -193,19 +188,6 @@ public class ChatRoomsFragment extends Fragment
}
};
if (getArguments() != null) {
String fileSharedUri = getArguments().getString("fileSharedUri");
String messageSharedUri = getArguments().getString("messageDraft");
if (fileSharedUri != null || messageSharedUri != null) {
Toast.makeText(
LinphoneActivity.instance(),
R.string.toast_choose_chat_room_for_sharing,
Toast.LENGTH_LONG)
.show();
}
Log.i("[ChatRooms] Arguments found: " + messageSharedUri + " / " + fileSharedUri);
}
return view;
}
@ -215,17 +197,11 @@ public class ChatRoomsFragment extends Fragment
mChatRoomsAdapter.toggleSelection(position);
} else {
ChatRoom room = (ChatRoom) mChatRoomsAdapter.getItem(position);
Bundle extras = null;
if (getArguments() != null) {
Log.i("[ChatRooms] Forwarding arguments to existing chat room");
extras = (Bundle) getArguments().clone();
getArguments().clear();
if (room != null) {
((ChatActivity) getActivity())
.showChatRoom(room.getLocalAddress(), room.getPeerAddress());
refreshChatRoom(room);
}
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asString(),
extras);
}
}
@ -238,64 +214,33 @@ public class ChatRoomsFragment extends Fragment
return true;
}
private void refreshChatRoomsList() {
mChatRoomsAdapter.refresh();
mNoChatHistory.setVisibility(
mChatRoomsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
public void displayFirstChat() {
ChatRoomsAdapter adapter = (ChatRoomsAdapter) mChatRoomsList.getAdapter();
if (adapter != null && adapter.getItemCount() > 0) {
ChatRoom room = (ChatRoom) adapter.getItem(0);
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asStringUriOnly(),
null);
} else {
LinphoneActivity.instance().displayEmptyFragment();
}
}
public void invalidate() {
if (mChatRoomsAdapter != null) {
mChatRoomsAdapter.notifyDataSetChanged();
}
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
if (LinphoneManager.getLc().getCallsNb() > 0) {
mBackToCallButton.setVisibility(View.VISIBLE);
} else {
mBackToCallButton.setVisibility(View.INVISIBLE);
}
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHAT_LIST);
if (core.getCallsNb() > 0) {
mBackToCallButton.setVisibility(View.VISIBLE);
}
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
}
refreshChatRoomsList();
ProxyConfig lpc = lc.getDefaultProxyConfig();
ProxyConfig lpc = core.getDefaultProxyConfig();
mNewGroupDiscussionButton.setVisibility(
(lpc != null && lpc.getConferenceFactoryUri() != null) ? View.VISIBLE : View.GONE);
}
@Override
public void onPause() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
ContactsManager.getInstance().removeContactsListener(this);
mChatRoomsAdapter.clear();
@ -304,42 +249,44 @@ public class ChatRoomsFragment extends Fragment
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
mChatRoomDeletionPendingCount = objectsToDelete.length;
for (Object obj : objectsToDelete) {
ChatRoom room = (ChatRoom) obj;
for (EventLog eventLog : room.getHistoryEvents(0)) {
if (eventLog.getType() == EventLog.Type.ConferenceChatMessage) {
ChatMessage message = eventLog.getChatMessage();
if (message.getAppdata() != null && !message.isOutgoing()) {
File file = new File(message.getAppdata());
if (file.exists()) {
file.delete(); // Delete downloaded file from incoming message that
// will be deleted
}
}
}
}
room.addListener(mChatRoomListener);
lc.deleteChatRoom(room);
core.deleteChatRoom(room);
}
if (mChatRoomDeletionPendingCount > 0) {
mWaitLayout.setVisibility(View.VISIBLE);
}
LinphoneActivity.instance()
.displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount());
((ChatActivity) getActivity()).displayMissedChats();
}
@Override
public void onContactsUpdated() {
if (!LinphoneActivity.isInstanciated()
|| LinphoneActivity.instance().getCurrentFragment() != CHAT_LIST) return;
ChatRoomsAdapter adapter = (ChatRoomsAdapter) mChatRoomsList.getAdapter();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
private void refreshChatRoom(ChatRoom cr) {
ChatRoomViewHolder holder = (ChatRoomViewHolder) cr.getUserData();
if (holder != null) {
int position = holder.getAdapterPosition();
if (position == 0) {
mChatRoomsAdapter.notifyItemChanged(0);
} else {
refreshChatRoomsList();
}
} else {
refreshChatRoomsList();
}
}
private void refreshChatRoomsList() {
mChatRoomsAdapter.refresh();
mNoChatHistory.setVisibility(
mChatRoomsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}

View file

@ -2,7 +2,7 @@ package org.linphone.chat;
/*
ChatScrollListener.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
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
@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView;
abstract class ChatScrollListener extends RecyclerView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before mLoading more.
private final int mVisibleThreshold = 5;
private static final int mVisibleThreshold = 5;
// The total number of items in the dataset after the last load
private int mPreviousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.

View file

@ -2,7 +2,7 @@ package org.linphone.chat;
/*
DeviceChildViewHolder.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
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

View file

@ -2,7 +2,7 @@ package org.linphone.chat;
/*
DeviceGroupViewHolder.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
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

View file

@ -2,7 +2,7 @@ package org.linphone.chat;
/*
DevicesAdapter.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
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

View file

@ -1,6 +1,8 @@
package org.linphone.chat;
/*
DevicesFragment.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
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
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
@ -29,28 +29,23 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.Arrays;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.call.CallManager;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomCapabilities;
import org.linphone.core.Core;
import org.linphone.core.Factory;
import org.linphone.core.ParticipantDevice;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.LinphoneUtils;
public class DevicesFragment extends Fragment {
private LayoutInflater mInflater;
private ImageView mBackButton;
private TextView mTitle;
private ExpandableListView mExpandableList;
private DevicesAdapter mAdapter;
private String mLocalSipUri, mRoomUri;
private Address mLocalSipAddr, mRoomAddr;
private ChatRoom mRoom;
private boolean mOnlyDisplayChilds;
@ -62,14 +57,13 @@ public class DevicesFragment extends Fragment {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mLocalSipUri = getArguments().getString("LocalSipUri");
mLocalSipAddr = LinphoneManager.getLc().createAddress(mLocalSipUri);
mRoomUri = getArguments().getString("RemoteSipUri");
mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri);
String localSipUri = getArguments().getString("LocalSipUri");
mLocalSipAddr = Factory.instance().createAddress(localSipUri);
String roomUri = getArguments().getString("RemoteSipUri");
mRoomAddr = Factory.instance().createAddress(roomUri);
}
mInflater = inflater;
View view = mInflater.inflate(R.layout.chat_devices, container, false);
View view = inflater.inflate(R.layout.chat_devices, container, false);
mOnlyDisplayChilds = false;
@ -85,7 +79,7 @@ public class DevicesFragment extends Fragment {
long l) {
ParticipantDevice device =
(ParticipantDevice) mAdapter.getChild(groupPosition, childPosition);
CallManager.getInstance().inviteAddress(device.getAddress(), true);
LinphoneManager.getCallManager().inviteAddress(device.getAddress(), true);
return false;
}
});
@ -101,13 +95,15 @@ public class DevicesFragment extends Fragment {
// in this case groups are childs, so call on click
ParticipantDevice device =
(ParticipantDevice) mAdapter.getGroup(groupPosition);
CallManager.getInstance().inviteAddress(device.getAddress(), true);
LinphoneManager.getCallManager()
.inviteAddress(device.getAddress(), true);
return true;
} else {
if (mAdapter.getChildrenCount(groupPosition) == 1) {
ParticipantDevice device =
(ParticipantDevice) mAdapter.getChild(groupPosition, 0);
CallManager.getInstance().inviteAddress(device.getAddress(), true);
LinphoneManager.getCallManager()
.inviteAddress(device.getAddress(), true);
return true;
}
}
@ -120,16 +116,12 @@ public class DevicesFragment extends Fragment {
mTitle = view.findViewById(R.id.title);
initHeader();
mBackButton = view.findViewById(R.id.back);
mBackButton.setOnClickListener(
ImageView backButton = view.findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mLocalSipUri, mRoomUri, null);
} else {
LinphoneActivity.instance().onBackPressed();
}
((ChatActivity) getActivity()).goBack();
}
});
@ -140,10 +132,6 @@ public class DevicesFragment extends Fragment {
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACT_DEVICES);
}
initValues();
if (LinphoneManager.getInstance().hasLastCallSasBeenRejected()) {
@ -153,7 +141,7 @@ public class DevicesFragment extends Fragment {
}
private void initChatRoom() {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
mRoom = core.getChatRoom(mRoomAddr, mLocalSipAddr);
}

View file

@ -1,3 +1,5 @@
package org.linphone.chat;
/*
GroupInfoAdapter.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -26,7 +26,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.contacts.ContactAddress;
import org.linphone.contacts.LinphoneContact;
@ -73,7 +73,7 @@ class GroupInfoAdapter extends RecyclerView.Adapter<GroupInfoViewHolder> {
holder.sipUri.setText(ca.getAddressAsDisplayableString());
if (!LinphoneActivity.instance().getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
if (!LinphoneService.instance().getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
holder.sipUri.setVisibility(View.GONE);
holder.name.setOnClickListener(
new View.OnClickListener() {

View file

@ -1,5 +1,7 @@
package org.linphone.chat;
/*
InfoGroupChatFragment.java
GroupInfoFragment.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
@ -17,13 +19,11 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import static android.content.Context.INPUT_METHOD_SERVICE;
import android.app.Dialog;
import android.app.Fragment;
import android.content.Context;
import android.app.FragmentManager;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
@ -40,34 +40,31 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactAddress;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomListener;
import org.linphone.core.ChatRoomCapabilities;
import org.linphone.core.ChatRoomListenerStub;
import org.linphone.core.ChatRoomParams;
import org.linphone.core.Core;
import org.linphone.core.EventLog;
import org.linphone.core.Factory;
import org.linphone.core.Participant;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.LinphoneUtils;
public class GroupInfoFragment extends Fragment implements ChatRoomListener {
private ImageView mBackButton, mConfirmButton, mAddParticipantsButton;
private RelativeLayout mAddParticipantsLayout;
public class GroupInfoFragment extends Fragment {
private ImageView mConfirmButton;
private ImageView mAddParticipantsButton;
private Address mGroupChatRoomAddress;
private EditText mSubjectField;
private RecyclerView mParticipantsList;
private LinearLayout mLeaveGroupButton;
private RelativeLayout mWaitLayout;
private GroupInfoAdapter mAdapter;
private boolean mIsAlreadyCreatedGroup;
@ -77,10 +74,8 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
private ChatRoom mChatRoom, mTempChatRoom;
private Dialog mAdminStateChangedDialog;
private ChatRoomListenerStub mChatRoomCreationListener;
private Bundle mShareInfos;
private Context mContext;
private LinearLayoutManager layoutManager;
private boolean mIsEncryptionEnabled;
private ChatRoomListenerStub mListener;
@Override
public View onCreateView(
@ -90,32 +85,34 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
if (getArguments() == null || getArguments().isEmpty()) {
return null;
}
mContext = getActivity().getApplicationContext();
mParticipants =
(ArrayList<ContactAddress>) getArguments().getSerializable("ContactAddress");
mParticipants = (ArrayList<ContactAddress>) getArguments().getSerializable("Participants");
mGroupChatRoomAddress = null;
mChatRoom = null;
String address = getArguments().getString("groupChatRoomAddress");
String address = getArguments().getString("RemoteSipUri");
if (address != null && address.length() > 0) {
mGroupChatRoomAddress = LinphoneManager.getLc().createAddress(address);
mGroupChatRoomAddress = Factory.instance().createAddress(address);
}
mIsAlreadyCreatedGroup = mGroupChatRoomAddress != null;
if (mIsAlreadyCreatedGroup) {
mChatRoom = LinphoneManager.getLc().getChatRoom(mGroupChatRoomAddress);
}
if (mChatRoom == null) mIsAlreadyCreatedGroup = false;
mIsEditionEnabled = getArguments().getBoolean("isEditionEnabled");
mSubject = getArguments().getString("subject");
if (mChatRoom != null && mChatRoom.hasBeenLeft()) {
mIsEditionEnabled = false;
mChatRoom = LinphoneManager.getCore().getChatRoom(mGroupChatRoomAddress);
}
mIsEncryptionEnabled = getArguments().getBoolean("encryptionEnabled", false);
if (mChatRoom == null) {
mIsAlreadyCreatedGroup = false;
mIsEditionEnabled = true;
mSubject = getArguments().getString("Subject", "");
mIsEncryptionEnabled = getArguments().getBoolean("Encrypted", false);
} else {
mIsEditionEnabled =
mChatRoom.getMe() != null
&& mChatRoom.getMe().isAdmin()
&& !mChatRoom.hasBeenLeft();
mSubject = mChatRoom.getSubject();
mIsEncryptionEnabled = mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt());
}
mParticipantsList = view.findViewById(R.id.chat_room_participants);
mAdapter = new GroupInfoAdapter(mParticipants, !mIsEditionEnabled, !mIsAlreadyCreatedGroup);
@ -133,126 +130,55 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
});
mParticipantsList.setAdapter(mAdapter);
mAdapter.setChatRoom(mChatRoom);
layoutManager = new LinearLayoutManager(mContext);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mParticipantsList.setLayoutManager(layoutManager);
// Divider between items
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(
mParticipantsList.getContext(), layoutManager.getOrientation());
dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider));
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider));
mParticipantsList.addItemDecoration(dividerItemDecoration);
String fileSharedUri = getArguments().getString("fileSharedUri");
String messageDraft = getArguments().getString("messageDraft");
if (fileSharedUri != null || messageDraft != null) {
Log.i("[GroupInfo] Forwarding arguments to group chat room");
mShareInfos = new Bundle();
}
if (fileSharedUri != null) mShareInfos.putString("fileSharedUri", fileSharedUri);
if (messageDraft != null) mShareInfos.putString("messageDraft", messageDraft);
mBackButton = view.findViewById(R.id.back);
mBackButton.setOnClickListener(
ImageView backButton = view.findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mIsAlreadyCreatedGroup) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance()
.goToChat(
mChatRoom.getLocalAddress().asStringUriOnly(),
mGroupChatRoomAddress.asStringUriOnly(),
mShareInfos);
} else {
getFragmentManager().popBackStack();
}
} else {
LinphoneActivity.instance()
.goToChatCreator(
null,
mParticipants,
null,
true,
mShareInfos,
true,
mIsEncryptionEnabled);
}
((ChatActivity) getActivity()).goBack();
}
});
mConfirmButton = view.findViewById(R.id.confirm);
mLeaveGroupButton = view.findViewById(R.id.leaveGroupLayout);
mLeaveGroupButton.setOnClickListener(
mConfirmButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
final Dialog dialog =
LinphoneActivity.instance()
.displayDialog(getString(R.string.chat_room_leave_dialog));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
delete.setText(getString(R.string.chat_room_leave_button));
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
applyChanges();
}
});
mConfirmButton.setEnabled(!mSubject.isEmpty() && mParticipants.size() > 0);
delete.setOnClickListener(
LinearLayout leaveGroupButton = view.findViewById(R.id.leaveGroupLayout);
leaveGroupButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mChatRoom != null) {
mChatRoom.leave();
LinphoneActivity.instance()
.goToChat(
mChatRoom
.getLocalAddress()
.asStringUriOnly(),
mGroupChatRoomAddress.asString(),
null);
} else {
Log.e(
"Can't leave, chatRoom for address "
+ mGroupChatRoomAddress.asString()
+ " is null...");
}
dialog.dismiss();
showLeaveGroupDialog();
}
});
cancel.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
});
mLeaveGroupButton.setVisibility(
leaveGroupButton.setVisibility(
mIsAlreadyCreatedGroup && mChatRoom.hasBeenLeft()
? View.GONE
: mIsAlreadyCreatedGroup ? View.VISIBLE : View.GONE);
mAddParticipantsLayout = view.findViewById(R.id.addParticipantsLayout);
mAddParticipantsLayout.setOnClickListener(
RelativeLayout addParticipantsLayout = view.findViewById(R.id.addParticipantsLayout);
addParticipantsLayout.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mIsEditionEnabled && mIsAlreadyCreatedGroup) {
LinphoneActivity.instance()
.goToChatCreator(
mGroupChatRoomAddress != null
? mGroupChatRoomAddress.asString()
: null,
mParticipants,
mSubject,
!mIsAlreadyCreatedGroup,
null,
true,
mIsEncryptionEnabled);
goBackToChatCreationFragment();
}
}
});
@ -262,17 +188,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
@Override
public void onClick(View view) {
if (mIsEditionEnabled && mIsAlreadyCreatedGroup) {
LinphoneActivity.instance()
.goToChatCreator(
mGroupChatRoomAddress != null
? mGroupChatRoomAddress.asString()
: null,
mParticipants,
mSubject,
!mIsAlreadyCreatedGroup,
null,
true,
mIsEncryptionEnabled);
goBackToChatCreationFragment();
}
}
});
@ -302,33 +218,202 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
// This will remove both the creation fragment and the group info
// fragment from the back stack
// Pop the back stack twice so we don't have in stack Creation -> Group
// Behind the chat room, so a back press will take us back to the rooms
getFragmentManager().popBackStack();
getFragmentManager().popBackStack();
LinphoneActivity.instance()
.goToChat(
cr.getLocalAddress().asStringUriOnly(),
cr.getPeerAddress().asStringUriOnly(),
mShareInfos);
((ChatActivity) getActivity())
.showChatRoom(cr.getLocalAddress(), cr.getPeerAddress());
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
((ChatActivity) getActivity()).displayChatRoomError();
Log.e(
"Group chat room for address "
"[Group Info] Group chat room for address "
+ cr.getPeerAddress()
+ " has failed !");
}
}
};
mConfirmButton.setOnClickListener(
if (!mIsEditionEnabled) {
mSubjectField.setEnabled(false);
mConfirmButton.setVisibility(View.INVISIBLE);
mAddParticipantsButton.setVisibility(View.GONE);
}
mWaitLayout = view.findViewById(R.id.waitScreen);
mWaitLayout.setVisibility(View.GONE);
mListener =
new ChatRoomListenerStub() {
@Override
public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event_log) {
if (mChatRoom.getMe().isAdmin() != mIsEditionEnabled) {
// Either we weren't admin and we are now or the other way around
mIsEditionEnabled = mChatRoom.getMe().isAdmin();
displayMeAdminStatusUpdated();
refreshAdminRights();
}
refreshParticipantsList();
}
@Override
public void onSubjectChanged(ChatRoom cr, EventLog event_log) {
mSubjectField.setText(event_log.getSubject());
}
};
if (mChatRoom != null) {
mChatRoom.addListener(mListener);
}
return view;
}
@Override
public void onResume() {
super.onResume();
InputMethodManager inputMethodManager =
(InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
if (getActivity().getCurrentFocus() != null) {
inputMethodManager.hideSoftInputFromWindow(
getActivity().getCurrentFocus().getWindowToken(), 0);
}
}
@Override
public void onPause() {
if (mTempChatRoom != null) {
mTempChatRoom.removeListener(mChatRoomCreationListener);
}
super.onPause();
}
@Override
public void onDestroy() {
if (mChatRoom != null) {
mChatRoom.removeListener(mListener);
}
super.onDestroy();
}
private void goBackToChatCreationFragment() {
boolean previousFragmentInBackStackIsChatRoomCreation = false;
FragmentManager fragmentManager = getActivity().getFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
if (count > 1) {
FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(count - 1);
if ("Chat room creation".equals(entry.getName())) {
previousFragmentInBackStackIsChatRoomCreation = true;
((ChatActivity) getActivity()).goBack();
}
}
if (!previousFragmentInBackStackIsChatRoomCreation) {
((ChatActivity) getActivity())
.showChatRoomCreation(
mGroupChatRoomAddress,
mParticipants,
mSubject,
mIsEncryptionEnabled,
true);
}
}
private void refreshParticipantsList() {
if (mChatRoom == null) return;
mParticipants = new ArrayList<>();
for (Participant p : mChatRoom.getParticipants()) {
Address a = p.getAddress();
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(a);
if (c == null) {
c = new LinphoneContact();
String displayName = LinphoneUtils.getAddressDisplayName(a);
c.setFullName(displayName);
}
ContactAddress ca = new ContactAddress(c, a.asString(), "", p.isAdmin());
mParticipants.add(ca);
}
mAdapter.updateDataSet(mParticipants);
mAdapter.setChatRoom(mChatRoom);
}
private void refreshAdminRights() {
mAdapter.setAdminFeaturesVisible(mIsEditionEnabled);
mAdapter.setChatRoom(mChatRoom);
mSubjectField.setEnabled(mIsEditionEnabled);
mConfirmButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.INVISIBLE);
mAddParticipantsButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.GONE);
}
private void displayMeAdminStatusUpdated() {
if (mAdminStateChangedDialog != null) mAdminStateChangedDialog.dismiss();
mAdminStateChangedDialog =
((ChatActivity) getActivity())
.displayDialog(
getString(
mIsEditionEnabled
? R.string.chat_room_you_are_now_admin
: R.string.chat_room_you_are_no_longer_admin));
Button cancel = mAdminStateChangedDialog.findViewById(R.id.dialog_cancel_button);
mAdminStateChangedDialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE);
cancel.setText(getString(R.string.ok));
cancel.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
mAdminStateChangedDialog.dismiss();
}
});
mAdminStateChangedDialog.show();
}
private void showLeaveGroupDialog() {
final Dialog dialog =
((ChatActivity) getActivity())
.displayDialog(getString(R.string.chat_room_leave_dialog));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
delete.setText(getString(R.string.chat_room_leave_button));
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
delete.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mChatRoom != null) {
mChatRoom.leave();
((ChatActivity) getActivity())
.showChatRoom(
mChatRoom.getLocalAddress(),
mChatRoom.getPeerAddress());
} else {
Log.e(
"[Group Info] Can't leave, chatRoom for address "
+ mGroupChatRoomAddress.asString()
+ " is null...");
}
dialog.dismiss();
}
});
cancel.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
private void applyChanges() {
if (!mIsAlreadyCreatedGroup) {
mWaitLayout.setVisibility(View.VISIBLE);
Core core = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
int i = 0;
Address[] participants = new Address[mParticipants.size()];
@ -342,14 +427,11 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
params.enableGroup(true);
mTempChatRoom =
core.createChatRoom(
params,
mSubjectField.getText().toString(),
participants);
core.createChatRoom(params, mSubjectField.getText().toString(), participants);
if (mTempChatRoom != null) {
mTempChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Group Info Fragment] createChatRoom returned null...");
Log.w("[Group Info] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
} else {
@ -403,188 +485,8 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
Address[] participantsToAdd = new Address[toAdd.size()];
toAdd.toArray(participantsToAdd);
mChatRoom.addParticipants(participantsToAdd);
LinphoneActivity.instance()
.goToChat(
mChatRoom.getLocalAddress().asStringUriOnly(),
mGroupChatRoomAddress.asString(),
null);
// Pop back stack to go back to the Messages fragment
getFragmentManager().popBackStack();
}
}
});
mConfirmButton.setEnabled(mSubjectField.getText().length() > 0 && mParticipants.size() > 0);
if (!mIsEditionEnabled) {
mSubjectField.setEnabled(false);
mConfirmButton.setVisibility(View.INVISIBLE);
mAddParticipantsButton.setVisibility(View.GONE);
}
mWaitLayout = view.findViewById(R.id.waitScreen);
mWaitLayout.setVisibility(View.GONE);
if (mChatRoom != null) {
mChatRoom.addListener(this);
}
return view;
}
@Override
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.INFO_GROUP_CHAT);
}
InputMethodManager inputMethodManager =
(InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
if (getActivity().getCurrentFocus() != null) {
inputMethodManager.hideSoftInputFromWindow(
getActivity().getCurrentFocus().getWindowToken(), 0);
}
}
@Override
public void onPause() {
if (mTempChatRoom != null) {
mTempChatRoom.removeListener(mChatRoomCreationListener);
}
super.onPause();
}
@Override
public void onDestroy() {
if (mChatRoom != null) {
mChatRoom.removeListener(this);
}
super.onDestroy();
}
private void refreshParticipantsList() {
if (mChatRoom == null) return;
mParticipants = new ArrayList<>();
for (Participant p : mChatRoom.getParticipants()) {
Address a = p.getAddress();
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(a);
if (c == null) {
c = new LinphoneContact();
String displayName = LinphoneUtils.getAddressDisplayName(a);
c.setFullName(displayName);
}
ContactAddress ca = new ContactAddress(c, a.asString(), "", c.isFriend(), p.isAdmin());
mParticipants.add(ca);
}
mAdapter.updateDataSet(mParticipants);
mAdapter.setChatRoom(mChatRoom);
}
private void refreshAdminRights() {
mAdapter.setAdminFeaturesVisible(mIsEditionEnabled);
mAdapter.setChatRoom(mChatRoom);
mSubjectField.setEnabled(mIsEditionEnabled);
mConfirmButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.INVISIBLE);
mAddParticipantsButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.GONE);
}
private void displayMeAdminStatusUpdated() {
if (mAdminStateChangedDialog != null) mAdminStateChangedDialog.dismiss();
mAdminStateChangedDialog =
LinphoneActivity.instance()
.displayDialog(
getString(
mIsEditionEnabled
? R.string.chat_room_you_are_now_admin
: R.string.chat_room_you_are_no_longer_admin));
Button cancel = mAdminStateChangedDialog.findViewById(R.id.dialog_cancel_button);
mAdminStateChangedDialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE);
cancel.setText(getString(R.string.ok));
cancel.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
mAdminStateChangedDialog.dismiss();
}
});
mAdminStateChangedDialog.show();
}
@Override
public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event_log) {
if (mChatRoom.getMe().isAdmin() != mIsEditionEnabled) {
// Either we weren't admin and we are now or the other way around
mIsEditionEnabled = mChatRoom.getMe().isAdmin();
displayMeAdminStatusUpdated();
refreshAdminRights();
}
refreshParticipantsList();
}
@Override
public void onSubjectChanged(ChatRoom cr, EventLog event_log) {
mSubjectField.setText(event_log.getSubject());
}
@Override
public void onConferenceJoined(ChatRoom cr, EventLog event_log) {}
@Override
public void onConferenceLeft(ChatRoom cr, EventLog event_log) {}
@Override
public void onParticipantAdded(ChatRoom cr, EventLog event_log) {
refreshParticipantsList();
}
@Override
public void onParticipantRemoved(ChatRoom cr, EventLog event_log) {
refreshParticipantsList();
}
@Override
public void onChatMessageShouldBeStored(ChatRoom cr, ChatMessage msg) {}
@Override
public void onIsComposingReceived(ChatRoom cr, Address remoteAddr, boolean isComposing) {}
@Override
public void onChatMessageSent(ChatRoom cr, EventLog event_log) {}
@Override
public void onConferenceAddressGeneration(ChatRoom cr) {}
@Override
public void onChatMessageReceived(ChatRoom cr, EventLog event_log) {}
@Override
public void onMessageReceived(ChatRoom cr, ChatMessage msg) {}
@Override
public void onParticipantDeviceRemoved(ChatRoom cr, EventLog event_log) {}
@Override
public void onParticipantDeviceAdded(ChatRoom cr, EventLog event_log) {}
@Override
public void onSecurityEvent(ChatRoom cr, EventLog eventLog) {
refreshParticipantsList();
}
@Override
public void onUndecryptableMessageReceived(ChatRoom cr, ChatMessage msg) {}
@Override
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {}
@Override
public void onParticipantRegistrationSubscriptionRequested(
ChatRoom cr, Address participantAddr) {}
@Override
public void onParticipantRegistrationUnsubscriptionRequested(
ChatRoom cr, Address participantAddr) {}
}

View file

@ -1,6 +1,8 @@
package org.linphone.chat;
/*
ImdnOldFragment.java
Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France
ImdnFragment.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
@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.chat;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
@ -28,7 +28,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
@ -38,8 +37,8 @@ import org.linphone.core.ChatMessage;
import org.linphone.core.ChatMessageListenerStub;
import org.linphone.core.ChatRoom;
import org.linphone.core.Core;
import org.linphone.core.Factory;
import org.linphone.core.ParticipantImdnState;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
@ -53,13 +52,11 @@ public class ImdnFragment extends Fragment {
mSentHeader,
mUndelivered,
mUndeliveredHeader;
private ImageView mBackButton;
private ChatMessageViewHolder mBubble;
private ViewGroup mContainer;
private String mLocalSipuri, mRoomUri, mMessageId;
private String mMessageId;
private Address mLocalSipAddr, mRoomAddr;
private ChatRoom mRoom;
private ChatMessage mMessage;
private ChatMessageListenerStub mListener;
@ -70,29 +67,29 @@ public class ImdnFragment extends Fragment {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mLocalSipuri = getArguments().getString("LocalSipUri");
mLocalSipAddr = LinphoneManager.getLc().createAddress(mLocalSipuri);
mRoomUri = getArguments().getString("RemoteSipUri");
mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri);
String localSipuri = getArguments().getString("LocalSipUri");
mLocalSipAddr = Factory.instance().createAddress(localSipuri);
String roomUri = getArguments().getString("RemoteSipUri");
mRoomAddr = Factory.instance().createAddress(roomUri);
mMessageId = getArguments().getString("MessageId");
}
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
mRoom = core.getChatRoom(mRoomAddr, mLocalSipAddr);
Core core = LinphoneManager.getCore();
ChatRoom room = core.getChatRoom(mRoomAddr, mLocalSipAddr);
mInflater = inflater;
mContainer = container;
View view = mInflater.inflate(R.layout.chat_imdn, container, false);
mBackButton = view.findViewById(R.id.back);
mBackButton.setOnClickListener(
ImageView backButton = view.findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mLocalSipuri, mRoomUri, null);
if (getResources().getBoolean(R.bool.isTablet)) {
((ChatActivity) getActivity()).showChatRoom(mLocalSipAddr, mRoomAddr);
} else {
LinphoneActivity.instance().onBackPressed();
((ChatActivity) getActivity()).popBackStack();
}
}
});
@ -108,7 +105,7 @@ public class ImdnFragment extends Fragment {
mBubble = new ChatMessageViewHolder(getActivity(), view.findViewById(R.id.bubble), null);
mMessage = mRoom.findMessage(mMessageId);
mMessage = room.findMessage(mMessageId);
mListener =
new ChatMessageListenerStub() {
@Override
@ -125,10 +122,6 @@ public class ImdnFragment extends Fragment {
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.MESSAGE_IMDN);
}
refreshInfo();
if (mMessage != null) {
mMessage.addListener(mListener);
@ -197,9 +190,7 @@ public class ImdnFragment extends Fragment {
final TextView sipUri = v.findViewById(R.id.sipUri);
sipUri.setText(address.asStringUriOnly());
if (!LinphoneActivity.instance()
.getResources()
.getBoolean(R.bool.show_sip_uri_in_chat)) {
if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
sipUri.setVisibility(View.GONE);
name.setOnClickListener(
new View.OnClickListener() {
@ -249,9 +240,7 @@ public class ImdnFragment extends Fragment {
final TextView sipUri = v.findViewById(R.id.sipUri);
sipUri.setText(address.asStringUriOnly());
if (!LinphoneActivity.instance()
.getResources()
.getBoolean(R.bool.show_sip_uri_in_chat)) {
if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
sipUri.setVisibility(View.GONE);
name.setOnClickListener(
new View.OnClickListener() {
@ -301,9 +290,7 @@ public class ImdnFragment extends Fragment {
final TextView sipUri = v.findViewById(R.id.sipUri);
sipUri.setText(address.asStringUriOnly());
if (!LinphoneActivity.instance()
.getResources()
.getBoolean(R.bool.show_sip_uri_in_chat)) {
if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
sipUri.setVisibility(View.GONE);
name.setOnClickListener(
new View.OnClickListener() {
@ -347,9 +334,7 @@ public class ImdnFragment extends Fragment {
final TextView sipUri = v.findViewById(R.id.sipUri);
sipUri.setText(address.asStringUriOnly());
if (!LinphoneActivity.instance()
.getResources()
.getBoolean(R.bool.show_sip_uri_in_chat)) {
if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) {
sipUri.setVisibility(View.GONE);
name.setOnClickListener(
new View.OnClickListener() {

View file

@ -1,357 +0,0 @@
package org.linphone.chat;
/*
ImdnOldFragment.java
Copyright (C) 2010-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 android.app.Fragment;
import android.os.Bundle;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatMessageListenerStub;
import org.linphone.core.ChatRoom;
import org.linphone.core.Core;
import org.linphone.core.ParticipantImdnState;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.FileUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
public class ImdnOldFragment extends Fragment {
private LayoutInflater mInflater;
private LinearLayout mRead,
mReadHeader,
mDelivered,
mDeliveredHeader,
mSent,
mSentHeader,
mUndelivered,
mUndeliveredHeader;
private ImageView mBackButton;
private ChatMessageOldViewHolder mBubble;
private ViewGroup mContainer;
private String mLocalSipUri, mRoomUri, mMessageId;
private Address mLocalAddr, mRoomAddr;
private ChatRoom mRoom;
private ChatMessage mMessage;
private ChatMessageListenerStub mListener;
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mLocalSipUri = getArguments().getString("LocalSipUri");
mLocalAddr = LinphoneManager.getLc().createAddress(mLocalSipUri);
mRoomUri = getArguments().getString("RemoteSipUri");
mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri);
mMessageId = getArguments().getString("MessageId");
}
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
mRoom = core.getChatRoom(mRoomAddr, mLocalAddr);
mInflater = inflater;
mContainer = container;
View view = mInflater.inflate(R.layout.chat_imdn_old, container, false);
mBackButton = view.findViewById(R.id.back);
mBackButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mLocalSipUri, mRoomUri, null);
} else {
LinphoneActivity.instance().onBackPressed();
}
}
});
mRead = view.findViewById(R.id.read_layout);
mDelivered = view.findViewById(R.id.delivered_layout);
mSent = view.findViewById(R.id.sent_layout);
mUndelivered = view.findViewById(R.id.undelivered_layout);
mReadHeader = view.findViewById(R.id.read_layout_header);
mDeliveredHeader = view.findViewById(R.id.delivered_layout_header);
mSentHeader = view.findViewById(R.id.sent_layout_header);
mUndeliveredHeader = view.findViewById(R.id.undelivered_layout_header);
mBubble = new ChatMessageOldViewHolder(view.findViewById(R.id.bubble));
mBubble.eventLayout.setVisibility(View.GONE);
mBubble.bubbleLayout.setVisibility(View.VISIBLE);
mBubble.delete.setVisibility(View.GONE);
mBubble.messageText.setVisibility(View.GONE);
mBubble.messageImage.setVisibility(View.GONE);
mBubble.fileTransferLayout.setVisibility(View.GONE);
mBubble.fileName.setVisibility(View.GONE);
mBubble.openFileButton.setVisibility(View.GONE);
mBubble.messageStatus.setVisibility(View.INVISIBLE);
mBubble.messageSendingInProgress.setVisibility(View.GONE);
mBubble.imdmLayout.setVisibility(View.INVISIBLE);
mMessage = mRoom.findMessage(mMessageId);
mListener =
new ChatMessageListenerStub() {
@Override
public void onParticipantImdnStateChanged(
ChatMessage msg, ParticipantImdnState state) {
refreshInfo();
}
};
if (mMessage == null) return null;
RelativeLayout.LayoutParams layoutParams =
new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
layoutParams.setMargins(100, 10, 10, 10);
if (mMessage.isOutgoing()) {
mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing);
Compatibility.setTextAppearance(mBubble.contactName, getActivity(), R.style.font3);
Compatibility.setTextAppearance(
mBubble.fileTransferAction, getActivity(), R.style.font15);
mBubble.fileTransferAction.setBackgroundResource(
R.drawable.resizable_confirm_delete_button);
} else {
mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming);
Compatibility.setTextAppearance(
mBubble.contactName, getActivity(), R.style.contact_organization_font);
Compatibility.setTextAppearance(
mBubble.fileTransferAction, getActivity(), R.style.button_font);
mBubble.fileTransferAction.setBackgroundResource(R.drawable.resizable_assistant_button);
}
return view;
}
@Override
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.MESSAGE_IMDN);
}
if (mMessage != null) {
mMessage.addListener(mListener);
}
refreshInfo();
}
@Override
public void onPause() {
if (mMessage != null) {
mMessage.removeListener(mListener);
}
super.onPause();
}
private void refreshInfo() {
Address remoteSender = mMessage.getFromAddress();
LinphoneContact contact =
ContactsManager.getInstance().findContactFromAddress(remoteSender);
String displayName;
if (contact != null) {
if (contact.getFullName() != null) {
displayName = contact.getFullName();
} else {
displayName = LinphoneUtils.getAddressDisplayName(remoteSender);
}
ContactAvatar.displayAvatar(contact, mBubble.avatarLayout);
} else {
displayName = LinphoneUtils.getAddressDisplayName(remoteSender);
ContactAvatar.displayAvatar(displayName, mBubble.avatarLayout);
}
mBubble.contactName.setText(
LinphoneUtils.timestampToHumanDate(
getActivity(), mMessage.getTime(), R.string.messages_date_format)
+ " - "
+ displayName);
if (mMessage.hasTextContent()) {
String msg = mMessage.getTextContent();
Spanned text = LinphoneUtils.getTextWithHttpLinks(msg);
mBubble.messageText.setText(text);
mBubble.messageText.setMovementMethod(LinkMovementMethod.getInstance());
mBubble.messageText.setVisibility(View.VISIBLE);
}
String appData = mMessage.getAppdata();
if (appData != null) { // Something to display
mBubble.fileName.setVisibility(View.VISIBLE);
mBubble.fileName.setText(FileUtils.getNameFromFilePath(appData));
// We purposely chose not to display the image
}
mRead.removeAllViews();
mDelivered.removeAllViews();
mSent.removeAllViews();
mUndelivered.removeAllViews();
ParticipantImdnState[] participants =
mMessage.getParticipantsByImdnState(ChatMessage.State.Displayed);
mReadHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE);
boolean first = true;
for (ParticipantImdnState participant : participants) {
Address address = participant.getParticipant().getAddress();
LinphoneContact participantContact =
ContactsManager.getInstance().findContactFromAddress(address);
String participantDisplayName =
participantContact != null
? participantContact.getFullName()
: LinphoneUtils.getAddressDisplayName(address);
View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false);
v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE);
((TextView) v.findViewById(R.id.time))
.setText(
LinphoneUtils.timestampToHumanDate(
getActivity(),
participant.getStateChangeTime(),
R.string.messages_date_format));
((TextView) v.findViewById(R.id.name)).setText(participantDisplayName);
if (participantContact != null) {
ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar(
participantDisplayName, v.findViewById(R.id.avatar_layout));
}
mRead.addView(v);
first = false;
}
participants = mMessage.getParticipantsByImdnState(ChatMessage.State.DeliveredToUser);
mDeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE);
first = true;
for (ParticipantImdnState participant : participants) {
Address address = participant.getParticipant().getAddress();
LinphoneContact participantContact =
ContactsManager.getInstance().findContactFromAddress(address);
String participantDisplayName =
participantContact != null
? participantContact.getFullName()
: LinphoneUtils.getAddressDisplayName(address);
View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false);
v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE);
((TextView) v.findViewById(R.id.time))
.setText(
LinphoneUtils.timestampToHumanDate(
getActivity(),
participant.getStateChangeTime(),
R.string.messages_date_format));
((TextView) v.findViewById(R.id.name)).setText(participantDisplayName);
if (participantContact != null) {
ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar(
participantDisplayName, v.findViewById(R.id.avatar_layout));
}
mDelivered.addView(v);
first = false;
}
participants = mMessage.getParticipantsByImdnState(ChatMessage.State.Delivered);
mSentHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE);
first = true;
for (ParticipantImdnState participant : participants) {
Address address = participant.getParticipant().getAddress();
LinphoneContact participantContact =
ContactsManager.getInstance().findContactFromAddress(address);
String participantDisplayName =
participantContact != null
? participantContact.getFullName()
: LinphoneUtils.getAddressDisplayName(address);
View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false);
v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE);
((TextView) v.findViewById(R.id.time))
.setText(
LinphoneUtils.timestampToHumanDate(
getActivity(),
participant.getStateChangeTime(),
R.string.messages_date_format));
((TextView) v.findViewById(R.id.name)).setText(participantDisplayName);
if (participantContact != null) {
ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar(
participantDisplayName, v.findViewById(R.id.avatar_layout));
}
mSent.addView(v);
first = false;
}
participants = mMessage.getParticipantsByImdnState(ChatMessage.State.NotDelivered);
mUndeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE);
first = true;
for (ParticipantImdnState participant : participants) {
Address address = participant.getParticipant().getAddress();
LinphoneContact participantContact =
ContactsManager.getInstance().findContactFromAddress(address);
String participantDisplayName =
participantContact != null
? participantContact.getFullName()
: LinphoneUtils.getAddressDisplayName(address);
View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false);
v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE);
((TextView) v.findViewById(R.id.name)).setText(participantDisplayName);
if (participantContact != null) {
ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar(
participantDisplayName, v.findViewById(R.id.avatar_layout));
}
mUndelivered.addView(v);
first = false;
}
}
}

View file

@ -141,15 +141,13 @@ class ApiTwentyFourPlus {
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action replyAction =
new Notification.Action.Builder(
return new Notification.Action.Builder(
R.drawable.chat_send_over,
context.getString(R.string.notification_reply_label),
replyPendingIntent)
.addRemoteInput(remoteInput)
.setAllowGeneratedReplies(true)
.build();
return replyAction;
}
public static Notification.Action getMarkMessageAsReadAction(
@ -166,14 +164,11 @@ class ApiTwentyFourPlus {
markAsReadIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action markAsReadAction =
new Notification.Action.Builder(
return new Notification.Action.Builder(
R.drawable.chat_send_over,
context.getString(R.string.notification_mark_as_read_label),
markAsReadPendingIntent)
.build();
return markAsReadAction;
}
public static Notification.Action getCallAnswerAction(Context context, int callId) {
@ -185,14 +180,11 @@ class ApiTwentyFourPlus {
PendingIntent.getBroadcast(
context, callId, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action answerAction =
new Notification.Action.Builder(
return new Notification.Action.Builder(
R.drawable.call_audio_start,
context.getString(R.string.notification_call_answer_label),
answerPendingIntent)
.build();
return answerAction;
}
public static Notification.Action getCallDeclineAction(Context context, int callId) {
@ -204,13 +196,11 @@ class ApiTwentyFourPlus {
PendingIntent.getBroadcast(
context, callId, hangupIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action declineAction =
new Notification.Action.Builder(
return new Notification.Action.Builder(
R.drawable.call_hangup,
context.getString(R.string.notification_call_hangup_label),
hangupPendingIntent)
.build();
return declineAction;
}
public static void closeContentProviderClient(ContentProviderClient client) {

View file

@ -33,7 +33,6 @@ import org.linphone.R;
@TargetApi(21)
class ApiTwentyOnePlus {
@SuppressWarnings("deprecation")
public static Notification createMessageNotification(
Context context,
int msgCount,

View file

@ -22,13 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import android.annotation.TargetApi;
import android.content.Context;
import android.os.PowerManager;
import android.widget.TextView;
@TargetApi(23)
class ApiTwentyThreePlus {
public static void setTextAppearance(TextView textview, int style) {
textview.setTextAppearance(style);
}
public static boolean isAppIdleMode(Context context) {
return ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).isDeviceIdleMode();

View file

@ -29,7 +29,6 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.provider.Settings;
import android.widget.TextView;
import org.linphone.mediastream.Version;
import org.linphone.notifications.Notifiable;
@ -167,14 +166,6 @@ public class Compatibility {
return true;
}
public static void setTextAppearance(TextView textview, Context context, int style) {
if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) {
ApiTwentyThreePlus.setTextAppearance(textview, style);
} else {
textview.setTextAppearance(context, style);
}
}
public static void startService(Context context, Intent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
ApiTwentySixPlus.startService(context, intent);

View file

@ -36,8 +36,8 @@ public class CompatibilityScaleGestureDetector
listener = newListener;
}
public boolean onTouchEvent(MotionEvent event) {
return detector.onTouchEvent(event);
public void onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
}
@Override

View file

@ -32,53 +32,40 @@ import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import java.io.Serializable;
import java.util.ArrayList;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.core.tools.Log;
class AndroidContact implements Serializable {
protected String mAndroidId, mAndroidRawId, mAndroidLookupKey;
protected boolean isAndroidRawIdLinphone;
String mAndroidId;
private String mAndroidRawId;
private boolean isAndroidRawIdLinphone;
private transient ArrayList<ContentProviderOperation> mChangesToCommit;
private final transient ArrayList<ContentProviderOperation> mChangesToCommit;
protected AndroidContact() {
AndroidContact() {
mChangesToCommit = new ArrayList<>();
isAndroidRawIdLinphone = false;
}
protected String getAndroidId() {
String getAndroidId() {
return mAndroidId;
}
protected void setAndroidId(String id) {
void setAndroidId(String id) {
mAndroidId = id;
}
protected String getAndroidLookupKey() {
return mAndroidLookupKey;
}
protected void setAndroidLookupKey(String lookupKey) {
mAndroidLookupKey = lookupKey;
}
protected Uri getAndroidLookupUri() {
return ContactsContract.Contacts.getLookupUri(
Long.parseLong(mAndroidId), getAndroidLookupKey());
}
protected boolean isAndroidContact() {
boolean isAndroidContact() {
return mAndroidId != null;
}
protected void addChangesToCommit(ContentProviderOperation operation) {
private void addChangesToCommit(ContentProviderOperation operation) {
Log.i("[Contact] Added operation " + operation);
mChangesToCommit.add(operation);
}
protected void saveChangesCommited() {
void saveChangesCommited() {
if (ContactsManager.getInstance().hasReadContactsAccess() && mChangesToCommit.size() > 0) {
try {
ContentResolver contentResolver = LinphoneService.instance().getContentResolver();
@ -123,11 +110,8 @@ class AndroidContact implements Serializable {
}
}
protected void createAndroidContact() {
if (LinphoneManager.getInstance()
.getContext()
.getResources()
.getBoolean(R.bool.use_linphone_tag)) {
void createAndroidContact() {
if (LinphoneService.instance().getResources().getBoolean(R.bool.use_linphone_tag)) {
Log.i("[Contact] Creating contact using linphone account type");
addChangesToCommit(
ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
@ -157,21 +141,21 @@ class AndroidContact implements Serializable {
}
}
protected void deleteAndroidContact() {
void deleteAndroidContact() {
ContactsManager.getInstance().delete(mAndroidId);
}
protected Uri getContactThumbnailPictureUri() {
Uri getContactThumbnailPictureUri() {
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(mAndroidId));
return Uri.withAppendedPath(person, Contacts.Photo.CONTENT_DIRECTORY);
}
protected Uri getContactPictureUri() {
Uri getContactPictureUri() {
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(mAndroidId));
return Uri.withAppendedPath(person, Contacts.Photo.DISPLAY_PHOTO);
}
protected void setName(String fn, String ln) {
void setName(String fn, String ln) {
if ((fn == null || fn.isEmpty()) && (ln == null || ln.isEmpty())) {
Log.e("[Contact] Can't set both first and last name to null or empty");
return;
@ -224,7 +208,7 @@ class AndroidContact implements Serializable {
}
}
protected void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) {
void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) {
if (value == null || value.isEmpty()) {
Log.e("[Contact] Can't add null or empty number or address");
return;
@ -373,7 +357,7 @@ class AndroidContact implements Serializable {
}
}
protected void removeNumberOrAddress(String noa, boolean isSIP) {
void removeNumberOrAddress(String noa, boolean isSIP) {
if (noa == null || noa.isEmpty()) {
Log.e("[Contact] Can't remove null or empty number or address.");
return;
@ -381,7 +365,6 @@ class AndroidContact implements Serializable {
if (mAndroidId == null) {
Log.e("[Contact] Can't remove a number or address from non existing contact");
return;
} else {
Log.i(
"[Contact] Removing number or address "
@ -433,7 +416,7 @@ class AndroidContact implements Serializable {
}
}
protected void setOrganization(String org, String previousValue) {
void setOrganization(String org, String previousValue) {
if (org == null || org.isEmpty()) {
if (mAndroidId == null) {
Log.e("[Contact] Can't set organization to null or empty for new contact");
@ -506,7 +489,7 @@ class AndroidContact implements Serializable {
}
}
protected void setPhoto(byte[] photo) {
void setPhoto(byte[] photo) {
if (photo == null) {
Log.e("[Contact] Can't set null picture.");
return;
@ -542,7 +525,7 @@ class AndroidContact implements Serializable {
}
}
protected String findRawContactID() {
private String findRawContactID() {
ContentResolver resolver = LinphoneService.instance().getContentResolver();
String result = null;
String[] projection = {ContactsContract.RawContacts._ID};
@ -564,11 +547,8 @@ class AndroidContact implements Serializable {
return result;
}
protected void createRawLinphoneContactFromExistingAndroidContactIfNeeded(String fullName) {
if (LinphoneManager.getInstance()
.getContext()
.getResources()
.getBoolean(R.bool.use_linphone_tag)) {
void createRawLinphoneContactFromExistingAndroidContactIfNeeded() {
if (LinphoneService.instance().getResources().getBoolean(R.bool.use_linphone_tag)) {
if (mAndroidId != null && (mAndroidRawId == null || !isAndroidRawIdLinphone)) {
if (mAndroidRawId == null) {
Log.i("[Contact] RAW ID not found for contact " + mAndroidId);

View file

@ -53,25 +53,18 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
"data4", // Normalized phone number
};
private Context mContext;
public AsyncContactsLoader(Context context) {
mContext = context;
}
public AsyncContactsLoader() {}
@Override
protected void onPreExecute() {
Log.i("[Contacts Manager] Synchronization started");
if (mContext == null) {
mContext = LinphoneService.instance().getApplicationContext();
}
Context context = LinphoneService.instance().getApplicationContext();
if (LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
String rls = mContext.getString(R.string.rls_uri);
for (FriendList list : LinphoneManager.getLc().getFriendsLists()) {
if (rls != null
&& (list.getRlsAddress() == null
|| !list.getRlsAddress().asStringUriOnly().equals(rls))) {
String rls = context.getString(R.string.rls_uri);
for (FriendList list : LinphoneManager.getCore().getFriendsLists()) {
if (list.getRlsAddress() == null
|| !list.getRlsAddress().asStringUriOnly().equals(rls)) {
list.setRlsUri(rls);
}
list.addListener(ContactsManager.getInstance());
@ -82,8 +75,9 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
@Override
protected AsyncContactsData doInBackground(Void... params) {
Log.i("[Contacts Manager] Background synchronization started");
Context context = LinphoneService.instance().getApplicationContext();
Cursor c =
mContext.getContentResolver()
context.getContentResolver()
.query(
ContactsContract.Data.CONTENT_URI,
PROJECTION,
@ -95,9 +89,9 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
AsyncContactsData data = new AsyncContactsData();
List<String> nativeIds = new ArrayList<>();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
for (FriendList list : lc.getFriendsLists()) {
Core core = LinphoneManager.getCore();
if (core != null) {
for (FriendList list : core.getFriendsLists()) {
for (Friend friend : list.getFriends()) {
if (isCancelled()) return data;
@ -139,7 +133,6 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
nativeIds.add(id);
contact = new LinphoneContact();
contact.setAndroidId(id);
contact.setAndroidLookupKey(lookupKey);
androidContactsCache.put(id, contact);
}
@ -147,7 +140,7 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
}
c.close();
for (FriendList list : lc.getFriendsLists()) {
for (FriendList list : core.getFriendsLists()) {
for (Friend friend : list.getFriends()) {
if (isCancelled()) return data;
@ -191,7 +184,7 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
}
}
if (!mContext.getResources().getBoolean(R.bool.hide_sip_contacts_without_presence)) {
if (!context.getResources().getBoolean(R.bool.hide_sip_contacts_without_presence)) {
if (contact.hasAddress() && !data.sipContacts.contains(contact)) {
data.sipContacts.add(contact);
}
@ -217,7 +210,7 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
// Now that contact fetching is asynchronous, this is required to ensure
// presence subscription event will be sent with all friends
if (LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
for (FriendList list : LinphoneManager.getLc().getFriendsLists()) {
for (FriendList list : LinphoneManager.getCore().getFriendsLists()) {
list.updateSubscriptions();
}
}

View file

@ -29,17 +29,15 @@ public class ContactAddress implements Serializable {
private LinphoneContact mContact;
private String mAddress;
private String mPhoneNumber;
private boolean mIsLinphoneContact;
private boolean mIsSelect = false;
private boolean mIsAdmin = false;
private transient View mView;
public ContactAddress(LinphoneContact c, String a, String pn, boolean isLC) {
init(c, a, pn, isLC);
public ContactAddress(LinphoneContact c, String a, String pn) {
init(c, a, pn);
}
public ContactAddress(LinphoneContact c, String a, String pn, boolean isLC, boolean isAdmin) {
init(c, a, pn, isLC);
public ContactAddress(LinphoneContact c, String a, String pn, boolean isAdmin) {
init(c, a, pn);
mIsAdmin = isAdmin;
}
@ -51,14 +49,6 @@ public class ContactAddress implements Serializable {
mIsAdmin = admin;
}
public boolean isSelect() {
return mIsSelect;
}
public void setSelect(boolean select) {
mIsSelect = select;
}
public View getView() {
return mView;
}
@ -122,11 +112,10 @@ public class ContactAddress implements Serializable {
return mContact != null && mContact.hasFriendCapability(capability);
}
private void init(LinphoneContact c, String a, String pn, boolean isLC) {
private void init(LinphoneContact c, String a, String pn) {
mContact = c;
mAddress = a;
mPhoneNumber = pn;
mIsLinphoneContact = isLC;
}
@Override

View file

@ -34,7 +34,6 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TextView;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Address;
@ -49,15 +48,12 @@ import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel;
import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
public class ContactDetailsFragment extends Fragment
implements OnClickListener, ContactsUpdatedListener {
public class ContactDetailsFragment extends Fragment implements ContactsUpdatedListener {
private LinphoneContact mContact;
private ImageView mEditContact, mDeleteContact, mBack;
private TextView mOrganization;
private RelativeLayout mWaitLayout;
private LayoutInflater mInflater;
@ -66,89 +62,16 @@ public class ContactDetailsFragment extends Fragment
private ChatRoom mChatRoom;
private ChatRoomListenerStub mChatRoomCreationListener;
private final OnClickListener mDialListener =
new OnClickListener() {
@Override
public void onClick(View v) {
if (LinphoneActivity.isInstanciated()) {
String tag = (String) v.getTag();
LinphoneActivity.instance()
.setAddresGoToDialerAndCall(tag, mContact.getFullName());
}
}
};
private final OnClickListener mChatListener =
new OnClickListener() {
@Override
public void onClick(View v) {
if (LinphoneActivity.isInstanciated()) {
String tag = (String) v.getTag();
Core lc = LinphoneManager.getLc();
Address participant = Factory.instance().createAddress(tag);
ProxyConfig defaultProxyConfig = lc.getDefaultProxyConfig();
boolean isSecured = v.getId() == R.id.contact_chat_secured;
if (defaultProxyConfig != null) {
ChatRoom room =
lc.findOneToOneChatRoom(
defaultProxyConfig.getContact(),
participant,
isSecured);
if (room != null) {
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asStringUriOnly(),
null);
} else {
if (defaultProxyConfig.getConferenceFactoryUri() != null
&& (isSecured
|| !LinphonePreferences.instance()
.useBasicChatRoomFor1To1())) {
mWaitLayout.setVisibility(View.VISIBLE);
ChatRoomParams params = lc.createDefaultChatRoomParams();
params.enableEncryption(isSecured);
params.enableGroup(false);
// We don't want a basic chat room,
// so if isSecured is false we have to set this manually
params.setBackend(ChatRoomBackend.FlexisipChat);
Address participants[] = new Address[1];
participants[0] = participant;
mChatRoom =
lc.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w(
"[Contact Details Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
} else {
room = lc.getChatRoom(participant);
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asStringUriOnly(),
null);
}
}
}
}
}
};
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContact = (LinphoneContact) getArguments().getSerializable("Contact");
if (mContact == null) {
if (savedInstanceState != null) {
mContact = (LinphoneContact) savedInstanceState.get("Contact");
}
}
this.mInflater = inflater;
mInflater = inflater;
mView = inflater.inflate(R.layout.contact, container, false);
if (getArguments() != null) {
@ -158,27 +81,62 @@ public class ContactDetailsFragment extends Fragment
mWaitLayout = mView.findViewById(R.id.waitScreen);
mWaitLayout.setVisibility(View.GONE);
mEditContact = mView.findViewById(R.id.editContact);
mEditContact.setOnClickListener(this);
ImageView editContact = mView.findViewById(R.id.editContact);
editContact.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
((ContactsActivity) getActivity()).showContactEdit(mContact);
}
});
mDeleteContact = mView.findViewById(R.id.deleteContact);
mDeleteContact.setOnClickListener(this);
ImageView deleteContact = mView.findViewById(R.id.deleteContact);
deleteContact.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
final Dialog dialog =
((ContactsActivity) getActivity())
.displayDialog(getString(R.string.delete_text));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
delete.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
mContact.delete();
// To ensure removed contact won't appear in the contacts
// list anymore
ContactsManager.getInstance().fetchContactsAsync();
((ContactsActivity) getActivity()).goBack();
dialog.dismiss();
}
});
cancel.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
});
mOrganization = mView.findViewById(R.id.contactOrganization);
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
String org = mContact.getOrganization();
if (org != null && !org.isEmpty() && isOrgVisible) {
mOrganization.setText(org);
} else {
mOrganization.setVisibility(View.GONE);
}
mBack = mView.findViewById(R.id.back);
if (getResources().getBoolean(R.bool.isTablet)) {
mBack.setVisibility(View.INVISIBLE);
} else {
mBack.setOnClickListener(this);
ImageView back = mView.findViewById(R.id.back);
back.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
((ContactsActivity) getActivity()).goBack();
}
});
back.setVisibility(
getResources().getBoolean(R.bool.isTablet) ? View.INVISIBLE : View.VISIBLE);
mChatRoomCreationListener =
new ChatRoomListenerStub() {
@ -186,14 +144,11 @@ public class ContactDetailsFragment extends Fragment
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance()
.goToChat(
cr.getLocalAddress().asStringUriOnly(),
cr.getPeerAddress().asStringUriOnly(),
null);
((ContactsActivity) getActivity())
.showChatRoom(cr.getLocalAddress(), cr.getPeerAddress());
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
((ContactsActivity) getActivity()).displayChatRoomError();
Log.e(
"Group chat room for address "
+ cr.getPeerAddress()
@ -205,15 +160,58 @@ public class ContactDetailsFragment extends Fragment
return mView;
}
public void changeDisplayedContact(LinphoneContact newContact) {
@Override
public void onContactsUpdated() {
LinphoneContact contact =
ContactsManager.getInstance().findContactFromAndroidId(mContact.getAndroidId());
if (contact != null) {
changeDisplayedContact(contact);
}
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
displayContact(mInflater, mView);
}
@Override
public void onPause() {
if (mChatRoom != null) {
mChatRoom.removeListener(mChatRoomCreationListener);
}
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("Contact", mContact);
}
private void changeDisplayedContact(LinphoneContact newContact) {
mContact = newContact;
displayContact(mInflater, mView);
}
@SuppressLint("InflateParams")
private void displayContact(LayoutInflater inflater, View view) {
if (mContact == null) return;
ContactAvatar.displayAvatar(mContact, view.findViewById(R.id.avatar_layout));
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
if (mContact != null
&& mContact.getOrganization() != null
&& !mContact.getOrganization().isEmpty()
&& isOrgVisible) {
mOrganization.setText(mContact.getOrganization());
} else {
mOrganization.setVisibility(View.GONE);
}
TextView contactName = view.findViewById(R.id.contact_name);
contactName.setText(mContact.getFullName());
mOrganization.setText(
@ -235,17 +233,17 @@ public class ContactDetailsFragment extends Fragment
TextView label = v.findViewById(R.id.address_label);
if (noa.isSIPAddress()) {
label.setText(R.string.sip_address);
skip |= getResources().getBoolean(R.bool.hide_contact_sip_addresses);
skip = getResources().getBoolean(R.bool.hide_contact_sip_addresses);
} else {
label.setText(R.string.phone_number);
skip |= getResources().getBoolean(R.bool.hide_contact_phone_numbers);
skip = getResources().getBoolean(R.bool.hide_contact_phone_numbers);
}
TextView tv = v.findViewById(R.id.numeroOrAddress);
tv.setText(displayedNumberOrAddress);
tv.setSelected(true);
ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig();
ProxyConfig lpc = LinphoneManager.getCore().getDefaultProxyConfig();
if (lpc != null) {
String username = lpc.normalizePhoneNumber(displayedNumberOrAddress);
if (username != null) {
@ -294,7 +292,15 @@ public class ContactDetailsFragment extends Fragment
String contactAddress = mContact.getContactFromPresenceModelForUriOrTel(noa.getValue());
if (!mDisplayChatAddressOnly) {
v.findViewById(R.id.contact_call).setOnClickListener(mDialListener);
v.findViewById(R.id.contact_call)
.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
String tag = (String) v.getTag();
LinphoneManager.getCallManager().newOutgoingCall(tag, null);
}
});
if (contactAddress != null) {
v.findViewById(R.id.contact_call).setTag(contactAddress);
} else {
@ -304,8 +310,22 @@ public class ContactDetailsFragment extends Fragment
v.findViewById(R.id.contact_call).setVisibility(View.GONE);
}
v.findViewById(R.id.contact_chat).setOnClickListener(mChatListener);
v.findViewById(R.id.contact_chat_secured).setOnClickListener(mChatListener);
v.findViewById(R.id.contact_chat)
.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
goToChat((String) v.getTag(), false);
}
});
v.findViewById(R.id.contact_chat_secured)
.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
goToChat((String) v.getTag(), true);
}
});
if (contactAddress != null) {
v.findViewById(R.id.contact_chat).setTag(contactAddress);
v.findViewById(R.id.contact_chat_secured).setTag(contactAddress);
@ -333,69 +353,53 @@ public class ContactDetailsFragment extends Fragment
}
}
@Override
public void onContactsUpdated() {
LinphoneContact contact =
ContactsManager.getInstance().findContactFromAndroidId(mContact.getAndroidId());
if (contact != null) {
changeDisplayedContact(contact);
}
}
private void goToChat(String tag, boolean isSecured) {
Core core = LinphoneManager.getCore();
Address participant = Factory.instance().createAddress(tag);
ProxyConfig defaultProxyConfig = core.getDefaultProxyConfig();
@Override
public void onResume() {
super.onResume();
if (defaultProxyConfig != null) {
ChatRoom room =
core.findOneToOneChatRoom(
defaultProxyConfig.getContact(), participant, isSecured);
if (room != null) {
((ContactsActivity) getActivity())
.showChatRoom(room.getLocalAddress(), room.getPeerAddress());
} else {
if (defaultProxyConfig.getConferenceFactoryUri() != null
&& (isSecured
|| !LinphonePreferences.instance().useBasicChatRoomFor1To1())) {
mWaitLayout.setVisibility(View.VISIBLE);
ContactsManager.getInstance().addContactsListener(this);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACT_DETAIL);
}
displayContact(mInflater, mView);
}
ChatRoomParams params = core.createDefaultChatRoomParams();
params.enableEncryption(isSecured);
params.enableGroup(false);
// We don't want a basic chat room,
// so if isSecured is false we have to set this manually
params.setBackend(ChatRoomBackend.FlexisipChat);
@Override
public void onPause() {
Address[] participants = new Address[1];
participants[0] = participant;
mChatRoom =
core.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
if (mChatRoom != null) {
mChatRoom.removeListener(mChatRoomCreationListener);
mChatRoom.addListener(mChatRoomCreationListener);
} else {
Log.w("[Contact Details Fragment] createChatRoom returned null...");
mWaitLayout.setVisibility(View.GONE);
}
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
} else {
room = core.getChatRoom(participant);
if (room != null) {
((ContactsActivity) getActivity())
.showChatRoom(room.getLocalAddress(), room.getPeerAddress());
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.editContact) {
ContactsManager.getInstance().editContact(getActivity(), mContact, null);
} else if (id == R.id.deleteContact) {
final Dialog dialog =
LinphoneActivity.instance().displayDialog(getString(R.string.delete_text));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
delete.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
mContact.delete();
// To ensure removed contact won't appear in the contacts list anymore
ContactsManager.getInstance().fetchContactsAsync();
LinphoneActivity.instance().displayContacts(false);
dialog.dismiss();
}
});
cancel.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
} else if (id == R.id.back) {
getFragmentManager().popBackStackImmediate();
}
}
}

View file

@ -19,6 +19,7 @@ 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.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
@ -49,11 +50,8 @@ import android.widget.LinearLayout;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.tools.Log;
import org.linphone.mediastream.Version;
@ -66,9 +64,8 @@ public class ContactEditorFragment extends Fragment {
private static final int PHOTO_SIZE = 128;
private View mView;
private ImageView mCancel, mDeleteContact, mOk;
private ImageView mAddNumber, mAddSipAddress, mContactPicture;
private LinearLayout mPhoneNumbersSection, mSipAddressesSection;
private ImageView mOk;
private ImageView mContactPicture;
private EditText mFirstName, mLastName, mOrganization;
private LayoutInflater mInflater;
private boolean mIsNewContact;
@ -88,48 +85,45 @@ public class ContactEditorFragment extends Fragment {
mIsNewContact = true;
if (getArguments() != null) {
Serializable obj = getArguments().getSerializable("Contact");
if (obj != null) {
mContact = (LinphoneContact) obj;
mContact.createRawLinphoneContactFromExistingAndroidContactIfNeeded(
mContact.getFullName());
mContact = (LinphoneContact) getArguments().getSerializable("Contact");
if (getArguments().containsKey("SipUri")) {
mNewSipOrNumberToAdd = getArguments().getString("SipUri");
}
if (getArguments().containsKey("DisplayName")) {
mNewDisplayName = getArguments().getString("DisplayName");
}
} else if (savedInstanceState != null) {
mContact = (LinphoneContact) savedInstanceState.get("Contact");
mNewSipOrNumberToAdd = savedInstanceState.getString("SipUri");
mNewDisplayName = savedInstanceState.getString("DisplayName");
}
if (mContact != null) {
mContact.createRawLinphoneContactFromExistingAndroidContactIfNeeded();
mIsNewContact = false;
if (getArguments().getString("NewSipAdress") != null) {
mNewSipOrNumberToAdd = getArguments().getString("NewSipAdress");
}
if (getArguments().getString("NewDisplayName") != null) {
mNewDisplayName = getArguments().getString("NewDisplayName");
}
} else if (getArguments().getString("NewSipAdress") != null) {
mNewSipOrNumberToAdd = getArguments().getString("NewSipAdress");
if (getArguments().getString("NewDisplayName") != null) {
mNewDisplayName = getArguments().getString("NewDisplayName");
}
}
}
mView = inflater.inflate(R.layout.contact_edit, container, false);
mPhoneNumbersSection = mView.findViewById(R.id.phone_numbers);
LinearLayout phoneNumbersSection = mView.findViewById(R.id.phone_numbers);
if (getResources().getBoolean(R.bool.hide_phone_numbers_in_editor)
|| !ContactsManager.getInstance().hasReadContactsAccess()) {
// Currently linphone friends don't support phone mNumbers, so hide them
mPhoneNumbersSection.setVisibility(View.GONE);
phoneNumbersSection.setVisibility(View.GONE);
}
mSipAddressesSection = mView.findViewById(R.id.sip_addresses);
LinearLayout sipAddressesSection = mView.findViewById(R.id.sip_addresses);
if (getResources().getBoolean(R.bool.hide_sip_addresses_in_editor)) {
mSipAddressesSection.setVisibility(View.GONE);
sipAddressesSection.setVisibility(View.GONE);
}
mDeleteContact = mView.findViewById(R.id.delete_contact);
ImageView deleteContact = mView.findViewById(R.id.delete_contact);
mCancel = mView.findViewById(R.id.cancel);
mCancel.setOnClickListener(
ImageView cancel = mView.findViewById(R.id.cancel);
cancel.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
getFragmentManager().popBackStackImmediate();
((ContactsActivity) getActivity()).goBack();
}
});
@ -201,8 +195,8 @@ public class ContactEditorFragment extends Fragment {
}
getFragmentManager().popBackStackImmediate();
if (mIsNewContact || LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().displayContact(mContact, false);
if (mIsNewContact || getResources().getBoolean(R.bool.isTablet)) {
((ContactsActivity) getActivity()).showContactDetails(mContact);
}
}
});
@ -216,7 +210,7 @@ public class ContactEditorFragment extends Fragment {
public void onClick(View v) {
InputMethodManager imm =
(InputMethodManager)
LinphoneActivity.instance()
getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
@ -258,15 +252,6 @@ public class ContactEditorFragment extends Fragment {
});
mOrganization = mView.findViewById(R.id.contactOrganization);
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
if (!isOrgVisible) {
mOrganization.setVisibility(View.GONE);
mView.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE);
} else {
if (!mIsNewContact) {
mOrganization.setText(mContact.getOrganization());
}
}
if (!mIsNewContact) {
String fn = mContact.getFirstName();
@ -279,12 +264,12 @@ public class ContactEditorFragment extends Fragment {
mFirstName.setText("");
}
mDeleteContact.setOnClickListener(
deleteContact.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
final Dialog dialog =
LinphoneActivity.instance()
((ContactsActivity) getActivity())
.displayDialog(getString(R.string.delete_text));
Button delete = dialog.findViewById(R.id.dialog_delete_button);
Button cancel = dialog.findViewById(R.id.dialog_cancel_button);
@ -294,7 +279,7 @@ public class ContactEditorFragment extends Fragment {
@Override
public void onClick(View view) {
mContact.delete();
LinphoneActivity.instance().displayContacts(false);
((ContactsActivity) getActivity()).goBack();
dialog.dismiss();
}
});
@ -310,34 +295,27 @@ public class ContactEditorFragment extends Fragment {
}
});
} else {
mDeleteContact.setVisibility(View.INVISIBLE);
deleteContact.setVisibility(View.INVISIBLE);
}
mContactPicture = mView.findViewById(R.id.contact_picture);
if (mContact != null) {
ContactAvatar.displayAvatar(mContact, mView.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar("", mView.findViewById(R.id.avatar_layout));
}
mContactPicture.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
pickImage();
LinphoneActivity.instance().checkAndRequestCameraPermission();
((ContactsActivity) getActivity())
.requestPermissionIfNotGranted(Manifest.permission.CAMERA);
}
});
mNumbersAndAddresses = new ArrayList<>();
mSipAddresses = initSipAddressFields(mContact);
mNumbers = initNumbersFields(mContact);
mAddSipAddress = mView.findViewById(R.id.add_address_field);
ImageView addSipAddress = mView.findViewById(R.id.add_address_field);
if (getResources().getBoolean(R.bool.allow_only_one_sip_address)) {
mAddSipAddress.setVisibility(View.GONE);
addSipAddress.setVisibility(View.GONE);
}
mAddSipAddress.setOnClickListener(
addSipAddress.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
@ -345,11 +323,11 @@ public class ContactEditorFragment extends Fragment {
}
});
mAddNumber = mView.findViewById(R.id.add_number_field);
ImageView addNumber = mView.findViewById(R.id.add_number_field);
if (getResources().getBoolean(R.bool.allow_only_one_phone_number)) {
mAddNumber.setVisibility(View.GONE);
addNumber.setVisibility(View.GONE);
}
mAddNumber.setOnClickListener(
addNumber.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View view) {
@ -362,10 +340,20 @@ public class ContactEditorFragment extends Fragment {
return mView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("Contact", mContact);
outState.putString("SipUri", mNewSipOrNumberToAdd);
outState.putString("DisplayName", mNewDisplayName);
}
@Override
public void onResume() {
super.onResume();
displayContact();
// Force hide keyboard
getActivity()
.getWindow()
@ -387,13 +375,71 @@ public class ContactEditorFragment extends Fragment {
super.onPause();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) {
if (data != null && data.getExtras() != null && data.getExtras().get("data") != null) {
Bitmap bm = (Bitmap) data.getExtras().get("data");
editContactPicture(null, bm);
} else if (data != null && data.getData() != null) {
Uri selectedImageUri = data.getData();
try {
Bitmap selectedImage =
MediaStore.Images.Media.getBitmap(
getActivity().getContentResolver(), selectedImageUri);
selectedImage =
Bitmap.createScaledBitmap(selectedImage, PHOTO_SIZE, PHOTO_SIZE, false);
editContactPicture(null, selectedImage);
} catch (IOException e) {
Log.e(e);
}
} else if (mPickedPhotoForContactUri != null) {
String filePath = mPickedPhotoForContactUri.getPath();
editContactPicture(filePath, null);
} else {
File file =
new File(
FileUtils.getStorageDirectory(getActivity()),
getString(R.string.temp_photo_name));
if (file.exists()) {
mPickedPhotoForContactUri = Uri.fromFile(file);
String filePath = mPickedPhotoForContactUri.getPath();
editContactPicture(filePath, null);
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void displayContact() {
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
if (!isOrgVisible) {
mOrganization.setVisibility(View.GONE);
mView.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE);
} else {
if (!mIsNewContact) {
mOrganization.setText(mContact.getOrganization());
}
}
if (mContact != null) {
ContactAvatar.displayAvatar(mContact, mView.findViewById(R.id.avatar_layout));
} else {
ContactAvatar.displayAvatar("", mView.findViewById(R.id.avatar_layout));
}
mSipAddresses = initSipAddressFields(mContact);
mNumbers = initNumbersFields(mContact);
}
private void pickImage() {
mPickedPhotoForContactUri = null;
final List<Intent> cameraIntents = new ArrayList<>();
final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file =
new File(
FileUtils.getStorageDirectory(LinphoneActivity.instance()),
FileUtils.getStorageDirectory(getActivity()),
getString(R.string.temp_photo_name));
mPickedPhotoForContactUri = Uri.fromFile(file);
captureIntent.putExtra("outputX", PHOTO_SIZE);
@ -417,44 +463,6 @@ public class ContactEditorFragment extends Fragment {
startActivityForResult(chooserIntent, ADD_PHOTO);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) {
if (data != null && data.getExtras() != null && data.getExtras().get("data") != null) {
Bitmap bm = (Bitmap) data.getExtras().get("data");
editContactPicture(null, bm);
} else if (data != null && data.getData() != null) {
Uri selectedImageUri = data.getData();
try {
Bitmap selectedImage =
MediaStore.Images.Media.getBitmap(
LinphoneManager.getInstance().getContext().getContentResolver(),
selectedImageUri);
selectedImage =
Bitmap.createScaledBitmap(selectedImage, PHOTO_SIZE, PHOTO_SIZE, false);
editContactPicture(null, selectedImage);
} catch (IOException e) {
Log.e(e);
}
} else if (mPickedPhotoForContactUri != null) {
String filePath = mPickedPhotoForContactUri.getPath();
editContactPicture(filePath, null);
} else {
File file =
new File(
FileUtils.getStorageDirectory(LinphoneActivity.instance()),
getString(R.string.temp_photo_name));
if (file.exists()) {
mPickedPhotoForContactUri = Uri.fromFile(file);
String filePath = mPickedPhotoForContactUri.getPath();
editContactPicture(filePath, null);
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void editContactPicture(String filePath, Bitmap image) {
if (image == null) {
image = BitmapFactory.decodeFile(filePath);
@ -478,7 +486,7 @@ public class ContactEditorFragment extends Fragment {
private int getThumbnailSize() {
int value = -1;
Cursor c =
LinphoneActivity.instance()
getActivity()
.getContentResolver()
.query(
DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,

View file

@ -0,0 +1,180 @@
package org.linphone.contacts;
/*
ContactsActivity.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.Manifest;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import org.linphone.R;
import org.linphone.activities.MainActivity;
public class ContactsActivity extends MainActivity {
private boolean mEditOnClick;
private String mEditSipUri, mEditDisplayName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPermissionsToHave =
new String[] {
Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS
};
}
@Override
protected void onStart() {
super.onStart();
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
if (currentFragment == null) {
if (getIntent() != null && getIntent().getExtras() != null) {
Bundle extras = getIntent().getExtras();
if (isTablet() || !extras.containsKey("Contact")) {
showContactsList();
}
handleIntentExtras(extras);
} else {
showContactsList();
if (isTablet()) {
showEmptyChildFragment();
}
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// Clean fragments stack upon return
while (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
}
handleIntentExtras(intent.getExtras());
}
@Override
protected void onResume() {
super.onResume();
mContactsSelected.setVisibility(View.VISIBLE);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("EditSipUri", mEditSipUri);
outState.putString("EditDisplayName", mEditDisplayName);
outState.putBoolean("EditOnClick", mEditOnClick);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mEditOnClick = savedInstanceState.getBoolean("EditOnClick", false);
mEditSipUri = savedInstanceState.getString("EditSipUri", null);
mEditDisplayName = savedInstanceState.getString("EditDisplayName", null);
}
@Override
public void goBack() {
// 1 is for the empty fragment on tablets
if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) {
if (popBackStack()) {
mEditOnClick = false;
return;
}
}
super.goBack();
}
private void handleIntentExtras(Bundle extras) {
if (extras == null) return;
if (extras.containsKey("Contact")) {
LinphoneContact contact = (LinphoneContact) extras.get("Contact");
if (extras.containsKey("Edit")) {
showContactEdit(contact, extras, false);
} else {
showContactDetails(contact, false);
}
} else if (extras.containsKey("CreateOrEdit")) {
mEditOnClick = extras.getBoolean("CreateOrEdit");
mEditSipUri = extras.getString("SipUri", null);
mEditDisplayName = extras.getString("DisplayName", null);
Toast.makeText(this, R.string.toast_choose_contact_for_edition, Toast.LENGTH_LONG)
.show();
}
}
public void showContactDetails(LinphoneContact contact) {
showContactDetails(contact, true);
}
public void showContactEdit(LinphoneContact contact) {
showContactEdit(contact, true);
}
private void showContactsList() {
ContactsFragment fragment = new ContactsFragment();
changeFragment(fragment, "Contacts", false);
}
private void showContactDetails(LinphoneContact contact, boolean isChild) {
if (mEditOnClick) {
showContactEdit(contact, isChild);
return;
}
Bundle extras = new Bundle();
if (contact != null) {
extras.putSerializable("Contact", contact);
}
ContactDetailsFragment fragment = new ContactDetailsFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Contact detail", isChild);
}
private void showContactEdit(LinphoneContact contact, boolean isChild) {
showContactEdit(contact, new Bundle(), isChild);
}
private void showContactEdit(LinphoneContact contact, Bundle extras, boolean isChild) {
if (contact != null) {
extras.putSerializable("Contact", contact);
}
if (mEditOnClick) {
mEditOnClick = false;
extras.putString("SipUri", mEditSipUri);
extras.putString("DisplayName", mEditDisplayName);
mEditSipUri = null;
mEditDisplayName = null;
}
ContactEditorFragment fragment = new ContactEditorFragment();
fragment.setArguments(extras);
changeFragment(fragment, "Contact editor", isChild);
}
}

View file

@ -79,8 +79,7 @@ public class ContactsAdapter extends SelectableAdapter<ContactViewHolder>
}
holder.separator.setVisibility(
mIsSearchMode
|| (!mIsSearchMode
&& getPositionForSection(getSectionForPosition(position))
|| (getPositionForSection(getSectionForPosition(position))
!= position)
? View.GONE
: View.VISIBLE);

View file

@ -31,17 +31,14 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.utils.SelectableHelper;
public class ContactsFragment extends Fragment
@ -51,12 +48,11 @@ public class ContactsFragment extends Fragment
SelectableHelper.DeleteListener {
private RecyclerView mContactsList;
private TextView mNoSipContact, mNoContact;
private ImageView mAllContacts, mLinphoneContacts, mNewContact;
private ImageView mAllContacts;
private ImageView mLinphoneContacts;
private boolean mOnlyDisplayLinphoneContacts;
private View mAllContactsSelected, mLinphoneContactsSelected;
private int mLastKnownPosition;
private boolean mEditOnClick = false, mEditConsumed = false, mOnlyDisplayChatAddress = false;
private String mSipAddressToAdd, mDisplayName = null;
private SearchView mSearchView;
private ProgressBar mContactsFetchInProgress;
private LinearLayoutManager mLayoutManager;
@ -73,24 +69,6 @@ public class ContactsFragment extends Fragment
mSelectionHelper = new SelectableHelper(view, this);
mSelectionHelper.setDialogMessage(R.string.delete_contacts_text);
if (getArguments() != null) {
mEditOnClick = getArguments().getBoolean("EditOnClick");
mSipAddressToAdd = getArguments().getString("SipAddress");
if (getArguments().getString("DisplayName") != null) {
mDisplayName = getArguments().getString("DisplayName");
}
mOnlyDisplayChatAddress = getArguments().getBoolean("ChatAddressOnly");
if (getArguments().getBoolean("EditOnClick")) {
Toast.makeText(
LinphoneActivity.instance(),
R.string.toast_choose_contact_for_edition,
Toast.LENGTH_LONG)
.show();
}
getArguments().clear();
}
mNoSipContact = view.findViewById(R.id.noSipContact);
mNoContact = view.findViewById(R.id.noContact);
mContactsList = view.findViewById(R.id.contactsList);
@ -100,7 +78,7 @@ public class ContactsFragment extends Fragment
mAllContactsSelected = view.findViewById(R.id.all_contacts_select);
mLinphoneContactsSelected = view.findViewById(R.id.linphone_contacts_select);
mContactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress);
mNewContact = view.findViewById(R.id.newContact);
ImageView newContact = view.findViewById(R.id.newContact);
mContactsRefresher = view.findViewById(R.id.contactsListRefresher);
mContactsRefresher.setOnRefreshListener(
@ -137,13 +115,11 @@ public class ContactsFragment extends Fragment
}
});
mNewContact.setOnClickListener(
newContact.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
mEditConsumed = true;
ContactsManager.getInstance()
.createContact(getActivity(), mDisplayName, mSipAddressToAdd);
((ContactsActivity) getActivity()).showContactEdit(null);
}
});
@ -159,13 +135,11 @@ public class ContactsFragment extends Fragment
mAllContacts.setEnabled(mOnlyDisplayLinphoneContacts);
mLinphoneContacts.setEnabled(!mAllContacts.isEnabled());
}
mNewContact.setEnabled(LinphoneManager.getLc().getCallsNb() == 0);
newContact.setEnabled(LinphoneManager.getCore().getCallsNb() == 0);
if (!ContactsManager.getInstance().contactsFetchedOnce()) {
if (ContactsManager.getInstance().hasReadContactsAccess()) {
mContactsFetchInProgress.setVisibility(View.VISIBLE);
} else {
LinphoneActivity.instance().checkAndRequestReadContactsPermission();
}
} else {
if (!mOnlyDisplayLinphoneContacts
@ -205,15 +179,90 @@ public class ContactsFragment extends Fragment
return view;
}
public void displayFirstContact() {
if (mContactsList != null
&& mContactsList.getAdapter() != null
&& mContactsList.getAdapter().getItemCount() > 0) {
ContactsAdapter mAdapt = (ContactsAdapter) mContactsList.getAdapter();
LinphoneActivity.instance().displayContact((LinphoneContact) mAdapt.getItem(0), false);
} else {
LinphoneActivity.instance().displayEmptyFragment();
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
LinphoneContact contact = (LinphoneContact) adapter.getItemAtPosition(position);
mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition();
((ContactsActivity) getActivity()).showContactDetails(contact);
}
@Override
public void onItemClicked(int position) {
LinphoneContact contact = (LinphoneContact) mContactAdapter.getItem(position);
if (mContactAdapter.isEditionEnabled()) {
mContactAdapter.toggleSelection(position);
} else {
mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition();
((ContactsActivity) getActivity()).showContactDetails(contact);
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mContactAdapter.isEditionEnabled()) {
mSelectionHelper.enterEditionMode();
}
mContactAdapter.toggleSelection(position);
return true;
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
mOnlyDisplayLinphoneContacts =
ContactsManager.getInstance().isLinphoneContactsPrefered()
|| getResources().getBoolean(R.bool.hide_non_linphone_contacts);
changeContactsToggle();
invalidate();
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
}
@Override
public void onContactsUpdated() {
if (mContactAdapter != null) {
mContactAdapter.updateDataSet(
mOnlyDisplayLinphoneContacts
? ContactsManager.getInstance().getSIPContacts()
: ContactsManager.getInstance().getContacts());
mContactAdapter.notifyDataSetChanged();
if (mContactAdapter.getItemCount() > 0) {
mNoContact.setVisibility(View.GONE);
mNoSipContact.setVisibility(View.GONE);
}
}
mContactsFetchInProgress.setVisibility(View.GONE);
mContactsRefresher.setRefreshing(false);
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
ArrayList<String> ids = new ArrayList<>();
int size = mContactAdapter.getSelectedItemCount();
for (int i = size - 1; i >= 0; i--) {
LinphoneContact contact = (LinphoneContact) objectsToDelete[i];
if (contact.isAndroidContact()) {
contact.deleteFriend();
ids.add(contact.getAndroidId());
} else {
contact.delete();
}
}
ContactsManager.getInstance().deleteMultipleContactsAtOnce(ids);
}
private void searchContacts(String search) {
@ -306,91 +355,6 @@ public class ContactsFragment extends Fragment
}
}
@Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
LinphoneContact contact = (LinphoneContact) adapter.getItemAtPosition(position);
if (mEditOnClick) {
mEditConsumed = true;
ContactsManager.getInstance().editContact(getActivity(), contact, mSipAddressToAdd);
} else {
mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition();
LinphoneActivity.instance().displayContact(contact, mOnlyDisplayChatAddress);
}
}
@Override
public void onItemClicked(int position) {
LinphoneContact contact = (LinphoneContact) mContactAdapter.getItem(position);
if (mContactAdapter.isEditionEnabled()) {
mContactAdapter.toggleSelection(position);
} else if (mEditOnClick) {
mEditConsumed = true;
ContactsManager.getInstance().editContact(getActivity(), contact, mSipAddressToAdd);
} else {
mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition();
LinphoneActivity.instance().displayContact(contact, mOnlyDisplayChatAddress);
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mContactAdapter.isEditionEnabled()) {
mSelectionHelper.enterEditionMode();
}
mContactAdapter.toggleSelection(position);
return true;
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
if (mEditConsumed) {
mEditOnClick = false;
mSipAddressToAdd = null;
}
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACTS_LIST);
mOnlyDisplayLinphoneContacts =
ContactsManager.getInstance().isLinphoneContactsPrefered()
|| getResources().getBoolean(R.bool.hide_non_linphone_contacts);
}
changeContactsToggle();
invalidate();
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
}
@Override
public void onContactsUpdated() {
if (!LinphoneActivity.isInstanciated()
|| (LinphoneActivity.instance().getCurrentFragment()
!= FragmentsAvailable.CONTACTS_LIST
&& !LinphoneActivity.instance().isTablet())) return;
if (mContactAdapter != null) {
mContactAdapter.updateDataSet(
mOnlyDisplayLinphoneContacts
? ContactsManager.getInstance().getSIPContacts()
: ContactsManager.getInstance().getContacts());
mContactAdapter.notifyDataSetChanged();
if (mContactAdapter.getItemCount() > 0) {
mNoContact.setVisibility(View.GONE);
mNoSipContact.setVisibility(View.GONE);
}
}
mContactsFetchInProgress.setVisibility(View.GONE);
mContactsRefresher.setRefreshing(false);
}
private void invalidate() {
if (mSearchView != null && mSearchView.getQuery().toString().length() > 0) {
searchContacts(mSearchView.getQuery().toString());
@ -399,20 +363,4 @@ public class ContactsFragment extends Fragment
}
mContactsList.scrollToPosition(mLastKnownPosition);
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
ArrayList<String> ids = new ArrayList<>();
int size = mContactAdapter.getSelectedItemCount();
for (int i = size - 1; i >= 0; i--) {
LinphoneContact contact = (LinphoneContact) objectsToDelete[i];
if (contact.isAndroidContact()) {
contact.deleteFriend();
ids.add(contact.getAndroidId());
} else {
contact.delete();
}
}
ContactsManager.getInstance().deleteMultipleContactsAtOnce(ids);
}
}

View file

@ -29,18 +29,17 @@ import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.provider.ContactsContract;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
@ -56,10 +55,8 @@ import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
public class ContactsManager extends ContentObserver implements FriendListListener {
private static ContactsManager sInstance;
private List<LinphoneContact> mContacts, mSipContacts;
private ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners;
private final ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners;
private MagicSearch mMagicSearch;
private boolean mContactsFetchedOnce = false;
private Context mContext;
@ -67,18 +64,18 @@ public class ContactsManager extends ContentObserver implements FriendListListen
private boolean mInitialized = false;
public static ContactsManager getInstance() {
if (sInstance == null) sInstance = new ContactsManager();
return sInstance;
return LinphoneService.instance().getContactsManager();
}
private ContactsManager() {
super(LinphoneService.instance().handler);
public ContactsManager(Context context, Handler handler) {
super(handler);
mContext = context;
mContactsUpdatedListeners = new ArrayList<>();
mContacts = new ArrayList<>();
mSipContacts = new ArrayList<>();
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
mMagicSearch = LinphoneManager.getLcIfManagerNotDestroyedOrNull().createMagicSearch();
if (LinphoneManager.getCore() != null) {
mMagicSearch = LinphoneManager.getCore().createMagicSearch();
mMagicSearch.setLimitedSearch(false); // Do not limit the number of results
}
}
@ -122,6 +119,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
public void destroy() {
mContext.getContentResolver().unregisterContentObserver(ContactsManager.getInstance());
if (mLoadContactTask != null) {
mLoadContactTask.cancel(true);
}
@ -136,13 +135,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
mSipContacts.clear();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
for (FriendList list : lc.getFriendsLists()) {
Core core = LinphoneManager.getCore();
if (core != null) {
for (FriendList list : core.getFriendsLists()) {
list.removeListener(this);
}
}
sInstance = null;
}
public void fetchContactsAsync() {
@ -153,45 +151,11 @@ public class ContactsManager extends ContentObserver implements FriendListListen
Log.w("[Contacts Manager] Can't fetch contact without READ permission");
return;
}
mLoadContactTask = new AsyncContactsLoader(mContext);
mLoadContactTask = new AsyncContactsLoader();
mContactsFetchedOnce = true;
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR);
}
public void editContact(Context context, LinphoneContact contact, String valueToAdd) {
if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) {
Intent intent = new Intent(Intent.ACTION_EDIT);
Uri contactUri = contact.getAndroidLookupUri();
intent.setDataAndType(contactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
intent.putExtra(
"finishActivityOnSaveCompleted", true); // So after save will go back here
if (valueToAdd != null) {
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, valueToAdd);
}
context.startActivity(intent);
} else {
LinphoneActivity.instance().editContact(contact, valueToAdd);
}
}
public void createContact(Context context, String name, String valueToAdd) {
if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) {
Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION);
intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
intent.putExtra(
"finishActivityOnSaveCompleted", true); // So after save will go back here
if (name != null) {
intent.putExtra(ContactsContract.Intents.Insert.NAME, name);
}
if (valueToAdd != null) {
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, valueToAdd);
}
context.startActivity(intent);
} else {
LinphoneActivity.instance().addContact(name, valueToAdd);
}
}
public MagicSearch getMagicSearch() {
return mMagicSearch;
}
@ -256,7 +220,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
&& !mContext.getResources().getBoolean(R.bool.force_use_of_linphone_friends);
}
public boolean hasWriteContactsAccess() {
private boolean hasWriteContactsAccess() {
if (mContext == null) {
return false;
}
@ -266,7 +230,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
Manifest.permission.WRITE_CONTACTS, mContext.getPackageName()));
}
public boolean hasWriteSyncPermission() {
private boolean hasWriteSyncPermission() {
if (mContext == null) {
return false;
}
@ -278,16 +242,14 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
public boolean isLinphoneContactsPrefered() {
ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig();
ProxyConfig lpc = LinphoneManager.getCore().getDefaultProxyConfig();
return lpc != null
&& lpc.getIdentityAddress()
.getDomain()
.equals(mContext.getString(R.string.default_domain));
}
public void initializeContactManager(Context context) {
mContext = context;
public void initializeContactManager() {
if (!mInitialized) {
if (mContext.getResources().getBoolean(R.bool.use_linphone_tag)) {
if (hasReadContactsAccess()
@ -352,12 +314,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen
Log.e("[Contacts Manager] Couldn't initialize sync account: " + e);
}
} else if (accounts != null) {
for (int i = 0; i < accounts.length; i++) {
for (Account account : accounts) {
Log.i(
"[Contacts Manager] Found account with name \""
+ accounts[i].name
+ account.name
+ "\" and type \""
+ accounts[i].type
+ account.type
+ "\"");
makeContactAccountVisible();
}
@ -377,8 +339,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public synchronized LinphoneContact findContactFromAddress(Address address) {
if (address == null) return null;
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Friend lf = lc.findFriend(address);
Core core = LinphoneManager.getCore();
Friend lf = core.findFriend(address);
if (lf != null) {
return (LinphoneContact) lf.getUserData();
}
@ -387,10 +349,10 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public synchronized LinphoneContact findContactFromPhoneNumber(String phoneNumber) {
if (phoneNumber == null) return null;
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
ProxyConfig lpc = null;
if (lc != null) {
lpc = lc.getDefaultProxyConfig();
if (core != null) {
lpc = core.getDefaultProxyConfig();
}
if (lpc == null) return null;
String normalized = lpc.normalizePhoneNumber(phoneNumber);
@ -402,7 +364,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
addr.setUriParam("user", "phone");
Friend lf =
lc.findFriend(
core.findFriend(
addr); // Without this, the hashmap inside liblinphone won't find it...
if (lf != null) {
return (LinphoneContact) lf.getUserData();

View file

@ -27,8 +27,8 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.core.Address;
import org.linphone.core.Core;
@ -53,7 +53,6 @@ public class LinphoneContact extends AndroidContact
super();
mAddresses = new ArrayList<>();
mAndroidId = null;
mAndroidLookupKey = null;
mThumbnailUri = null;
mPhotoUri = null;
mHasSipAddress = false;
@ -176,10 +175,6 @@ public class LinphoneContact extends AndroidContact
Picture related
*/
public boolean hasPhoto() {
return mPhotoUri != null;
}
public Uri getPhotoUri() {
return mPhotoUri;
}
@ -202,7 +197,7 @@ public class LinphoneContact extends AndroidContact
Number or address related
*/
public void addNumberOrAddress(LinphoneNumberOrAddress noa) {
private void addNumberOrAddress(LinphoneNumberOrAddress noa) {
if (noa == null) return;
if (noa.isSIPAddress()) {
mHasSipAddress = true;
@ -316,11 +311,11 @@ public class LinphoneContact extends AndroidContact
private void createOrUpdateFriend() {
boolean created = false;
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null) return;
Core core = LinphoneManager.getCore();
if (core == null) return;
if (!isFriend()) {
mFriend = lc.createFriend();
mFriend = core.createFriend();
mFriend.enableSubscribes(false);
mFriend.setIncSubscribePolicy(SubscribePolicy.SPDeny);
if (isAndroidContact()) {
@ -350,7 +345,7 @@ public class LinphoneContact extends AndroidContact
}
for (LinphoneNumberOrAddress noa : mAddresses) {
if (noa.isSIPAddress()) {
Address addr = lc.interpretUrl(noa.getValue());
Address addr = core.interpretUrl(noa.getValue());
if (addr != null) {
mFriend.addAddress(addr);
}
@ -361,7 +356,7 @@ public class LinphoneContact extends AndroidContact
mFriend.done();
}
if (created) {
lc.addFriend(mFriend);
core.addFriend(mFriend);
}
if (!ContactsManager.getInstance().hasReadContactsAccess()) {
@ -374,9 +369,9 @@ public class LinphoneContact extends AndroidContact
}
public void deleteFriend() {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (mFriend != null && lc != null) {
for (FriendList list : lc.getFriendsLists()) {
Core core = LinphoneManager.getCore();
if (mFriend != null && core != null) {
for (FriendList list : core.getFriendsLists()) {
list.removeFriend(mFriend);
}
}
@ -436,7 +431,7 @@ public class LinphoneContact extends AndroidContact
private void createFriend() {
LinphoneContact contact = new LinphoneContact();
Friend friend = LinphoneManager.getLc().createFriend();
Friend friend = LinphoneManager.getCore().createFriend();
// Disable subscribes for now
friend.enableSubscribes(false);
friend.setIncSubscribePolicy(SubscribePolicy.SPDeny);
@ -465,8 +460,8 @@ public class LinphoneContact extends AndroidContact
mHasSipAddress = mFriend.getAddress() != null;
mOrganization = mFriend.getVcard().getOrganization();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null && lc.vcardSupported()) {
Core core = LinphoneManager.getCore();
if (core != null && core.vcardSupported()) {
for (Address addr : mFriend.getAddresses()) {
if (addr != null) {
addNumberOrAddress(
@ -485,7 +480,7 @@ public class LinphoneContact extends AndroidContact
}
}
public void syncValuesFromAndroidContact(Context context) {
private void syncValuesFromAndroidContact(Context context) {
Cursor c =
context.getContentResolver()
.query(
@ -515,16 +510,13 @@ public class LinphoneContact extends AndroidContact
String data2 = c.getString(c.getColumnIndex("data2"));
String data3 = c.getString(c.getColumnIndex("data3"));
String data4 = c.getString(c.getColumnIndex("data4"));
String lookupKey = c.getString(c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
setAndroidLookupKey(lookupKey);
setFullName(displayName);
if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) {
addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4));
} else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime)
|| LinphoneManager.getInstance()
.getContext()
|| LinphoneService.instance()
.getString(R.string.linphone_address_mime_type)
.equals(mime)) {
addNumberOrAddress(new LinphoneNumberOrAddress(data1, true));
@ -537,7 +529,7 @@ public class LinphoneContact extends AndroidContact
public void save() {
saveChangesCommited();
syncValuesFromAndroidContact(LinphoneActivity.instance());
syncValuesFromAndroidContact(LinphoneService.instance());
createOrUpdateFriend();
}

View file

@ -63,7 +63,7 @@ public class LinphoneNumberOrAddress implements Serializable, Comparable<Linphon
public boolean equals(Object obj) {
if (obj.getClass() != LinphoneNumberOrAddress.class) return false;
LinphoneNumberOrAddress noa = (LinphoneNumberOrAddress) obj;
return (this != null && this.compareTo(noa) == 0);
return this.compareTo(noa) == 0;
}
public boolean isSIPAddress() {

View file

@ -26,8 +26,9 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import java.util.Objects;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.core.Address;
import org.linphone.core.FriendCapability;
@ -41,7 +42,7 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
private List<SearchResult> mContacts;
private ArrayList<ContactAddress> mContactsSelected;
private boolean mOnlySipContact = false;
private SearchContactViewHolder.ClickListener mListener;
private final SearchContactViewHolder.ClickListener mListener;
private final boolean mIsOnlyOnePersonSelection;
private String mPreviousSearch;
private boolean mSecurityEnabled;
@ -116,12 +117,6 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
holder.name.setVisibility(View.VISIBLE);
holder.name.setText(searchResult.getAddress().getDisplayName());
}
} else if (searchResult.getAddress() != null) {
holder.name.setVisibility(View.VISIBLE);
holder.name.setText(
(searchResult.getAddress().getDisplayName() != null)
? searchResult.getAddress().getDisplayName()
: searchResult.getAddress().getUsername());
}
holder.disabled.setVisibility(View.GONE);
@ -144,7 +139,7 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
holder.disabled.setVisibility(View.VISIBLE);
} else if (mSecurityEnabled || !mIsOnlyOnePersonSelection) {
ProxyConfig lpc =
LinphoneManager.getLcIfManagerNotDestroyedOrNull().getDefaultProxyConfig();
Objects.requireNonNull(LinphoneManager.getCore()).getDefaultProxyConfig();
if (lpc != null
&& searchResult.getAddress() != null
&& lpc.getIdentityAddress().weakEqual(searchResult.getAddress())) {
@ -182,7 +177,7 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
return position;
}
public synchronized boolean isContactSelected(SearchResult sr) {
private synchronized boolean isContactSelected(SearchResult sr) {
for (ContactAddress c : mContactsSelected) {
Address addr = c.getAddress();
if (addr != null && sr.getAddress() != null) {
@ -240,7 +235,7 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
mPreviousSearch = search;
String domain = "";
ProxyConfig prx = LinphoneManager.getLc().getDefaultProxyConfig();
ProxyConfig prx = Objects.requireNonNull(LinphoneManager.getCore()).getDefaultProxyConfig();
if (prx != null) domain = prx.getDomain();
SearchResult[] searchResults =
ContactsManager.getInstance()
@ -248,7 +243,7 @@ public class SearchContactsAdapter extends RecyclerView.Adapter<SearchContactVie
.getContactListFromFilter(search, mOnlySipContact ? domain : "");
for (SearchResult sr : searchResults) {
if (LinphoneActivity.instance()
if (LinphoneService.instance()
.getResources()
.getBoolean(R.bool.hide_sip_contacts_without_presence)) {
if (sr.getFriend() != null) {

View file

@ -1,235 +0,0 @@
package org.linphone.fragments;
/*
DialerFragment.java
Copyright (C) 2017 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.Fragment;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.views.AddressAware;
import org.linphone.views.AddressText;
import org.linphone.views.CallButton;
import org.linphone.views.EraseButton;
public class DialerFragment extends Fragment {
private static DialerFragment sInstance;
private static boolean sIsCallTransferOngoing = false;
private AddressAware mNumpad;
private AddressText mAddress;
private CallButton mCall;
private ImageView mAddContact;
private OnClickListener mAddContactListener, mCancelListener, mTransferListener;
/** @return null if not ready yet */
public static DialerFragment instance() {
return sInstance;
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialer, container, false);
mAddress = view.findViewById(R.id.address);
mAddress.setDialerFragment(this);
EraseButton erase = view.findViewById(R.id.erase);
erase.setAddressWidget(mAddress);
mCall = view.findViewById(R.id.call);
mCall.setAddressWidget(mAddress);
if (LinphoneActivity.isInstanciated()
&& LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null
&& LinphoneManager.getLcIfManagerNotDestroyedOrNull().getCallsNb() > 0) {
if (sIsCallTransferOngoing) {
mCall.setImageResource(R.drawable.call_transfer);
} else {
mCall.setImageResource(R.drawable.call_add);
}
} else {
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null
&& LinphoneManager.getLcIfManagerNotDestroyedOrNull()
.getVideoActivationPolicy()
.getAutomaticallyInitiate()) {
mCall.setImageResource(R.drawable.call_video_start);
} else {
mCall.setImageResource(R.drawable.call_audio_start);
}
}
mNumpad = view.findViewById(R.id.numpad);
if (mNumpad != null) {
mNumpad.setAddressWidget(mAddress);
}
mAddContact = view.findViewById(R.id.add_contact);
mAddContact.setEnabled(
!(LinphoneActivity.isInstanciated()
&& LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null
&& LinphoneManager.getLc().getCallsNb() > 0));
mAddContactListener =
new OnClickListener() {
@Override
public void onClick(View v) {
LinphoneActivity.instance()
.displayContactsForEdition(mAddress.getText().toString());
}
};
mCancelListener =
new OnClickListener() {
@Override
public void onClick(View v) {
LinphoneActivity.instance()
.resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
};
mTransferListener =
new OnClickListener() {
@Override
public void onClick(View v) {
Core lc = LinphoneManager.getLc();
if (lc.getCurrentCall() == null) {
return;
}
lc.transferCall(lc.getCurrentCall(), mAddress.getText().toString());
sIsCallTransferOngoing = false;
LinphoneActivity.instance()
.resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
};
resetLayout();
if (getArguments() != null) {
String number = getArguments().getString("SipUri");
String displayName = getArguments().getString("DisplayName");
mAddress.setText(number);
if (displayName != null) {
mAddress.setDisplayedName(displayName);
}
}
sInstance = this;
return view;
}
@Override
public void onPause() {
sInstance = null;
super.onPause();
}
@Override
public void onResume() {
super.onResume();
sInstance = this;
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.DIALER);
LinphoneActivity.instance().updateDialerFragment();
LinphoneActivity.instance().showStatusBar();
}
boolean isOrientationLandscape =
getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
if (isOrientationLandscape && !getResources().getBoolean(R.bool.isTablet)) {
((LinearLayout) mNumpad).setVisibility(View.GONE);
} else {
((LinearLayout) mNumpad).setVisibility(View.VISIBLE);
}
resetLayout();
String addressWaitingToBeCalled = LinphoneActivity.instance().addressWaitingToBeCalled;
if (addressWaitingToBeCalled != null) {
mAddress.setText(addressWaitingToBeCalled);
if (!LinphoneActivity.instance().isCallTransfer()
&& getResources()
.getBoolean(R.bool.automatically_start_intercepted_outgoing_gsm_call)) {
newOutgoingCall(addressWaitingToBeCalled);
}
LinphoneActivity.instance().addressWaitingToBeCalled = null;
}
}
public void resetLayout() {
if (!LinphoneActivity.isInstanciated()) {
return;
}
sIsCallTransferOngoing = LinphoneActivity.instance().isCallTransfer();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null) {
return;
}
if (lc.getCallsNb() > 0) {
if (sIsCallTransferOngoing) {
mCall.setImageResource(R.drawable.call_transfer);
mCall.setExternalClickListener(mTransferListener);
} else {
mCall.setImageResource(R.drawable.call_add);
mCall.resetClickListener();
}
mAddContact.setEnabled(true);
mAddContact.setImageResource(R.drawable.call_back);
mAddContact.setOnClickListener(mCancelListener);
} else {
mCall.resetClickListener();
if (LinphoneManager.getLc().getVideoActivationPolicy().getAutomaticallyInitiate()) {
mCall.setImageResource(R.drawable.call_video_start);
} else {
mCall.setImageResource(R.drawable.call_audio_start);
}
mAddContact.setEnabled(false);
mAddContact.setImageResource(R.drawable.contact_add);
mAddContact.setOnClickListener(mAddContactListener);
enableDisableAddContact();
}
}
public void enableDisableAddContact() {
mAddContact.setEnabled(
LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null
&& LinphoneManager.getLc().getCallsNb() > 0
|| !mAddress.getText().toString().equals(""));
}
public void displayTextInAddressBar(String numberOrSipAddress) {
mAddress.setText(numberOrSipAddress);
}
public void newOutgoingCall(String numberOrSipAddress) {
displayTextInAddressBar(numberOrSipAddress);
LinphoneManager.getInstance().newOutgoingCall(mAddress);
}
}

View file

@ -1,81 +0,0 @@
package org.linphone.fragments;
/*
FragmentsAvailable.java
Copyright (C) 2017 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.
*/
public enum FragmentsAvailable {
UNKNOW,
DIALER,
EMPTY,
HISTORY_LIST,
HISTORY_DETAIL,
CONTACTS_LIST,
CONTACT_DETAIL,
CONTACT_EDITOR,
ABOUT,
ACCOUNT_SETTINGS,
SETTINGS,
SETTINGS_SUBLEVEL,
CHAT_LIST,
CHAT,
CREATE_CHAT,
INFO_GROUP_CHAT,
GROUP_CHAT,
MESSAGE_IMDN,
CONTACT_DEVICES,
RECORDING_LIST;
public boolean shouldAddItselfToTheRightOf(FragmentsAvailable fragment) {
switch (this) {
case HISTORY_DETAIL:
return fragment == HISTORY_LIST || fragment == HISTORY_DETAIL;
case CONTACT_DETAIL:
return fragment == CONTACTS_LIST
|| fragment == CONTACT_EDITOR
|| fragment == CONTACT_DETAIL;
case CONTACT_EDITOR:
return fragment == CONTACTS_LIST
|| fragment == CONTACT_DETAIL
|| fragment == CONTACT_EDITOR;
case CHAT:
return fragment == CHAT_LIST || fragment == CHAT;
case GROUP_CHAT:
return fragment == CHAT_LIST
|| fragment == GROUP_CHAT
|| fragment == INFO_GROUP_CHAT
|| fragment == CREATE_CHAT;
case MESSAGE_IMDN:
return fragment == GROUP_CHAT || fragment == MESSAGE_IMDN;
case SETTINGS_SUBLEVEL:
return fragment == SETTINGS || fragment == SETTINGS_SUBLEVEL;
case CONTACT_DEVICES:
return fragment == GROUP_CHAT || fragment == CONTACT_DEVICES;
default:
return false;
}
}
}

View file

@ -36,7 +36,6 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
@ -63,6 +62,7 @@ public class StatusFragment extends Fragment {
private CoreListenerStub mListener;
private Dialog mZrtpDialog = null;
private int mDisplayedQuality = -1;
private MenuClikedListener mMenuListener;
@Override
public View onCreateView(
@ -77,6 +77,17 @@ public class StatusFragment extends Fragment {
mVoicemail = view.findViewById(R.id.voicemail);
mVoicemailCount = view.findViewById(R.id.voicemail_count);
mMenuListener = null;
mMenu.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
if (mMenuListener != null) {
mMenuListener.onMenuCliked();
}
}
});
// We create it once to not delay the first display
populateSliderContent();
@ -84,7 +95,7 @@ public class StatusFragment extends Fragment {
new CoreListenerStub() {
@Override
public void onRegistrationStateChanged(
final Core lc,
final Core core,
final ProxyConfig proxy,
final RegistrationState state,
String smessage) {
@ -92,18 +103,18 @@ public class StatusFragment extends Fragment {
return;
}
if (lc.getProxyConfigList() == null) {
if (core.getProxyConfigList() == null) {
mStatusLed.setImageResource(R.drawable.led_disconnected);
mStatusText.setText(getString(R.string.no_account));
} else {
mStatusLed.setVisibility(View.VISIBLE);
}
if (lc.getDefaultProxyConfig() != null
&& lc.getDefaultProxyConfig().equals(proxy)) {
if (core.getDefaultProxyConfig() != null
&& core.getDefaultProxyConfig().equals(proxy)) {
mStatusLed.setImageResource(getStatusIconResource(state));
mStatusText.setText(getStatusIconText(state));
} else if (lc.getDefaultProxyConfig() == null) {
} else if (core.getDefaultProxyConfig() == null) {
mStatusLed.setImageResource(getStatusIconResource(state));
mStatusText.setText(getStatusIconText(state));
}
@ -113,9 +124,7 @@ public class StatusFragment extends Fragment {
new OnClickListener() {
@Override
public void onClick(View v) {
Core core =
LinphoneManager
.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
core.refreshRegisters();
}
@ -128,7 +137,7 @@ public class StatusFragment extends Fragment {
@Override
public void onNotifyReceived(
Core lc, Event ev, String eventName, Content content) {
Core core, Event ev, String eventName, Content content) {
if (!content.getType().equals("application")) return;
if (!content.getSubtype().equals("simple-message-summary")) return;
@ -143,7 +152,7 @@ public class StatusFragment extends Fragment {
try {
unreadCount = Integer.parseInt(intToParse[0]);
} catch (NumberFormatException nfe) {
Log.e("[Status Fragment] " + nfe);
}
if (unreadCount > 0) {
mVoicemailCount.setText(String.valueOf(unreadCount));
@ -160,9 +169,7 @@ public class StatusFragment extends Fragment {
mIsAttached = true;
Activity activity = getActivity();
if (activity instanceof LinphoneActivity) {
((LinphoneActivity) activity).updateStatusFragment(this);
} else if (activity instanceof CallActivity) {
if (activity instanceof CallActivity) {
((CallActivity) activity).updateStatusFragment(this);
}
mIsInCall =
@ -179,44 +186,35 @@ public class StatusFragment extends Fragment {
mIsAttached = false;
}
public void setMenuListener(MenuClikedListener listener) {
mMenuListener = listener;
}
// NORMAL STATUS BAR
private void populateSliderContent() {
if (LinphoneManager.isInstanciated() && LinphoneManager.getLc() != null) {
Core core = LinphoneManager.getCore();
if (core != null) {
mVoicemailCount.setVisibility(View.GONE);
if (mIsInCall && mIsAttached) {
// Call call = LinphoneManager.getLc().getCurrentCall();
// initCallStatsRefresher(call, callStats);
} else if (!mIsInCall) {
if (!mIsInCall) {
mVoicemailCount.setVisibility(View.VISIBLE);
}
if (LinphoneManager.getLc().getProxyConfigList().length == 0) {
if (core.getProxyConfigList().length == 0) {
mStatusLed.setImageResource(R.drawable.led_disconnected);
mStatusText.setText(getString(R.string.no_account));
}
}
}
public void resetAccountStatus() {
if (LinphoneManager.getLc().getProxyConfigList().length == 0) {
mStatusLed.setImageResource(R.drawable.led_disconnected);
mStatusText.setText(getString(R.string.no_account));
}
}
public void enableSideMenu(boolean enabled) {
mMenu.setEnabled(enabled);
}
private int getStatusIconResource(RegistrationState state) {
try {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
boolean defaultAccountConnected =
(lc != null
&& lc.getDefaultProxyConfig() != null
&& lc.getDefaultProxyConfig().getState() == RegistrationState.Ok);
(core != null
&& core.getDefaultProxyConfig() != null
&& core.getDefaultProxyConfig().getState() == RegistrationState.Ok);
if (state == RegistrationState.Ok && defaultAccountConnected) {
return R.drawable.led_connected;
} else if (state == RegistrationState.Progress) {
@ -235,15 +233,11 @@ public class StatusFragment extends Fragment {
private String getStatusIconText(RegistrationState state) {
Context context = getActivity();
if (!mIsAttached && LinphoneActivity.isInstanciated())
context = LinphoneActivity.instance();
else if (!mIsAttached && LinphoneService.isReady()) context = LinphoneService.instance();
if (!mIsAttached && LinphoneService.isReady()) context = LinphoneService.instance();
try {
if (state == RegistrationState.Ok
&& LinphoneManager.getLcIfManagerNotDestroyedOrNull()
.getDefaultProxyConfig()
.getState()
&& LinphoneManager.getCore().getDefaultProxyConfig().getState()
== RegistrationState.Ok) {
return context.getString(R.string.status_connected);
} else if (state == RegistrationState.Progress) {
@ -266,7 +260,7 @@ public class StatusFragment extends Fragment {
mRefreshHandler.postDelayed(
mCallQualityUpdater =
new Runnable() {
final Call mCurrentCall = LinphoneManager.getLc().getCurrentCall();
final Call mCurrentCall = LinphoneManager.getCore().getCurrentCall();
public void run() {
if (mCurrentCall == null) {
@ -311,16 +305,17 @@ public class StatusFragment extends Fragment {
public void onResume() {
super.onResume();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
ProxyConfig lpc = lc.getDefaultProxyConfig();
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
ProxyConfig lpc = core.getDefaultProxyConfig();
if (lpc != null) {
mListener.onRegistrationStateChanged(lc, lpc, lpc.getState(), null);
mListener.onRegistrationStateChanged(core, lpc, lpc.getState(), null);
}
Call call = lc.getCurrentCall();
if (mIsInCall && (call != null || lc.getConferenceSize() > 1 || lc.getCallsNb() > 0)) {
Call call = core.getCurrentCall();
if (mIsInCall
&& (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0)) {
if (call != null) {
startCallQuality();
refreshStatusItems(call);
@ -329,13 +324,13 @@ public class StatusFragment extends Fragment {
mCallQuality.setVisibility(View.VISIBLE);
// We are obviously connected
if (lc.getDefaultProxyConfig() == null) {
if (core.getDefaultProxyConfig() == null) {
mStatusLed.setImageResource(R.drawable.led_disconnected);
mStatusText.setText(getString(R.string.no_account));
} else {
mStatusLed.setImageResource(
getStatusIconResource(lc.getDefaultProxyConfig().getState()));
mStatusText.setText(getStatusIconText(lc.getDefaultProxyConfig().getState()));
getStatusIconResource(core.getDefaultProxyConfig().getState()));
mStatusText.setText(getStatusIconText(core.getDefaultProxyConfig().getState()));
}
}
} else {
@ -348,9 +343,9 @@ public class StatusFragment extends Fragment {
public void onPause() {
super.onPause();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
if (mCallQualityUpdater != null) {
@ -397,7 +392,7 @@ public class StatusFragment extends Fragment {
public void showZRTPDialog(final Call call) {
if (getActivity() == null) {
Log.w("Can't display ZRTP popup, no Activity");
Log.w("[Status Fragment] Can't display ZRTP popup, no Activity");
return;
}
@ -405,11 +400,14 @@ public class StatusFragment extends Fragment {
String token = call.getAuthenticationToken();
if (token == null) {
Log.w("Can't display ZRTP popup, no token !");
Log.w("[Status Fragment] Can't display ZRTP popup, no token !");
return;
}
if (token.length() < 4) {
Log.w("Can't display ZRTP popup, token is invalid (" + token + ")");
Log.w(
"[Status Fragment] Can't display ZRTP popup, token is invalid ("
+ token
+ ")");
return;
}
@ -492,4 +490,8 @@ public class StatusFragment extends Fragment {
mZrtpDialog.show();
}
}
public interface MenuClikedListener {
void onMenuCliked();
}
}

View file

@ -0,0 +1,115 @@
package org.linphone.history;
/*
HistoryActivity.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.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.activities.MainActivity;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.utils.LinphoneUtils;
public class HistoryActivity extends MainActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
if (currentFragment == null) {
HistoryFragment fragment = new HistoryFragment();
changeFragment(fragment, "History", false);
if (isTablet()) {
fragment.displayFirstLog();
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// Clean fragments stack upon return
while (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
}
}
@Override
protected void onResume() {
super.onResume();
mHistorySelected.setVisibility(View.VISIBLE);
LinphoneManager.getCore().resetMissedCallsCount();
displayMissedCalls();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
@Override
public void goBack() {
// 1 is for the empty fragment on tablets
if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) {
if (popBackStack()) {
return;
}
}
super.goBack();
}
public void showHistoryDetails(Address address) {
Bundle extras = new Bundle();
if (address != null) {
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address);
String displayName =
contact != null
? contact.getFullName()
: LinphoneUtils.getAddressDisplayName(address.asStringUriOnly());
String pictureUri =
contact != null && contact.getPhotoUri() != null
? contact.getPhotoUri().toString()
: null;
extras.putString("SipUri", address.asStringUriOnly());
extras.putString("DisplayName", displayName);
extras.putString("PictureUri", pictureUri);
}
HistoryDetailFragment fragment = new HistoryDetailFragment();
fragment.setArguments(extras);
changeFragment(fragment, "History detail", true);
}
}

View file

@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,7 +27,6 @@ import androidx.annotation.NonNull;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
@ -42,17 +40,17 @@ import org.linphone.views.ContactAvatar;
public class HistoryAdapter extends SelectableAdapter<HistoryViewHolder> {
private final List<CallLog> mLogs;
private final Context mContext;
private final HistoryActivity mActivity;
private final HistoryViewHolder.ClickListener mClickListener;
public HistoryAdapter(
Context aContext,
HistoryActivity activity,
List<CallLog> logs,
HistoryViewHolder.ClickListener listener,
SelectableHelper helper) {
super(helper);
mLogs = logs;
mContext = aContext;
mActivity = activity;
mClickListener = listener;
}
@ -71,9 +69,9 @@ public class HistoryAdapter extends SelectableAdapter<HistoryViewHolder> {
@Override
public void onBindViewHolder(@NonNull final HistoryViewHolder holder, final int position) {
final CallLog log = mLogs.get(position);
CallLog log = mLogs.get(position);
long timestamp = log.getStartDate() * 1000;
Address address;
final Address address;
holder.contact.setSelected(true); // For automated horizontal scrolling of long texts
Calendar logTime = Calendar.getInstance();
@ -111,7 +109,7 @@ public class HistoryAdapter extends SelectableAdapter<HistoryViewHolder> {
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
String displayName = null;
final String sipUri = (address != null) ? address.asString() : "";
String sipUri = (address != null) ? address.asString() : "";
if (c != null) {
displayName = c.getFullName();
@ -134,9 +132,7 @@ public class HistoryAdapter extends SelectableAdapter<HistoryViewHolder> {
? new View.OnClickListener() {
@Override
public void onClick(View v) {
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().displayHistoryDetail(sipUri, log);
}
mActivity.showHistoryDetails(address);
}
}
: null);
@ -151,13 +147,13 @@ public class HistoryAdapter extends SelectableAdapter<HistoryViewHolder> {
private String timestampToHumanDate(Calendar cal) {
SimpleDateFormat dateFormat;
if (isToday(cal)) {
return mContext.getString(R.string.today);
return mActivity.getString(R.string.today);
} else if (isYesterday(cal)) {
return mContext.getString(R.string.yesterday);
return mActivity.getString(R.string.yesterday);
} else {
dateFormat =
new SimpleDateFormat(
mContext.getResources().getString(R.string.history_date_format));
mActivity.getResources().getString(R.string.history_date_format));
}
return dateFormat.format(cal.getTime());

View file

@ -31,7 +31,6 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
@ -47,14 +46,13 @@ import org.linphone.core.Factory;
import org.linphone.core.FriendCapability;
import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
public class HistoryDetailFragment extends Fragment implements OnClickListener {
private ImageView mDialBack, mChat, mAddToContacts, mGoToContact, mBack;
private View mView;
public class HistoryDetailFragment extends Fragment {
private ImageView mAddToContacts;
private ImageView mGoToContact;
private TextView mContactName, mContactAddress;
private String mSipUri, mDisplayName;
private RelativeLayout mWaitLayout, mAvatarLayout, mChatSecured;
@ -69,41 +67,80 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
mSipUri = getArguments().getString("SipUri");
mDisplayName = getArguments().getString("DisplayName");
mView = inflater.inflate(R.layout.history_detail, container, false);
View view = inflater.inflate(R.layout.history_detail, container, false);
mWaitLayout = mView.findViewById(R.id.waitScreen);
mWaitLayout = view.findViewById(R.id.waitScreen);
mWaitLayout.setVisibility(View.GONE);
mDialBack = mView.findViewById(R.id.call);
mDialBack.setOnClickListener(this);
mBack = mView.findViewById(R.id.back);
if (getResources().getBoolean(R.bool.isTablet)) {
mBack.setVisibility(View.INVISIBLE);
} else {
mBack.setOnClickListener(this);
ImageView dialBack = view.findViewById(R.id.call);
dialBack.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
LinphoneManager.getCallManager().newOutgoingCall(mSipUri, mDisplayName);
}
});
mChat = mView.findViewById(R.id.chat);
mChat.setOnClickListener(this);
ImageView back = view.findViewById(R.id.back);
back.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
((HistoryActivity) getActivity()).goBack();
}
});
back.setVisibility(
getResources().getBoolean(R.bool.isTablet) ? View.INVISIBLE : View.VISIBLE);
mChatSecured = mView.findViewById(R.id.chat_secured);
mChatSecured.setOnClickListener(this);
ImageView chat = view.findViewById(R.id.chat);
chat.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
goToChat(false);
}
});
mChatSecured = view.findViewById(R.id.chat_secured);
mChatSecured.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
goToChat(true);
}
});
if (getResources().getBoolean(R.bool.disable_chat)) {
mChat.setVisibility(View.GONE);
chat.setVisibility(View.GONE);
mChatSecured.setVisibility(View.GONE);
}
mAddToContacts = mView.findViewById(R.id.add_contact);
mAddToContacts.setOnClickListener(this);
mAddToContacts = view.findViewById(R.id.add_contact);
mAddToContacts.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
Address addr = Factory.instance().createAddress(mSipUri);
if (addr != null) {
addr.clean();
((HistoryActivity) getActivity())
.showContactsListForCreationOrEdition(addr);
}
}
});
mGoToContact = mView.findViewById(R.id.goto_contact);
mGoToContact.setOnClickListener(this);
mGoToContact = view.findViewById(R.id.goto_contact);
mGoToContact.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
((HistoryActivity) getActivity()).showContactDetails(mContact);
}
});
mAvatarLayout = mView.findViewById(R.id.avatar_layout);
mContactName = mView.findViewById(R.id.contact_name);
mContactAddress = mView.findViewById(R.id.contact_address);
mAvatarLayout = view.findViewById(R.id.avatar_layout);
mContactName = view.findViewById(R.id.contact_name);
mContactAddress = view.findViewById(R.id.contact_address);
mChatRoomCreationListener =
new ChatRoomListenerStub() {
@ -111,14 +148,11 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance()
.goToChat(
cr.getLocalAddress().asStringUriOnly(),
cr.getPeerAddress().asStringUriOnly(),
null);
((HistoryActivity) getActivity())
.showChatRoom(cr.getLocalAddress(), cr.getPeerAddress());
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
((HistoryActivity) getActivity()).displayChatRoomError();
Log.e(
"Group mChat room for address "
+ cr.getPeerAddress()
@ -127,24 +161,31 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
}
};
mLogsList = mView.findViewById(R.id.logs_list);
mLogsList = view.findViewById(R.id.logs_list);
displayHistory();
return mView;
return view;
}
@Override
public void onPause() {
if (mChatRoom != null) {
mChatRoom.removeListener(mChatRoomCreationListener);
}
super.onPause();
}
private void displayHistory() {
if (mSipUri != null) {
Address lAddress = Factory.instance().createAddress(mSipUri);
mChatSecured.setVisibility(View.GONE);
if (lAddress != null) {
CallLog[] logs =
LinphoneManager.getLcIfManagerNotDestroyedOrNull()
.getCallHistoryForAddress(lAddress);
CallLog[] logs = LinphoneManager.getCore().getCallHistoryForAddress(lAddress);
List<CallLog> logsList = Arrays.asList(logs);
mLogsList.setAdapter(
new HistoryLogAdapter(
LinphoneActivity.instance(), R.layout.history_detail_cell, logsList));
getActivity(), R.layout.history_detail_cell, logsList));
mContactAddress.setText(LinphoneUtils.getDisplayableAddress(lAddress));
mContact = ContactsManager.getInstance().findContactFromAddress(lAddress);
@ -178,78 +219,36 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
: mDisplayName);
}
}
@Override
public void onPause() {
if (mChatRoom != null) {
mChatRoom.removeListener(mChatRoomCreationListener);
}
super.onPause();
}
public void changeDisplayedHistory(String sipUri, String displayName) {
if (displayName == null) {
displayName = LinphoneUtils.getUsernameFromAddress(sipUri);
}
mSipUri = sipUri;
mDisplayName = displayName;
displayHistory();
}
@Override
public void onResume() {
super.onResume();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_DETAIL);
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.back) {
getFragmentManager().popBackStackImmediate();
}
if (id == R.id.call) {
LinphoneActivity.instance().setAddresGoToDialerAndCall(mSipUri, mDisplayName);
} else if (id == R.id.chat || id == R.id.chat_secured) {
boolean isSecured = id == R.id.chat_secured;
Core lc = LinphoneManager.getLc();
private void goToChat(boolean isSecured) {
Core core = LinphoneManager.getCore();
Address participant = Factory.instance().createAddress(mSipUri);
ChatRoom room =
lc.findOneToOneChatRoom(
lc.getDefaultProxyConfig().getContact(), participant, isSecured);
core.findOneToOneChatRoom(
core.getDefaultProxyConfig().getContact(), participant, isSecured);
if (room != null) {
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asStringUriOnly(),
null);
((HistoryActivity) getActivity())
.showChatRoom(room.getLocalAddress(), room.getPeerAddress());
} else {
ProxyConfig lpc = lc.getDefaultProxyConfig();
ProxyConfig lpc = core.getDefaultProxyConfig();
if (lpc != null
&& lpc.getConferenceFactoryUri() != null
&& (isSecured
|| !LinphonePreferences.instance().useBasicChatRoomFor1To1())) {
&& (isSecured || !LinphonePreferences.instance().useBasicChatRoomFor1To1())) {
mWaitLayout.setVisibility(View.VISIBLE);
ChatRoomParams params = lc.createDefaultChatRoomParams();
ChatRoomParams params = core.createDefaultChatRoomParams();
params.enableEncryption(isSecured);
params.enableGroup(false);
// We don't want a basic chat room
params.setBackend(ChatRoomBackend.FlexisipChat);
Address participants[] = new Address[1];
Address[] participants = new Address[1];
participants[0] = participant;
mChatRoom =
lc.createChatRoom(
params,
getString(R.string.dummy_group_chat_subject),
participants);
core.createChatRoom(
params, getString(R.string.dummy_group_chat_subject), participants);
if (mChatRoom != null) {
mChatRoom.addListener(mChatRoomCreationListener);
} else {
@ -257,28 +256,12 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
mWaitLayout.setVisibility(View.GONE);
}
} else {
room = lc.getChatRoom(participant);
LinphoneActivity.instance()
.goToChat(
room.getLocalAddress().asStringUriOnly(),
room.getPeerAddress().asStringUriOnly(),
null);
room = core.getChatRoom(participant);
if (room != null) {
((HistoryActivity) getActivity())
.showChatRoom(room.getLocalAddress(), room.getPeerAddress());
}
}
} else if (id == R.id.add_contact) {
Address addr = Factory.instance().createAddress(mSipUri);
if (addr != null) {
String address =
"sip:" + addr.getUsername() + "@" + addr.getDomain(); // Clean gruu param
if (addr.getDisplayName() != null) {
LinphoneActivity.instance()
.displayContactsForEdition(address, addr.getDisplayName());
} else {
LinphoneActivity.instance().displayContactsForEdition(address);
}
}
} else if (id == R.id.goto_contact) {
LinphoneActivity.instance().displayContact(mContact, false);
}
}
}

View file

@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -36,7 +35,6 @@ import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
@ -44,7 +42,7 @@ import org.linphone.contacts.ContactsUpdatedListener;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.CallLog;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.core.Core;
import org.linphone.utils.SelectableHelper;
public class HistoryFragment extends Fragment
@ -60,15 +58,12 @@ public class HistoryFragment extends Fragment
private boolean mOnlyDisplayMissedCalls;
private List<CallLog> mLogs;
private HistoryAdapter mHistoryAdapter;
private LinearLayoutManager mLayoutManager;
private Context mContext;
private SelectableHelper mSelectionHelper;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.history, container, false);
mContext = getActivity().getApplicationContext();
mSelectionHelper = new SelectableHelper(view, this);
mNoCallHistory = view.findViewById(R.id.no_call_history);
@ -76,13 +71,13 @@ public class HistoryFragment extends Fragment
mHistoryList = view.findViewById(R.id.history_list);
mLayoutManager = new LinearLayoutManager(mContext);
mHistoryList.setLayoutManager(mLayoutManager);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mHistoryList.setLayoutManager(layoutManager);
// Divider between items
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(
mHistoryList.getContext(), mLayoutManager.getOrientation());
dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider));
mHistoryList.getContext(), layoutManager.getOrientation());
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider));
mHistoryList.addItemDecoration(dividerItemDecoration);
mAllCalls = view.findViewById(R.id.all_calls);
@ -101,22 +96,124 @@ public class HistoryFragment extends Fragment
return view;
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs());
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter =
new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog);
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
}
@Override
public void onContactsUpdated() {
HistoryAdapter adapter = (HistoryAdapter) mHistoryList.getAdapter();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.all_calls) {
mAllCalls.setEnabled(false);
mAllCallsSelected.setVisibility(View.VISIBLE);
mMissedCallsSelected.setVisibility(View.INVISIBLE);
mMissedCalls.setEnabled(true);
mOnlyDisplayMissedCalls = false;
refresh();
}
if (id == R.id.missed_calls) {
mAllCalls.setEnabled(true);
mAllCallsSelected.setVisibility(View.INVISIBLE);
mMissedCallsSelected.setVisibility(View.VISIBLE);
mMissedCalls.setEnabled(false);
mOnlyDisplayMissedCalls = true;
}
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter =
new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog);
}
@Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
if (mHistoryAdapter.isEditionEnabled()) {
CallLog log = mLogs.get(position);
Core core = LinphoneManager.getCore();
core.removeCallLog(log);
mLogs = Arrays.asList(core.getCallLogs());
}
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
int size = mHistoryAdapter.getSelectedItemCount();
for (int i = 0; i < size; i++) {
CallLog log = (CallLog) objectsToDelete[i];
LinphoneManager.getCore().removeCallLog(log);
onResume();
}
}
@Override
public void onItemClicked(int position) {
if (mHistoryAdapter.isEditionEnabled()) {
mHistoryAdapter.toggleSelection(position);
} else {
CallLog log = mLogs.get(position);
Address address;
if (log.getDir() == Call.Dir.Incoming) {
address = log.getFromAddress();
} else {
address = log.getToAddress();
}
if (address != null) {
LinphoneManager.getCallManager().newOutgoingCall(address.asStringUriOnly(), null);
}
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mHistoryAdapter.isEditionEnabled()) {
mSelectionHelper.enterEditionMode();
}
mHistoryAdapter.toggleSelection(position);
return true;
}
private void refresh() {
mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs());
}
public void displayFirstLog() {
Address addr;
if (mLogs != null && mLogs.size() > 0) {
CallLog log = mLogs.get(0);
String addr;
CallLog log = mLogs.get(0); // More recent one is 0
if (log.getDir() == Call.Dir.Incoming) {
addr = log.getFromAddress().asString();
addr = log.getFromAddress();
} else {
addr = log.getToAddress().asString();
addr = log.getToAddress();
}
LinphoneActivity.instance().displayHistoryDetail(addr, log);
((HistoryActivity) getActivity()).showHistoryDetails(addr);
} else {
LinphoneActivity.instance().displayEmptyFragment();
((HistoryActivity) getActivity()).showEmptyChildFragment();
}
}
@ -150,115 +247,4 @@ public class HistoryFragment extends Fragment
mHistoryList.setVisibility(View.VISIBLE);
}
}
@Override
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_LIST);
LinphoneActivity.instance().displayMissedCalls(0);
}
mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter =
new HistoryAdapter(
getActivity().getApplicationContext(), mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog);
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
super.onPause();
}
@Override
public void onContactsUpdated() {
if (!LinphoneActivity.isInstanciated()
|| LinphoneActivity.instance().getCurrentFragment()
!= FragmentsAvailable.HISTORY_LIST) return;
HistoryAdapter adapter = (HistoryAdapter) mHistoryList.getAdapter();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.all_calls) {
mAllCalls.setEnabled(false);
mAllCallsSelected.setVisibility(View.VISIBLE);
mMissedCallsSelected.setVisibility(View.INVISIBLE);
mMissedCalls.setEnabled(true);
mOnlyDisplayMissedCalls = false;
refresh();
}
if (id == R.id.missed_calls) {
mAllCalls.setEnabled(true);
mAllCallsSelected.setVisibility(View.INVISIBLE);
mMissedCallsSelected.setVisibility(View.VISIBLE);
mMissedCalls.setEnabled(false);
mOnlyDisplayMissedCalls = true;
}
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter = new HistoryAdapter(mContext, mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog);
}
@Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
if (mHistoryAdapter.isEditionEnabled()) {
CallLog log = mLogs.get(position);
LinphoneManager.getLc().removeCallLog(log);
mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
}
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
int size = mHistoryAdapter.getSelectedItemCount();
for (int i = 0; i < size; i++) {
CallLog log = (CallLog) objectsToDelete[i];
LinphoneManager.getLc().removeCallLog(log);
onResume();
}
}
@Override
public void onItemClicked(int position) {
if (mHistoryAdapter.isEditionEnabled()) {
mHistoryAdapter.toggleSelection(position);
} else {
if (LinphoneActivity.isInstanciated()) {
CallLog log = mLogs.get(position);
Address address;
if (log.getDir() == Call.Dir.Incoming) {
address = log.getFromAddress();
} else {
address = log.getToAddress();
}
LinphoneActivity.instance()
.setAddresGoToDialerAndCall(
address.asStringUriOnly(), address.getDisplayName());
}
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mHistoryAdapter.isEditionEnabled()) {
mSelectionHelper.enterEditionMode();
}
mHistoryAdapter.toggleSelection(position);
return true;
}
}

View file

@ -38,7 +38,7 @@ import org.linphone.core.CallLog;
import org.linphone.utils.LinphoneUtils;
class HistoryLogAdapter extends ArrayAdapter<CallLog> {
private Context mContext;
private final Context mContext;
private final List<CallLog> mItems;
private final int mResource;
@ -74,7 +74,10 @@ class HistoryLogAdapter extends ArrayAdapter<CallLog> {
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(mResource, parent, false);
View rowView = convertView;
if (rowView == null) {
rowView = inflater.inflate(mResource, parent, false);
}
CallLog callLog = getItem(position);
String callTime = secondsToDisplayableString(callLog.getDuration());
@ -103,7 +106,7 @@ class HistoryLogAdapter extends ArrayAdapter<CallLog> {
}
time.setText(callTime == null ? "" : callTime);
Long longDate = Long.parseLong(callDate);
long longDate = Long.parseLong(callDate);
date.setText(
LinphoneUtils.timestampToHumanDate(
mContext,

View file

@ -0,0 +1,126 @@
package org.linphone.menu;
/*
SideMenuAccountsListAdapter.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.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.ProxyConfig;
import org.linphone.core.RegistrationState;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
class SideMenuAccountsListAdapter extends BaseAdapter {
private final Context mContext;
private List<ProxyConfig> proxy_list;
SideMenuAccountsListAdapter(Context context) {
mContext = context;
proxy_list = new ArrayList<>();
refresh();
}
private void refresh() {
proxy_list = new ArrayList<>();
Core core = LinphoneManager.getCore();
for (ProxyConfig proxyConfig : core.getProxyConfigList()) {
if (proxyConfig != core.getDefaultProxyConfig()) {
proxy_list.add(proxyConfig);
}
}
}
public int getCount() {
if (proxy_list != null) {
return proxy_list.size();
} else {
return 0;
}
}
public Object getItem(int position) {
return proxy_list.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
ProxyConfig lpc = (ProxyConfig) getItem(position);
if (convertView != null) {
view = convertView;
} else {
view =
LayoutInflater.from(mContext)
.inflate(R.layout.side_menu_account_cell, parent, false);
}
ImageView status = view.findViewById(R.id.account_status);
TextView address = view.findViewById(R.id.account_address);
String sipAddress = lpc.getIdentityAddress().asStringUriOnly();
address.setText(sipAddress);
int nbAccounts = LinphonePreferences.instance().getAccountCount();
int accountIndex;
for (int i = 0; i < nbAccounts; i++) {
String username = LinphonePreferences.instance().getAccountUsername(i);
String domain = LinphonePreferences.instance().getAccountDomain(i);
String id = "sip:" + username + "@" + domain;
if (id.equals(sipAddress)) {
accountIndex = i;
view.setTag(accountIndex);
break;
}
}
status.setImageResource(getStatusIconResource(lpc.getState()));
return view;
}
private int getStatusIconResource(RegistrationState state) {
try {
if (state == RegistrationState.Ok) {
return R.drawable.led_connected;
} else if (state == RegistrationState.Progress) {
return R.drawable.led_inprogress;
} else if (state == RegistrationState.Failed) {
return R.drawable.led_error;
} else {
return R.drawable.led_disconnected;
}
} catch (Exception e) {
Log.e(e);
}
return R.drawable.led_disconnected;
}
}

View file

@ -0,0 +1,75 @@
package org.linphone.menu;
/*
SideMenuAdapter.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.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;
import org.linphone.R;
class SideMenuAdapter extends ArrayAdapter<SideMenuItem> {
private final List<SideMenuItem> mItems;
private final int mResource;
SideMenuAdapter(@NonNull Context context, int resource, @NonNull List<SideMenuItem> objects) {
super(context, resource, objects);
mResource = resource;
mItems = objects;
}
@Nullable
@Override
public SideMenuItem getItem(int position) {
return mItems.get(position);
}
@Override
public int getCount() {
return mItems.size();
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = convertView;
if (rowView == null) {
rowView = inflater.inflate(mResource, parent, false);
}
TextView textView = rowView.findViewById(R.id.item_name);
ImageView imageView = rowView.findViewById(R.id.item_icon);
SideMenuItem item = getItem(position);
textView.setText(item.name);
imageView.setImageResource(item.icon);
return rowView;
}
}

View file

@ -0,0 +1,257 @@
package org.linphone.menu;
/*
SideMenuFragment.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.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.activities.AboutActivity;
import org.linphone.activities.MainActivity;
import org.linphone.assistant.MenuAssistantActivity;
import org.linphone.core.Core;
import org.linphone.core.ProxyConfig;
import org.linphone.core.RegistrationState;
import org.linphone.core.tools.Log;
import org.linphone.recording.RecordingsActivity;
import org.linphone.settings.LinphonePreferences;
import org.linphone.settings.SettingsActivity;
import org.linphone.utils.LinphoneUtils;
public class SideMenuFragment extends Fragment {
private DrawerLayout mSideMenu;
private RelativeLayout mSideMenuContent;
private RelativeLayout mDefaultAccount;
private ListView mAccountsList, mSideMenuItemList;
private QuitClikedListener mQuitListener;
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.side_menu, container, false);
List<SideMenuItem> sideMenuItems = new ArrayList<>();
if (getResources().getBoolean(R.bool.show_log_out_in_side_menu)) {
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.menu_logout),
R.drawable.quit_default));
}
if (!getResources().getBoolean(R.bool.hide_assistant_from_side_menu)) {
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.menu_assistant),
R.drawable.menu_assistant));
}
if (!getResources().getBoolean(R.bool.hide_settings_from_side_menu)) {
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.menu_settings),
R.drawable.menu_options));
}
if (getResources().getBoolean(R.bool.enable_in_app_purchase)) {
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.inapp), R.drawable.menu_options));
}
if (!getResources().getBoolean(R.bool.hide_recordings_from_side_menu)) {
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.menu_recordings),
R.drawable.menu_recordings));
}
sideMenuItems.add(
new SideMenuItem(
getResources().getString(R.string.menu_about), R.drawable.menu_about));
mSideMenuItemList = view.findViewById(R.id.item_list);
mSideMenuItemList.setAdapter(
new SideMenuAdapter(getActivity(), R.layout.side_menu_item_cell, sideMenuItems));
mSideMenuItemList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String selectedItem = mSideMenuItemList.getAdapter().getItem(i).toString();
if (selectedItem.equals(getString(R.string.menu_logout))) {
Core core = LinphoneManager.getCore();
if (core != null) {
core.setDefaultProxyConfig(null);
core.clearAllAuthInfo();
core.clearProxyConfig();
startActivity(
new Intent()
.setClass(
getActivity(),
MenuAssistantActivity.class));
getActivity().finish();
}
} else if (selectedItem.equals(getString(R.string.menu_settings))) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
} else if (selectedItem.equals(getString(R.string.menu_about))) {
startActivity(new Intent(getActivity(), AboutActivity.class));
} else if (selectedItem.equals(getString(R.string.menu_assistant))) {
startActivity(new Intent(getActivity(), MenuAssistantActivity.class));
} else if (selectedItem.equals(getString(R.string.menu_recordings))) {
startActivity(new Intent(getActivity(), RecordingsActivity.class));
}
}
});
mAccountsList = view.findViewById(R.id.accounts_list);
mDefaultAccount = view.findViewById(R.id.default_account);
RelativeLayout quitLayout = view.findViewById(R.id.side_menu_quit);
quitLayout.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mQuitListener != null) {
mQuitListener.onQuitClicked();
}
}
});
return view;
}
public void setQuitListener(QuitClikedListener listener) {
mQuitListener = listener;
}
public void setDrawer(DrawerLayout drawer, RelativeLayout content) {
mSideMenu = drawer;
mSideMenuContent = content;
}
public boolean isOpened() {
return mSideMenu != null && mSideMenu.isDrawerVisible(Gravity.LEFT);
}
public void closeDrawer() {
openOrCloseSideMenu(false, false);
}
public void openOrCloseSideMenu(boolean open, boolean animate) {
if (mSideMenu == null || mSideMenuContent == null) return;
if (open) {
mSideMenu.openDrawer(mSideMenuContent, animate);
} else {
mSideMenu.closeDrawer(mSideMenuContent, animate);
}
}
private void displayMainAccount() {
mDefaultAccount.setVisibility(View.VISIBLE);
ImageView status = mDefaultAccount.findViewById(R.id.main_account_status);
TextView address = mDefaultAccount.findViewById(R.id.main_account_address);
TextView displayName = mDefaultAccount.findViewById(R.id.main_account_display_name);
ProxyConfig proxy = LinphoneManager.getCore().getDefaultProxyConfig();
if (proxy == null) {
displayName.setText(getString(R.string.no_account));
status.setVisibility(View.GONE);
address.setText("");
mDefaultAccount.setOnClickListener(null);
} else {
address.setText(proxy.getIdentityAddress().asStringUriOnly());
displayName.setText(LinphoneUtils.getAddressDisplayName(proxy.getIdentityAddress()));
status.setImageResource(getStatusIconResource(proxy.getState()));
status.setVisibility(View.VISIBLE);
if (!getResources().getBoolean(R.bool.disable_accounts_settings_from_side_menu)) {
mDefaultAccount.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
((MainActivity) getActivity())
.showAccountSettings(
LinphonePreferences.instance()
.getDefaultAccountIndex());
}
});
}
}
}
private int getStatusIconResource(RegistrationState state) {
try {
if (state == RegistrationState.Ok) {
return R.drawable.led_connected;
} else if (state == RegistrationState.Progress) {
return R.drawable.led_inprogress;
} else if (state == RegistrationState.Failed) {
return R.drawable.led_error;
} else {
return R.drawable.led_disconnected;
}
} catch (Exception e) {
Log.e(e);
}
return R.drawable.led_disconnected;
}
public void displayAccountsInSideMenu() {
Core core = LinphoneManager.getCore();
if (core != null
&& core.getProxyConfigList() != null
&& core.getProxyConfigList().length > 1) {
mAccountsList.setVisibility(View.VISIBLE);
mAccountsList.setAdapter(new SideMenuAccountsListAdapter(getActivity()));
mAccountsList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(
AdapterView<?> adapterView, View view, int i, long l) {
if (view != null && view.getTag() != null) {
int position = Integer.parseInt(view.getTag().toString());
((MainActivity) getActivity()).showAccountSettings(position);
}
}
});
} else {
mAccountsList.setVisibility(View.GONE);
}
displayMainAccount();
}
public interface QuitClikedListener {
void onQuitClicked();
}
}

View file

@ -0,0 +1,34 @@
package org.linphone.menu;
/*
SideMenuItem.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.
*/
public class SideMenuItem {
final String name;
final int icon;
SideMenuItem(String name, int icon) {
this.name = name;
this.icon = icon;
}
public String toString() {
return name;
}
}

View file

@ -25,7 +25,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
@ -51,7 +50,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
.getNotificationManager()
.getSipUriForNotificationId(notifId);
Core core = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
if (core == null) {
Log.e("[Notification Broadcast Receiver] Couldn't get Core instance");
onError(context, notifId);
@ -88,10 +87,6 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
}
room.markAsRead();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount());
}
if (intent.getAction().equals(Compatibility.INTENT_REPLY_NOTIF_ACTION)) {
final String reply = getMessageText(intent).toString();
@ -131,7 +126,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
.getNotificationManager()
.getSipUriForCallNotificationId(notifId);
Core core = LinphoneManager.getLc();
Core core = LinphoneManager.getCore();
if (core == null) {
Log.e("[Notification Broadcast Receiver] Couldn't get Core instance");
return;

View file

@ -29,23 +29,35 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import java.io.File;
import java.util.HashMap;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.activities.DialerActivity;
import org.linphone.call.CallActivity;
import org.linphone.call.CallIncomingActivity;
import org.linphone.call.CallOutgoingActivity;
import org.linphone.chat.ChatActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomCapabilities;
import org.linphone.core.Content;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.Reason;
import org.linphone.core.tools.Log;
import org.linphone.history.HistoryActivity;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.FileUtils;
import org.linphone.utils.ImageUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.utils.MediaScannerListener;
public class NotificationsManager {
private static final int SERVICE_NOTIF_ID = 1;
@ -59,12 +71,15 @@ public class NotificationsManager {
private int mLastNotificationId;
private final Notification mServiceNotification;
private int mCurrentForegroundServiceNotification;
private String mCurrentChatRoomAddress;
private CoreListenerStub mListener;
public NotificationsManager(Context context) {
mContext = context;
mChatNotifMap = new HashMap<>();
mCallNotifMap = new HashMap<>();
mCurrentForegroundServiceNotification = 0;
mCurrentChatRoomAddress = null;
mNM = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
mNM.cancelAll();
@ -80,7 +95,7 @@ public class NotificationsManager {
Log.e(e);
}
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
Intent notifIntent = new Intent(mContext, DialerActivity.class);
notifIntent.putExtra("Notification", true);
PendingIntent pendingIntent =
@ -100,10 +115,97 @@ public class NotificationsManager {
if (isServiceNotificationDisplayed()) {
startForeground();
}
mListener =
new CoreListenerStub() {
@Override
public void onMessageReceived(
Core core, final ChatRoom cr, final ChatMessage message) {
if (message.isOutgoing()
|| mContext.getResources().getBoolean(R.bool.disable_chat)
|| mContext.getResources()
.getBoolean(R.bool.disable_chat_message_notification)) {
return;
}
if (mCurrentChatRoomAddress != null
&& mCurrentChatRoomAddress.equals(
cr.getPeerAddress().asStringUriOnly())) {
Log.i(
"[Notifications 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(
"[Notifications Manager] Message received but content is unsupported, do not notify it");
return;
}
if (!message.hasTextContent()
&& message.getFileTransferInformation() == null) {
Log.w(
"[Notifications Manager] Message has no text or file transfer information to display, ignoring it...");
return;
}
final Address from = message.getFromAddress();
final LinphoneContact contact =
ContactsManager.getInstance().findContactFromAddress(from);
final String textMessage =
(message.hasTextContent())
? message.getTextContent()
: mContext.getString(
R.string.content_description_incoming_file);
String file = null;
for (Content c : message.getContents()) {
if (c.isFile()) {
file = c.getFilePath();
LinphoneManager.getInstance()
.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);
}
}
};
Core core = LinphoneManager.getCore();
if (core != null) {
core.addListener(mListener);
}
}
public void destroy() {
mNM.cancelAll();
Core core = LinphoneManager.getCore();
if (core != null) {
core.removeListener(mListener);
}
}
public void startForeground() {
@ -111,7 +213,7 @@ public class NotificationsManager {
mCurrentForegroundServiceNotification = SERVICE_NOTIF_ID;
}
public void startForeground(Notification notification, int id) {
private void startForeground(Notification notification, int id) {
LinphoneService.instance().startForeground(id, notification);
mCurrentForegroundServiceNotification = id;
}
@ -128,6 +230,13 @@ public class NotificationsManager {
}
}
public void setCurrentlyDisplayedChatRoom(String address) {
mCurrentChatRoomAddress = address;
if (address != null) {
resetMessageNotifCount(address);
}
}
public void sendNotification(int id, Notification notif) {
mNM.notify(id, notif);
}
@ -181,9 +290,8 @@ public class NotificationsManager {
notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity));
notif.setLocalIdentity(localIdentity.asString());
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", conferenceAddress);
Intent notifIntent = new Intent(mContext, ChatActivity.class);
notifIntent.putExtra("RemoteSipUri", conferenceAddress);
notifIntent.putExtra("LocalSipUri", localIdentity.asStringUriOnly());
PendingIntent pendingIntent =
PendingIntent.getActivity(
@ -234,9 +342,8 @@ public class NotificationsManager {
notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity));
notif.setLocalIdentity(localIdentity.asString());
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", fromSipUri);
Intent notifIntent = new Intent(mContext, ChatActivity.class);
notifIntent.putExtra("RemoteSipUri", fromSipUri);
notifIntent.putExtra("LocalSipUri", localIdentity.asStringUriOnly());
PendingIntent pendingIntent =
PendingIntent.getActivity(
@ -252,8 +359,7 @@ public class NotificationsManager {
}
public void displayMissedCallNotification(Call call) {
Intent missedCallNotifIntent = new Intent(mContext, LinphoneActivity.class);
missedCallNotifIntent.putExtra("GoToHistory", true);
Intent missedCallNotifIntent = new Intent(mContext, HistoryActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(
mContext,
@ -261,8 +367,7 @@ public class NotificationsManager {
missedCallNotifIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
int missedCallCount =
LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount();
int missedCallCount = LinphoneManager.getCore().getMissedCallsCount();
String body;
if (missedCallCount > 1) {
body =
@ -411,9 +516,8 @@ public class NotificationsManager {
return null;
}
public void displayInappNotification(String message) {
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToInapp", true);
/*public void displayInappNotification(String message) {
Intent notifIntent = new Intent(mContext, InAppPurchaseActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(
mContext, IN_APP_NOTIF_ID, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
@ -425,9 +529,67 @@ public class NotificationsManager {
message,
pendingIntent);
sendNotification(IN_APP_NOTIF_ID, notif);
}
}*/
public void dismissNotification(int notifId) {
mNM.cancel(notifId);
}
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) {
displayMessageNotification(
cr.getPeerAddress().asStringUriOnly(),
contact.getFullName(),
contact.getThumbnailUri(),
textMessage,
cr.getLocalAddress(),
time,
file,
mime);
} else {
displayMessageNotification(
cr.getPeerAddress().asStringUriOnly(),
from.getUsername(),
null,
textMessage,
cr.getLocalAddress(),
time,
file,
mime);
}
} else {
String subject = cr.getSubject();
if (contact != null) {
displayGroupChatMessageNotification(
subject,
cr.getPeerAddress().asStringUriOnly(),
contact.getFullName(),
contact.getThumbnailUri(),
textMessage,
cr.getLocalAddress(),
time,
file,
mime);
} else {
displayGroupChatMessageNotification(
subject,
cr.getPeerAddress().asStringUriOnly(),
from.getUsername(),
null,
textMessage,
cr.getLocalAddress(),
time,
file,
mime);
}
}
}
}

View file

@ -42,7 +42,6 @@ public class InAppPurchaseActivity extends Activity
private static InAppPurchaseActivity sInstance;
private InAppPurchaseHelper mInAppPurchaseHelper;
private ImageView mCancel, mBack;
private ProgressBar mInProgress;
private List<Purchasable> mPurchasedItems;
@ -63,10 +62,10 @@ public class InAppPurchaseActivity extends Activity
mInProgress = findViewById(R.id.purchaseItemsFetchInProgress);
mInProgress.setVisibility(View.VISIBLE);
mBack = findViewById(R.id.back);
ImageView mBack = findViewById(R.id.back);
mBack.setOnClickListener(this);
mBack.setVisibility(View.INVISIBLE);
mCancel = findViewById(R.id.cancel);
ImageView mCancel = findViewById(R.id.cancel);
mCancel.setOnClickListener(this);
sInstance = this;
@ -168,9 +167,7 @@ public class InAppPurchaseActivity extends Activity
xmlRpcHelper.updateAccountExpireAsync(
new XmlRpcListenerBase() {
@Override
public void onAccountExpireUpdated() {
// TODO
}
public void onAccountExpireUpdated() {}
},
LinphonePreferences.instance().getAccountUsername(0),
LinphonePreferences.instance().getAccountHa1(0),

View file

@ -36,12 +36,10 @@ import org.linphone.core.ProxyConfig;
import org.linphone.settings.LinphonePreferences;
public class InAppPurchaseFragment extends Fragment implements View.OnClickListener {
private LinearLayout mUsernameLayout;
private EditText mUsername, mEmail;
private EditText mUsername;
private TextView mErrorMessage;
private boolean mUsernameOk = false, mEmailOk = false;
private String mDefaultUsername, mDefaultEmail;
private Button mBuyItemButton;
@Override
@ -58,13 +56,13 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe
displayBuySubscriptionButton(item);
mDefaultEmail = InAppPurchaseActivity.instance().getGmailAccount();
mDefaultUsername =
String mDefaultEmail = InAppPurchaseActivity.instance().getGmailAccount();
String mDefaultUsername =
LinphonePreferences.instance()
.getAccountUsername(
LinphonePreferences.instance().getDefaultAccountIndex());
mUsernameLayout = view.findViewById(R.id.username_layout);
LinearLayout mUsernameLayout = view.findViewById(R.id.username_layout);
mUsername = view.findViewById(R.id.username);
if (!getResources().getBoolean(R.bool.hide_username_in_inapp)) {
mUsernameLayout.setVisibility(View.VISIBLE);
@ -81,7 +79,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe
}
}
mEmail = view.findViewById(R.id.email);
EditText mEmail = view.findViewById(R.id.email);
if (mDefaultEmail != null) {
mEmail.setText(mDefaultEmail);
mEmailOk = true;
@ -116,7 +114,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe
}
private boolean isUsernameCorrect(String username) {
ProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
ProxyConfig lpc = LinphoneManager.getCore().createProxyConfig();
return lpc.isPhoneNumber(username);
}
@ -135,7 +133,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe
private String getUsername() {
String username = this.mUsername.getText().toString();
ProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
ProxyConfig lpc = LinphoneManager.getCore().createProxyConfig();
username = lpc.normalizePhoneNumber(username);
return username.toLowerCase(Locale.getDefault());
}

View file

@ -43,33 +43,33 @@ import org.linphone.xmlrpc.XmlRpcHelper;
import org.linphone.xmlrpc.XmlRpcListenerBase;
class InAppPurchaseHelper {
public static final int API_VERSION = 3;
public static final int ACTIVITY_RESULT_CODE_PURCHASE_ITEM = 11089;
private static final int API_VERSION = 3;
private static final int ACTIVITY_RESULT_CODE_PURCHASE_ITEM = 11089;
public static final String SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST";
public static final String SKU_DETAILS_LIST = "DETAILS_LIST";
public static final String SKU_DETAILS_PRODUCT_ID = "productId";
public static final String SKU_DETAILS_PRICE = "price";
public static final String SKU_DETAILS_TITLE = "title";
public static final String SKU_DETAILS_DESC = "description";
private static final String SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST";
private static final String SKU_DETAILS_LIST = "DETAILS_LIST";
private static final String SKU_DETAILS_PRODUCT_ID = "productId";
private static final String SKU_DETAILS_PRICE = "price";
private static final String SKU_DETAILS_TITLE = "title";
private static final String SKU_DETAILS_DESC = "description";
public static final String ITEM_TYPE_INAPP = "inapp";
public static final String ITEM_TYPE_SUBS = "subs";
private static final String ITEM_TYPE_SUBS = "subs";
public static final int RESPONSE_RESULT_OK = 0;
public static final int RESULT_USER_CANCELED = 1;
public static final int RESULT_SERVICE_UNAVAILABLE = 2;
public static final int RESULT_BILLING_UNAVAILABLE = 3;
public static final int RESULT_ITEM_UNAVAILABLE = 4;
public static final int RESULT_DEVELOPER_ERROR = 5;
public static final int RESULT_ERROR = 6;
public static final int RESULT_ITEM_ALREADY_OWNED = 7;
public static final int RESULT_ITEM_NOT_OWNED = 8;
private static final int RESPONSE_RESULT_OK = 0;
private static final int RESULT_USER_CANCELED = 1;
private static final int RESULT_SERVICE_UNAVAILABLE = 2;
private static final int RESULT_BILLING_UNAVAILABLE = 3;
private static final int RESULT_ITEM_UNAVAILABLE = 4;
private static final int RESULT_DEVELOPER_ERROR = 5;
private static final int RESULT_ERROR = 6;
private static final int RESULT_ITEM_ALREADY_OWNED = 7;
private static final int RESULT_ITEM_NOT_OWNED = 8;
public static final String RESPONSE_CODE = "RESPONSE_CODE";
public static final String RESPONSE_BUY_INTENT = "BUY_INTENT";
public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE";
private static final String RESPONSE_CODE = "RESPONSE_CODE";
private static final String RESPONSE_BUY_INTENT = "BUY_INTENT";
private static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
private static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE";
public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST";
public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
@ -83,11 +83,11 @@ class InAppPurchaseHelper {
public static final String PURCHASE_DETAILS_PAYLOAD = "developerPayload";
public static final String PURCHASE_DETAILS_PURCHASE_TOKEN = "purchaseToken";
public static final String CLIENT_ERROR_SUBSCRIPTION_PURCHASE_NOT_AVAILABLE =
private static final String CLIENT_ERROR_SUBSCRIPTION_PURCHASE_NOT_AVAILABLE =
"SUBSCRIPTION_PURCHASE_NOT_AVAILABLE";
public static final String CLIENT_ERROR_BIND_TO_BILLING_SERVICE_FAILED =
private static final String CLIENT_ERROR_BIND_TO_BILLING_SERVICE_FAILED =
"BIND_TO_BILLING_SERVICE_FAILED";
public static final String CLIENT_ERROR_BILLING_SERVICE_UNAVAILABLE =
private static final String CLIENT_ERROR_BILLING_SERVICE_UNAVAILABLE =
"BILLING_SERVICE_UNAVAILABLE";
private final Context mContext;
@ -333,7 +333,7 @@ class InAppPurchaseHelper {
}
private Purchasable verifySignature() {
// TODO FIXME rework to be async
// TODO rework to be async
/*XmlRpcHelper helper = new XmlRpcHelper();
if (helper.verifySignature(payload, signature)) {
try {

View file

@ -32,7 +32,6 @@ import java.util.List;
import org.linphone.R;
public class InAppPurchaseListFragment extends Fragment implements AdapterView.OnItemClickListener {
private ListView mInappList;
private LayoutInflater mInflater;
private List<Purchasable> mPurchasableItems;
@ -43,7 +42,7 @@ public class InAppPurchaseListFragment extends Fragment implements AdapterView.O
View view = inflater.inflate(R.layout.in_app_list, container, false);
mPurchasableItems = InAppPurchaseActivity.instance().getPurchasedItems();
mInappList = view.findViewById(R.id.inapp_list);
ListView mInappList = view.findViewById(R.id.inapp_list);
if (mPurchasableItems != null) {
mInappList.setAdapter(new InAppListAdapter());

View file

@ -23,44 +23,23 @@ import java.util.ArrayList;
public class InAppPurchaseListenerBase implements InAppPurchaseListener {
@Override
public void onServiceAvailableForQueries() {
// TODO Auto-generated method stub
}
public void onServiceAvailableForQueries() {}
@Override
public void onAvailableItemsForPurchaseQueryFinished(ArrayList<Purchasable> items) {
// TODO Auto-generated method stub
}
public void onAvailableItemsForPurchaseQueryFinished(ArrayList<Purchasable> items) {}
@Override
public void onPurchasedItemsQueryFinished(ArrayList<Purchasable> items) {
// TODO Auto-generated method stub
}
public void onPurchasedItemsQueryFinished(ArrayList<Purchasable> items) {}
@Override
public void onPurchasedItemConfirmationQueryFinished(boolean success) {
// TODO Auto-generated method stub
}
public void onPurchasedItemConfirmationQueryFinished(boolean success) {}
@Override
public void onRecoverAccountSuccessful() {
// TODO Auto-generated method stub
}
public void onRecoverAccountSuccessful() {}
@Override
public void onActivateAccountSuccessful(boolean success) {
// TODO Auto-generated method stub
}
public void onActivateAccountSuccessful(boolean success) {}
@Override
public void onError(String error) {
// TODO Auto-generated method stub
}
public void onError(String error) {}
}

View file

@ -34,12 +34,7 @@ public class AccountEnableReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
int prefsAccountIndex = (int) (long) intent.getLongExtra(FIELD_ID, -1);
boolean enable = intent.getBooleanExtra(FIELD_ACTIVE, true);
Log.i(
TAG,
"Received broadcast for index="
+ Integer.toString(prefsAccountIndex)
+ ",enable="
+ Boolean.toString(enable));
Log.i(TAG, "Received broadcast for index=" + prefsAccountIndex + ",enable=" + enable);
if (prefsAccountIndex < 0
|| prefsAccountIndex >= LinphonePreferences.instance().getAccountCount()) return;
LinphonePreferences.instance().setAccountEnabled(prefsAccountIndex, enable);

View file

@ -31,12 +31,9 @@ import android.media.AudioManager;
import java.util.List;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.call.CallActivity;
import org.linphone.core.tools.Log;
public class BluetoothManager extends BroadcastReceiver {
private static BluetoothManager sInstance;
private Context mContext;
private AudioManager mAudioManager;
private BluetoothAdapter mBluetoothAdapter;
@ -53,17 +50,17 @@ public class BluetoothManager extends BroadcastReceiver {
"BluetoothManager",
"[Bluetooth] Manager tried to init but LinphoneService not ready yet...");
}
sInstance = this;
initBluetooth();
}
public static BluetoothManager getInstance() {
if (sInstance == null) {
sInstance = new BluetoothManager();
if (LinphoneService.isReady()) {
return LinphoneService.instance().getBluetoothManager();
}
return sInstance;
return null;
}
public void initBluetooth() {
private void initBluetooth() {
if (!ensureInit()) {
android.util.Log.w(
"BluetoothManager",
@ -118,7 +115,7 @@ public class BluetoothManager extends BroadcastReceiver {
mIsBluetoothConnected = false;
android.util.Log.d(
"BluetoothManager", "[Bluetooth] Headset disconnected");
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
}
}
};
@ -134,9 +131,7 @@ public class BluetoothManager extends BroadcastReceiver {
}
private void refreshCallView() {
if (CallActivity.isInstanciated()) {
CallActivity.instance().refreshInCallActions();
}
LinphoneManager.getCallManager().refreshInCallActions();
}
private boolean ensureInit() {
@ -283,8 +278,8 @@ public class BluetoothManager extends BroadcastReceiver {
android.util.Log.w("BluetoothManager", "[Bluetooth] Stopped!");
if (LinphoneManager.isInstanciated()) {
LinphoneManager.getInstance().routeAudioToReceiver();
if (LinphoneService.isReady()) {
LinphoneManager.getAudioManager().routeAudioToEarPiece();
}
refreshCallView();
@ -306,7 +301,7 @@ public class BluetoothManager extends BroadcastReceiver {
}
public void onReceive(Context context, Intent intent) {
if (!LinphoneManager.isInstanciated()) return;
if (!LinphoneService.isReady()) return;
String action = intent.getAction();
if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {

View file

@ -22,7 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.compatibility.Compatibility;
import org.linphone.settings.LinphonePreferences;
@ -31,21 +30,21 @@ public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
LinphonePreferences.instance().setContext(context);
if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SHUTDOWN)) {
android.util.Log.d(
"LinphoneBootReceiver",
"Device is shutting down, destroying Core to unregister");
LinphoneManager.destroy();
context.stopService(
new Intent(Intent.ACTION_MAIN).setClass(context, LinphoneService.class));
} else {
boolean autostart = LinphonePreferences.instance().isAutoStartEnabled();
android.util.Log.i(
"LinphoneBootReceiver", "Device is starting, auto_start is " + autostart);
if (autostart && !LinphoneService.isReady()) {
Intent lLinphoneServiceIntent = new Intent(Intent.ACTION_MAIN);
lLinphoneServiceIntent.setClass(context, LinphoneService.class);
lLinphoneServiceIntent.putExtra("ForceStartForeground", true);
Compatibility.startService(context, lLinphoneServiceIntent);
Intent linphoneServiceIntent = new Intent(Intent.ACTION_MAIN);
linphoneServiceIntent.setClass(context, LinphoneService.class);
linphoneServiceIntent.putExtra("ForceStartForeground", true);
Compatibility.startService(context, linphoneServiceIntent);
}
}
}

View file

@ -31,19 +31,14 @@ public class HookReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (isOrderedBroadcast()) abortBroadcast();
Bundle extras = intent.getExtras();
boolean b = extras.getBoolean("hookoff");
if (b) {
// handset on
Log.i(" ======>>>>>> HookReceiver - handset ON");
LinphoneManager.getInstance().enableSpeaker(false);
if (!LinphoneManager.getInstance().isHansetModeOn())
LinphoneManager.getInstance().setHandsetMode(true);
boolean handsetOn = extras.getBoolean("hookoff");
Log.i("[Hook Receiver] Handset " + handsetOn);
LinphoneManager.getCallManager().setHandsetMode(handsetOn);
if (handsetOn) {
LinphoneManager.getAudioManager().routeAudioToEarPiece();
} else {
// handset off
Log.i(" ======>>>>>> HookReceiver - handset OFF");
LinphoneManager.getInstance().enableSpeaker(true);
LinphoneManager.getInstance().setHandsetMode(false);
LinphoneManager.getAudioManager().routeAudioToSpeaker();
}
}
}

View file

@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.core.Core;
/** Pause current SIP calls when GSM phone rings or is active. */
@ -32,14 +33,14 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
final String extraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (!LinphoneManager.isInstanciated()) return;
if (!LinphoneService.isReady()) return;
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(extraState)
|| TelephonyManager.EXTRA_STATE_RINGING.equals(extraState)) {
LinphoneManager.getInstance().setCallGsmON(true);
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.pauseAllCalls();
Core core = LinphoneManager.getCore();
if (core != null) {
core.pauseAllCalls();
}
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(extraState)) {
LinphoneManager.getInstance().setCallGsmON(false);

View file

@ -71,7 +71,7 @@ class Recording implements PlayerListener, Comparable<Recording> {
}
};
mPlayer = LinphoneManager.getLc().createLocalPlayer(null, null, null);
mPlayer = LinphoneManager.getCore().createLocalPlayer(null, null, null);
mPlayer.addListener(this);
}

View file

@ -1,8 +1,8 @@
package org.linphone.recording;
/*
RecordingsFragment.java
Copyright (C) 2018 Belledonne Communications, Grenoble, France
RecordingsActivity.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
@ -19,14 +19,13 @@ 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.Fragment;
import android.content.Context;
import android.Manifest;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -35,63 +34,135 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.activities.MainActivity;
import org.linphone.utils.FileUtils;
import org.linphone.utils.SelectableHelper;
public class RecordingsFragment extends Fragment
implements AdapterView.OnItemClickListener,
RecordingViewHolder.ClickListener,
SelectableHelper.DeleteListener {
public class RecordingsActivity extends MainActivity
implements SelectableHelper.DeleteListener, RecordingViewHolder.ClickListener {
private RecyclerView mRecordingList;
private List<Recording> mRecordings;
private TextView mNoRecordings;
private RecordingsAdapter mRecordingsAdapter;
private LinearLayoutManager mLayoutManager;
private Context mContext;
private SelectableHelper mSelectableHelper;
private ImageView mBackButton;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recordings_list, container, false);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOnBackPressGoHome = false;
mContext = getActivity().getApplicationContext();
mSelectableHelper = new SelectableHelper(view, this);
// Uses the fragment container layout to inflate the about view instead of using a fragment
View recordingsView =
LayoutInflater.from(this).inflate(R.layout.recordings_list, null, false);
LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
fragmentContainer.addView(recordingsView, params);
mRecordingList = view.findViewById(R.id.recording_list);
mNoRecordings = view.findViewById(R.id.no_recordings);
if (isTablet()) {
findViewById(R.id.fragmentContainer2).setVisibility(View.GONE);
}
mBackButton = view.findViewById(R.id.back);
if (getResources().getBoolean(R.bool.isTablet)) {
mBackButton.setVisibility(View.INVISIBLE);
} else {
mBackButton.setOnClickListener(
ImageView backButton = findViewById(R.id.back);
backButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
LinphoneActivity.instance().popBackStack();
public void onClick(View v) {
goBack();
}
});
}
mLayoutManager = new LinearLayoutManager(mContext);
mSelectableHelper = new SelectableHelper(findViewById(R.id.root_layout), this);
mRecordingList = findViewById(R.id.recording_list);
mNoRecordings = findViewById(R.id.no_recordings);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
mRecordingList.setLayoutManager(mLayoutManager);
// Divider between items
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(
mRecordingList.getContext(), mLayoutManager.getOrientation());
dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider));
new DividerItemDecoration(this, mLayoutManager.getOrientation());
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider));
mRecordingList.addItemDecoration(dividerItemDecoration);
mRecordings = new ArrayList<>();
return view;
mPermissionsToHave =
new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE,
};
}
@Override
protected void onResume() {
super.onResume();
hideTopBar();
hideTabBar();
LinphoneManager.getAudioManager().setAudioManagerModeNormal();
LinphoneManager.getAudioManager().routeAudioToSpeaker();
removeDeletedRecordings();
searchForRecordings();
hideRecordingListAndDisplayMessageIfEmpty();
mRecordingsAdapter = new RecordingsAdapter(this, mRecordings, this, mSelectableHelper);
mRecordingList.setAdapter(mRecordingsAdapter);
mSelectableHelper.setAdapter(mRecordingsAdapter);
mSelectableHelper.setDialogMessage(R.string.recordings_delete_dialog);
}
@Override
protected void onPause() {
super.onPause();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
// Close all opened mRecordings
for (Recording r : mRecordings) {
if (!r.isClosed()) {
if (r.isPlaying()) r.pause();
r.close();
}
}
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
int size = mRecordingsAdapter.getSelectedItemCount();
for (int i = 0; i < size; i++) {
Recording record = (Recording) objectsToDelete[i];
if (record.isPlaying()) record.pause();
record.close();
File recordingFile = new File(record.getRecordPath());
if (recordingFile.delete()) {
mRecordings.remove(record);
}
}
hideRecordingListAndDisplayMessageIfEmpty();
}
@Override
public void onItemClicked(int position) {
if (mRecordingsAdapter.isEditionEnabled()) {
mRecordingsAdapter.toggleSelection(position);
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mRecordingsAdapter.isEditionEnabled()) {
mSelectableHelper.enterEditionMode();
}
mRecordingsAdapter.toggleSelection(position);
return true;
}
private void hideRecordingListAndDisplayMessageIfEmpty() {
@ -105,7 +176,7 @@ public class RecordingsFragment extends Fragment
}
private void removeDeletedRecordings() {
String recordingsDirectory = FileUtils.getRecordingsDirectory(mContext);
String recordingsDirectory = FileUtils.getRecordingsDirectory(this);
File directory = new File(recordingsDirectory);
if (directory.exists() && directory.isDirectory()) {
@ -129,11 +200,12 @@ public class RecordingsFragment extends Fragment
}
private void searchForRecordings() {
String recordingsDirectory = FileUtils.getRecordingsDirectory(mContext);
String recordingsDirectory = FileUtils.getRecordingsDirectory(this);
File directory = new File(recordingsDirectory);
if (directory.exists() && directory.isDirectory()) {
File[] existingRecordings = directory.listFiles();
if (existingRecordings == null) return;
for (File f : existingRecordings) {
boolean exists = false;
@ -146,7 +218,7 @@ public class RecordingsFragment extends Fragment
if (!exists) {
if (Recording.RECORD_PATTERN.matcher(f.getPath()).matches()) {
mRecordings.add(new Recording(mContext, f.getPath()));
mRecordings.add(new Recording(this, f.getPath()));
}
}
}
@ -154,97 +226,4 @@ public class RecordingsFragment extends Fragment
Collections.sort(mRecordings);
}
}
@Override
public void onResume() {
super.onResume();
// This is necessary, without it you won't be able to remove mRecordings as you won't be
// allowed to.
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
LinphoneManager.getInstance().setAudioManagerModeNormal();
LinphoneManager.getInstance().routeAudioToSpeaker();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.RECORDING_LIST);
}
removeDeletedRecordings();
searchForRecordings();
hideRecordingListAndDisplayMessageIfEmpty();
mRecordingsAdapter =
new RecordingsAdapter(
getActivity().getApplicationContext(),
mRecordings,
this,
mSelectableHelper);
mRecordingList.setAdapter(mRecordingsAdapter);
mSelectableHelper.setAdapter(mRecordingsAdapter);
mSelectableHelper.setDialogMessage(R.string.recordings_delete_dialog);
}
@Override
public void onPause() {
super.onPause();
LinphoneManager.getInstance().routeAudioToReceiver();
// Close all opened mRecordings
for (Recording r : mRecordings) {
if (!r.isClosed()) {
if (r.isPlaying()) r.pause();
r.close();
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mRecordingsAdapter.isEditionEnabled()) {
Recording record = mRecordings.get(position);
if (record.isPlaying()) record.pause();
record.close();
File recordingFile = new File(record.getRecordPath());
if (recordingFile.delete()) {
mRecordings.remove(record);
}
}
}
@Override
public void onItemClicked(int position) {
if (mRecordingsAdapter.isEditionEnabled()) {
mRecordingsAdapter.toggleSelection(position);
}
}
@Override
public boolean onItemLongClicked(int position) {
if (!mRecordingsAdapter.isEditionEnabled()) {
mSelectableHelper.enterEditionMode();
}
mRecordingsAdapter.toggleSelection(position);
return true;
}
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
int size = mRecordingsAdapter.getSelectedItemCount();
for (int i = 0; i < size; i++) {
Recording record = (Recording) objectsToDelete[i];
if (record.isPlaying()) record.pause();
record.close();
File recordingFile = new File(record.getRecordPath());
if (recordingFile.delete()) {
mRecordings.remove(record);
}
}
hideRecordingListAndDisplayMessageIfEmpty();
}
}

View file

@ -19,7 +19,6 @@ 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.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.text.InputType;
@ -29,7 +28,6 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.assistant.PhoneAccountLinkingAssistantActivity;
@ -42,7 +40,6 @@ import org.linphone.core.NatPolicy;
import org.linphone.core.ProxyConfig;
import org.linphone.core.TransportType;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.widget.BasicSetting;
import org.linphone.settings.widget.ListSetting;
import org.linphone.settings.widget.SettingListenerBase;
@ -50,9 +47,8 @@ import org.linphone.settings.widget.SwitchSetting;
import org.linphone.settings.widget.TextSetting;
import org.linphone.utils.PushNotificationUtils;
public class AccountSettingsFragment extends Fragment {
protected View mRootView;
protected LinphonePreferences mPrefs;
public class AccountSettingsFragment extends SettingsFragment {
private View mRootView;
private int mAccountIndex;
private ProxyConfig mProxyConfig;
private AuthInfo mAuthInfo;
@ -93,7 +89,7 @@ public class AccountSettingsFragment extends Fragment {
}
mProxyConfig = null;
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (mAccountIndex >= 0 && core != null) {
ProxyConfig[] proxyConfigs = core.getProxyConfigList();
if (proxyConfigs.length > mAccountIndex) {
@ -117,14 +113,6 @@ public class AccountSettingsFragment extends Fragment {
public void onResume() {
super.onResume();
mPrefs = LinphonePreferences.instance();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.selectMenu(
FragmentsAvailable.SETTINGS_SUBLEVEL,
getString(R.string.pref_sipaccount));
}
updateValues();
}
@ -132,7 +120,7 @@ public class AccountSettingsFragment extends Fragment {
public void onPause() {
super.onPause();
if (mIsNewlyCreatedAccount) {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null && mProxyConfig != null && mAuthInfo != null) {
core.addAuthInfo(mAuthInfo);
core.addProxyConfig(mProxyConfig);
@ -143,7 +131,7 @@ public class AccountSettingsFragment extends Fragment {
}
}
protected void loadSettings() {
private void loadSettings() {
mUsername = mRootView.findViewById(R.id.pref_username);
mUserId = mRootView.findViewById(R.id.pref_auth_userid);
@ -188,7 +176,7 @@ public class AccountSettingsFragment extends Fragment {
PushNotificationUtils.isAvailable(getActivity()) ? View.VISIBLE : View.GONE);
mChangePassword = mRootView.findViewById(R.id.pref_change_password);
mChangePassword.setVisibility(View.GONE); // TODO
mChangePassword.setVisibility(View.GONE); // TODO add feature
mDeleteAccount = mRootView.findViewById(R.id.pref_delete_account);
@ -198,7 +186,7 @@ public class AccountSettingsFragment extends Fragment {
initTransportList();
}
protected void setListeners() {
private void setListeners() {
mUsername.setListener(
new SettingListenerBase() {
@Override
@ -234,7 +222,7 @@ public class AccountSettingsFragment extends Fragment {
if (mAuthInfo != null) {
mAuthInfo.setUserid(newValue);
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
core.refreshRegisters();
}
@ -251,8 +239,7 @@ public class AccountSettingsFragment extends Fragment {
if (mAuthInfo != null) {
mAuthInfo.setHa1(null);
mAuthInfo.setPassword(newValue);
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
core.addAuthInfo(mAuthInfo);
core.refreshRegisters();
@ -338,7 +325,7 @@ public class AccountSettingsFragment extends Fragment {
mProxyConfig.edit();
NatPolicy natPolicy = mProxyConfig.getNatPolicy();
if (natPolicy == null) {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
natPolicy = core.createNatPolicy();
mProxyConfig.setNatPolicy(natPolicy);
@ -427,12 +414,13 @@ public class AccountSettingsFragment extends Fragment {
@Override
public void onBoolValueChanged(boolean newValue) {
if (mProxyConfig != null) {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null && newValue) {
core.setDefaultProxyConfig(mProxyConfig);
mUseAsDefault.setEnabled(false);
}
LinphoneActivity.instance().refreshAccounts();
// FIXME TODO
// LinphoneActivity.instance().refreshAccounts();
} else {
Log.e("[Account Settings] No proxy config !");
}
@ -466,7 +454,7 @@ public class AccountSettingsFragment extends Fragment {
NatPolicy natPolicy = mProxyConfig.getNatPolicy();
if (natPolicy == null) {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
natPolicy = core.createNatPolicy();
mProxyConfig.setNatPolicy(natPolicy);
@ -531,7 +519,7 @@ public class AccountSettingsFragment extends Fragment {
new SettingListenerBase() {
@Override
public void onClicked() {
// TODO
// TODO add feature
}
});
@ -539,7 +527,7 @@ public class AccountSettingsFragment extends Fragment {
new SettingListenerBase() {
@Override
public void onClicked() {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
if (mProxyConfig != null) {
core.removeProxyConfig(mProxyConfig);
@ -548,8 +536,9 @@ public class AccountSettingsFragment extends Fragment {
core.removeAuthInfo(mAuthInfo);
}
}
LinphoneActivity.instance().displaySettings();
LinphoneActivity.instance().refreshAccounts();
// FIXME TODO
/*LinphoneActivity.instance().displaySettings();
LinphoneActivity.instance().refreshAccounts();*/
}
});
@ -559,8 +548,7 @@ public class AccountSettingsFragment extends Fragment {
public void onClicked() {
Intent assistant = new Intent();
assistant.setClass(
LinphoneActivity.instance(),
PhoneAccountLinkingAssistantActivity.class);
getActivity(), PhoneAccountLinkingAssistantActivity.class);
assistant.putExtra("AccountNumber", mAccountIndex);
startActivity(assistant);
}
@ -596,8 +584,8 @@ public class AccountSettingsFragment extends Fragment {
});
}
protected void updateValues() {
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
private void updateValues() {
Core core = LinphoneManager.getCore();
if (core == null) return;
// Create a proxy config if there is none
@ -645,8 +633,7 @@ public class AccountSettingsFragment extends Fragment {
mDisable.setChecked(!mProxyConfig.registerEnabled());
mUseAsDefault.setChecked(
core != null && mProxyConfig.equals(core.getDefaultProxyConfig()));
mUseAsDefault.setChecked(mProxyConfig.equals(core.getDefaultProxyConfig()));
mUseAsDefault.setEnabled(!mUseAsDefault.isChecked());
mOutboundProxy.setChecked(mProxyConfig.getRoute() != null);

View file

@ -19,7 +19,6 @@ 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.Fragment;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@ -31,18 +30,16 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.widget.BasicSetting;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.settings.widget.SwitchSetting;
import org.linphone.settings.widget.TextSetting;
public class AdvancedSettingsFragment extends Fragment {
protected View mRootView;
protected LinphonePreferences mPrefs;
public class AdvancedSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private SwitchSetting mDebug,
mJavaLogger,
@ -69,17 +66,11 @@ public class AdvancedSettingsFragment extends Fragment {
super.onResume();
mPrefs = LinphonePreferences.instance();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.selectMenu(
FragmentsAvailable.SETTINGS_SUBLEVEL,
getString(R.string.pref_advanced_title));
}
updateValues();
}
protected void loadSettings() {
private void loadSettings() {
mDebug = mRootView.findViewById(R.id.pref_debug);
mJavaLogger = mRootView.findViewById(R.id.pref_java_debug);
@ -108,7 +99,7 @@ public class AdvancedSettingsFragment extends Fragment {
mDeviceName = mRootView.findViewById(R.id.pref_device_name);
}
protected void setListeners() {
private void setListeners() {
mDebug.setListener(
new SettingListenerBase() {
@Override
@ -159,6 +150,7 @@ public class AdvancedSettingsFragment extends Fragment {
@Override
public void onBoolValueChanged(boolean newValue) {
mPrefs.enableDarkMode(newValue);
getActivity().recreate();
}
});
@ -190,7 +182,7 @@ public class AdvancedSettingsFragment extends Fragment {
new SettingListenerBase() {
@Override
public void onClicked() {
Context context = LinphoneActivity.instance();
Context context = getActivity();
Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
@ -198,7 +190,10 @@ public class AdvancedSettingsFragment extends Fragment {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityForResult(i, LinphoneActivity.ANDROID_APP_SETTINGS_ACTIVITY);
// FIXME TODO
// startActivityForResult(i,
// LinphoneActivity.ANDROID_APP_SETTINGS_ACTIVITY);
startActivity(i);
}
});
@ -211,7 +206,7 @@ public class AdvancedSettingsFragment extends Fragment {
});
}
protected void updateValues() {
private void updateValues() {
mDebug.setChecked(mPrefs.isDebugEnabled());
mJavaLogger.setChecked(mPrefs.useJavaLogger());
@ -230,7 +225,7 @@ public class AdvancedSettingsFragment extends Fragment {
mUsername.setValue(mPrefs.getDefaultUsername());
mDeviceName.setValue(mPrefs.getDeviceName(LinphoneActivity.instance()));
mDeviceName.setValue(mPrefs.getDeviceName(getActivity()));
setListeners();
}

View file

@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.Manifest;
import android.app.Fragment;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
@ -31,23 +30,21 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.EcCalibratorStatus;
import org.linphone.core.PayloadType;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.widget.BasicSetting;
import org.linphone.settings.widget.ListSetting;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.settings.widget.SwitchSetting;
import org.linphone.settings.widget.TextSetting;
public class AudioSettingsFragment extends Fragment {
protected View mRootView;
protected LinphonePreferences mPrefs;
public class AudioSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private SwitchSetting mEchoCanceller, mAdaptiveRateControl;
private TextSetting mMicGain, mSpeakerGain;
@ -71,17 +68,11 @@ public class AudioSettingsFragment extends Fragment {
super.onResume();
mPrefs = LinphonePreferences.instance();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.selectMenu(
FragmentsAvailable.SETTINGS_SUBLEVEL,
getString(R.string.pref_audio_title));
}
updateValues();
}
protected void loadSettings() {
private void loadSettings() {
mEchoCanceller = mRootView.findViewById(R.id.pref_echo_cancellation);
mAdaptiveRateControl = mRootView.findViewById(R.id.pref_adaptive_rate_control);
@ -101,7 +92,7 @@ public class AudioSettingsFragment extends Fragment {
mAudioCodecs = mRootView.findViewById(R.id.pref_audio_codecs);
}
protected void setListeners() {
private void setListeners() {
mEchoCanceller.setListener(
new SettingListenerBase() {
@Override
@ -141,7 +132,7 @@ public class AudioSettingsFragment extends Fragment {
int bitrate = Integer.valueOf(newValue);
mPrefs.setCodecBitrateLimit(bitrate);
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
for (final PayloadType pt : core.getAudioPayloadTypes()) {
if (pt.isVbr()) {
pt.setNormalBitrate(bitrate);
@ -165,8 +156,9 @@ public class AudioSettingsFragment extends Fragment {
if (recordAudio == PackageManager.PERMISSION_GRANTED) {
startEchoCancellerCalibration();
} else {
LinphoneActivity.instance()
.checkAndRequestRecordAudioPermissionForEchoCanceller();
((SettingsActivity) getActivity())
.requestPermissionIfNotGranted(
Manifest.permission.RECORD_AUDIO);
}
}
});
@ -182,20 +174,21 @@ public class AudioSettingsFragment extends Fragment {
Manifest.permission.RECORD_AUDIO,
getActivity().getPackageName());
if (recordAudio == PackageManager.PERMISSION_GRANTED) {
if (LinphoneManager.getInstance().getEchoTesterStatus()) {
if (LinphoneManager.getAudioManager().getEchoTesterStatus()) {
stopEchoTester();
} else {
startEchoTester();
}
} else {
LinphoneActivity.instance()
.checkAndRequestRecordAudioPermissionsForEchoTester();
((SettingsActivity) getActivity())
.requestPermissionIfNotGranted(
Manifest.permission.RECORD_AUDIO);
}
}
});
}
protected void updateValues() {
private void updateValues() {
mEchoCanceller.setChecked(mPrefs.echoCancellationEnabled());
mAdaptiveRateControl.setChecked(mPrefs.adaptiveRateControlEnabled());
@ -220,7 +213,7 @@ public class AudioSettingsFragment extends Fragment {
private void populateAudioCodecs() {
mAudioCodecs.removeAllViews();
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null) {
for (final PayloadType pt : core.getAudioPayloadTypes()) {
final SwitchSetting codec = new SwitchSetting(getActivity());
@ -248,21 +241,19 @@ public class AudioSettingsFragment extends Fragment {
}
}
public void startEchoTester() {
if (LinphoneManager.getInstance().startEchoTester() > 0) {
private void startEchoTester() {
LinphoneManager.getAudioManager().startEchoTester();
mEchoTester.setSubtitle("Is running");
}
}
private void stopEchoTester() {
if (LinphoneManager.getInstance().stopEchoTester() > 0) {
LinphoneManager.getAudioManager().stopEchoTester();
mEchoTester.setSubtitle("Is stopped");
}
}
public void startEchoCancellerCalibration() {
if (LinphoneManager.getInstance().getEchoTesterStatus()) stopEchoTester();
LinphoneManager.getLc()
private void startEchoCancellerCalibration() {
if (LinphoneManager.getAudioManager().getEchoTesterStatus()) stopEchoTester();
LinphoneManager.getCore()
.addListener(
new CoreListenerStub() {
@Override
@ -270,7 +261,7 @@ public class AudioSettingsFragment extends Fragment {
Core core, EcCalibratorStatus status, int delayMs) {
if (status == EcCalibratorStatus.InProgress) return;
core.removeListener(this);
LinphoneManager.getInstance().routeAudioToReceiver();
LinphoneManager.getAudioManager().routeAudioToEarPiece();
if (status == EcCalibratorStatus.DoneNoEcho) {
mEchoCalibration.setSubtitle(getString(R.string.no_echo));
@ -289,6 +280,6 @@ public class AudioSettingsFragment extends Fragment {
.setMode(AudioManager.MODE_NORMAL);
}
});
LinphoneManager.getInstance().startEcCalibration();
LinphoneManager.getAudioManager().startEcCalibration();
}
}

View file

@ -19,7 +19,8 @@ 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.Fragment;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.InputType;
import android.view.LayoutInflater;
@ -28,21 +29,19 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.MediaEncryption;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.settings.widget.ListSetting;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.settings.widget.SwitchSetting;
import org.linphone.settings.widget.TextSetting;
public class CallSettingsFragment extends Fragment {
protected View mRootView;
protected LinphonePreferences mPrefs;
public class CallSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private SwitchSetting mDeviceRingtone,
mVibrateIncomingCall,
@ -68,17 +67,11 @@ public class CallSettingsFragment extends Fragment {
super.onResume();
mPrefs = LinphonePreferences.instance();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.selectMenu(
FragmentsAvailable.SETTINGS_SUBLEVEL,
getString(R.string.pref_call_title));
}
updateValues();
}
protected void loadSettings() {
private void loadSettings() {
mDeviceRingtone = mRootView.findViewById(R.id.pref_device_ringtone);
mVibrateIncomingCall = mRootView.findViewById(R.id.pref_vibrate_on_incoming_calls);
@ -102,12 +95,24 @@ public class CallSettingsFragment extends Fragment {
mAutoAnswerTime.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
}
protected void setListeners() {
private void setListeners() {
mDeviceRingtone.setListener(
new SettingListenerBase() {
@Override
public void onBoolValueChanged(boolean newValue) {
int readExternalStorage =
getActivity()
.getPackageManager()
.checkPermission(
Manifest.permission.READ_EXTERNAL_STORAGE,
getActivity().getPackageName());
if (readExternalStorage == PackageManager.PERMISSION_GRANTED) {
mPrefs.enableDeviceRingtone(newValue);
} else {
((SettingsActivity) getActivity())
.requestPermissionIfNotGranted(
Manifest.permission.READ_EXTERNAL_STORAGE);
}
}
});
@ -193,7 +198,7 @@ public class CallSettingsFragment extends Fragment {
});
}
protected void updateValues() {
private void updateValues() {
mDeviceRingtone.setChecked(mPrefs.isDeviceRingtoneEnabled());
mVibrateIncomingCall.setChecked(mPrefs.isIncomingCallVibrationEnabled());
@ -223,7 +228,7 @@ public class CallSettingsFragment extends Fragment {
entries.add(getString(R.string.pref_none));
values.add(String.valueOf(MediaEncryption.None.toInt()));
Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
Core core = LinphoneManager.getCore();
if (core != null
&& !getResources().getBoolean(R.bool.disable_all_security_features_for_markets)) {
boolean hasZrtp = core.mediaEncryptionSupported(MediaEncryption.ZRTP);

View file

@ -19,7 +19,6 @@ 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.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
@ -30,19 +29,17 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import org.linphone.LinphoneActivity;
import org.linphone.R;
import org.linphone.core.tools.Log;
import org.linphone.fragments.FragmentsAvailable;
import org.linphone.mediastream.Version;
import org.linphone.settings.widget.BasicSetting;
import org.linphone.settings.widget.ListSetting;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.settings.widget.TextSetting;
public class ChatSettingsFragment extends Fragment {
protected View mRootView;
protected LinphonePreferences mPrefs;
public class ChatSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private TextSetting mSharingServer, mMaxSizeForAutoDownloadIncomingFiles;
private BasicSetting mAndroidNotificationSettings;
@ -64,17 +61,11 @@ public class ChatSettingsFragment extends Fragment {
super.onResume();
mPrefs = LinphonePreferences.instance();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance()
.selectMenu(
FragmentsAvailable.SETTINGS_SUBLEVEL,
getString(R.string.pref_chat_title));
}
updateValues();
}
protected void loadSettings() {
private void loadSettings() {
mSharingServer = mRootView.findViewById(R.id.pref_image_sharing_server);
mSharingServer.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
@ -86,7 +77,7 @@ public class ChatSettingsFragment extends Fragment {
mAndroidNotificationSettings = mRootView.findViewById(R.id.pref_android_app_notif_settings);
}
protected void setListeners() {
private void setListeners() {
mSharingServer.setListener(
new SettingListenerBase() {
@Override
@ -126,7 +117,7 @@ public class ChatSettingsFragment extends Fragment {
@Override
public void onClicked() {
if (Build.VERSION.SDK_INT >= Version.API26_O_80) {
Context context = LinphoneActivity.instance();
Context context = getActivity();
Intent i = new Intent();
i.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
i.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
@ -143,7 +134,7 @@ public class ChatSettingsFragment extends Fragment {
});
}
protected void updateValues() {
private void updateValues() {
mSharingServer.setValue(mPrefs.getSharingPictureServerUrl());
updateAutoDownloadSettingsFromValue(mPrefs.getAutoDownloadFileMaxSize());

View file

@ -29,8 +29,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.Address;
@ -67,32 +67,37 @@ public class LinphonePreferences {
return sInstance;
}
public void destroy() {
mContext = null;
sInstance = null;
}
public void setContext(Context c) {
mContext = c;
mBasePath = mContext.getFilesDir().getAbsolutePath();
}
private String getString(int key) {
if (mContext == null && LinphoneManager.isInstanciated()) {
mContext = LinphoneManager.getInstance().getContext();
if (mContext == null && LinphoneService.isReady()) {
mContext = LinphoneService.instance();
}
return mContext.getString(key);
}
private Core getLc() {
if (!LinphoneManager.isInstanciated()) return null;
if (!LinphoneService.isReady()) return null;
return LinphoneManager.getLcIfManagerNotDestroyedOrNull();
return LinphoneManager.getCore();
}
public Config getConfig() {
Core lc = getLc();
if (lc != null) {
return lc.getConfig();
Core core = getLc();
if (core != null) {
return core.getConfig();
}
if (!LinphoneManager.isInstanciated()) {
if (!LinphoneService.isReady()) {
File linphonerc = new File(mBasePath + "/.linphonerc");
if (linphonerc.exists()) {
return Factory.instance().createConfig(linphonerc.getAbsolutePath());
@ -114,7 +119,7 @@ public class LinphonePreferences {
return Factory.instance().createConfigFromString(text.toString());
}
} else {
return Factory.instance().createConfig(LinphoneManager.getInstance().configFile);
return Factory.instance().createConfig(LinphoneManager.getInstance().getConfigFile());
}
return null;
}
@ -225,7 +230,7 @@ public class LinphonePreferences {
}
}
public boolean isAccountEnabled(int n) {
private boolean isAccountEnabled(int n) {
return getProxyConfig(n).registerEnabled();
}
// End of accounts settings
@ -575,8 +580,8 @@ public class LinphonePreferences {
public void setPushNotificationEnabled(boolean enable) {
getConfig().setBool("app", "push_notification", enable);
Core lc = getLc();
if (lc == null) {
Core core = getLc();
if (core == null) {
return;
}
@ -584,8 +589,8 @@ public class LinphonePreferences {
// Add push infos to exisiting proxy configs
String regId = getPushNotificationRegistrationID();
String appId = getString(R.string.gcm_defaultSenderId);
if (regId != null && lc.getProxyConfigList().length > 0) {
for (ProxyConfig lpc : lc.getProxyConfigList()) {
if (regId != null && core.getProxyConfigList().length > 0) {
for (ProxyConfig lpc : core.getProxyConfigList()) {
if (lpc == null) continue;
if (!lpc.isPushNotificationAllowed()) {
lpc.edit();
@ -621,11 +626,11 @@ public class LinphonePreferences {
Log.i(
"[Push Notification] Refreshing registers to ensure token is up to date: "
+ regId);
lc.refreshRegisters();
core.refreshRegisters();
}
} else {
if (lc.getProxyConfigList().length > 0) {
for (ProxyConfig lpc : lc.getProxyConfigList()) {
if (core.getProxyConfigList().length > 0) {
for (ProxyConfig lpc : core.getProxyConfigList()) {
lpc.edit();
lpc.setContactUriParameters(null);
lpc.done();
@ -634,7 +639,7 @@ public class LinphonePreferences {
"[Push Notification] infos removed from proxy config "
+ lpc.getIdentityAddress().asStringUriOnly());
}
lc.refreshRegisters();
core.refreshRegisters();
}
}
}
@ -742,7 +747,7 @@ public class LinphonePreferences {
if (getLc().tunnelAvailable()) {
Tunnel tunnel = getLc().getTunnel();
if (mTunnelConfig == null) {
TunnelConfig servers[] = tunnel.getServers();
TunnelConfig[] servers = tunnel.getServers();
if (servers.length > 0) {
mTunnelConfig = servers[0];
} else {
@ -800,10 +805,6 @@ public class LinphonePreferences {
// End of tunnel settings
public boolean isFirstRemoteProvisioning() {
return getConfig().getBool("app", "first_remote_provisioning", true);
}
public boolean adaptiveRateControlEnabled() {
if (getLc() == null) return false;
return getLc().adaptiveRateControlEnabled();
@ -935,13 +936,7 @@ public class LinphonePreferences {
}
public void enableOverlay(boolean enable) {
getConfig()
.setBool(
"app",
"display_overlay",
enable
&& LinphoneActivity.isInstanciated()
&& LinphoneActivity.instance().checkAndRequestOverlayPermission());
getConfig().setBool("app", "display_overlay", enable);
}
public boolean isDeviceRingtoneEnabled() {
@ -1025,9 +1020,6 @@ public class LinphonePreferences {
public void enableDarkMode(boolean enable) {
getConfig().setBool("app", "dark_mode", enable);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().recreate();
}
}
public String getDeviceName(Context context) {

View file

@ -0,0 +1,223 @@
package org.linphone.settings;
/*
MenuSettingsFragment.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.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.Core;
import org.linphone.core.ProxyConfig;
import org.linphone.settings.widget.BasicSetting;
import org.linphone.settings.widget.LedSetting;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.utils.LinphoneUtils;
public class MenuSettingsFragment extends SettingsFragment {
private View mRootView;
private BasicSetting mTunnel, mAudio, mVideo, mCall, mChat, mNetwork, mAdvanced;
private LinearLayout mAccounts;
private TextView mAccountsHeader;
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.settings, container, false);
loadSettings();
setListeners();
return mRootView;
}
@Override
public void onResume() {
super.onResume();
updateValues();
}
private void loadSettings() {
mAccounts = mRootView.findViewById(R.id.accounts_settings_list);
mAccountsHeader = mRootView.findViewById(R.id.accounts_settings_list_header);
mTunnel = mRootView.findViewById(R.id.pref_tunnel);
mAudio = mRootView.findViewById(R.id.pref_audio);
mVideo = mRootView.findViewById(R.id.pref_video);
mCall = mRootView.findViewById(R.id.pref_call);
mChat = mRootView.findViewById(R.id.pref_chat);
mNetwork = mRootView.findViewById(R.id.pref_network);
mAdvanced = mRootView.findViewById(R.id.pref_advanced);
}
private void setListeners() {
mTunnel.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new TunnelSettingsFragment(),
getString(R.string.pref_tunnel_title));
}
});
mAudio.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new AudioSettingsFragment(),
getString(R.string.pref_audio_title));
}
});
mVideo.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new VideoSettingsFragment(),
getString(R.string.pref_video_title));
}
});
mCall.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new CallSettingsFragment(),
getString(R.string.pref_call_title));
}
});
mChat.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new ChatSettingsFragment(),
getString(R.string.pref_chat_title));
}
});
mNetwork.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new NetworkSettingsFragment(),
getString(R.string.pref_network_title));
}
});
mAdvanced.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new AdvancedSettingsFragment(),
getString(R.string.pref_advanced_title));
}
});
}
private void updateValues() {
Core core = LinphoneManager.getCore();
if (core != null) {
mTunnel.setVisibility(core.tunnelAvailable() ? View.VISIBLE : View.GONE);
initAccounts(core);
}
if (getResources().getBoolean(R.bool.hide_accounts)) {
mAccounts.setVisibility(View.GONE);
mAccountsHeader.setVisibility(View.GONE);
}
}
private void initAccounts(Core core) {
mAccounts.removeAllViews();
ProxyConfig[] proxyConfigs = core.getProxyConfigList();
if (proxyConfigs == null || proxyConfigs.length == 0) {
mAccountsHeader.setVisibility(View.GONE);
} else {
mAccountsHeader.setVisibility(View.VISIBLE);
int i = 0;
for (ProxyConfig proxyConfig : proxyConfigs) {
final LedSetting account = new LedSetting(getActivity());
account.setTitle(
LinphoneUtils.getDisplayableAddress(proxyConfig.getIdentityAddress()));
if (proxyConfig.equals(core.getDefaultProxyConfig())) {
account.setSubtitle(getString(R.string.default_account_flag));
}
switch (proxyConfig.getState()) {
case Ok:
account.setColor(LedSetting.Color.GREEN);
break;
case Failed:
account.setColor(LedSetting.Color.RED);
break;
case Progress:
account.setColor(LedSetting.Color.ORANGE);
break;
case None:
case Cleared:
account.setColor(LedSetting.Color.GRAY);
break;
}
final int accountIndex = i;
account.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showAccountSettings(accountIndex, true);
}
});
mAccounts.addView(account);
i += 1;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more