Feature/reworked call code
This commit is contained in:
parent
81588d6906
commit
a1ee586a13
103 changed files with 3242 additions and 4341 deletions
|
@ -6,6 +6,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
|
<!-- Needed for bluetooth headset -->
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
@ -183,8 +184,9 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".call.CallActivity"
|
android:name=".call.CallActivity"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:noHistory="true"
|
android:showWhenLocked="true"
|
||||||
android:showWhenLocked="true"/>
|
android:resizeableActivity="true"
|
||||||
|
android:supportsPictureInPicture="true"/>
|
||||||
|
|
||||||
<!-- Assistant activities -->
|
<!-- Assistant activities -->
|
||||||
|
|
||||||
|
@ -252,10 +254,6 @@
|
||||||
|
|
||||||
<!-- Receivers -->
|
<!-- Receivers -->
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".receivers.BluetoothManager"
|
|
||||||
android:enabled="false"/>
|
|
||||||
|
|
||||||
<receiver android:name=".receivers.BootReceiver">
|
<receiver android:name=".receivers.BootReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
@ -265,12 +263,6 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".receivers.PhoneStateChangedReceiver">
|
|
||||||
<intent-filter android:priority="999">
|
|
||||||
<action android:name="android.intent.action.PHONE_STATE" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".notifications.NotificationBroadcastReceiver"
|
android:name=".notifications.NotificationBroadcastReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
|
|
|
@ -22,11 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
import android.hardware.SensorEvent;
|
||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
|
@ -37,6 +35,8 @@ import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
@ -73,8 +73,6 @@ import org.linphone.core.tools.H264Helper;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
||||||
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
|
||||||
import org.linphone.receivers.HookReceiver;
|
|
||||||
import org.linphone.receivers.OutgoingCallReceiver;
|
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
import org.linphone.utils.AndroidAudioManager;
|
import org.linphone.utils.AndroidAudioManager;
|
||||||
import org.linphone.utils.LinphoneUtils;
|
import org.linphone.utils.LinphoneUtils;
|
||||||
|
@ -98,8 +96,8 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
private CallManager mCallManager;
|
private CallManager mCallManager;
|
||||||
private final PowerManager mPowerManager;
|
private final PowerManager mPowerManager;
|
||||||
private final ConnectivityManager mConnectivityManager;
|
private final ConnectivityManager mConnectivityManager;
|
||||||
private BroadcastReceiver mHookReceiver;
|
private TelephonyManager mTelephonyManager;
|
||||||
private BroadcastReceiver mCallReceiver;
|
private PhoneStateListener mPhoneStateListener;
|
||||||
private WakeLock mProximityWakelock;
|
private WakeLock mProximityWakelock;
|
||||||
private final SensorManager mSensorManager;
|
private final SensorManager mSensorManager;
|
||||||
private final Sensor mProximity;
|
private final Sensor mProximity;
|
||||||
|
@ -138,6 +136,27 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
|
mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
|
||||||
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||||
|
mTelephonyManager = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
mPhoneStateListener =
|
||||||
|
new PhoneStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onCallStateChanged(int state, String phoneNumber) {
|
||||||
|
switch (state) {
|
||||||
|
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||||
|
Log.i("[Manager] Phone state is off hook");
|
||||||
|
setCallGsmON(true);
|
||||||
|
break;
|
||||||
|
case TelephonyManager.CALL_STATE_RINGING:
|
||||||
|
Log.i("[Manager] Phone state is ringing");
|
||||||
|
setCallGsmON(true);
|
||||||
|
break;
|
||||||
|
case TelephonyManager.CALL_STATE_IDLE:
|
||||||
|
Log.i("[Manager] Phone state is idle");
|
||||||
|
setCallGsmON(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
mHasLastCallSasBeenRejected = false;
|
mHasLastCallSasBeenRejected = false;
|
||||||
mCallManager = new CallManager(c);
|
mCallManager = new CallManager(c);
|
||||||
|
|
||||||
|
@ -194,8 +213,7 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
if (state == State.IncomingReceived
|
if (state == State.IncomingReceived
|
||||||
&& !call.equals(core.getCurrentCall())) {
|
&& !call.equals(core.getCurrentCall())) {
|
||||||
if (call.getReplacedCall() != null) {
|
if (call.getReplacedCall() != null) {
|
||||||
// attended transfer
|
// attended transfer will be accepted automatically.
|
||||||
// it will be accepted automatically.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,15 +240,16 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
};
|
};
|
||||||
mTimer = new Timer("Auto answer");
|
mTimer = new Timer("Auto answer");
|
||||||
mTimer.schedule(lTask, mPrefs.getAutoAnswerTime());
|
mTimer.schedule(lTask, mPrefs.getAutoAnswerTime());
|
||||||
}
|
} else if (state == State.End || state == State.Error) {
|
||||||
|
|
||||||
if (state == State.End || state == State.Error) {
|
|
||||||
if (mCore.getCallsNb() == 0) {
|
if (mCore.getCallsNb() == 0) {
|
||||||
// Disabling proximity sensor
|
// Disabling proximity sensor
|
||||||
enableProximitySensing(false);
|
enableProximitySensing(false);
|
||||||
|
|
||||||
|
Log.i("[Manager] Unregistering phone state listener");
|
||||||
|
mTelephonyManager.listen(
|
||||||
|
mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||||
}
|
}
|
||||||
}
|
} else if (state == State.UpdatedByRemote) {
|
||||||
if (state == State.UpdatedByRemote) {
|
|
||||||
// If the correspondent proposes video while audio call
|
// If the correspondent proposes video while audio call
|
||||||
boolean remoteVideo = call.getRemoteParams().videoEnabled();
|
boolean remoteVideo = call.getRemoteParams().videoEnabled();
|
||||||
boolean localVideo = call.getCurrentParams().videoEnabled();
|
boolean localVideo = call.getCurrentParams().videoEnabled();
|
||||||
|
@ -243,6 +262,12 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
&& mCore.getConference() == null) {
|
&& mCore.getConference() == null) {
|
||||||
call.deferUpdate();
|
call.deferUpdate();
|
||||||
}
|
}
|
||||||
|
} else if (state == State.Connected) {
|
||||||
|
if (core.getCallsNb() == 1) {
|
||||||
|
Log.i("[Manager] Registering phone state listener");
|
||||||
|
mTelephonyManager.listen(
|
||||||
|
mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,17 +439,6 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e("[Manager] Destroy Core Runtime Exception: " + e);
|
Log.e("[Manager] Destroy Core Runtime Exception: " + e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
|
||||||
mContext.unregisterReceiver(mHookReceiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("[Manager] unregister receiver exception: " + e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mContext.unregisterReceiver(mCallReceiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("[Manager] unregister receiver exception: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
mCore = null;
|
mCore = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,25 +543,11 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
PushNotificationUtils.init(mContext);
|
PushNotificationUtils.init(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
IntentFilter mCallIntentFilter =
|
|
||||||
new IntentFilter("android.intent.action.ACTION_NEW_OUTGOING_CALL");
|
|
||||||
mCallIntentFilter.setPriority(99999999);
|
|
||||||
mCallReceiver = new OutgoingCallReceiver();
|
|
||||||
try {
|
|
||||||
mContext.registerReceiver(mCallReceiver, mCallIntentFilter);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
mProximityWakelock =
|
mProximityWakelock =
|
||||||
mPowerManager.newWakeLock(
|
mPowerManager.newWakeLock(
|
||||||
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
||||||
mContext.getPackageName() + ";manager_proximity_sensor");
|
mContext.getPackageName() + ";manager_proximity_sensor");
|
||||||
|
|
||||||
IntentFilter mHookIntentFilter = new IntentFilter("com.base.module.phone.HOOKEVENT");
|
|
||||||
mHookIntentFilter.setPriority(999);
|
|
||||||
mHookReceiver = new HookReceiver();
|
|
||||||
mContext.registerReceiver(mHookReceiver, mHookIntentFilter);
|
|
||||||
|
|
||||||
resetCameraFromPreferences();
|
resetCameraFromPreferences();
|
||||||
|
|
||||||
mAccountCreator = mCore.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl());
|
mAccountCreator = mCore.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl());
|
||||||
|
@ -886,6 +886,9 @@ public class LinphoneManager implements SensorEventListener {
|
||||||
|
|
||||||
public void setCallGsmON(boolean on) {
|
public void setCallGsmON(boolean on) {
|
||||||
mCallGsmON = on;
|
mCallGsmON = on;
|
||||||
|
if (on) {
|
||||||
|
mCore.pauseAllCalls();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(int key) {
|
private String getString(int key) {
|
||||||
|
|
|
@ -45,7 +45,6 @@ import org.linphone.core.LoggingServiceListener;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.mediastream.Version;
|
import org.linphone.mediastream.Version;
|
||||||
import org.linphone.notifications.NotificationsManager;
|
import org.linphone.notifications.NotificationsManager;
|
||||||
import org.linphone.receivers.BluetoothManager;
|
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
import org.linphone.utils.ActivityMonitor;
|
import org.linphone.utils.ActivityMonitor;
|
||||||
import org.linphone.utils.DeviceOrientationEventListener;
|
import org.linphone.utils.DeviceOrientationEventListener;
|
||||||
|
@ -103,7 +102,6 @@ public final class LinphoneService extends Service {
|
||||||
private NotificationsManager mNotificationManager;
|
private NotificationsManager mNotificationManager;
|
||||||
private LinphoneManager mLinphoneManager;
|
private LinphoneManager mLinphoneManager;
|
||||||
private ContactsManager mContactsManager;
|
private ContactsManager mContactsManager;
|
||||||
private BluetoothManager mBluetoothManager;
|
|
||||||
private DeviceOrientationEventListener mOrientationHelper;
|
private DeviceOrientationEventListener mOrientationHelper;
|
||||||
|
|
||||||
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
|
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
|
||||||
|
@ -215,8 +213,6 @@ public final class LinphoneService extends Service {
|
||||||
ContactsContract.Contacts.CONTENT_URI, true, mContactsManager);
|
ContactsContract.Contacts.CONTENT_URI, true, mContactsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
mBluetoothManager = new BluetoothManager();
|
|
||||||
|
|
||||||
Compatibility.createChatShortcuts(this);
|
Compatibility.createChatShortcuts(this);
|
||||||
mOrientationHelper.enable();
|
mOrientationHelper.enable();
|
||||||
|
|
||||||
|
@ -268,7 +264,6 @@ public final class LinphoneService extends Service {
|
||||||
mNotificationManager.destroy();
|
mNotificationManager.destroy();
|
||||||
}
|
}
|
||||||
mContactsManager.destroy();
|
mContactsManager.destroy();
|
||||||
mBluetoothManager.destroy();
|
|
||||||
|
|
||||||
if (LinphonePreferences.instance().useJavaLogger()) {
|
if (LinphonePreferences.instance().useJavaLogger()) {
|
||||||
Factory.instance().getLoggingService().removeListener(mJavaLoggingService);
|
Factory.instance().getLoggingService().removeListener(mJavaLoggingService);
|
||||||
|
@ -311,10 +306,6 @@ public final class LinphoneService extends Service {
|
||||||
return mContactsManager;
|
return mContactsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BluetoothManager getBluetoothManager() {
|
|
||||||
return mBluetoothManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createOverlay() {
|
public void createOverlay() {
|
||||||
if (mOverlay != null) destroyOverlay();
|
if (mOverlay != null) destroyOverlay();
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@ public class AboutActivity extends MainActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mOnBackPressGoHome = false;
|
mOnBackPressGoHome = false;
|
||||||
mAlwaysHideTabBar = true;
|
mAlwaysHideTabBar = true;
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ public class DialerActivity extends MainActivity implements AddressText.AddressC
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Uses the fragment container layout to inflate the dialer view instead of using a fragment
|
// 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);
|
View dialerView = LayoutInflater.from(this).inflate(R.layout.dialer, null, false);
|
||||||
|
|
|
@ -22,14 +22,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import org.linphone.LinphoneService;
|
import org.linphone.LinphoneService;
|
||||||
|
|
||||||
public abstract class LinphoneGenericActivity extends ThemableActivity {
|
public abstract class LinphoneGenericActivity extends ThemeableActivity {
|
||||||
|
protected boolean mAbortCreation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
mAbortCreation = false;
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
// After a crash, Android restart the last Activity so we need to check
|
// After a crash, Android restart the last Activity so we need to check
|
||||||
// if all dependencies are loaded
|
// if all dependencies are loaded
|
||||||
if (!LinphoneService.isReady()) {
|
if (!LinphoneService.isReady()) {
|
||||||
startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class));
|
startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class));
|
||||||
|
mAbortCreation = true;
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ import org.linphone.core.ProxyConfig;
|
||||||
import org.linphone.core.RegistrationState;
|
import org.linphone.core.RegistrationState;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.fragments.EmptyFragment;
|
import org.linphone.fragments.EmptyFragment;
|
||||||
import org.linphone.fragments.StatusFragment;
|
import org.linphone.fragments.StatusBarFragment;
|
||||||
import org.linphone.history.HistoryActivity;
|
import org.linphone.history.HistoryActivity;
|
||||||
import org.linphone.menu.SideMenuFragment;
|
import org.linphone.menu.SideMenuFragment;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
@ -73,7 +73,7 @@ import org.linphone.utils.LinphoneUtils;
|
||||||
import org.linphone.utils.PushNotificationUtils;
|
import org.linphone.utils.PushNotificationUtils;
|
||||||
|
|
||||||
public abstract class MainActivity extends LinphoneGenericActivity
|
public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
implements StatusFragment.MenuClikedListener, SideMenuFragment.QuitClikedListener {
|
implements StatusBarFragment.MenuClikedListener, SideMenuFragment.QuitClikedListener {
|
||||||
private static final int MAIN_PERMISSIONS = 1;
|
private static final int MAIN_PERMISSIONS = 1;
|
||||||
private static final int FRAGMENT_SPECIFIC_PERMISSION = 2;
|
private static final int FRAGMENT_SPECIFIC_PERMISSION = 2;
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
private LinearLayout mTabBar;
|
private LinearLayout mTabBar;
|
||||||
|
|
||||||
private SideMenuFragment mSideMenuFragment;
|
private SideMenuFragment mSideMenuFragment;
|
||||||
private StatusFragment mStatusFragment;
|
private StatusBarFragment mStatusBarFragment;
|
||||||
|
|
||||||
protected boolean mOnBackPressGoHome;
|
protected boolean mOnBackPressGoHome;
|
||||||
protected boolean mAlwaysHideTabBar;
|
protected boolean mAlwaysHideTabBar;
|
||||||
|
@ -99,6 +99,9 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!LinphoneService.isReady()) {
|
if (!LinphoneService.isReady()) {
|
||||||
finish();
|
finish();
|
||||||
|
@ -171,8 +174,8 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mStatusFragment =
|
mStatusBarFragment =
|
||||||
(StatusFragment) getFragmentManager().findFragmentById(R.id.status_fragment);
|
(StatusBarFragment) getFragmentManager().findFragmentById(R.id.status_fragment);
|
||||||
|
|
||||||
DrawerLayout mSideMenu = findViewById(R.id.side_menu);
|
DrawerLayout mSideMenu = findViewById(R.id.side_menu);
|
||||||
RelativeLayout mSideMenuContent = findViewById(R.id.side_menu_content);
|
RelativeLayout mSideMenuContent = findViewById(R.id.side_menu_content);
|
||||||
|
@ -316,7 +319,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
mDialerSelected.setVisibility(View.GONE);
|
mDialerSelected.setVisibility(View.GONE);
|
||||||
mChatSelected.setVisibility(View.GONE);
|
mChatSelected.setVisibility(View.GONE);
|
||||||
|
|
||||||
mStatusFragment.setMenuListener(this);
|
mStatusBarFragment.setMenuListener(this);
|
||||||
mSideMenuFragment.setQuitListener(this);
|
mSideMenuFragment.setQuitListener(this);
|
||||||
mSideMenuFragment.displayAccountsInSideMenu();
|
mSideMenuFragment.displayAccountsInSideMenu();
|
||||||
|
|
||||||
|
@ -334,7 +337,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
mStatusFragment.setMenuListener(null);
|
mStatusBarFragment.setMenuListener(null);
|
||||||
mSideMenuFragment.setQuitListener(null);
|
mSideMenuFragment.setQuitListener(null);
|
||||||
|
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.linphone.activities;
|
package org.linphone.activities;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ThemableActivity.java
|
ThemeableActivity.java
|
||||||
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
@ -23,9 +23,10 @@ import android.content.pm.ActivityInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
|
||||||
public abstract class ThemableActivity extends AppCompatActivity {
|
public abstract class ThemeableActivity extends AppCompatActivity {
|
||||||
private int mTheme;
|
private int mTheme;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,16 +44,30 @@ public abstract class ThemableActivity extends AppCompatActivity {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
outState.putInt("Theme", mTheme);
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
mTheme = savedInstanceState.getInt("Theme");
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
if (LinphonePreferences.instance().isDarkModeEnabled()) {
|
if (LinphonePreferences.instance().isDarkModeEnabled()) {
|
||||||
if (mTheme != R.style.LinphoneStyleDark) {
|
if (mTheme != R.style.LinphoneStyleDark) {
|
||||||
|
Log.w("[Themeable Activity] Recreate Activity cause theme doesn't match");
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mTheme != R.style.LinphoneStyleLight) {
|
if (mTheme != R.style.LinphoneStyleLight) {
|
||||||
|
Log.w("[Themeable Activity] Recreate Activity cause theme doesn't match");
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,7 +30,7 @@ import android.widget.ImageView;
|
||||||
import org.linphone.LinphoneManager;
|
import org.linphone.LinphoneManager;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
import org.linphone.activities.DialerActivity;
|
import org.linphone.activities.DialerActivity;
|
||||||
import org.linphone.activities.ThemableActivity;
|
import org.linphone.activities.ThemeableActivity;
|
||||||
import org.linphone.core.AccountCreator;
|
import org.linphone.core.AccountCreator;
|
||||||
import org.linphone.core.Core;
|
import org.linphone.core.Core;
|
||||||
import org.linphone.core.DialPlan;
|
import org.linphone.core.DialPlan;
|
||||||
|
@ -39,7 +39,7 @@ import org.linphone.core.ProxyConfig;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
|
||||||
public abstract class AssistantActivity extends ThemableActivity
|
public abstract class AssistantActivity extends ThemeableActivity
|
||||||
implements CountryPicker.CountryPickedListener {
|
implements CountryPicker.CountryPickedListener {
|
||||||
static AccountCreator mAccountCreator;
|
static AccountCreator mAccountCreator;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class CountryAdapter extends BaseAdapter implements Filterable {
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
view = convertView;
|
view = convertView;
|
||||||
} else {
|
} else {
|
||||||
view = mInflater.inflate(R.layout.country_cell, parent, false);
|
view = mInflater.inflate(R.layout.assistant_country_cell, parent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DialPlan c = mFilteredCountries.get(position);
|
DialPlan c = mFilteredCountries.get(position);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,26 @@
|
||||||
|
package org.linphone.call;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CallActivityInterface.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 interface CallActivityInterface {
|
||||||
|
void refreshInCallActions();
|
||||||
|
|
||||||
|
void resetCallControlsHidingTimer();
|
||||||
|
}
|
|
@ -1,47 +0,0 @@
|
||||||
package org.linphone.call;
|
|
||||||
|
|
||||||
/*
|
|
||||||
CallAudioFragment.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.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import org.linphone.R;
|
|
||||||
|
|
||||||
public class CallAudioFragment extends Fragment {
|
|
||||||
@Override
|
|
||||||
public View onCreateView(
|
|
||||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
return inflater.inflate(R.layout.audio, container, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
CallActivity incallActvityInstance = (CallActivity) getActivity();
|
|
||||||
|
|
||||||
if (incallActvityInstance != null) {
|
|
||||||
incallActvityInstance.bindAudioFragment(this);
|
|
||||||
// Just to be sure we have incall controls
|
|
||||||
incallActvityInstance.removeCallbacks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -63,6 +63,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Compatibility.setShowWhenLocked(this, true);
|
Compatibility.setShowWhenLocked(this, true);
|
||||||
Compatibility.setTurnScreenOn(this, true);
|
Compatibility.setTurnScreenOn(this, true);
|
||||||
|
|
|
@ -44,8 +44,7 @@ import org.linphone.views.AddressType;
|
||||||
/** Handle call updating, reinvites. */
|
/** Handle call updating, reinvites. */
|
||||||
public class CallManager {
|
public class CallManager {
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private boolean mHandsetON = false;
|
private CallActivityInterface mCallInterface;
|
||||||
private CallActivity.CallActivityInterface mCallInterface;
|
|
||||||
private BandwidthManager mBandwidthManager;
|
private BandwidthManager mBandwidthManager;
|
||||||
|
|
||||||
public CallManager(Context context) {
|
public CallManager(Context context) {
|
||||||
|
@ -57,90 +56,113 @@ public class CallManager {
|
||||||
mBandwidthManager.destroy();
|
mBandwidthManager.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void inviteAddress(Address lAddress, boolean forceZRTP) {
|
public void terminateCurrentCallOrConferenceOrAll() {
|
||||||
boolean isLowBandwidthConnection =
|
|
||||||
!LinphoneUtils.isHighBandwidthConnection(
|
|
||||||
LinphoneService.instance().getApplicationContext());
|
|
||||||
|
|
||||||
inviteAddress(lAddress, false, isLowBandwidthConnection, forceZRTP);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inviteAddress(
|
|
||||||
Address lAddress, boolean videoEnabled, boolean lowBandwidth, boolean forceZRTP) {
|
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
|
Call call = core.getCurrentCall();
|
||||||
CallParams params = core.createCallParams(null);
|
if (call != null) {
|
||||||
mBandwidthManager.updateWithProfileSettings(params);
|
call.terminate();
|
||||||
|
} else if (core.isInConference()) {
|
||||||
if (videoEnabled && params.videoEnabled()) {
|
core.terminateConference();
|
||||||
params.enableVideo(true);
|
|
||||||
} else {
|
} else {
|
||||||
params.enableVideo(false);
|
core.terminateAllCalls();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowBandwidth) {
|
public void addVideo() {
|
||||||
params.enableLowBandwidth(true);
|
Call call = LinphoneManager.getCore().getCurrentCall();
|
||||||
Log.d("[Call Manager] Low bandwidth enabled in call params");
|
if (call.getState() == Call.State.End || call.getState() == Call.State.Released) return;
|
||||||
|
if (!call.getCurrentParams().videoEnabled()) {
|
||||||
|
enableCamera(call, true);
|
||||||
|
reinviteWithVideo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceZRTP) {
|
public void removeVideo() {
|
||||||
params.setMediaEncryption(MediaEncryption.ZRTP);
|
|
||||||
}
|
|
||||||
|
|
||||||
String recordFile =
|
|
||||||
FileUtils.getCallRecordingFilename(LinphoneService.instance(), lAddress);
|
|
||||||
params.setRecordFile(recordFile);
|
|
||||||
|
|
||||||
core.inviteAddressWithParams(lAddress, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void inviteAddress(Address lAddress, boolean videoEnabled, boolean lowBandwidth) {
|
|
||||||
inviteAddress(lAddress, videoEnabled, lowBandwidth, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add video to a currently running voice only call. No re-invite is sent if the current call is
|
|
||||||
* already video or if the bandwidth settings are too low.
|
|
||||||
*
|
|
||||||
* @return if updateCall called
|
|
||||||
*/
|
|
||||||
public boolean reinviteWithVideo() {
|
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
Call call = core.getCurrentCall();
|
Call call = core.getCurrentCall();
|
||||||
if (call == null) {
|
|
||||||
Log.e("[Call Manager] Trying to reinviteWithVideo while not in call: doing nothing");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
CallParams params = core.createCallParams(call);
|
CallParams params = core.createCallParams(call);
|
||||||
|
params.enableVideo(false);
|
||||||
if (params.videoEnabled()) return false;
|
|
||||||
|
|
||||||
// Check if video possible regarding bandwidth limitations
|
|
||||||
mBandwidthManager.updateWithProfileSettings(params);
|
|
||||||
|
|
||||||
// Abort if not enough bandwidth...
|
|
||||||
if (!params.videoEnabled()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not yet in video call: try to re-invite with video
|
|
||||||
call.update(params);
|
call.update(params);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void switchCamera() {
|
||||||
* Change the preferred video size used by linphone core. (impact landscape/portrait buffer).
|
|
||||||
* Update current call, without reinvite. The camera will be restarted when mediastreamer chain
|
|
||||||
* is recreated and setParameters is called.
|
|
||||||
*/
|
|
||||||
public void updateCall() {
|
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
|
try {
|
||||||
|
String currentDevice = core.getVideoDevice();
|
||||||
|
String[] devices = core.getVideoDevicesList();
|
||||||
|
int index = 0;
|
||||||
|
for (String d : devices) {
|
||||||
|
if (d.equals(currentDevice)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
String newDevice;
|
||||||
|
if (index == 1) newDevice = devices[0];
|
||||||
|
else if (devices.length > 1) newDevice = devices[1];
|
||||||
|
else newDevice = devices[index];
|
||||||
|
core.setVideoDevice(newDevice);
|
||||||
|
|
||||||
Call call = core.getCurrentCall();
|
Call call = core.getCurrentCall();
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
Log.e("[Call Manager] Trying to updateCall while not in call: doing nothing");
|
Log.e("[Call Manager] Trying to switch camera while not in call");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
call.update(null);
|
call.update(null);
|
||||||
|
} catch (ArithmeticException ae) {
|
||||||
|
Log.e("[Call Manager] [Video] Cannot switch camera: no camera");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
call.acceptWithParams(params);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptCallUpdate(boolean accept) {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
Call call = core.getCurrentCall();
|
||||||
|
if (call == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallParams params = core.createCallParams(call);
|
||||||
|
if (accept) {
|
||||||
|
params.enableVideo(true);
|
||||||
|
core.enableVideoCapture(true);
|
||||||
|
core.enableVideoDisplay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
call.acceptUpdate(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inviteAddress(Address address, boolean forceZRTP) {
|
||||||
|
boolean isLowBandwidthConnection =
|
||||||
|
!LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance());
|
||||||
|
|
||||||
|
inviteAddress(address, false, isLowBandwidthConnection, forceZRTP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inviteAddress(Address address, boolean videoEnabled, boolean lowBandwidth) {
|
||||||
|
inviteAddress(address, videoEnabled, lowBandwidth, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void newOutgoingCall(AddressType address) {
|
public void newOutgoingCall(AddressType address) {
|
||||||
|
@ -149,10 +171,6 @@ public class CallManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void newOutgoingCall(String to, String displayName) {
|
public void newOutgoingCall(String to, String displayName) {
|
||||||
// if (mCore.inCall()) {
|
|
||||||
// listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
if (to == null) return;
|
if (to == null) return;
|
||||||
|
|
||||||
// If to is only a username, try to find the contact to get an alias if existing
|
// If to is only a username, try to find the contact to get an alias if existing
|
||||||
|
@ -184,8 +202,7 @@ public class CallManager {
|
||||||
address.setDisplayName(displayName);
|
address.setDisplayName(displayName);
|
||||||
|
|
||||||
boolean isLowBandwidthConnection =
|
boolean isLowBandwidthConnection =
|
||||||
!LinphoneUtils.isHighBandwidthConnection(
|
!LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance());
|
||||||
LinphoneService.instance().getApplicationContext());
|
|
||||||
|
|
||||||
if (core.isNetworkReachable()) {
|
if (core.isNetworkReachable()) {
|
||||||
if (Version.isVideoCapable()) {
|
if (Version.isVideoCapable()) {
|
||||||
|
@ -210,16 +227,6 @@ public class CallManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
public void playDtmf(ContentResolver r, char dtmf) {
|
||||||
try {
|
try {
|
||||||
if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) {
|
if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) {
|
||||||
|
@ -233,44 +240,20 @@ public class CallManager {
|
||||||
LinphoneManager.getCore().playDtmf(dtmf, -1);
|
LinphoneManager.getCore().playDtmf(dtmf, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void terminateCall() {
|
public boolean shouldShowAcceptCallUpdateDialog(Call call) {
|
||||||
Core core = LinphoneManager.getCore();
|
if (call == null) return true;
|
||||||
if (core.inCall()) {
|
|
||||||
core.getCurrentCall().terminate();
|
boolean remoteVideo = call.getRemoteParams().videoEnabled();
|
||||||
}
|
boolean localVideo = call.getCurrentParams().videoEnabled();
|
||||||
|
boolean autoAcceptCameraPolicy =
|
||||||
|
LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests();
|
||||||
|
return remoteVideo
|
||||||
|
&& !localVideo
|
||||||
|
&& !autoAcceptCameraPolicy
|
||||||
|
&& !call.getCore().isInConference();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return false if already in video call. */
|
public void setCallInterface(CallActivityInterface callInterface) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
call.acceptWithParams(params);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCallInterface(CallActivity.CallActivityInterface callInterface) {
|
|
||||||
mCallInterface = callInterface;
|
mCallInterface = callInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,20 +269,102 @@ public class CallManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHandsetMode(Boolean on) {
|
public void removeCallFromConference(Call call) {
|
||||||
if (mHandsetON == on) return;
|
if (call == null || call.getConference() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
call.getConference().removeParticipant(call.getRemoteAddress());
|
||||||
|
|
||||||
|
if (call.getCore().getConferenceSize() <= 1) {
|
||||||
|
call.getCore().leaveConference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pauseConference() {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core == null) return;
|
||||||
|
if (core.isInConference()) {
|
||||||
|
Log.i("[Call Manager] Pausing conference");
|
||||||
|
core.leaveConference();
|
||||||
|
} else {
|
||||||
|
Log.w("[Call Manager] Core isn't in a conference, can't pause it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resumeConference() {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core == null) return;
|
||||||
|
if (!core.isInConference()) {
|
||||||
|
Log.i("[Call Manager] Resuming conference");
|
||||||
|
core.enterConference();
|
||||||
|
} else {
|
||||||
|
Log.w("[Call Manager] Core is already in a conference, can't resume it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void inviteAddress(
|
||||||
|
Address address, boolean videoEnabled, boolean lowBandwidth, boolean forceZRTP) {
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
|
|
||||||
if (core.isIncomingInvitePending() && on) {
|
CallParams params = core.createCallParams(null);
|
||||||
mHandsetON = true;
|
mBandwidthManager.updateWithProfileSettings(params);
|
||||||
acceptCall(core.getCurrentCall());
|
|
||||||
} else if (on && mCallInterface != null) {
|
if (videoEnabled && params.videoEnabled()) {
|
||||||
mHandsetON = true;
|
params.enableVideo(true);
|
||||||
mCallInterface.setSpeakerEnabled(true);
|
} else {
|
||||||
mCallInterface.refreshInCallActions();
|
params.enableVideo(false);
|
||||||
} else if (!on) {
|
}
|
||||||
mHandsetON = false;
|
|
||||||
terminateCall();
|
if (lowBandwidth) {
|
||||||
|
params.enableLowBandwidth(true);
|
||||||
|
Log.d("[Call Manager] Low bandwidth enabled in call params");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceZRTP) {
|
||||||
|
params.setMediaEncryption(MediaEncryption.ZRTP);
|
||||||
|
}
|
||||||
|
|
||||||
|
String recordFile = FileUtils.getCallRecordingFilename(LinphoneService.instance(), address);
|
||||||
|
params.setRecordFile(recordFile);
|
||||||
|
|
||||||
|
core.inviteAddressWithParams(address, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reinviteWithVideo() {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
Call call = core.getCurrentCall();
|
||||||
|
if (call == null) {
|
||||||
|
Log.e("[Call Manager] Trying to add video while not in call");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (call.getRemoteParams().lowBandwidthEnabled()) {
|
||||||
|
Log.e("[Call Manager] Remote has low bandwidth, won't be able to do video");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallParams params = core.createCallParams(call);
|
||||||
|
if (params.videoEnabled()) return false;
|
||||||
|
|
||||||
|
// Check if video possible regarding bandwidth limitations
|
||||||
|
mBandwidthManager.updateWithProfileSettings(params);
|
||||||
|
|
||||||
|
// Abort if not enough bandwidth...
|
||||||
|
if (!params.videoEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not yet in video call: try to re-invite with video
|
||||||
|
call.update(params);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,9 @@ import android.Manifest;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -63,6 +60,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
setContentView(R.layout.call_outgoing);
|
setContentView(R.layout.call_outgoing);
|
||||||
|
@ -89,36 +89,49 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
||||||
if (state == State.Error) {
|
if (state == State.Error) {
|
||||||
// Convert Core message for internalization
|
// Convert Core message for internalization
|
||||||
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
|
CallOutgoingActivity.this,
|
||||||
getString(R.string.error_call_declined),
|
getString(R.string.error_call_declined),
|
||||||
Toast.LENGTH_SHORT);
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
} else if (call.getErrorInfo().getReason() == Reason.NotFound) {
|
} else if (call.getErrorInfo().getReason() == Reason.NotFound) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
|
CallOutgoingActivity.this,
|
||||||
getString(R.string.error_user_not_found),
|
getString(R.string.error_user_not_found),
|
||||||
Toast.LENGTH_SHORT);
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
} else if (call.getErrorInfo().getReason() == Reason.NotAcceptable) {
|
} else if (call.getErrorInfo().getReason() == Reason.NotAcceptable) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
|
CallOutgoingActivity.this,
|
||||||
getString(R.string.error_incompatible_media),
|
getString(R.string.error_incompatible_media),
|
||||||
Toast.LENGTH_SHORT);
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
} else if (call.getErrorInfo().getReason() == Reason.Busy) {
|
} else if (call.getErrorInfo().getReason() == Reason.Busy) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
getString(R.string.error_user_busy), Toast.LENGTH_SHORT);
|
CallOutgoingActivity.this,
|
||||||
|
getString(R.string.error_user_busy),
|
||||||
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
} else if (message != null) {
|
} else if (message != null) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
|
CallOutgoingActivity.this,
|
||||||
getString(R.string.error_unknown) + " - " + message,
|
getString(R.string.error_unknown) + " - " + message,
|
||||||
Toast.LENGTH_SHORT);
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
}
|
}
|
||||||
} else if (state == State.End) {
|
} else if (state == State.End) {
|
||||||
// Convert Core message for internalization
|
// Convert Core message for internalization
|
||||||
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
||||||
displayCustomToast(
|
Toast.makeText(
|
||||||
|
CallOutgoingActivity.this,
|
||||||
getString(R.string.error_call_declined),
|
getString(R.string.error_call_declined),
|
||||||
Toast.LENGTH_SHORT);
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
decline();
|
decline();
|
||||||
}
|
}
|
||||||
} else if (state == State.Connected) {
|
} else if (state == State.Connected) {
|
||||||
|
@ -223,20 +236,6 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
||||||
return super.onKeyDown(keyCode, event);
|
return super.onKeyDown(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayCustomToast(final String message, final int duration) {
|
|
||||||
LayoutInflater inflater = getLayoutInflater();
|
|
||||||
View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastRoot));
|
|
||||||
|
|
||||||
TextView toastText = layout.findViewById(R.id.toastMessage);
|
|
||||||
toastText.setText(message);
|
|
||||||
|
|
||||||
final Toast toast = new Toast(getApplicationContext());
|
|
||||||
toast.setGravity(Gravity.CENTER, 0, 0);
|
|
||||||
toast.setDuration(duration);
|
|
||||||
toast.setView(layout);
|
|
||||||
toast.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void decline() {
|
private void decline() {
|
||||||
mCall.terminate();
|
mCall.terminate();
|
||||||
finish();
|
finish();
|
||||||
|
|
424
app/src/main/java/org/linphone/call/CallStatsFragment.java
Normal file
424
app/src/main/java/org/linphone/call/CallStatsFragment.java
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
package org.linphone.call;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CallStatsFragment.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.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.AddressFamily;
|
||||||
|
import org.linphone.core.Call;
|
||||||
|
import org.linphone.core.CallListenerStub;
|
||||||
|
import org.linphone.core.CallParams;
|
||||||
|
import org.linphone.core.CallStats;
|
||||||
|
import org.linphone.core.Core;
|
||||||
|
import org.linphone.core.PayloadType;
|
||||||
|
import org.linphone.core.StreamType;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
|
|
||||||
|
public class CallStatsFragment extends Fragment {
|
||||||
|
private final Handler mHandler = new Handler();
|
||||||
|
private Timer mTimer;
|
||||||
|
private TimerTask mTask;
|
||||||
|
|
||||||
|
private View mView;
|
||||||
|
private DrawerLayout mSideMenu;
|
||||||
|
private RelativeLayout mSideMenuContent;
|
||||||
|
|
||||||
|
private HashMap<String, String> mEncoderTexts;
|
||||||
|
private HashMap<String, String> mDecoderTexts;
|
||||||
|
|
||||||
|
private Call mCall;
|
||||||
|
private CallListenerStub mListener;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(
|
||||||
|
LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.call_stats, container, false);
|
||||||
|
mView = view;
|
||||||
|
|
||||||
|
mEncoderTexts = new HashMap<>();
|
||||||
|
mDecoderTexts = new HashMap<>();
|
||||||
|
|
||||||
|
mListener =
|
||||||
|
new CallListenerStub() {
|
||||||
|
public void onStateChanged(Call call, Call.State cstate, String message) {
|
||||||
|
if (cstate == Call.State.End || cstate == Call.State.Error) {
|
||||||
|
if (mTimer != null) {
|
||||||
|
Log.i(
|
||||||
|
"[Call Stats] Call is terminated, stopping mCountDownTimer in charge of stats refreshing.");
|
||||||
|
mTimer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core != null) {
|
||||||
|
setCall(core.getCurrentCall());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
setCall(null);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawer(DrawerLayout drawer, RelativeLayout content) {
|
||||||
|
mSideMenu = drawer;
|
||||||
|
mSideMenuContent = content;
|
||||||
|
|
||||||
|
if (getResources().getBoolean(R.bool.hide_in_call_stats)) {
|
||||||
|
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (getResources().getBoolean(R.bool.hide_in_call_stats)) return;
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
mSideMenu.openDrawer(mSideMenuContent, animate);
|
||||||
|
} else {
|
||||||
|
mSideMenu.closeDrawer(mSideMenuContent, animate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCall(Call call) {
|
||||||
|
if (mCall != null) {
|
||||||
|
mCall.removeListener(mListener);
|
||||||
|
}
|
||||||
|
mCall = call;
|
||||||
|
init(mView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(View view) {
|
||||||
|
if (getResources().getBoolean(R.bool.hide_in_call_stats)) return;
|
||||||
|
|
||||||
|
if (mTimer != null && mTask != null) {
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer = null;
|
||||||
|
mTask = null;
|
||||||
|
}
|
||||||
|
if (mCall == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextView titleAudio = view.findViewById(R.id.call_stats_audio);
|
||||||
|
final TextView titleVideo = view.findViewById(R.id.call_stats_video);
|
||||||
|
final TextView codecAudio = view.findViewById(R.id.codec_audio);
|
||||||
|
final TextView codecVideo = view.findViewById(R.id.codec_video);
|
||||||
|
final TextView encoderAudio = view.findViewById(R.id.encoder_audio);
|
||||||
|
final TextView decoderAudio = view.findViewById(R.id.decoder_audio);
|
||||||
|
final TextView encoderVideo = view.findViewById(R.id.encoder_video);
|
||||||
|
final TextView decoderVideo = view.findViewById(R.id.decoder_video);
|
||||||
|
final TextView displayFilter = view.findViewById(R.id.display_filter);
|
||||||
|
final TextView dlAudio = view.findViewById(R.id.downloadBandwith_audio);
|
||||||
|
final TextView ulAudio = view.findViewById(R.id.uploadBandwith_audio);
|
||||||
|
final TextView dlVideo = view.findViewById(R.id.downloadBandwith_video);
|
||||||
|
final TextView ulVideo = view.findViewById(R.id.uploadBandwith_video);
|
||||||
|
final TextView edlVideo = view.findViewById(R.id.estimatedDownloadBandwidth_video);
|
||||||
|
final TextView iceAudio = view.findViewById(R.id.ice_audio);
|
||||||
|
final TextView iceVideo = view.findViewById(R.id.ice_video);
|
||||||
|
final TextView videoResolutionSent = view.findViewById(R.id.video_resolution_sent);
|
||||||
|
final TextView videoResolutionReceived = view.findViewById(R.id.video_resolution_received);
|
||||||
|
final TextView videoFpsSent = view.findViewById(R.id.video_fps_sent);
|
||||||
|
final TextView videoFpsReceived = view.findViewById(R.id.video_fps_received);
|
||||||
|
final TextView senderLossRateAudio = view.findViewById(R.id.senderLossRateAudio);
|
||||||
|
final TextView receiverLossRateAudio = view.findViewById(R.id.receiverLossRateAudio);
|
||||||
|
final TextView senderLossRateVideo = view.findViewById(R.id.senderLossRateVideo);
|
||||||
|
final TextView receiverLossRateVideo = view.findViewById(R.id.receiverLossRateVideo);
|
||||||
|
final TextView ipAudio = view.findViewById(R.id.ip_audio);
|
||||||
|
final TextView ipVideo = view.findViewById(R.id.ip_video);
|
||||||
|
final TextView jitterBufferAudio = view.findViewById(R.id.jitterBufferAudio);
|
||||||
|
final View videoLayout = view.findViewById(R.id.callStatsVideo);
|
||||||
|
final View audioLayout = view.findViewById(R.id.callStatsAudio);
|
||||||
|
|
||||||
|
mTimer = new Timer();
|
||||||
|
mTask =
|
||||||
|
new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mCall == null) {
|
||||||
|
mTimer.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (titleAudio == null
|
||||||
|
|| codecAudio == null
|
||||||
|
|| dlVideo == null
|
||||||
|
|| edlVideo == null
|
||||||
|
|| iceAudio == null
|
||||||
|
|| videoResolutionSent == null
|
||||||
|
|| videoLayout == null
|
||||||
|
|| titleVideo == null
|
||||||
|
|| ipVideo == null
|
||||||
|
|| ipAudio == null
|
||||||
|
|| codecVideo == null
|
||||||
|
|| dlAudio == null
|
||||||
|
|| ulAudio == null
|
||||||
|
|| ulVideo == null
|
||||||
|
|| iceVideo == null
|
||||||
|
|| videoResolutionReceived == null) {
|
||||||
|
mTimer.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mHandler.post(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mCall == null) return;
|
||||||
|
|
||||||
|
if (mCall.getState() != Call.State.Released) {
|
||||||
|
CallParams params = mCall.getCurrentParams();
|
||||||
|
if (params != null) {
|
||||||
|
CallStats audioStats =
|
||||||
|
mCall.getStats(StreamType.Audio);
|
||||||
|
CallStats videoStats = null;
|
||||||
|
|
||||||
|
if (params.videoEnabled())
|
||||||
|
videoStats = mCall.getStats(StreamType.Video);
|
||||||
|
|
||||||
|
PayloadType payloadAudio =
|
||||||
|
params.getUsedAudioPayloadType();
|
||||||
|
PayloadType payloadVideo =
|
||||||
|
params.getUsedVideoPayloadType();
|
||||||
|
|
||||||
|
formatText(
|
||||||
|
displayFilter,
|
||||||
|
getString(
|
||||||
|
R.string.call_stats_display_filter),
|
||||||
|
mCall.getCore().getVideoDisplayFilter());
|
||||||
|
|
||||||
|
displayMediaStats(
|
||||||
|
params,
|
||||||
|
audioStats,
|
||||||
|
payloadAudio,
|
||||||
|
audioLayout,
|
||||||
|
titleAudio,
|
||||||
|
codecAudio,
|
||||||
|
dlAudio,
|
||||||
|
ulAudio,
|
||||||
|
null,
|
||||||
|
iceAudio,
|
||||||
|
ipAudio,
|
||||||
|
senderLossRateAudio,
|
||||||
|
receiverLossRateAudio,
|
||||||
|
encoderAudio,
|
||||||
|
decoderAudio,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
jitterBufferAudio);
|
||||||
|
|
||||||
|
displayMediaStats(
|
||||||
|
params,
|
||||||
|
videoStats,
|
||||||
|
payloadVideo,
|
||||||
|
videoLayout,
|
||||||
|
titleVideo,
|
||||||
|
codecVideo,
|
||||||
|
dlVideo,
|
||||||
|
ulVideo,
|
||||||
|
edlVideo,
|
||||||
|
iceVideo,
|
||||||
|
ipVideo,
|
||||||
|
senderLossRateVideo,
|
||||||
|
receiverLossRateVideo,
|
||||||
|
encoderVideo,
|
||||||
|
decoderVideo,
|
||||||
|
videoResolutionSent,
|
||||||
|
videoResolutionReceived,
|
||||||
|
videoFpsSent,
|
||||||
|
videoFpsReceived,
|
||||||
|
true,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mCall.addListener(mListener);
|
||||||
|
mTimer.scheduleAtFixedRate(mTask, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatText(TextView tv, String name, String value) {
|
||||||
|
tv.setText(Html.fromHtml("<b>" + name + " </b>" + value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getEncoderText(String mime) {
|
||||||
|
String ret = mEncoderTexts.get(mime);
|
||||||
|
if (ret == null) {
|
||||||
|
org.linphone.mediastream.Factory msfactory =
|
||||||
|
LinphoneManager.getCore().getMediastreamerFactory();
|
||||||
|
ret = msfactory.getEncoderText(mime);
|
||||||
|
mEncoderTexts.put(mime, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDecoderText(String mime) {
|
||||||
|
String ret = mDecoderTexts.get(mime);
|
||||||
|
if (ret == null) {
|
||||||
|
org.linphone.mediastream.Factory msfactory =
|
||||||
|
LinphoneManager.getCore().getMediastreamerFactory();
|
||||||
|
ret = msfactory.getDecoderText(mime);
|
||||||
|
mDecoderTexts.put(mime, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayMediaStats(
|
||||||
|
CallParams params,
|
||||||
|
CallStats stats,
|
||||||
|
PayloadType media,
|
||||||
|
View layout,
|
||||||
|
TextView title,
|
||||||
|
TextView codec,
|
||||||
|
TextView dl,
|
||||||
|
TextView ul,
|
||||||
|
TextView edl,
|
||||||
|
TextView ice,
|
||||||
|
TextView ip,
|
||||||
|
TextView senderLossRate,
|
||||||
|
TextView receiverLossRate,
|
||||||
|
TextView enc,
|
||||||
|
TextView dec,
|
||||||
|
TextView videoResolutionSent,
|
||||||
|
TextView videoResolutionReceived,
|
||||||
|
TextView videoFpsSent,
|
||||||
|
TextView videoFpsReceived,
|
||||||
|
boolean isVideo,
|
||||||
|
TextView jitterBuffer) {
|
||||||
|
if (stats != null) {
|
||||||
|
String mime = null;
|
||||||
|
|
||||||
|
layout.setVisibility(View.VISIBLE);
|
||||||
|
title.setVisibility(TextView.VISIBLE);
|
||||||
|
if (media != null) {
|
||||||
|
mime = media.getMimeType();
|
||||||
|
formatText(
|
||||||
|
codec,
|
||||||
|
getString(R.string.call_stats_codec),
|
||||||
|
mime + " / " + (media.getClockRate() / 1000) + "kHz");
|
||||||
|
}
|
||||||
|
if (mime != null) {
|
||||||
|
formatText(enc, getString(R.string.call_stats_encoder_name), getEncoderText(mime));
|
||||||
|
formatText(dec, getString(R.string.call_stats_decoder_name), getDecoderText(mime));
|
||||||
|
}
|
||||||
|
formatText(
|
||||||
|
dl,
|
||||||
|
getString(R.string.call_stats_download),
|
||||||
|
(int) stats.getDownloadBandwidth() + " kbits/s");
|
||||||
|
formatText(
|
||||||
|
ul,
|
||||||
|
getString(R.string.call_stats_upload),
|
||||||
|
(int) stats.getUploadBandwidth() + " kbits/s");
|
||||||
|
if (isVideo) {
|
||||||
|
formatText(
|
||||||
|
edl,
|
||||||
|
getString(R.string.call_stats_estimated_download),
|
||||||
|
stats.getEstimatedDownloadBandwidth() + " kbits/s");
|
||||||
|
}
|
||||||
|
formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString());
|
||||||
|
formatText(
|
||||||
|
ip,
|
||||||
|
getString(R.string.call_stats_ip),
|
||||||
|
(stats.getIpFamilyOfRemote() == AddressFamily.Inet6)
|
||||||
|
? "IpV6"
|
||||||
|
: (stats.getIpFamilyOfRemote() == AddressFamily.Inet)
|
||||||
|
? "IpV4"
|
||||||
|
: "Unknown");
|
||||||
|
formatText(
|
||||||
|
senderLossRate,
|
||||||
|
getString(R.string.call_stats_sender_loss_rate),
|
||||||
|
new DecimalFormat("##.##").format(stats.getSenderLossRate()) + "%");
|
||||||
|
formatText(
|
||||||
|
receiverLossRate,
|
||||||
|
getString(R.string.call_stats_receiver_loss_rate),
|
||||||
|
new DecimalFormat("##.##").format(stats.getReceiverLossRate()) + "%");
|
||||||
|
if (isVideo) {
|
||||||
|
formatText(
|
||||||
|
videoResolutionSent,
|
||||||
|
getString(R.string.call_stats_video_resolution_sent),
|
||||||
|
"\u2191 " + params.getSentVideoDefinition() != null
|
||||||
|
? params.getSentVideoDefinition().getName()
|
||||||
|
: "");
|
||||||
|
formatText(
|
||||||
|
videoResolutionReceived,
|
||||||
|
getString(R.string.call_stats_video_resolution_received),
|
||||||
|
"\u2193 " + params.getReceivedVideoDefinition() != null
|
||||||
|
? params.getReceivedVideoDefinition().getName()
|
||||||
|
: "");
|
||||||
|
formatText(
|
||||||
|
videoFpsSent,
|
||||||
|
getString(R.string.call_stats_video_fps_sent),
|
||||||
|
"\u2191 " + params.getSentFramerate());
|
||||||
|
formatText(
|
||||||
|
videoFpsReceived,
|
||||||
|
getString(R.string.call_stats_video_fps_received),
|
||||||
|
"\u2193 " + params.getReceivedFramerate());
|
||||||
|
} else {
|
||||||
|
formatText(
|
||||||
|
jitterBuffer,
|
||||||
|
getString(R.string.call_stats_jitter_buffer),
|
||||||
|
new DecimalFormat("##.##").format(stats.getJitterBufferSizeMs()) + " ms");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
layout.setVisibility(View.GONE);
|
||||||
|
title.setVisibility(TextView.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
package org.linphone.fragments;
|
package org.linphone.call;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
StatusFragment.java
|
CallStatusBarFragment.java
|
||||||
Copyright (C) 2017 Belledonne Communications, Grenoble, France
|
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License
|
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.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -37,60 +37,47 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import org.linphone.LinphoneManager;
|
import org.linphone.LinphoneManager;
|
||||||
import org.linphone.LinphoneService;
|
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
import org.linphone.call.CallActivity;
|
|
||||||
import org.linphone.call.CallIncomingActivity;
|
|
||||||
import org.linphone.call.CallOutgoingActivity;
|
|
||||||
import org.linphone.core.Call;
|
import org.linphone.core.Call;
|
||||||
import org.linphone.core.Content;
|
|
||||||
import org.linphone.core.Core;
|
import org.linphone.core.Core;
|
||||||
import org.linphone.core.CoreListenerStub;
|
import org.linphone.core.CoreListenerStub;
|
||||||
import org.linphone.core.Event;
|
|
||||||
import org.linphone.core.MediaEncryption;
|
import org.linphone.core.MediaEncryption;
|
||||||
import org.linphone.core.ProxyConfig;
|
import org.linphone.core.ProxyConfig;
|
||||||
import org.linphone.core.RegistrationState;
|
import org.linphone.core.RegistrationState;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
|
||||||
public class StatusFragment extends Fragment {
|
public class CallStatusBarFragment extends Fragment {
|
||||||
private final Handler mRefreshHandler = new Handler();
|
private final Handler mRefreshHandler = new Handler();
|
||||||
private TextView mStatusText, mVoicemailCount;
|
private TextView mStatusText;
|
||||||
private ImageView mStatusLed, mCallQuality, mEncryption, mMenu, mVoicemail;
|
private ImageView mStatusLed, mCallQuality, mEncryption;
|
||||||
private Runnable mCallQualityUpdater;
|
private Runnable mCallQualityUpdater;
|
||||||
private boolean mIsInCall, mIsAttached = false;
|
|
||||||
private CoreListenerStub mListener;
|
private CoreListenerStub mListener;
|
||||||
private Dialog mZrtpDialog = null;
|
private Dialog mZrtpDialog = null;
|
||||||
private int mDisplayedQuality = -1;
|
private int mDisplayedQuality = -1;
|
||||||
private MenuClikedListener mMenuListener;
|
private StatsClikedListener mStatsListener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(
|
public View onCreateView(
|
||||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.status, container, false);
|
View view = inflater.inflate(R.layout.call_status_bar, container, false);
|
||||||
|
|
||||||
mStatusText = view.findViewById(R.id.status_text);
|
mStatusText = view.findViewById(R.id.status_text);
|
||||||
mStatusLed = view.findViewById(R.id.status_led);
|
mStatusLed = view.findViewById(R.id.status_led);
|
||||||
mCallQuality = view.findViewById(R.id.call_quality);
|
mCallQuality = view.findViewById(R.id.call_quality);
|
||||||
mEncryption = view.findViewById(R.id.encryption);
|
mEncryption = view.findViewById(R.id.encryption);
|
||||||
mMenu = view.findViewById(R.id.side_menu_button);
|
|
||||||
mVoicemail = view.findViewById(R.id.voicemail);
|
|
||||||
mVoicemailCount = view.findViewById(R.id.voicemail_count);
|
|
||||||
|
|
||||||
mMenuListener = null;
|
mStatsListener = null;
|
||||||
mMenu.setOnClickListener(
|
mCallQuality.setOnClickListener(
|
||||||
new OnClickListener() {
|
new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (mMenuListener != null) {
|
if (mStatsListener != null) {
|
||||||
mMenuListener.onMenuCliked();
|
mStatsListener.onStatsClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// We create it once to not delay the first display
|
|
||||||
populateSliderContent();
|
|
||||||
|
|
||||||
mListener =
|
mListener =
|
||||||
new CoreListenerStub() {
|
new CoreListenerStub() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,11 +85,7 @@ public class StatusFragment extends Fragment {
|
||||||
final Core core,
|
final Core core,
|
||||||
final ProxyConfig proxy,
|
final ProxyConfig proxy,
|
||||||
final RegistrationState state,
|
final RegistrationState state,
|
||||||
String smessage) {
|
String message) {
|
||||||
if (!mIsAttached || !LinphoneService.isReady()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (core.getProxyConfigList() == null) {
|
if (core.getProxyConfigList() == null) {
|
||||||
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
||||||
mStatusText.setText(getString(R.string.no_account));
|
mStatusText.setText(getString(R.string.no_account));
|
||||||
|
@ -136,169 +119,27 @@ public class StatusFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotifyReceived(
|
public void onCallStateChanged(
|
||||||
Core core, Event ev, String eventName, Content content) {
|
Core core, Call call, Call.State state, String message) {
|
||||||
|
if (state == Call.State.Resuming || state == Call.State.StreamsRunning) {
|
||||||
if (!content.getType().equals("application")) return;
|
refreshStatusItems(call);
|
||||||
if (!content.getSubtype().equals("simple-message-summary")) return;
|
|
||||||
|
|
||||||
if (content.getSize() == 0) return;
|
|
||||||
|
|
||||||
int unreadCount = 0;
|
|
||||||
String data = content.getStringBuffer().toLowerCase();
|
|
||||||
String[] voiceMail = data.split("voice-message: ");
|
|
||||||
if (voiceMail.length >= 2) {
|
|
||||||
final String[] intToParse = voiceMail[1].split("/", 0);
|
|
||||||
try {
|
|
||||||
unreadCount = Integer.parseInt(intToParse[0]);
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
Log.e("[Status Fragment] " + nfe);
|
|
||||||
}
|
}
|
||||||
if (unreadCount > 0) {
|
|
||||||
mVoicemailCount.setText(String.valueOf(unreadCount));
|
|
||||||
mVoicemail.setVisibility(View.VISIBLE);
|
|
||||||
mVoicemailCount.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
mVoicemail.setVisibility(View.GONE);
|
|
||||||
mVoicemailCount.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mIsAttached = true;
|
|
||||||
Activity activity = getActivity();
|
|
||||||
|
|
||||||
if (activity instanceof CallActivity) {
|
|
||||||
((CallActivity) activity).updateStatusFragment(this);
|
|
||||||
}
|
|
||||||
mIsInCall =
|
|
||||||
activity instanceof CallActivity
|
|
||||||
|| activity instanceof CallIncomingActivity
|
|
||||||
|| activity instanceof CallOutgoingActivity;
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetach() {
|
public void onCallEncryptionChanged(
|
||||||
super.onDetach();
|
Core core, Call call, boolean on, String authenticationToken) {
|
||||||
mIsAttached = false;
|
if (call.getCurrentParams()
|
||||||
|
.getMediaEncryption()
|
||||||
|
.equals(MediaEncryption.ZRTP)
|
||||||
|
&& !call.getAuthenticationTokenVerified()) {
|
||||||
|
showZRTPDialog(call);
|
||||||
}
|
}
|
||||||
|
refreshStatusItems(call);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public void setMenuListener(MenuClikedListener listener) {
|
return view;
|
||||||
mMenuListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NORMAL STATUS BAR
|
|
||||||
|
|
||||||
private void populateSliderContent() {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
if (core != null) {
|
|
||||||
mVoicemailCount.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
if (!mIsInCall) {
|
|
||||||
mVoicemailCount.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (core.getProxyConfigList().length == 0) {
|
|
||||||
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
|
||||||
mStatusText.setText(getString(R.string.no_account));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getStatusIconResource(RegistrationState state) {
|
|
||||||
try {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
boolean defaultAccountConnected =
|
|
||||||
(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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStatusIconText(RegistrationState state) {
|
|
||||||
Context context = getActivity();
|
|
||||||
if (!mIsAttached && LinphoneService.isReady()) context = LinphoneService.instance();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (state == RegistrationState.Ok
|
|
||||||
&& LinphoneManager.getCore().getDefaultProxyConfig().getState()
|
|
||||||
== RegistrationState.Ok) {
|
|
||||||
return context.getString(R.string.status_connected);
|
|
||||||
} else if (state == RegistrationState.Progress) {
|
|
||||||
return context.getString(R.string.status_in_progress);
|
|
||||||
} else if (state == RegistrationState.Failed) {
|
|
||||||
return context.getString(R.string.status_error);
|
|
||||||
} else {
|
|
||||||
return context.getString(R.string.status_not_connected);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.getString(R.string.status_not_connected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// INCALL STATUS BAR
|
|
||||||
private void startCallQuality() {
|
|
||||||
mCallQuality.setVisibility(View.VISIBLE);
|
|
||||||
mRefreshHandler.postDelayed(
|
|
||||||
mCallQualityUpdater =
|
|
||||||
new Runnable() {
|
|
||||||
final Call mCurrentCall = LinphoneManager.getCore().getCurrentCall();
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
if (mCurrentCall == null) {
|
|
||||||
mCallQualityUpdater = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float newQuality = mCurrentCall.getCurrentQuality();
|
|
||||||
updateQualityOfSignalIcon(newQuality);
|
|
||||||
|
|
||||||
if (mIsInCall) {
|
|
||||||
mRefreshHandler.postDelayed(this, 1000);
|
|
||||||
} else mCallQualityUpdater = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateQualityOfSignalIcon(float quality) {
|
|
||||||
int iQuality = (int) quality;
|
|
||||||
|
|
||||||
if (iQuality == mDisplayedQuality) return;
|
|
||||||
if (quality >= 4) // Good Quality
|
|
||||||
{
|
|
||||||
mCallQuality.setImageResource(R.drawable.call_quality_indicator_4);
|
|
||||||
} else if (quality >= 3) // Average quality
|
|
||||||
{
|
|
||||||
mCallQuality.setImageResource(R.drawable.call_quality_indicator_3);
|
|
||||||
} else if (quality >= 2) // Low quality
|
|
||||||
{
|
|
||||||
mCallQuality.setImageResource(R.drawable.call_quality_indicator_2);
|
|
||||||
} else if (quality >= 1) // Very low quality
|
|
||||||
{
|
|
||||||
mCallQuality.setImageResource(R.drawable.call_quality_indicator_1);
|
|
||||||
} else // Worst quality
|
|
||||||
{
|
|
||||||
mCallQuality.setImageResource(R.drawable.call_quality_indicator_0);
|
|
||||||
}
|
|
||||||
mDisplayedQuality = iQuality;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -314,14 +155,15 @@ public class StatusFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
Call call = core.getCurrentCall();
|
Call call = core.getCurrentCall();
|
||||||
if (mIsInCall
|
if (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0) {
|
||||||
&& (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0)) {
|
|
||||||
if (call != null) {
|
if (call != null) {
|
||||||
startCallQuality();
|
startCallQuality();
|
||||||
refreshStatusItems(call);
|
refreshStatusItems(call);
|
||||||
|
|
||||||
|
if (!call.getAuthenticationTokenVerified()) {
|
||||||
|
showZRTPDialog(call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mMenu.setVisibility(View.INVISIBLE);
|
|
||||||
mCallQuality.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
// We are obviously connected
|
// We are obviously connected
|
||||||
if (core.getDefaultProxyConfig() == null) {
|
if (core.getDefaultProxyConfig() == null) {
|
||||||
|
@ -354,9 +196,99 @@ public class StatusFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStatsListener(StatsClikedListener listener) {
|
||||||
|
mStatsListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getStatusIconResource(RegistrationState state) {
|
||||||
|
try {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
boolean defaultAccountConnected =
|
||||||
|
(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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStatusIconText(RegistrationState state) {
|
||||||
|
Context context = getActivity();
|
||||||
|
try {
|
||||||
|
if (state == RegistrationState.Ok
|
||||||
|
&& LinphoneManager.getCore().getDefaultProxyConfig().getState()
|
||||||
|
== RegistrationState.Ok) {
|
||||||
|
return context.getString(R.string.status_connected);
|
||||||
|
} else if (state == RegistrationState.Progress) {
|
||||||
|
return context.getString(R.string.status_in_progress);
|
||||||
|
} else if (state == RegistrationState.Failed) {
|
||||||
|
return context.getString(R.string.status_error);
|
||||||
|
} else {
|
||||||
|
return context.getString(R.string.status_not_connected);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getString(R.string.status_not_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCallQuality() {
|
||||||
|
mRefreshHandler.postDelayed(
|
||||||
|
mCallQualityUpdater =
|
||||||
|
new Runnable() {
|
||||||
|
final Call mCurrentCall = LinphoneManager.getCore().getCurrentCall();
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
if (mCurrentCall == null) {
|
||||||
|
mCallQualityUpdater = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float newQuality = mCurrentCall.getCurrentQuality();
|
||||||
|
updateQualityOfSignalIcon(newQuality);
|
||||||
|
|
||||||
|
mRefreshHandler.postDelayed(this, 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateQualityOfSignalIcon(float quality) {
|
||||||
|
int iQuality = (int) quality;
|
||||||
|
|
||||||
|
if (iQuality == mDisplayedQuality) return;
|
||||||
|
if (quality >= 4) // Good Quality
|
||||||
|
{
|
||||||
|
mCallQuality.setImageResource(R.drawable.call_quality_indicator_4);
|
||||||
|
} else if (quality >= 3) // Average quality
|
||||||
|
{
|
||||||
|
mCallQuality.setImageResource(R.drawable.call_quality_indicator_3);
|
||||||
|
} else if (quality >= 2) // Low quality
|
||||||
|
{
|
||||||
|
mCallQuality.setImageResource(R.drawable.call_quality_indicator_2);
|
||||||
|
} else if (quality >= 1) // Very low quality
|
||||||
|
{
|
||||||
|
mCallQuality.setImageResource(R.drawable.call_quality_indicator_1);
|
||||||
|
} else // Worst quality
|
||||||
|
{
|
||||||
|
mCallQuality.setImageResource(R.drawable.call_quality_indicator_0);
|
||||||
|
}
|
||||||
|
mDisplayedQuality = iQuality;
|
||||||
|
}
|
||||||
|
|
||||||
public void refreshStatusItems(final Call call) {
|
public void refreshStatusItems(final Call call) {
|
||||||
if (call != null) {
|
if (call != null) {
|
||||||
mVoicemailCount.setVisibility(View.GONE);
|
|
||||||
MediaEncryption mediaEncryption = call.getCurrentParams().getMediaEncryption();
|
MediaEncryption mediaEncryption = call.getCurrentParams().getMediaEncryption();
|
||||||
|
|
||||||
mEncryption.setVisibility(View.VISIBLE);
|
mEncryption.setVisibility(View.VISIBLE);
|
||||||
|
@ -491,7 +423,7 @@ public class StatusFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface MenuClikedListener {
|
public interface StatsClikedListener {
|
||||||
void onMenuCliked();
|
void onStatsClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,367 +0,0 @@
|
||||||
package org.linphone.call;
|
|
||||||
|
|
||||||
/*
|
|
||||||
CallVideoFragment.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.os.Bundle;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.GestureDetector.OnDoubleTapListener;
|
|
||||||
import android.view.GestureDetector.OnGestureListener;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.TextureView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnTouchListener;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import org.linphone.LinphoneManager;
|
|
||||||
import org.linphone.LinphoneService;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.compatibility.CompatibilityScaleGestureDetector;
|
|
||||||
import org.linphone.compatibility.CompatibilityScaleGestureListener;
|
|
||||||
import org.linphone.core.Call;
|
|
||||||
import org.linphone.core.Core;
|
|
||||||
import org.linphone.core.VideoDefinition;
|
|
||||||
import org.linphone.core.tools.Log;
|
|
||||||
import org.linphone.settings.LinphonePreferences;
|
|
||||||
import org.linphone.utils.LinphoneUtils;
|
|
||||||
|
|
||||||
public class CallVideoFragment extends Fragment
|
|
||||||
implements OnGestureListener, OnDoubleTapListener, CompatibilityScaleGestureListener {
|
|
||||||
private TextureView mVideoView;
|
|
||||||
private TextureView mCaptureView;
|
|
||||||
private GestureDetector mGestureDetector;
|
|
||||||
private float mZoomFactor = 1.f;
|
|
||||||
private float mZoomCenterX, mZoomCenterY;
|
|
||||||
private CompatibilityScaleGestureDetector mScaleDetector;
|
|
||||||
private CallActivity mInCallActivity;
|
|
||||||
private int mPreviewX, mPreviewY;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(
|
|
||||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
mVideoView = view.findViewById(R.id.videoSurface);
|
|
||||||
mCaptureView = view.findViewById(R.id.videoCaptureSurface);
|
|
||||||
|
|
||||||
core.setNativeVideoWindowId(mVideoView);
|
|
||||||
core.setNativePreviewWindowId(mCaptureView);
|
|
||||||
|
|
||||||
mVideoView.setOnTouchListener(
|
|
||||||
new OnTouchListener() {
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
if (mScaleDetector != null) {
|
|
||||||
mScaleDetector.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
mGestureDetector.onTouchEvent(event);
|
|
||||||
if (mInCallActivity != null) {
|
|
||||||
mInCallActivity.displayVideoCallControlsIfHidden();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mCaptureView.setOnTouchListener(
|
|
||||||
new OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
|
||||||
switch (motionEvent.getAction()) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
mPreviewX = (int) motionEvent.getX();
|
|
||||||
mPreviewY = (int) motionEvent.getY();
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
int x = (int) motionEvent.getX();
|
|
||||||
int y = (int) motionEvent.getY();
|
|
||||||
RelativeLayout.LayoutParams lp =
|
|
||||||
(RelativeLayout.LayoutParams)
|
|
||||||
mCaptureView.getLayoutParams();
|
|
||||||
lp.addRule(
|
|
||||||
RelativeLayout.ALIGN_PARENT_BOTTOM,
|
|
||||||
0); // Clears the rule, as there is no removeRule until API
|
|
||||||
// 17.
|
|
||||||
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
|
|
||||||
int left = lp.leftMargin + (x - mPreviewX);
|
|
||||||
int top = lp.topMargin + (y - mPreviewY);
|
|
||||||
lp.leftMargin = left;
|
|
||||||
lp.topMargin = top;
|
|
||||||
view.setLayoutParams(lp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mInCallActivity = (CallActivity) getActivity();
|
|
||||||
if (mInCallActivity != null) {
|
|
||||||
mInCallActivity.bindVideoFragment(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resizePreview() {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
if (core.getCallsNb() > 0) {
|
|
||||||
Call call = core.getCurrentCall();
|
|
||||||
if (call == null) {
|
|
||||||
call = core.getCalls()[0];
|
|
||||||
}
|
|
||||||
if (call == null) return;
|
|
||||||
|
|
||||||
DisplayMetrics metrics = new DisplayMetrics();
|
|
||||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
|
||||||
int screenHeight = metrics.heightPixels;
|
|
||||||
int maxHeight =
|
|
||||||
screenHeight / 4; // Let's take at most 1/4 of the screen for the camera preview
|
|
||||||
|
|
||||||
VideoDefinition videoSize =
|
|
||||||
call.getCurrentParams()
|
|
||||||
.getSentVideoDefinition(); // It already takes care of rotation
|
|
||||||
if (videoSize.getWidth() == 0 || videoSize.getHeight() == 0) {
|
|
||||||
Log.w(
|
|
||||||
"[Video Fragment] Couldn't get sent video definition, using default video definition");
|
|
||||||
videoSize = core.getPreferredVideoDefinition();
|
|
||||||
}
|
|
||||||
int width = videoSize.getWidth();
|
|
||||||
int height = videoSize.getHeight();
|
|
||||||
|
|
||||||
Log.d("[Video Fragment] Video height is " + height + ", width is " + width);
|
|
||||||
width = width * maxHeight / height;
|
|
||||||
height = maxHeight;
|
|
||||||
|
|
||||||
if (mCaptureView == null) {
|
|
||||||
Log.e("[Video Fragment] mCaptureView is null !");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RelativeLayout.LayoutParams newLp = new RelativeLayout.LayoutParams(width, height);
|
|
||||||
newLp.addRule(
|
|
||||||
RelativeLayout.ALIGN_PARENT_BOTTOM,
|
|
||||||
1); // Clears the rule, as there is no removeRule until API 17.
|
|
||||||
newLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 1);
|
|
||||||
mCaptureView.setLayoutParams(newLp);
|
|
||||||
Log.d("[Video Fragment] Video preview size set to " + width + "x" + height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void switchCamera() {
|
|
||||||
try {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
String currentDevice = core.getVideoDevice();
|
|
||||||
String[] devices = core.getVideoDevicesList();
|
|
||||||
int index = 0;
|
|
||||||
for (String d : devices) {
|
|
||||||
if (d.equals(currentDevice)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
String newDevice;
|
|
||||||
if (index == 1) newDevice = devices[0];
|
|
||||||
else if (devices.length > 1) newDevice = devices[1];
|
|
||||||
else newDevice = devices[index];
|
|
||||||
core.setVideoDevice(newDevice);
|
|
||||||
|
|
||||||
LinphoneManager.getCallManager().updateCall();
|
|
||||||
} catch (ArithmeticException ae) {
|
|
||||||
Log.e("[Video Fragment] Cannot swtich camera : no camera");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
if (LinphonePreferences.instance().isOverlayEnabled()) {
|
|
||||||
LinphoneService.instance().destroyOverlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
mGestureDetector = new GestureDetector(mInCallActivity, this);
|
|
||||||
mScaleDetector = new CompatibilityScaleGestureDetector(mInCallActivity);
|
|
||||||
mScaleDetector.setOnScaleListener(this);
|
|
||||||
|
|
||||||
resizePreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
if (LinphonePreferences.instance().isOverlayEnabled()
|
|
||||||
&& 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onScale(CompatibilityScaleGestureDetector detector) {
|
|
||||||
mZoomFactor *= detector.getScaleFactor();
|
|
||||||
// Don't let the object get too small or too large.
|
|
||||||
// Zoom to make the video fill the screen vertically
|
|
||||||
float portraitZoomFactor =
|
|
||||||
((float) mVideoView.getHeight()) / (float) ((3 * mVideoView.getWidth()) / 4);
|
|
||||||
// Zoom to make the video fill the screen horizontally
|
|
||||||
float landscapeZoomFactor =
|
|
||||||
((float) mVideoView.getWidth()) / (float) ((3 * mVideoView.getHeight()) / 4);
|
|
||||||
mZoomFactor =
|
|
||||||
Math.max(
|
|
||||||
0.1f,
|
|
||||||
Math.min(mZoomFactor, Math.max(portraitZoomFactor, landscapeZoomFactor)));
|
|
||||||
|
|
||||||
Call currentCall = LinphoneManager.getCore().getCurrentCall();
|
|
||||||
if (currentCall != null) {
|
|
||||||
currentCall.zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
|
||||||
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) {
|
|
||||||
mZoomCenterX += 0.01;
|
|
||||||
} else if (distanceX < 0 && mZoomCenterX > 0) {
|
|
||||||
mZoomCenterX -= 0.01;
|
|
||||||
}
|
|
||||||
if (distanceY < 0 && mZoomCenterY < 1) {
|
|
||||||
mZoomCenterY += 0.01;
|
|
||||||
} else if (distanceY > 0 && mZoomCenterY > 0) {
|
|
||||||
mZoomCenterY -= 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mZoomCenterX > 1) mZoomCenterX = 1;
|
|
||||||
if (mZoomCenterX < 0) mZoomCenterX = 0;
|
|
||||||
if (mZoomCenterY > 1) mZoomCenterY = 1;
|
|
||||||
if (mZoomCenterY < 0) mZoomCenterY = 0;
|
|
||||||
|
|
||||||
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDoubleTap(MotionEvent e) {
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) {
|
|
||||||
if (mZoomFactor == 1.f) {
|
|
||||||
// Zoom to make the video fill the screen vertically
|
|
||||||
float portraitZoomFactor =
|
|
||||||
((float) mVideoView.getHeight())
|
|
||||||
/ (float) ((3 * mVideoView.getWidth()) / 4);
|
|
||||||
// Zoom to make the video fill the screen horizontally
|
|
||||||
float landscapeZoomFactor =
|
|
||||||
((float) mVideoView.getWidth())
|
|
||||||
/ (float) ((3 * mVideoView.getHeight()) / 4);
|
|
||||||
|
|
||||||
mZoomFactor = Math.max(portraitZoomFactor, landscapeZoomFactor);
|
|
||||||
} else {
|
|
||||||
resetZoom();
|
|
||||||
}
|
|
||||||
|
|
||||||
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetZoom() {
|
|
||||||
mZoomFactor = 1.f;
|
|
||||||
mZoomCenterX = mZoomCenterY = 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
mInCallActivity = null;
|
|
||||||
|
|
||||||
mCaptureView = null;
|
|
||||||
if (mVideoView != null) {
|
|
||||||
mVideoView.setOnTouchListener(null);
|
|
||||||
mVideoView = null;
|
|
||||||
}
|
|
||||||
if (mGestureDetector != null) {
|
|
||||||
mGestureDetector.setOnDoubleTapListener(null);
|
|
||||||
mGestureDetector = null;
|
|
||||||
}
|
|
||||||
if (mScaleDetector != null) {
|
|
||||||
mScaleDetector.destroy();
|
|
||||||
mScaleDetector = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDown(MotionEvent e) {
|
|
||||||
return true; // Needed to make the GestureDetector working
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDoubleTapEvent(MotionEvent e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLongPress(MotionEvent e) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onShowPress(MotionEvent e) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSingleTapUp(MotionEvent e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
169
app/src/main/java/org/linphone/call/VideoZoomHelper.java
Normal file
169
app/src/main/java/org/linphone/call/VideoZoomHelper.java
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
package org.linphone.call;
|
||||||
|
|
||||||
|
/*
|
||||||
|
VideoZoomHelper.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.GestureDetector;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.compatibility.CompatibilityScaleGestureDetector;
|
||||||
|
import org.linphone.compatibility.CompatibilityScaleGestureListener;
|
||||||
|
import org.linphone.core.Call;
|
||||||
|
import org.linphone.core.Core;
|
||||||
|
import org.linphone.utils.LinphoneUtils;
|
||||||
|
|
||||||
|
public class VideoZoomHelper extends GestureDetector.SimpleOnGestureListener
|
||||||
|
implements CompatibilityScaleGestureListener {
|
||||||
|
private View mVideoView;
|
||||||
|
private Context mContext;
|
||||||
|
private GestureDetector mGestureDetector;
|
||||||
|
private float mZoomFactor = 1.f;
|
||||||
|
private float mZoomCenterX, mZoomCenterY;
|
||||||
|
private CompatibilityScaleGestureDetector mScaleDetector;
|
||||||
|
|
||||||
|
public VideoZoomHelper(Context context, View videoView) {
|
||||||
|
mContext = context;
|
||||||
|
mGestureDetector = new GestureDetector(mContext, this);
|
||||||
|
mScaleDetector = new CompatibilityScaleGestureDetector(mContext);
|
||||||
|
mScaleDetector.setOnScaleListener(this);
|
||||||
|
|
||||||
|
mVideoView = videoView;
|
||||||
|
mVideoView.setOnTouchListener(
|
||||||
|
new View.OnTouchListener() {
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
float currentZoomFactor = mZoomFactor;
|
||||||
|
if (mScaleDetector != null) {
|
||||||
|
mScaleDetector.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
if (currentZoomFactor != mZoomFactor) {
|
||||||
|
// We did scale, prevent touch event from going further
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean touch = mGestureDetector.onTouchEvent(event);
|
||||||
|
// If true, gesture detected, prevent touch event from going further
|
||||||
|
// Otherwise it seems we didn't use event,
|
||||||
|
// allow it to be dispatched somewhere else
|
||||||
|
return touch;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onScale(CompatibilityScaleGestureDetector detector) {
|
||||||
|
mZoomFactor *= detector.getScaleFactor();
|
||||||
|
// Don't let the object get too small or too large.
|
||||||
|
// Zoom to make the video fill the screen vertically
|
||||||
|
float portraitZoomFactor =
|
||||||
|
((float) mVideoView.getHeight()) / (float) ((3 * mVideoView.getWidth()) / 4);
|
||||||
|
// Zoom to make the video fill the screen horizontally
|
||||||
|
float landscapeZoomFactor =
|
||||||
|
((float) mVideoView.getWidth()) / (float) ((3 * mVideoView.getHeight()) / 4);
|
||||||
|
mZoomFactor =
|
||||||
|
Math.max(
|
||||||
|
0.1f,
|
||||||
|
Math.min(mZoomFactor, Math.max(portraitZoomFactor, landscapeZoomFactor)));
|
||||||
|
|
||||||
|
Call currentCall = LinphoneManager.getCore().getCurrentCall();
|
||||||
|
if (currentCall != null) {
|
||||||
|
currentCall.zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
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) {
|
||||||
|
mZoomCenterX += 0.01;
|
||||||
|
} else if (distanceX < 0 && mZoomCenterX > 0) {
|
||||||
|
mZoomCenterX -= 0.01;
|
||||||
|
}
|
||||||
|
if (distanceY < 0 && mZoomCenterY < 1) {
|
||||||
|
mZoomCenterY += 0.01;
|
||||||
|
} else if (distanceY > 0 && mZoomCenterY > 0) {
|
||||||
|
mZoomCenterY -= 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mZoomCenterX > 1) mZoomCenterX = 1;
|
||||||
|
if (mZoomCenterX < 0) mZoomCenterX = 0;
|
||||||
|
if (mZoomCenterY > 1) mZoomCenterY = 1;
|
||||||
|
if (mZoomCenterY < 0) mZoomCenterY = 0;
|
||||||
|
|
||||||
|
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) {
|
||||||
|
if (mZoomFactor == 1.f) {
|
||||||
|
// Zoom to make the video fill the screen vertically
|
||||||
|
float portraitZoomFactor =
|
||||||
|
((float) mVideoView.getHeight())
|
||||||
|
/ (float) ((3 * mVideoView.getWidth()) / 4);
|
||||||
|
// Zoom to make the video fill the screen horizontally
|
||||||
|
float landscapeZoomFactor =
|
||||||
|
((float) mVideoView.getWidth())
|
||||||
|
/ (float) ((3 * mVideoView.getHeight()) / 4);
|
||||||
|
|
||||||
|
mZoomFactor = Math.max(portraitZoomFactor, landscapeZoomFactor);
|
||||||
|
} else {
|
||||||
|
resetZoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
mContext = null;
|
||||||
|
|
||||||
|
if (mVideoView != null) {
|
||||||
|
mVideoView.setOnTouchListener(null);
|
||||||
|
mVideoView = null;
|
||||||
|
}
|
||||||
|
if (mGestureDetector != null) {
|
||||||
|
mGestureDetector.setOnDoubleTapListener(null);
|
||||||
|
mGestureDetector = null;
|
||||||
|
}
|
||||||
|
if (mScaleDetector != null) {
|
||||||
|
mScaleDetector.destroy();
|
||||||
|
mScaleDetector = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetZoom() {
|
||||||
|
mZoomFactor = 1.f;
|
||||||
|
mZoomCenterX = mZoomCenterY = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
import static org.linphone.compatibility.Compatibility.CHAT_NOTIFICATIONS_GROUP;
|
import static org.linphone.compatibility.Compatibility.CHAT_NOTIFICATIONS_GROUP;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.FragmentTransaction;
|
import android.app.FragmentTransaction;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
|
@ -30,10 +31,12 @@ import android.app.PendingIntent;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.notifications.Notifiable;
|
import org.linphone.notifications.Notifiable;
|
||||||
import org.linphone.notifications.NotifiableMessage;
|
import org.linphone.notifications.NotifiableMessage;
|
||||||
|
|
||||||
|
@ -260,4 +263,14 @@ class ApiTwentySixPlus {
|
||||||
FragmentTransaction transaction, boolean allowed) {
|
FragmentTransaction transaction, boolean allowed) {
|
||||||
transaction.setReorderingAllowed(allowed);
|
transaction.setReorderingAllowed(allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void enterPipMode(Activity activity) {
|
||||||
|
boolean supportsPip =
|
||||||
|
activity.getPackageManager()
|
||||||
|
.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
|
||||||
|
Log.i("[Call] Is picture in picture supported: " + supportsPip);
|
||||||
|
if (supportsPip) {
|
||||||
|
activity.enterPictureInPictureMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,7 @@ class ApiTwentyThreePlus {
|
||||||
public static boolean isDoNotDisturbSettingsAccessGranted(Context context) {
|
public static boolean isDoNotDisturbSettingsAccessGranted(Context context) {
|
||||||
NotificationManager notificationManager =
|
NotificationManager notificationManager =
|
||||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
boolean accessGranted = notificationManager.isNotificationPolicyAccessGranted();
|
return notificationManager.isNotificationPolicyAccessGranted();
|
||||||
return accessGranted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDoNotDisturbPolicyAllowingRinging(
|
public static boolean isDoNotDisturbPolicyAllowingRinging(
|
||||||
|
|
|
@ -256,4 +256,10 @@ public class Compatibility {
|
||||||
ApiTwentyFivePlus.updateShortcuts(context);
|
ApiTwentyFivePlus.updateShortcuts(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void enterPipMode(Activity activity) {
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
|
||||||
|
ApiTwentySixPlus.enterPipMode(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ public class ContactDetailsFragment extends Fragment implements ContactsUpdatedL
|
||||||
controls.removeAllViews();
|
controls.removeAllViews();
|
||||||
for (LinphoneNumberOrAddress noa : mContact.getNumbersOrAddresses()) {
|
for (LinphoneNumberOrAddress noa : mContact.getNumbersOrAddresses()) {
|
||||||
boolean skip;
|
boolean skip;
|
||||||
View v = inflater.inflate(R.layout.contact_control_row, null);
|
View v = inflater.inflate(R.layout.contact_control_cell, null);
|
||||||
|
|
||||||
String value = noa.getValue();
|
String value = noa.getValue();
|
||||||
String displayedNumberOrAddress = value;
|
String displayedNumberOrAddress = value;
|
||||||
|
|
|
@ -597,7 +597,7 @@ public class ContactEditorFragment extends Fragment {
|
||||||
final LinphoneNumberOrAddress nounoa = tempNounoa;
|
final LinphoneNumberOrAddress nounoa = tempNounoa;
|
||||||
mNumbersAndAddresses.add(nounoa);
|
mNumbersAndAddresses.add(nounoa);
|
||||||
|
|
||||||
final View view = mInflater.inflate(R.layout.contact_edit_row, null);
|
final View view = mInflater.inflate(R.layout.contact_edit_cell, null);
|
||||||
|
|
||||||
final EditText noa = view.findViewById(R.id.numoraddr);
|
final EditText noa = view.findViewById(R.id.numoraddr);
|
||||||
if (!isSIP) {
|
if (!isSIP) {
|
||||||
|
@ -641,7 +641,7 @@ public class ContactEditorFragment extends Fragment {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
private void addEmptyRowToAllowNewNumberOrAddress(
|
private void addEmptyRowToAllowNewNumberOrAddress(
|
||||||
final LinearLayout controls, final boolean isSip) {
|
final LinearLayout controls, final boolean isSip) {
|
||||||
final View view = mInflater.inflate(R.layout.contact_edit_row, null);
|
final View view = mInflater.inflate(R.layout.contact_edit_cell, null);
|
||||||
final LinphoneNumberOrAddress nounoa = new LinphoneNumberOrAddress(null, isSip);
|
final LinphoneNumberOrAddress nounoa = new LinphoneNumberOrAddress(null, isSip);
|
||||||
|
|
||||||
final EditText noa = view.findViewById(R.id.numoraddr);
|
final EditText noa = view.findViewById(R.id.numoraddr);
|
||||||
|
|
236
app/src/main/java/org/linphone/fragments/StatusBarFragment.java
Normal file
236
app/src/main/java/org/linphone/fragments/StatusBarFragment.java
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
package org.linphone.fragments;
|
||||||
|
|
||||||
|
/*
|
||||||
|
StatusBarFragment.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.Context;
|
||||||
|
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.TextView;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.Content;
|
||||||
|
import org.linphone.core.Core;
|
||||||
|
import org.linphone.core.CoreListenerStub;
|
||||||
|
import org.linphone.core.Event;
|
||||||
|
import org.linphone.core.ProxyConfig;
|
||||||
|
import org.linphone.core.RegistrationState;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
|
|
||||||
|
public class StatusBarFragment extends Fragment {
|
||||||
|
private TextView mStatusText, mVoicemailCount;
|
||||||
|
private ImageView mStatusLed;
|
||||||
|
private ImageView mVoicemail;
|
||||||
|
private CoreListenerStub mListener;
|
||||||
|
private MenuClikedListener mMenuListener;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(
|
||||||
|
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.status_bar, container, false);
|
||||||
|
|
||||||
|
mStatusText = view.findViewById(R.id.status_text);
|
||||||
|
mStatusLed = view.findViewById(R.id.status_led);
|
||||||
|
ImageView menu = view.findViewById(R.id.side_menu_button);
|
||||||
|
mVoicemail = view.findViewById(R.id.voicemail);
|
||||||
|
mVoicemailCount = view.findViewById(R.id.voicemail_count);
|
||||||
|
|
||||||
|
mMenuListener = null;
|
||||||
|
menu.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();
|
||||||
|
|
||||||
|
mListener =
|
||||||
|
new CoreListenerStub() {
|
||||||
|
@Override
|
||||||
|
public void onRegistrationStateChanged(
|
||||||
|
final Core core,
|
||||||
|
final ProxyConfig proxy,
|
||||||
|
final RegistrationState state,
|
||||||
|
String smessage) {
|
||||||
|
if (core.getProxyConfigList() == null) {
|
||||||
|
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
||||||
|
mStatusText.setText(getString(R.string.no_account));
|
||||||
|
} else {
|
||||||
|
mStatusLed.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core.getDefaultProxyConfig() != null
|
||||||
|
&& core.getDefaultProxyConfig().equals(proxy)) {
|
||||||
|
mStatusLed.setImageResource(getStatusIconResource(state));
|
||||||
|
mStatusText.setText(getStatusIconText(state));
|
||||||
|
} else if (core.getDefaultProxyConfig() == null) {
|
||||||
|
mStatusLed.setImageResource(getStatusIconResource(state));
|
||||||
|
mStatusText.setText(getStatusIconText(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mStatusText.setOnClickListener(
|
||||||
|
new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core != null) {
|
||||||
|
core.refreshRegisters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IllegalStateException ise) {
|
||||||
|
Log.e(ise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotifyReceived(
|
||||||
|
Core core, Event ev, String eventName, Content content) {
|
||||||
|
|
||||||
|
if (!content.getType().equals("application")) return;
|
||||||
|
if (!content.getSubtype().equals("simple-message-summary")) return;
|
||||||
|
|
||||||
|
if (content.getSize() == 0) return;
|
||||||
|
|
||||||
|
int unreadCount = 0;
|
||||||
|
String data = content.getStringBuffer().toLowerCase();
|
||||||
|
String[] voiceMail = data.split("voice-message: ");
|
||||||
|
if (voiceMail.length >= 2) {
|
||||||
|
final String[] intToParse = voiceMail[1].split("/", 0);
|
||||||
|
try {
|
||||||
|
unreadCount = Integer.parseInt(intToParse[0]);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
Log.e("[Status Fragment] " + nfe);
|
||||||
|
}
|
||||||
|
if (unreadCount > 0) {
|
||||||
|
mVoicemailCount.setText(String.valueOf(unreadCount));
|
||||||
|
mVoicemail.setVisibility(View.VISIBLE);
|
||||||
|
mVoicemailCount.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mVoicemail.setVisibility(View.GONE);
|
||||||
|
mVoicemailCount.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core != null) {
|
||||||
|
core.addListener(mListener);
|
||||||
|
ProxyConfig lpc = core.getDefaultProxyConfig();
|
||||||
|
if (lpc != null) {
|
||||||
|
mListener.onRegistrationStateChanged(core, lpc, lpc.getState(), null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mStatusText.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core != null) {
|
||||||
|
core.removeListener(mListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuListener(MenuClikedListener listener) {
|
||||||
|
mMenuListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateSliderContent() {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
if (core != null) {
|
||||||
|
mVoicemailCount.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
if (core.getProxyConfigList().length == 0) {
|
||||||
|
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
||||||
|
mStatusText.setText(getString(R.string.no_account));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getStatusIconResource(RegistrationState state) {
|
||||||
|
try {
|
||||||
|
Core core = LinphoneManager.getCore();
|
||||||
|
boolean defaultAccountConnected =
|
||||||
|
(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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStatusIconText(RegistrationState state) {
|
||||||
|
Context context = getActivity();
|
||||||
|
try {
|
||||||
|
if (state == RegistrationState.Ok
|
||||||
|
&& LinphoneManager.getCore().getDefaultProxyConfig().getState()
|
||||||
|
== RegistrationState.Ok) {
|
||||||
|
return context.getString(R.string.status_connected);
|
||||||
|
} else if (state == RegistrationState.Progress) {
|
||||||
|
return context.getString(R.string.status_in_progress);
|
||||||
|
} else if (state == RegistrationState.Failed) {
|
||||||
|
return context.getString(R.string.status_error);
|
||||||
|
} else {
|
||||||
|
return context.getString(R.string.status_not_connected);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getString(R.string.status_not_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MenuClikedListener {
|
||||||
|
void onMenuCliked();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package org.linphone.receivers;
|
|
||||||
|
|
||||||
/*
|
|
||||||
AccountEnableReceiver.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.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.util.Log;
|
|
||||||
import org.linphone.settings.LinphonePreferences;
|
|
||||||
|
|
||||||
public class AccountEnableReceiver extends BroadcastReceiver {
|
|
||||||
private static final String TAG = "AccountEnableReceiver";
|
|
||||||
private static final String FIELD_ID = "id";
|
|
||||||
private static final String FIELD_ACTIVE = "active";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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=" + prefsAccountIndex + ",enable=" + enable);
|
|
||||||
if (prefsAccountIndex < 0
|
|
||||||
|| prefsAccountIndex >= LinphonePreferences.instance().getAccountCount()) return;
|
|
||||||
LinphonePreferences.instance().setAccountEnabled(prefsAccountIndex, enable);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,377 +0,0 @@
|
||||||
package org.linphone.receivers;
|
|
||||||
/*
|
|
||||||
BluetoothManager.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.bluetooth.BluetoothAdapter;
|
|
||||||
import android.bluetooth.BluetoothAssignedNumbers;
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothHeadset;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import java.util.List;
|
|
||||||
import org.linphone.LinphoneManager;
|
|
||||||
import org.linphone.LinphoneService;
|
|
||||||
import org.linphone.core.tools.Log;
|
|
||||||
|
|
||||||
public class BluetoothManager extends BroadcastReceiver {
|
|
||||||
private Context mContext;
|
|
||||||
private AudioManager mAudioManager;
|
|
||||||
private BluetoothAdapter mBluetoothAdapter;
|
|
||||||
private BluetoothHeadset mBluetoothHeadset;
|
|
||||||
private BluetoothDevice mBluetoothDevice;
|
|
||||||
private BluetoothProfile.ServiceListener mProfileListener;
|
|
||||||
private boolean mIsBluetoothConnected;
|
|
||||||
private boolean mIsScoConnected;
|
|
||||||
|
|
||||||
public BluetoothManager() {
|
|
||||||
mIsBluetoothConnected = false;
|
|
||||||
if (!ensureInit()) {
|
|
||||||
android.util.Log.w(
|
|
||||||
"BluetoothManager",
|
|
||||||
"[Bluetooth] Manager tried to init but LinphoneService not ready yet...");
|
|
||||||
}
|
|
||||||
initBluetooth();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BluetoothManager getInstance() {
|
|
||||||
if (LinphoneService.isReady()) {
|
|
||||||
return LinphoneService.instance().getBluetoothManager();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initBluetooth() {
|
|
||||||
if (!ensureInit()) {
|
|
||||||
android.util.Log.w(
|
|
||||||
"BluetoothManager",
|
|
||||||
"[Bluetooth] Manager tried to init bluetooth but LinphoneService not ready yet...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addCategory(
|
|
||||||
BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY
|
|
||||||
+ "."
|
|
||||||
+ BluetoothAssignedNumbers.PLANTRONICS);
|
|
||||||
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
|
||||||
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
|
|
||||||
filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
|
||||||
mContext.registerReceiver(this, filter);
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] Receiver started");
|
|
||||||
|
|
||||||
startBluetooth();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startBluetooth() {
|
|
||||||
if (mIsBluetoothConnected) {
|
|
||||||
android.util.Log.e("BluetoothManager", "[Bluetooth] Already started, skipping...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
|
|
||||||
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
|
|
||||||
if (mProfileListener != null) {
|
|
||||||
android.util.Log.w(
|
|
||||||
"BluetoothManager",
|
|
||||||
"[Bluetooth] Headset profile was already opened, let's close it");
|
|
||||||
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
|
||||||
}
|
|
||||||
|
|
||||||
mProfileListener =
|
|
||||||
new BluetoothProfile.ServiceListener() {
|
|
||||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager", "[Bluetooth] Headset connected");
|
|
||||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
|
||||||
mIsBluetoothConnected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onServiceDisconnected(int profile) {
|
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
|
||||||
mBluetoothHeadset = null;
|
|
||||||
mIsBluetoothConnected = false;
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager", "[Bluetooth] Headset disconnected");
|
|
||||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
boolean success =
|
|
||||||
mBluetoothAdapter.getProfileProxy(
|
|
||||||
mContext, mProfileListener, BluetoothProfile.HEADSET);
|
|
||||||
if (!success) {
|
|
||||||
android.util.Log.e("BluetoothManager", "[Bluetooth] getProfileProxy failed !");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
android.util.Log.w("BluetoothManager", "[Bluetooth] Interface disabled on device");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshCallView() {
|
|
||||||
LinphoneManager.getCallManager().refreshInCallActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean ensureInit() {
|
|
||||||
if (mBluetoothAdapter == null) {
|
|
||||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
}
|
|
||||||
if (mContext == null) {
|
|
||||||
if (LinphoneService.isReady()) {
|
|
||||||
mContext = LinphoneService.instance().getApplicationContext();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mContext != null && mAudioManager == null) {
|
|
||||||
mAudioManager = ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean routeAudioToBluetooth() {
|
|
||||||
ensureInit();
|
|
||||||
|
|
||||||
if (mBluetoothAdapter != null
|
|
||||||
&& mBluetoothAdapter.isEnabled()
|
|
||||||
&& mAudioManager != null
|
|
||||||
&& mAudioManager.isBluetoothScoAvailableOffCall()) {
|
|
||||||
if (isBluetoothHeadsetAvailable()) {
|
|
||||||
if (mAudioManager != null && !mAudioManager.isBluetoothScoOn()) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] SCO off, let's start it");
|
|
||||||
mAudioManager.setBluetoothScoOn(true);
|
|
||||||
mAudioManager.startBluetoothSco();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack to ensure bluetooth sco is really running
|
|
||||||
boolean ok = isUsingBluetoothAudioRoute();
|
|
||||||
int retries = 0;
|
|
||||||
while (!ok && retries < 5) {
|
|
||||||
retries++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAudioManager != null) {
|
|
||||||
mAudioManager.setBluetoothScoOn(true);
|
|
||||||
mAudioManager.startBluetoothSco();
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = isUsingBluetoothAudioRoute();
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
if (retries > 0) {
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager",
|
|
||||||
"[Bluetooth] Audio route ok after " + retries + " retries");
|
|
||||||
} else {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] Audio route ok");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] Audio route still not ok...");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUsingBluetoothAudioRoute() {
|
|
||||||
return mBluetoothHeadset != null
|
|
||||||
&& mBluetoothHeadset.isAudioConnected(mBluetoothDevice)
|
|
||||||
&& mIsScoConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBluetoothHeadsetAvailable() {
|
|
||||||
ensureInit();
|
|
||||||
if (mBluetoothAdapter != null
|
|
||||||
&& mBluetoothAdapter.isEnabled()
|
|
||||||
&& mAudioManager != null
|
|
||||||
&& mAudioManager.isBluetoothScoAvailableOffCall()) {
|
|
||||||
boolean isHeadsetConnected = false;
|
|
||||||
if (mBluetoothHeadset != null) {
|
|
||||||
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
|
|
||||||
mBluetoothDevice = null;
|
|
||||||
for (final BluetoothDevice dev : devices) {
|
|
||||||
if (mBluetoothHeadset.getConnectionState(dev)
|
|
||||||
== BluetoothHeadset.STATE_CONNECTED) {
|
|
||||||
mBluetoothDevice = dev;
|
|
||||||
isHeadsetConnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager",
|
|
||||||
isHeadsetConnected
|
|
||||||
? "[Bluetooth] Headset found, bluetooth audio route available"
|
|
||||||
: "[Bluetooth] No headset found, bluetooth audio route unavailable");
|
|
||||||
}
|
|
||||||
return isHeadsetConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disableBluetoothSCO() {
|
|
||||||
if (mAudioManager != null && mAudioManager.isBluetoothScoOn()) {
|
|
||||||
mAudioManager.stopBluetoothSco();
|
|
||||||
mAudioManager.setBluetoothScoOn(false);
|
|
||||||
|
|
||||||
// Hack to ensure bluetooth sco is really stopped
|
|
||||||
int retries = 0;
|
|
||||||
while (mIsScoConnected && retries < 10) {
|
|
||||||
retries++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
mAudioManager.stopBluetoothSco();
|
|
||||||
mAudioManager.setBluetoothScoOn(false);
|
|
||||||
}
|
|
||||||
android.util.Log.w("BluetoothManager", "[Bluetooth] SCO disconnected!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopBluetooth() {
|
|
||||||
android.util.Log.w("BluetoothManager", "[Bluetooth] Stopping...");
|
|
||||||
mIsBluetoothConnected = false;
|
|
||||||
|
|
||||||
disableBluetoothSCO();
|
|
||||||
|
|
||||||
if (mBluetoothAdapter != null && mProfileListener != null && mBluetoothHeadset != null) {
|
|
||||||
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
|
||||||
mProfileListener = null;
|
|
||||||
}
|
|
||||||
mBluetoothDevice = null;
|
|
||||||
|
|
||||||
android.util.Log.w("BluetoothManager", "[Bluetooth] Stopped!");
|
|
||||||
|
|
||||||
if (LinphoneService.isReady()) {
|
|
||||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshCallView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
try {
|
|
||||||
stopBluetooth();
|
|
||||||
|
|
||||||
try {
|
|
||||||
mContext.unregisterReceiver(this);
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] Receiver stopped");
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
android.util.Log.e("BluetoothManager", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!LinphoneService.isReady()) return;
|
|
||||||
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {
|
|
||||||
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
|
||||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] SCO state: connected");
|
|
||||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
|
||||||
mIsScoConnected = true;
|
|
||||||
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] SCO state: disconnected");
|
|
||||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER);
|
|
||||||
mIsScoConnected = false;
|
|
||||||
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] SCO state: connecting");
|
|
||||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
|
||||||
mIsScoConnected = true;
|
|
||||||
} else {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] SCO state: " + state);
|
|
||||||
}
|
|
||||||
refreshCallView();
|
|
||||||
} else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
|
|
||||||
int state =
|
|
||||||
intent.getIntExtra(
|
|
||||||
BluetoothAdapter.EXTRA_CONNECTION_STATE,
|
|
||||||
BluetoothAdapter.STATE_DISCONNECTED);
|
|
||||||
if (state == 0) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] State: disconnected");
|
|
||||||
stopBluetooth();
|
|
||||||
} else if (state == 2) {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] State: connected");
|
|
||||||
startBluetooth();
|
|
||||||
} else {
|
|
||||||
android.util.Log.d("BluetoothManager", "[Bluetooth] State: " + state);
|
|
||||||
}
|
|
||||||
} else if (intent.getAction()
|
|
||||||
.equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
|
|
||||||
String command =
|
|
||||||
intent.getExtras()
|
|
||||||
.getString(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
|
|
||||||
// int type =
|
|
||||||
// intent.getExtras().getInt(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE);
|
|
||||||
|
|
||||||
Object[] args =
|
|
||||||
(Object[])
|
|
||||||
intent.getExtras()
|
|
||||||
.get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
|
|
||||||
if (args.length <= 0) {
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager", "[Bluetooth] Event: " + command + ", no args");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String eventName = (args[0]).toString();
|
|
||||||
if (eventName.equals("BUTTON") && args.length >= 3) {
|
|
||||||
String buttonID = args[1].toString();
|
|
||||||
String mode = args[2].toString();
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager",
|
|
||||||
"[Bluetooth] Event: "
|
|
||||||
+ command
|
|
||||||
+ " : "
|
|
||||||
+ eventName
|
|
||||||
+ ", id = "
|
|
||||||
+ buttonID
|
|
||||||
+ " ("
|
|
||||||
+ mode
|
|
||||||
+ ")");
|
|
||||||
} else {
|
|
||||||
android.util.Log.d(
|
|
||||||
"BluetoothManager", "[Bluetooth] Event: " + command + " : " + eventName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package org.linphone.receivers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
BluetoothReceiver.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.bluetooth.BluetoothHeadset;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
|
|
||||||
|
public class BluetoothReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
||||||
|
int state =
|
||||||
|
intent.getIntExtra(
|
||||||
|
BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED);
|
||||||
|
if (state == BluetoothHeadset.STATE_CONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset connected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetConnectionChanged(true);
|
||||||
|
} else if (state == BluetoothHeadset.STATE_DISCONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset disconnected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetConnectionChanged(false);
|
||||||
|
} else {
|
||||||
|
Log.w("[Bluetooth] Bluetooth headset unknown state changed: " + state);
|
||||||
|
}
|
||||||
|
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
|
||||||
|
int state =
|
||||||
|
intent.getIntExtra(
|
||||||
|
BluetoothHeadset.EXTRA_STATE,
|
||||||
|
BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
|
||||||
|
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset audio connected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetAudioConnectionChanged(true);
|
||||||
|
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset audio disconnected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetAudioConnectionChanged(false);
|
||||||
|
} else {
|
||||||
|
Log.w("[Bluetooth] Bluetooth headset unknown audio state changed: " + state);
|
||||||
|
}
|
||||||
|
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
|
||||||
|
int state =
|
||||||
|
intent.getIntExtra(
|
||||||
|
AudioManager.EXTRA_SCO_AUDIO_STATE,
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset SCO connected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetScoConnectionChanged(true);
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset SCO disconnected");
|
||||||
|
LinphoneManager.getAudioManager().bluetoothHeadetScoConnectionChanged(false);
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset SCO connecting");
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_ERROR) {
|
||||||
|
Log.i("[Bluetooth] Bluetooth headset SCO connection error");
|
||||||
|
} else {
|
||||||
|
Log.w("[Bluetooth] Bluetooth headset unknown SCO state changed: " + state);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("[Bluetooth] Bluetooth unknown action: " + action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package org.linphone.receivers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
HeadsetReceiver.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.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.core.tools.Log;
|
||||||
|
|
||||||
|
public class HeadsetReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
|
||||||
|
// This happens when the user plugs a Jack headset to the device for example
|
||||||
|
int state = intent.getIntExtra("state", 0);
|
||||||
|
String name = intent.getStringExtra("name");
|
||||||
|
int hasMicrophone = intent.getIntExtra("microphone", 0);
|
||||||
|
|
||||||
|
if (state == 0) {
|
||||||
|
Log.i("[Headset] Headset disconnected:" + name);
|
||||||
|
} else if (state == 1) {
|
||||||
|
Log.i("[Headset] Headset connected:" + name);
|
||||||
|
if (hasMicrophone == 1) {
|
||||||
|
Log.i("[Headset] Headset " + name + " has a microphone");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("[Headset] Unknow headset plugged state: " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||||
|
LinphoneManager.getCallManager().refreshInCallActions();
|
||||||
|
} else if (action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
|
||||||
|
// This happens when the user disconnect a headset, so we shouldn't play audio loudly
|
||||||
|
Log.i("[Headset] Noisy state detected, most probably a headset has been disconnected");
|
||||||
|
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||||
|
LinphoneManager.getCallManager().refreshInCallActions();
|
||||||
|
} else {
|
||||||
|
Log.w("[Headset] Unknow action: " + action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
package org.linphone.receivers;
|
|
||||||
|
|
||||||
/*
|
|
||||||
HookReceiver.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.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import org.linphone.LinphoneManager;
|
|
||||||
import org.linphone.core.tools.Log;
|
|
||||||
|
|
||||||
public class HookReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (isOrderedBroadcast()) abortBroadcast();
|
|
||||||
Bundle extras = intent.getExtras();
|
|
||||||
boolean handsetOn = extras.getBoolean("hookoff");
|
|
||||||
Log.i("[Hook Receiver] Handset " + handsetOn);
|
|
||||||
|
|
||||||
LinphoneManager.getCallManager().setHandsetMode(handsetOn);
|
|
||||||
if (handsetOn) {
|
|
||||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
|
||||||
} else {
|
|
||||||
LinphoneManager.getAudioManager().routeAudioToSpeaker();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package org.linphone.receivers;
|
|
||||||
|
|
||||||
/*
|
|
||||||
OutgoingCallReceiver.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_ACTIVITY_NEW_TASK;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.util.Log;
|
|
||||||
import org.linphone.settings.LinphonePreferences;
|
|
||||||
|
|
||||||
public class OutgoingCallReceiver extends BroadcastReceiver {
|
|
||||||
private static final String TAG = "CallHandler";
|
|
||||||
private static final String ACTION_CALL_LINPHONE = "org.linphone.intent.action.CallLaunched";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
LinphonePreferences mPrefs = LinphonePreferences.instance();
|
|
||||||
Log.e(TAG, "===>>>> Linphone OutgoingCallReceiver ");
|
|
||||||
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
|
|
||||||
Log.e(TAG, "===>>>> Linphone OutgoingCallReceiver : ACTION_NEW_OUTGOING_CALL");
|
|
||||||
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
|
|
||||||
if (mPrefs.getConfig() != null && mPrefs.getNativeDialerCall()) {
|
|
||||||
abortBroadcast();
|
|
||||||
setResultData(null);
|
|
||||||
Intent newIntent = new Intent(ACTION_CALL_LINPHONE);
|
|
||||||
newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
newIntent.putExtra("StartCall", true);
|
|
||||||
newIntent.putExtra("NumberToCall", number);
|
|
||||||
context.startActivity(newIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package org.linphone.receivers;
|
|
||||||
|
|
||||||
/*
|
|
||||||
PhoneStateReceiver.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.content.BroadcastReceiver;
|
|
||||||
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. */
|
|
||||||
public class PhoneStateChangedReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
final String extraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
|
||||||
|
|
||||||
if (!LinphoneService.isReady()) return;
|
|
||||||
|
|
||||||
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(extraState)
|
|
||||||
|| TelephonyManager.EXTRA_STATE_RINGING.equals(extraState)) {
|
|
||||||
LinphoneManager.getInstance().setCallGsmON(true);
|
|
||||||
Core core = LinphoneManager.getCore();
|
|
||||||
if (core != null) {
|
|
||||||
core.pauseAllCalls();
|
|
||||||
}
|
|
||||||
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(extraState)) {
|
|
||||||
LinphoneManager.getInstance().setCallGsmON(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,6 +52,10 @@ public class RecordingsActivity extends MainActivity
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (mAbortCreation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mOnBackPressGoHome = false;
|
mOnBackPressGoHome = false;
|
||||||
mAlwaysHideTabBar = true;
|
mAlwaysHideTabBar = true;
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.linphone.core.TunnelConfig;
|
||||||
import org.linphone.core.VideoActivationPolicy;
|
import org.linphone.core.VideoActivationPolicy;
|
||||||
import org.linphone.core.VideoDefinition;
|
import org.linphone.core.VideoDefinition;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
|
import org.linphone.mediastream.Version;
|
||||||
import org.linphone.purchase.Purchasable;
|
import org.linphone.purchase.Purchasable;
|
||||||
import org.linphone.utils.LinphoneUtils;
|
import org.linphone.utils.LinphoneUtils;
|
||||||
|
|
||||||
|
@ -943,6 +944,11 @@ public class LinphonePreferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOverlayEnabled() {
|
public boolean isOverlayEnabled() {
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API26_O_80)
|
||||||
|
&& mContext.getResources().getBoolean(R.bool.allow_pip_while_video_call)) {
|
||||||
|
// Disable overlay and use PIP feature
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return getConfig().getBool("app", "display_overlay", false);
|
return getConfig().getBool("app", "display_overlay", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.linphone.core.Factory;
|
||||||
import org.linphone.core.PayloadType;
|
import org.linphone.core.PayloadType;
|
||||||
import org.linphone.core.VideoDefinition;
|
import org.linphone.core.VideoDefinition;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
|
import org.linphone.mediastream.Version;
|
||||||
import org.linphone.settings.widget.ListSetting;
|
import org.linphone.settings.widget.ListSetting;
|
||||||
import org.linphone.settings.widget.SettingListenerBase;
|
import org.linphone.settings.widget.SettingListenerBase;
|
||||||
import org.linphone.settings.widget.SwitchSetting;
|
import org.linphone.settings.widget.SwitchSetting;
|
||||||
|
@ -189,6 +190,11 @@ public class VideoSettingsFragment extends SettingsFragment {
|
||||||
mAutoAccept.setChecked(mPrefs.shouldAutomaticallyAcceptVideoRequests());
|
mAutoAccept.setChecked(mPrefs.shouldAutomaticallyAcceptVideoRequests());
|
||||||
|
|
||||||
mOverlay.setChecked(mPrefs.isOverlayEnabled());
|
mOverlay.setChecked(mPrefs.isOverlayEnabled());
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API26_O_80)
|
||||||
|
&& getResources().getBoolean(R.bool.allow_pip_while_video_call)) {
|
||||||
|
// Disable overlay and use PIP feature
|
||||||
|
mOverlay.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
mBandwidth.setValue(mPrefs.getBandwidthLimit());
|
mBandwidth.setValue(mPrefs.getBandwidthLimit());
|
||||||
mBandwidth.setVisibility(
|
mBandwidth.setVisibility(
|
||||||
|
|
|
@ -23,7 +23,13 @@ import static android.media.AudioManager.MODE_RINGTONE;
|
||||||
import static android.media.AudioManager.STREAM_RING;
|
import static android.media.AudioManager.STREAM_RING;
|
||||||
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothHeadset;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -33,6 +39,7 @@ import android.telephony.TelephonyManager;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import org.linphone.LinphoneManager;
|
import org.linphone.LinphoneManager;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
import org.linphone.compatibility.Compatibility;
|
import org.linphone.compatibility.Compatibility;
|
||||||
|
@ -42,7 +49,8 @@ import org.linphone.core.Core;
|
||||||
import org.linphone.core.CoreListenerStub;
|
import org.linphone.core.CoreListenerStub;
|
||||||
import org.linphone.core.EcCalibratorStatus;
|
import org.linphone.core.EcCalibratorStatus;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.receivers.BluetoothManager;
|
import org.linphone.receivers.BluetoothReceiver;
|
||||||
|
import org.linphone.receivers.HeadsetReceiver;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
|
||||||
public class AndroidAudioManager {
|
public class AndroidAudioManager {
|
||||||
|
@ -53,10 +61,16 @@ public class AndroidAudioManager {
|
||||||
private Call mRingingCall;
|
private Call mRingingCall;
|
||||||
private MediaPlayer mRingerPlayer;
|
private MediaPlayer mRingerPlayer;
|
||||||
private final Vibrator mVibrator;
|
private final Vibrator mVibrator;
|
||||||
|
private BluetoothAdapter mBluetoothAdapter;
|
||||||
|
private BluetoothHeadset mBluetoothHeadset;
|
||||||
|
private BluetoothReceiver mBluetoothReceiver;
|
||||||
|
private HeadsetReceiver mHeadsetReceiver;
|
||||||
|
|
||||||
private boolean mIsRinging;
|
private boolean mIsRinging;
|
||||||
private boolean mAudioFocused;
|
private boolean mAudioFocused;
|
||||||
private boolean mEchoTesterIsRunning;
|
private boolean mEchoTesterIsRunning;
|
||||||
|
private boolean mIsBluetoothHeadsetConnected;
|
||||||
|
private boolean mIsBluetoothHeadsetScoConnected;
|
||||||
|
|
||||||
private CoreListenerStub mListener;
|
private CoreListenerStub mListener;
|
||||||
|
|
||||||
|
@ -66,6 +80,8 @@ public class AndroidAudioManager {
|
||||||
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
mEchoTesterIsRunning = false;
|
mEchoTesterIsRunning = false;
|
||||||
|
|
||||||
|
startBluetooth();
|
||||||
|
|
||||||
mListener =
|
mListener =
|
||||||
new CoreListenerStub() {
|
new CoreListenerStub() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,6 +119,15 @@ public class AndroidAudioManager {
|
||||||
// mAudioManager.abandonAudioFocus(null);
|
// mAudioManager.abandonAudioFocus(null);
|
||||||
requestAudioFocus(STREAM_VOICE_CALL);
|
requestAudioFocus(STREAM_VOICE_CALL);
|
||||||
}
|
}
|
||||||
|
if (!mIsBluetoothHeadsetConnected) {
|
||||||
|
if (mContext.getResources().getBoolean(R.bool.isTablet)) {
|
||||||
|
routeAudioToSpeaker();
|
||||||
|
} else {
|
||||||
|
routeAudioToEarPiece();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only register this one when a call is active
|
||||||
|
enableHeadsetReceiver();
|
||||||
}
|
}
|
||||||
} else if (state == Call.State.End || state == Call.State.Error) {
|
} else if (state == Call.State.End || state == Call.State.Error) {
|
||||||
if (core.getCallsNb() == 0) {
|
if (core.getCallsNb() == 0) {
|
||||||
|
@ -118,6 +143,12 @@ public class AndroidAudioManager {
|
||||||
mAudioFocused = false;
|
mAudioFocused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only register this one when a call is active
|
||||||
|
if (mHeadsetReceiver != null) {
|
||||||
|
Log.i("[Audio Manager] Unregistering headset receiver");
|
||||||
|
mContext.unregisterReceiver(mHeadsetReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
TelephonyManager tm =
|
TelephonyManager tm =
|
||||||
(TelephonyManager)
|
(TelephonyManager)
|
||||||
mContext.getSystemService(
|
mContext.getSystemService(
|
||||||
|
@ -137,12 +168,16 @@ public class AndroidAudioManager {
|
||||||
// ringback is heard normally in earpiece or bluetooth receiver.
|
// ringback is heard normally in earpiece or bluetooth receiver.
|
||||||
setAudioManagerInCallMode();
|
setAudioManagerInCallMode();
|
||||||
requestAudioFocus(STREAM_VOICE_CALL);
|
requestAudioFocus(STREAM_VOICE_CALL);
|
||||||
startBluetooth();
|
if (mIsBluetoothHeadsetConnected) {
|
||||||
|
routeAudioToBluetooth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == Call.State.StreamsRunning) {
|
if (state == Call.State.StreamsRunning) {
|
||||||
startBluetooth();
|
|
||||||
setAudioManagerInCallMode();
|
setAudioManagerInCallMode();
|
||||||
|
if (mIsBluetoothHeadsetConnected) {
|
||||||
|
routeAudioToBluetooth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +197,16 @@ public class AndroidAudioManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
if (mBluetoothAdapter != null && mBluetoothHeadset != null) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] Closing HEADSET profile proxy");
|
||||||
|
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
||||||
|
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] Unegistering bluetooth receiver");
|
||||||
|
if (mBluetoothReceiver != null) {
|
||||||
|
mContext.unregisterReceiver(mBluetoothReceiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
if (core != null) {
|
if (core != null) {
|
||||||
core.removeListener(mListener);
|
core.removeListener(mListener);
|
||||||
|
@ -183,7 +228,11 @@ public class AndroidAudioManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAudioRoutedToSpeaker() {
|
public boolean isAudioRoutedToSpeaker() {
|
||||||
return mAudioManager.isSpeakerphoneOn();
|
return mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAudioRoutedToEarpiece() {
|
||||||
|
return !mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Echo cancellation */
|
/* Echo cancellation */
|
||||||
|
@ -263,12 +312,6 @@ public class AndroidAudioManager {
|
||||||
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startBluetooth() {
|
|
||||||
if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
|
||||||
BluetoothManager.getInstance().routeAudioToBluetooth();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestAudioFocus(int stream) {
|
private void requestAudioFocus(int stream) {
|
||||||
if (!mAudioFocused) {
|
if (!mAudioFocused) {
|
||||||
int res =
|
int res =
|
||||||
|
@ -297,10 +340,7 @@ public class AndroidAudioManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mContext.getResources().getBoolean(R.bool.allow_ringing_while_early_media)) {
|
routeAudioToSpeaker();
|
||||||
routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media
|
|
||||||
}
|
|
||||||
|
|
||||||
mAudioManager.setMode(MODE_RINGTONE);
|
mAudioManager.setMode(MODE_RINGTONE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -354,23 +394,14 @@ public class AndroidAudioManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsRinging = false;
|
mIsRinging = false;
|
||||||
if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
|
||||||
if (mContext.getResources().getBoolean(R.bool.isTablet)) {
|
|
||||||
Log.d("[Audio Manager] Stopped ringing, routing back to speaker");
|
|
||||||
routeAudioToSpeaker();
|
|
||||||
} else {
|
|
||||||
Log.d("[Audio Manager] Stopped ringing, routing back to earpiece");
|
|
||||||
routeAudioToEarPiece();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
||||||
Log.w(
|
Log.w("[Audio Manager] Routing audio to " + (speakerOn ? "speaker" : "earpiece"));
|
||||||
"[Audio Manager] Routing audio to "
|
if (mIsBluetoothHeadsetScoConnected) {
|
||||||
+ (speakerOn ? "speaker" : "earpiece")
|
Log.w("[Audio Manager] [Bluetooth] Disabling bluetooth audio route");
|
||||||
+ ", disabling bluetooth audio route");
|
changeBluetoothSco(false);
|
||||||
BluetoothManager.getInstance().disableBluetoothSCO();
|
}
|
||||||
|
|
||||||
mAudioManager.setSpeakerphoneOn(speakerOn);
|
mAudioManager.setSpeakerphoneOn(speakerOn);
|
||||||
}
|
}
|
||||||
|
@ -383,4 +414,187 @@ public class AndroidAudioManager {
|
||||||
i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE,
|
i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE,
|
||||||
AudioManager.FLAG_SHOW_UI);
|
AudioManager.FLAG_SHOW_UI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bluetooth
|
||||||
|
|
||||||
|
public synchronized void bluetoothHeadetConnectionChanged(boolean connected) {
|
||||||
|
mIsBluetoothHeadsetConnected = connected;
|
||||||
|
mAudioManager.setBluetoothScoOn(connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void bluetoothHeadetAudioConnectionChanged(boolean connected) {
|
||||||
|
mIsBluetoothHeadsetScoConnected = connected;
|
||||||
|
mAudioManager.setBluetoothScoOn(connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isBluetoothHeadsetConnected() {
|
||||||
|
return mIsBluetoothHeadsetConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void bluetoothHeadetScoConnectionChanged(boolean connected) {
|
||||||
|
mIsBluetoothHeadsetScoConnected = connected;
|
||||||
|
LinphoneManager.getCallManager().refreshInCallActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isUsingBluetoothAudioRoute() {
|
||||||
|
return mIsBluetoothHeadsetScoConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void routeAudioToBluetooth() {
|
||||||
|
if (!isBluetoothHeadsetConnected()) {
|
||||||
|
Log.w("[Audio Manager] [Bluetooth] No headset connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mAudioManager.getMode() != AudioManager.MODE_IN_COMMUNICATION) {
|
||||||
|
Log.w(
|
||||||
|
"[Audio Manager] [Bluetooth] Changing audio mode to MODE_IN_COMMUNICATION and requesting STREAM_VOICE_CALL focus");
|
||||||
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||||
|
requestAudioFocus(STREAM_VOICE_CALL);
|
||||||
|
}
|
||||||
|
changeBluetoothSco(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void changeBluetoothSco(final boolean enable) {
|
||||||
|
// IT WILL TAKE A CERTAIN NUMBER OF CALLS TO EITHER START/STOP BLUETOOTH SCO FOR IT TO WORK
|
||||||
|
if (enable && mIsBluetoothHeadsetScoConnected) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] SCO already enabled, skipping");
|
||||||
|
return;
|
||||||
|
} else if (!enable && !mIsBluetoothHeadsetScoConnected) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] SCO already disabled, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
boolean resultAcknoledged;
|
||||||
|
int retries = 0;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Thread.sleep(200);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (AndroidAudioManager.this) {
|
||||||
|
if (enable) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Starting SCO: try number "
|
||||||
|
+ retries);
|
||||||
|
mAudioManager.startBluetoothSco();
|
||||||
|
} else {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Stopping SCO: try number "
|
||||||
|
+ retries);
|
||||||
|
mAudioManager.stopBluetoothSco();
|
||||||
|
}
|
||||||
|
resultAcknoledged = isUsingBluetoothAudioRoute() == enable;
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
} while (!resultAcknoledged && retries < 10);
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startBluetooth() {
|
||||||
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
if (mBluetoothAdapter != null) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] Adapter found");
|
||||||
|
if (mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] SCO available off call, continue");
|
||||||
|
} else {
|
||||||
|
Log.w("[Audio Manager] [Bluetooth] SCO not available off call !");
|
||||||
|
}
|
||||||
|
if (mBluetoothAdapter.isEnabled()) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] Adapter enabled");
|
||||||
|
mBluetoothReceiver = new BluetoothReceiver();
|
||||||
|
mIsBluetoothHeadsetConnected = false;
|
||||||
|
mIsBluetoothHeadsetScoConnected = false;
|
||||||
|
|
||||||
|
BluetoothProfile.ServiceListener bluetoothServiceListener =
|
||||||
|
new BluetoothProfile.ServiceListener() {
|
||||||
|
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||||
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
|
Log.i("[Audio Manager] [Bluetooth] HEADSET profile connected");
|
||||||
|
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||||
|
|
||||||
|
List<BluetoothDevice> devices =
|
||||||
|
mBluetoothHeadset.getConnectedDevices();
|
||||||
|
if (devices.size() > 0) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] A device is already connected");
|
||||||
|
bluetoothHeadetConnectionChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Registering bluetooth receiver");
|
||||||
|
|
||||||
|
mContext.registerReceiver(
|
||||||
|
mBluetoothReceiver,
|
||||||
|
new IntentFilter(
|
||||||
|
BluetoothHeadset
|
||||||
|
.ACTION_CONNECTION_STATE_CHANGED));
|
||||||
|
mContext.registerReceiver(
|
||||||
|
mBluetoothReceiver,
|
||||||
|
new IntentFilter(
|
||||||
|
BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));
|
||||||
|
Intent sticky =
|
||||||
|
mContext.registerReceiver(
|
||||||
|
mBluetoothReceiver,
|
||||||
|
new IntentFilter(
|
||||||
|
AudioManager
|
||||||
|
.ACTION_SCO_AUDIO_STATE_UPDATED));
|
||||||
|
int state =
|
||||||
|
sticky.getIntExtra(
|
||||||
|
AudioManager.EXTRA_SCO_AUDIO_STATE,
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
|
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connected");
|
||||||
|
bluetoothHeadetScoConnectionChanged(true);
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO disconnected");
|
||||||
|
bluetoothHeadetScoConnectionChanged(false);
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connecting");
|
||||||
|
} else if (state == AudioManager.SCO_AUDIO_STATE_ERROR) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connection error");
|
||||||
|
} else {
|
||||||
|
Log.w(
|
||||||
|
"[Audio Manager] [Bluetooth] Bluetooth headset unknown SCO state changed: "
|
||||||
|
+ state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(int profile) {
|
||||||
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
|
Log.i(
|
||||||
|
"[Audio Manager] [Bluetooth] HEADSET profile disconnected");
|
||||||
|
mBluetoothHeadset = null;
|
||||||
|
mIsBluetoothHeadsetConnected = false;
|
||||||
|
mIsBluetoothHeadsetScoConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mBluetoothAdapter.getProfileProxy(
|
||||||
|
mContext, bluetoothServiceListener, BluetoothProfile.HEADSET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEADSET
|
||||||
|
|
||||||
|
private void enableHeadsetReceiver() {
|
||||||
|
mHeadsetReceiver = new HeadsetReceiver();
|
||||||
|
|
||||||
|
Log.i("[Audio Manager] Registering headset receiver");
|
||||||
|
mContext.registerReceiver(
|
||||||
|
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
|
||||||
|
mContext.registerReceiver(
|
||||||
|
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_HEADSET_PLUG));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,10 @@ import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.Toast;
|
|
||||||
import org.linphone.LinphoneManager;
|
import org.linphone.LinphoneManager;
|
||||||
import org.linphone.LinphoneService;
|
import org.linphone.LinphoneService;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.Call;
|
||||||
import org.linphone.core.Core;
|
import org.linphone.core.Core;
|
||||||
import org.linphone.core.tools.Log;
|
import org.linphone.core.tools.Log;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
@ -95,12 +95,7 @@ public class Digit extends Button implements AddressAware {
|
||||||
|
|
||||||
private boolean linphoneServiceReady() {
|
private boolean linphoneServiceReady() {
|
||||||
if (!LinphoneService.isReady()) {
|
if (!LinphoneService.isReady()) {
|
||||||
Log.w("Service is not ready while pressing digit");
|
Log.e("[Numpad] Service is not ready while pressing digit");
|
||||||
Toast.makeText(
|
|
||||||
getContext(),
|
|
||||||
getContext().getString(R.string.skipable_error_service_not_ready),
|
|
||||||
Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -112,18 +107,19 @@ public class Digit extends Button implements AddressAware {
|
||||||
Core core = LinphoneManager.getCore();
|
Core core = LinphoneManager.getCore();
|
||||||
core.stopDtmf();
|
core.stopDtmf();
|
||||||
mIsDtmfStarted = false;
|
mIsDtmfStarted = false;
|
||||||
if (core.inCall()) {
|
Call call = core.getCurrentCall();
|
||||||
core.getCurrentCall().sendDtmf(mKeyCode);
|
if (call != null) {
|
||||||
|
call.sendDtmf(mKeyCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAddress != null) {
|
if (mAddress != null) {
|
||||||
int lBegin = mAddress.getSelectionStart();
|
int begin = mAddress.getSelectionStart();
|
||||||
if (lBegin == -1) {
|
if (begin == -1) {
|
||||||
lBegin = mAddress.length();
|
begin = mAddress.length();
|
||||||
}
|
}
|
||||||
if (lBegin >= 0) {
|
if (begin >= 0) {
|
||||||
mAddress.getEditableText().insert(lBegin, String.valueOf(mKeyCode));
|
mAddress.getEditableText().insert(begin, String.valueOf(mKeyCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LinphonePreferences.instance().getDebugPopupAddress() != null
|
if (LinphonePreferences.instance().getDebugPopupAddress() != null
|
||||||
|
@ -212,12 +208,12 @@ public class Digit extends Button implements AddressAware {
|
||||||
|
|
||||||
if (mAddress == null) return true;
|
if (mAddress == null) return true;
|
||||||
|
|
||||||
int lBegin = mAddress.getSelectionStart();
|
int begin = mAddress.getSelectionStart();
|
||||||
if (lBegin == -1) {
|
if (begin == -1) {
|
||||||
lBegin = mAddress.getEditableText().length();
|
begin = mAddress.getEditableText().length();
|
||||||
}
|
}
|
||||||
if (lBegin >= 0) {
|
if (begin >= 0) {
|
||||||
mAddress.getEditableText().insert(lBegin, "+");
|
mAddress.getEditableText().insert(begin, "+");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,21 +31,13 @@ import java.util.Collection;
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
|
|
||||||
public class Numpad extends LinearLayout implements AddressAware {
|
public class Numpad extends LinearLayout implements AddressAware {
|
||||||
|
|
||||||
private final boolean mPlayDtmf;
|
private final boolean mPlayDtmf;
|
||||||
|
|
||||||
public Numpad(Context context, boolean playDtmf) {
|
|
||||||
super(context);
|
|
||||||
mPlayDtmf = playDtmf;
|
|
||||||
LayoutInflater.from(context).inflate(R.layout.numpad, this);
|
|
||||||
setLongClickable(true);
|
|
||||||
onFinishInflate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Numpad(Context context, AttributeSet attrs) {
|
public Numpad(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Numpad);
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Numpad);
|
||||||
mPlayDtmf = 1 == a.getInt(org.linphone.R.styleable.Numpad_play_dtmf, 1);
|
mPlayDtmf = 1 == a.getInt(R.styleable.Numpad_play_dtmf, 1);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
LayoutInflater.from(context).inflate(R.layout.numpad, this);
|
LayoutInflater.from(context).inflate(R.layout.numpad, this);
|
||||||
setLongClickable(true);
|
setLongClickable(true);
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
<bitmap android:src="@drawable/route_bluetooth_default"
|
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||||
android:tint="?attr/drawableTintOverColor"/>
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||||
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
|
</item>
|
||||||
<item android:state_enabled="false">
|
<item android:state_enabled="false">
|
||||||
<bitmap android:src="@drawable/route_bluetooth_default"
|
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||||
android:tint="?attr/drawableTintDisabledColor"/>
|
android:tint="?attr/drawableTintDisabledColor"/>
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
<bitmap android:src="@drawable/route_earpiece_default"
|
<bitmap android:src="@drawable/route_earpiece_default"
|
||||||
android:tint="?attr/drawableTintOverColor"/>
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<bitmap android:src="@drawable/route_earpiece_default"
|
||||||
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
|
</item>
|
||||||
<item android:state_enabled="false">
|
<item android:state_enabled="false">
|
||||||
<bitmap android:src="@drawable/route_earpiece_default"
|
<bitmap android:src="@drawable/route_earpiece_default"
|
||||||
android:tint="?attr/drawableTintDisabledColor"/>
|
android:tint="?attr/drawableTintDisabledColor"/>
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
<bitmap android:src="@drawable/route_speaker_default"
|
<bitmap android:src="@drawable/route_speaker_default"
|
||||||
android:tint="?attr/drawableTintOverColor"/>
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<bitmap android:src="@drawable/route_speaker_default"
|
||||||
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
|
</item>
|
||||||
<item android:state_enabled="false">
|
<item android:state_enabled="false">
|
||||||
<bitmap android:src="@drawable/route_speaker_default"
|
<bitmap android:src="@drawable/route_speaker_default"
|
||||||
android:tint="?attr/drawableTintDisabledColor"/>
|
android:tint="?attr/drawableTintDisabledColor"/>
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
<bitmap android:src="@drawable/routes_default"
|
<bitmap android:src="@drawable/routes_default"
|
||||||
android:tint="?attr/drawableTintOverColor"/>
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<bitmap android:src="@drawable/routes_default"
|
||||||
|
android:tint="?attr/drawableTintOverColor"/>
|
||||||
|
</item>
|
||||||
<item android:state_enabled="false">
|
<item android:state_enabled="false">
|
||||||
<bitmap android:src="@drawable/routes_default"
|
<bitmap android:src="@drawable/routes_default"
|
||||||
android:tint="?attr/drawableTintDisabledColor"/>
|
android:tint="?attr/drawableTintDisabledColor"/>
|
||||||
|
|
|
@ -8,21 +8,19 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<GridLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@color/dark_grey_color"
|
android:background="@color/dark_grey_color"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:padding="20dp"
|
android:columnCount="2"
|
||||||
android:orientation="horizontal">
|
android:padding="20dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
@ -53,10 +51,9 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
@ -75,10 +72,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="left"
|
android:layout_gravity="left"
|
||||||
android:text="@string/about_liblinphone_sdk_version" />
|
android:text="@string/about_liblinphone_sdk_version" />
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -10,66 +10,37 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<FrameLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<TextureView
|
||||||
android:id="@+id/fragmentContainer"
|
android:id="@+id/remote_video_texture"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:orientation="horizontal" />
|
|
||||||
|
<TextureView
|
||||||
|
android:id="@+id/local_preview_texture"
|
||||||
|
android:layout_width="300dp"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentBottom="true" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
android:id="@+id/active_calls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="60dp"
|
android:layout_marginBottom="60dp"
|
||||||
android:layout_marginTop="40dp">
|
android:layout_marginTop="40dp">
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_conference_header" android:visibility="gone" />
|
||||||
android:id="@+id/conference_list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/active_call"
|
android:id="@+id/active_call"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:visibility="visible">
|
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_active_header" />
|
||||||
android:id="@+id/active_call_info"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:alpha="0.8"
|
|
||||||
android:background="?attr/backgroundColor"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/current_contact_name"
|
|
||||||
style="@style/big_contact_name_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="5dp" />
|
|
||||||
|
|
||||||
<Chronometer
|
|
||||||
android:id="@+id/current_call_timer"
|
|
||||||
style="@style/sip_uri_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
remote_pause
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -83,30 +54,7 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_paused_by_remote" android:visibility="gone" />
|
||||||
android:id="@+id/remote_pause"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:alpha="0.9"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/waiting_time" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/call_status_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/call_paused_by_remote" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/pause"
|
android:id="@+id/pause"
|
||||||
|
@ -140,30 +88,6 @@
|
||||||
android:background="@color/white_color"
|
android:background="@color/white_color"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical"/>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/no_current_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_above="@id/calls_list"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/waiting_time" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/call_status_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/no_current_call" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/recording"
|
android:id="@+id/recording"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
|
@ -179,262 +103,46 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:id="@+id/menu"
|
android:id="@+id/buttons"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/main_bar"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_weight="0.5"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/dialer"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:contentDescription="@string/content_description_numpad"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/footer_dialer" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/hang_up"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_weight="0.5"
|
|
||||||
android:background="@drawable/hangup"
|
|
||||||
android:contentDescription="@string/content_description_hang_up"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:src="@drawable/call_hangup" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="@drawable/footer_button">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/chat"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerInParent="true"
|
android:gravity="bottom">
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:contentDescription="@string/content_description_chat_button"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/footer_chat" />
|
|
||||||
|
|
||||||
<TextView
|
<!-- This is a better way of splitting screen 50/50 than using weights -->
|
||||||
android:id="@+id/missed_chats"
|
<View
|
||||||
style="@style/unread_count_font"
|
android:id="@+id/vertical_divider"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="15dp"
|
|
||||||
android:background="@drawable/unread_message_count_bg"
|
|
||||||
android:gravity="center"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/secondary_bar"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="0.5"
|
android:layout_centerHorizontal="true" />
|
||||||
android:gravity="bottom"
|
|
||||||
android:minHeight="60dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<RelativeLayout
|
<include layout="@layout/call_primary_buttons"
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/video"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_switch_video"
|
|
||||||
android:padding="20dp"
|
|
||||||
android:src="@drawable/camera" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/video_in_progress"
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/micro"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_toggle_micro"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:src="@drawable/micro" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/speaker"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:background="?attr/button_background_drawable"
|
android:layout_toLeftOf="@id/vertical_divider" />
|
||||||
android:contentDescription="@string/content_description_toggle_speaker"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/speaker" />
|
|
||||||
|
|
||||||
<ImageView
|
<include layout="@layout/call_secondary_buttons"
|
||||||
android:id="@+id/audio_route"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_audio_route"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/routes"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_bluetooth"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/audio_route"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_bluetooth"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_bluetooth"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_earpiece"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/route_bluetooth"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_earpiece"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_earpiece"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_speaker"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/route_earpiece"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_toggle_speaker"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_speaker"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/options"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_call_options"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/record_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/options"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_record_call"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_rec"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/add_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/record_call"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_add_call"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_add_call"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/transfer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/add_call"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_transfer"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_transfer_call"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/conference"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/transfer"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_conference"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_start_conference"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="60dp">
|
android:layout_toRightOf="@id/vertical_divider" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<org.linphone.views.Numpad
|
<org.linphone.views.Numpad
|
||||||
android:id="@+id/numpad"
|
android:id="@+id/numpad"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:background="@color/toolbar_color"
|
android:background="@color/toolbar_color"
|
||||||
android:contentDescription="@string/content_description_numpad"
|
android:contentDescription="@string/content_description_numpad" />
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/side_menu_content"
|
android:id="@+id/side_menu_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -443,19 +151,22 @@
|
||||||
android:layout_marginTop="40dp"
|
android:layout_marginTop="40dp"
|
||||||
android:background="@color/white_color">
|
android:background="@color/white_color">
|
||||||
|
|
||||||
<include
|
<fragment
|
||||||
android:id="@+id/incall_stats"
|
android:id="@+id/call_stats_fragment"
|
||||||
layout="@layout/incall_stats" />
|
android:name="org.linphone.call.CallStatsFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:layout="@layout/call_stats" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status_bar_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.call.CallStatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status_fragment"
|
android:id="@+id/status_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
android:id="@+id/side_menu"
|
android:id="@+id/side_menu"
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status_fragment"
|
android:id="@+id/status_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
android:id="@+id/side_menu"
|
android:id="@+id/side_menu"
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status_fragment"
|
android:id="@+id/status_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
android:id="@+id/side_menu"
|
android:id="@+id/side_menu"
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?attr/backgroundContastColor"
|
android:background="?attr/backgroundContastColor"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
@ -59,7 +58,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="?attr/backgroundColor"
|
android:background="?attr/backgroundColor"
|
||||||
android:padding="10dp">
|
android:padding="10dp">
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/answer_no"
|
android:id="@+id/answer_no"
|
||||||
android:text="No"
|
android:text="@string/no"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/answer_yes"
|
android:id="@+id/answer_yes"
|
||||||
android:text="Yes"
|
android:text="@string/yes"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:paddingTop="40dp"/>
|
|
|
@ -10,66 +10,37 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<FrameLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<TextureView
|
||||||
android:id="@+id/fragmentContainer"
|
android:id="@+id/remote_video_texture"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"/>
|
||||||
android:orientation="horizontal" />
|
|
||||||
|
<TextureView
|
||||||
|
android:id="@+id/local_preview_texture"
|
||||||
|
android:layout_width="300dp"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentBottom="true" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
android:id="@+id/active_calls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="120dp"
|
android:layout_marginBottom="120dp"
|
||||||
android:layout_marginTop="40dp">
|
android:layout_marginTop="40dp">
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_conference_header" android:visibility="gone" />
|
||||||
android:id="@+id/conference_list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/active_call"
|
android:id="@+id/active_call"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:visibility="visible">
|
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_active_header" />
|
||||||
android:id="@+id/active_call_info"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:alpha="0.8"
|
|
||||||
android:background="?attr/backgroundColor"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/current_contact_name"
|
|
||||||
style="@style/big_contact_name_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="5dp" />
|
|
||||||
|
|
||||||
<Chronometer
|
|
||||||
android:id="@+id/current_call_timer"
|
|
||||||
style="@style/sip_uri_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -83,30 +54,7 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_paused_by_remote" android:visibility="gone" />
|
||||||
android:id="@+id/remote_pause"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:alpha="0.9"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/waiting_time" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/call_status_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/call_paused_by_remote" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/pause"
|
android:id="@+id/pause"
|
||||||
|
@ -140,30 +88,6 @@
|
||||||
android:background="?attr/backgroundColor"
|
android:background="?attr/backgroundColor"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical"/>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/no_current_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_above="@id/calls_list"
|
|
||||||
android:background="?attr/backgroundColor"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/waiting_time" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/call_status_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/no_current_call" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/recording"
|
android:id="@+id/recording"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
@ -179,260 +103,38 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:id="@+id/menu"
|
android:id="@+id/buttons"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_primary_buttons"
|
||||||
android:id="@+id/secondary_bar"
|
android:id="@+id/call_primary_buttons"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:minHeight="60dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/video"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_switch_video"
|
|
||||||
android:padding="20dp"
|
|
||||||
android:src="@drawable/camera" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/video_in_progress"
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/micro"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_toggle_micro"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:src="@drawable/micro" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/speaker"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true" />
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_toggle_speaker"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/speaker" />
|
|
||||||
|
|
||||||
<ImageView
|
<include layout="@layout/call_secondary_buttons"
|
||||||
android:id="@+id/audio_route"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_audio_route"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/routes"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_bluetooth"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/audio_route"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_bluetooth"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_bluetooth"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_earpiece"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/route_bluetooth"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_earpiece"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_earpiece"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/route_speaker"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/route_earpiece"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_toggle_speaker"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/route_speaker"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="0.25">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/options"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_call_options"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/record_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/options"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_record_call"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_rec"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/add_call"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/record_call"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_add_call"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_add_call"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/transfer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/add_call"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_transfer"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_transfer_call"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/conference"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_above="@id/transfer"
|
|
||||||
android:background="?attr/button_background_drawable"
|
|
||||||
android:contentDescription="@string/content_description_conference"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/options_start_conference"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/main_bar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/dialer"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:contentDescription="@string/content_description_numpad"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/footer_dialer" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/hang_up"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_weight="0.5"
|
|
||||||
android:background="@drawable/hangup"
|
|
||||||
android:contentDescription="@string/content_description_hang_up"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:src="@drawable/call_hangup" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:background="@drawable/footer_button">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/chat"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:background="@color/dark_grey_color"
|
|
||||||
android:contentDescription="@string/content_description_chat_button"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:src="@drawable/footer_chat" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/missed_chats"
|
|
||||||
style="@style/unread_count_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="15dp"
|
|
||||||
android:background="@drawable/unread_message_count_bg"
|
|
||||||
android:gravity="center"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="120dp">
|
android:layout_above="@id/call_primary_buttons" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<org.linphone.views.Numpad
|
<org.linphone.views.Numpad
|
||||||
android:id="@+id/numpad"
|
android:id="@+id/numpad"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:background="@color/toolbar_color"
|
android:background="@color/toolbar_color"
|
||||||
android:contentDescription="@string/content_description_numpad"
|
android:contentDescription="@string/content_description_numpad" />
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/side_menu_content"
|
android:id="@+id/side_menu_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -441,19 +143,22 @@
|
||||||
android:layout_marginTop="40dp"
|
android:layout_marginTop="40dp"
|
||||||
android:background="?attr/backgroundColor">
|
android:background="?attr/backgroundColor">
|
||||||
|
|
||||||
<include
|
<fragment
|
||||||
android:id="@+id/incall_stats"
|
android:id="@+id/call_stats_fragment"
|
||||||
layout="@layout/incall_stats" />
|
android:name="org.linphone.call.CallStatsFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:layout="@layout/call_stats" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status_bar_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.call.CallStatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
28
app/src/main/res/layout/call_active_header.xml
Normal file
28
app/src/main/res/layout/call_active_header.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/active_call_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="80dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:alpha="0.8"
|
||||||
|
android:background="?attr/backgroundColor"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/current_contact_name"
|
||||||
|
style="@style/big_contact_name_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="5dp" />
|
||||||
|
|
||||||
|
<Chronometer
|
||||||
|
android:id="@+id/current_call_timer"
|
||||||
|
style="@style/sip_uri_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
70
app/src/main/res/layout/call_conference_cell.xml
Normal file
70
app/src/main/res/layout/call_conference_cell.xml
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<include layout="@layout/contact_avatar" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/contact"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/contact_name"
|
||||||
|
style="@style/contact_name_list_cell_font"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|left"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
|
||||||
|
<Chronometer
|
||||||
|
android:id="@+id/call_timer"
|
||||||
|
style="@style/call_timer_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|right" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/remove_from_conference"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:contentDescription="@string/content_description_exit_conference"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:src="@drawable/conference_exit_default" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
51
app/src/main/res/layout/call_conference_header.xml
Normal file
51
app/src/main/res/layout/call_conference_header.xml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/conference_header"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/header"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentTop="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/header_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:text="@string/conference" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/conference_pause"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:contentDescription="@string/content_description_pause"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/pause" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_below="@id/header"
|
||||||
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/conference_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/divider"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -2,7 +2,6 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_margin="2dp"
|
|
||||||
android:alpha="0.5"
|
android:alpha="0.5"
|
||||||
android:background="?attr/accentColor"
|
android:background="?attr/accentColor"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
@ -10,13 +9,11 @@
|
||||||
android:padding="5dp">
|
android:padding="5dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_picture"
|
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:src="@drawable/conference_start" />
|
android:src="@drawable/conference_start" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/contact_name"
|
|
||||||
style="@style/call_contact_name_paused_font"
|
style="@style/call_contact_name_paused_font"
|
||||||
android:layout_width="0dip"
|
android:layout_width="0dip"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -28,7 +25,7 @@
|
||||||
android:text="@string/conference" />
|
android:text="@string/conference" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/conference_pause"
|
android:id="@+id/conference_resume"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:contentDescription="@string/content_description_pause"
|
android:contentDescription="@string/content_description_pause"
|
|
@ -2,7 +2,8 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:background="?attr/accentColorLight30"
|
android:alpha="0.5"
|
||||||
|
android:background="?attr/accentColor"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="5dp">
|
android:padding="5dp">
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.call.CallStatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.call.CallStatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/top_bar"
|
android:id="@+id/top_bar"
|
||||||
|
|
24
app/src/main/res/layout/call_paused_by_remote.xml
Normal file
24
app/src/main/res/layout/call_paused_by_remote.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/remote_pause"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0.9"
|
||||||
|
android:background="@color/dark_grey_color"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/waiting_time" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/call_status_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/call_paused_by_remote" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
86
app/src/main/res/layout/call_primary_buttons.xml
Normal file
86
app/src/main/res/layout/call_primary_buttons.xml
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/hang_up"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/hangup"
|
||||||
|
android:contentDescription="@string/content_description_hang_up"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/call_hangup" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toLeftOf="@id/vertical_divider">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/left_vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dialer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_toLeftOf="@id/left_vertical_divider"
|
||||||
|
android:background="@drawable/button_background_dark"
|
||||||
|
android:contentDescription="@string/content_description_numpad"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/footer_dialer" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toRightOf="@id/vertical_divider">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/right_vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_toRightOf="@id/right_vertical_divider"
|
||||||
|
android:background="@drawable/footer_button">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/chat"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:background="@drawable/button_background_dark"
|
||||||
|
android:contentDescription="@string/content_description_chat_button"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/footer_chat" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/missed_chats"
|
||||||
|
style="@style/unread_count_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="15dp"
|
||||||
|
android:background="@drawable/unread_message_count_bg"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
200
app/src/main/res/layout/call_secondary_buttons.xml
Normal file
200
app/src/main/res/layout/call_secondary_buttons.xml
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/secondary_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:minHeight="60dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toLeftOf="@id/vertical_divider">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/left_vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_toLeftOf="@id/left_vertical_divider">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/video"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_switch_video"
|
||||||
|
android:padding="20dp"
|
||||||
|
android:src="@drawable/camera" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/video_in_progress"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/micro"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_toRightOf="@id/left_vertical_divider"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_toggle_micro"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/micro" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toRightOf="@id/vertical_divider">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/right_vertical_divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerHorizontal="true" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toLeftOf="@id/right_vertical_divider">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/speaker"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_toggle_speaker"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/speaker" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/audio_route"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_audio_route"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/routes"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/route_bluetooth"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/audio_route"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_bluetooth"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/route_bluetooth"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/route_earpiece"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/route_bluetooth"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_earpiece"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/route_earpiece"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/route_speaker"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/route_earpiece"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_toggle_speaker"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/route_speaker"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toRightOf="@id/right_vertical_divider">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/options"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_call_options"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/options" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/record_call"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/options"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_record_call"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/options_rec"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/add_call"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/record_call"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_add_call"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/options_add_call"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/transfer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/add_call"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_transfer"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/options_transfer_call"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/conference"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_above="@id/transfer"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:contentDescription="@string/content_description_conference"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:src="@drawable/options_start_conference"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
52
app/src/main/res/layout/call_status_bar.xml
Normal file
52
app/src/main/res/layout/call_status_bar.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="?attr/accentColor"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/call_quality"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:contentDescription="@string/content_description_call_quality"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/call_quality_indicator_0" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/status_led"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_toRightOf="@id/call_quality"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:src="@drawable/led_disconnected" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_text"
|
||||||
|
style="@style/status_bar_font"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@id/status_led"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:text="@string/status_not_connected" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/encryption"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:contentDescription="@string/content_description_encryption"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:src="@drawable/security_ko"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -102,7 +102,7 @@
|
||||||
android:src="@drawable/delete" />
|
android:src="@drawable/delete" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/edit_list" />
|
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
android:src="@drawable/delete" />
|
android:src="@drawable/delete" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/edit_list" />
|
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/chatList"
|
android:id="@+id/chatList"
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:layout_margin="2dp"
|
|
||||||
android:divider="?attr/dividerColor"
|
|
||||||
android:dividerHeight="1dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="2dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/contactPicture"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:src="@drawable/avatar" />
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/contactNameOrNumber"
|
|
||||||
style="@style/contact_name_list_cell_font"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingRight="10dp" />
|
|
||||||
|
|
||||||
|
|
||||||
<Chronometer
|
|
||||||
android:id="@+id/call_timer"
|
|
||||||
style="@style/call_timer_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical|right"
|
|
||||||
android:paddingLeft="10dp"
|
|
||||||
android:paddingRight="20dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/quitConference"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:contentDescription="@string/content_description_exit_conference"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/conference_exit_default" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingLeft="10dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/header_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/conference" />
|
|
||||||
|
|
||||||
<Chronometer
|
|
||||||
android:id="@+id/callTimer"
|
|
||||||
style="@style/call_timer_font"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/conference_pause"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:contentDescription="@string/content_description_pause"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/pause" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:background="?attr/dividerColor" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -85,7 +85,7 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/edit_list" />
|
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:background="?attr/lighToolbarBackgroundColor"
|
android:background="?attr/lighToolbarBackgroundColor"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/cancel"
|
android:id="@+id/cancel"
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="gone"/>
|
|
|
@ -79,7 +79,7 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/edit_list" />
|
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/history_list"
|
android:id="@+id/history_list"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/topbar"
|
android:id="@+id/topbar"
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/status_fragment"
|
android:id="@+id/status_fragment"
|
||||||
android:name="org.linphone.fragments.StatusFragment"
|
android:name="org.linphone.fragments.StatusBarFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
tools:layout="@layout/status" />
|
tools:layout="@layout/status_bar" />
|
||||||
|
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
android:id="@+id/side_menu"
|
android:id="@+id/side_menu"
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
style="@style/header_font"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="20dp"
|
|
||||||
android:text="@string/password" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/password1"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:background="@drawable/resizable_textfield"
|
|
||||||
android:hint="@string/password"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/black_color"
|
|
||||||
android:textCursorDrawable="@null" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/customText"
|
|
||||||
style="@style/header_font"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="20dp"
|
|
||||||
android:text="@string/confirm_password" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/password2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:background="@drawable/resizable_textfield"
|
|
||||||
android:hint="@string/confirm_password"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/black_color"
|
|
||||||
android:textCursorDrawable="@null" />
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/led"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right|center_vertical"
|
|
||||||
android:src="@drawable/led_disconnected" />
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@android:id/list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:cacheColorHint="@color/transparent_color"
|
|
||||||
android:drawSelectorOnTop="false"
|
|
||||||
android:scrollbarAlwaysDrawVerticalTrack="true" />
|
|
|
@ -44,7 +44,7 @@
|
||||||
android:src="@drawable/delete" />
|
android:src="@drawable/delete" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/edit_list" />
|
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:scaleType="center"
|
|
||||||
android:src="@drawable/linphone_logo_orange" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/spinner"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -16,17 +16,6 @@
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:src="@drawable/menu" />
|
android:src="@drawable/menu" />
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/call_quality"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:contentDescription="@string/content_description_call_quality"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:src="@drawable/call_quality_indicator_0"
|
|
||||||
android:visibility="invisible" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/status_led"
|
android:id="@+id/status_led"
|
||||||
android:layout_width="20dp"
|
android:layout_width="20dp"
|
||||||
|
@ -68,16 +57,4 @@
|
||||||
android:paddingRight="10dp"
|
android:paddingRight="10dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/encryption"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:contentDescription="@string/content_description_encryption"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:src="@drawable/security_ko"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/toastRoot"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/backgroundContastColor"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/toastMessage"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:textColor="?attr/secondaryTextColor" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="top|center_horizontal"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/carddav_username"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="Username"
|
|
||||||
android:text="sylvain" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/carddav_pwd"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="Pwd" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/carddav_ha1"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="HA1"
|
|
||||||
android:text="4747ce2517a985f2fc20234a38f068b6" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/carddav_server"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="Server URL"
|
|
||||||
android:text="http://192.168.0.230/sabredav/addressbookserver.php/addressbooks/sylvain/default" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/carddav_synchronize"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Synchronize" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/carddav_events"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/video_frame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/black_color">
|
|
||||||
|
|
||||||
<TextureView
|
|
||||||
android:id="@+id/videoSurface"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<TextureView
|
|
||||||
android:id="@+id/videoCaptureSurface"
|
|
||||||
android:layout_width="300dp"
|
|
||||||
android:layout_height="200dp"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentBottom="true" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue