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.RECORD_AUDIO" />
|
||||
<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.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
@ -183,8 +184,9 @@
|
|||
<activity
|
||||
android:name=".call.CallActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:noHistory="true"
|
||||
android:showWhenLocked="true"/>
|
||||
android:showWhenLocked="true"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"/>
|
||||
|
||||
<!-- Assistant activities -->
|
||||
|
||||
|
@ -252,10 +254,6 @@
|
|||
|
||||
<!-- Receivers -->
|
||||
|
||||
<receiver
|
||||
android:name=".receivers.BluetoothManager"
|
||||
android:enabled="false"/>
|
||||
|
||||
<receiver android:name=".receivers.BootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
|
@ -265,12 +263,6 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receivers.PhoneStateChangedReceiver">
|
||||
<intent-filter android:priority="999">
|
||||
<action android:name="android.intent.action.PHONE_STATE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".notifications.NotificationBroadcastReceiver"
|
||||
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.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
|
@ -37,6 +35,8 @@ import android.net.Uri;
|
|||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
|
@ -73,8 +73,6 @@ import org.linphone.core.tools.H264Helper;
|
|||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
||||
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.utils.AndroidAudioManager;
|
||||
import org.linphone.utils.LinphoneUtils;
|
||||
|
@ -98,8 +96,8 @@ public class LinphoneManager implements SensorEventListener {
|
|||
private CallManager mCallManager;
|
||||
private final PowerManager mPowerManager;
|
||||
private final ConnectivityManager mConnectivityManager;
|
||||
private BroadcastReceiver mHookReceiver;
|
||||
private BroadcastReceiver mCallReceiver;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private PhoneStateListener mPhoneStateListener;
|
||||
private WakeLock mProximityWakelock;
|
||||
private final SensorManager mSensorManager;
|
||||
private final Sensor mProximity;
|
||||
|
@ -138,6 +136,27 @@ public class LinphoneManager implements SensorEventListener {
|
|||
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
|
||||
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;
|
||||
mCallManager = new CallManager(c);
|
||||
|
||||
|
@ -194,8 +213,7 @@ public class LinphoneManager implements SensorEventListener {
|
|||
if (state == State.IncomingReceived
|
||||
&& !call.equals(core.getCurrentCall())) {
|
||||
if (call.getReplacedCall() != null) {
|
||||
// attended transfer
|
||||
// it will be accepted automatically.
|
||||
// attended transfer will be accepted automatically.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -222,15 +240,16 @@ public class LinphoneManager implements SensorEventListener {
|
|||
};
|
||||
mTimer = new Timer("Auto answer");
|
||||
mTimer.schedule(lTask, mPrefs.getAutoAnswerTime());
|
||||
}
|
||||
|
||||
if (state == State.End || state == State.Error) {
|
||||
} else if (state == State.End || state == State.Error) {
|
||||
if (mCore.getCallsNb() == 0) {
|
||||
// Disabling proximity sensor
|
||||
enableProximitySensing(false);
|
||||
|
||||
Log.i("[Manager] Unregistering phone state listener");
|
||||
mTelephonyManager.listen(
|
||||
mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||
}
|
||||
}
|
||||
if (state == State.UpdatedByRemote) {
|
||||
} else if (state == State.UpdatedByRemote) {
|
||||
// If the correspondent proposes video while audio call
|
||||
boolean remoteVideo = call.getRemoteParams().videoEnabled();
|
||||
boolean localVideo = call.getCurrentParams().videoEnabled();
|
||||
|
@ -243,6 +262,12 @@ public class LinphoneManager implements SensorEventListener {
|
|||
&& mCore.getConference() == null) {
|
||||
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) {
|
||||
Log.e("[Manager] Destroy Core Runtime Exception: " + e);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
@ -529,25 +543,11 @@ public class LinphoneManager implements SensorEventListener {
|
|||
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 =
|
||||
mPowerManager.newWakeLock(
|
||||
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
||||
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();
|
||||
|
||||
mAccountCreator = mCore.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl());
|
||||
|
@ -886,6 +886,9 @@ public class LinphoneManager implements SensorEventListener {
|
|||
|
||||
public void setCallGsmON(boolean on) {
|
||||
mCallGsmON = on;
|
||||
if (on) {
|
||||
mCore.pauseAllCalls();
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(int key) {
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.linphone.core.LoggingServiceListener;
|
|||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.mediastream.Version;
|
||||
import org.linphone.notifications.NotificationsManager;
|
||||
import org.linphone.receivers.BluetoothManager;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
import org.linphone.utils.ActivityMonitor;
|
||||
import org.linphone.utils.DeviceOrientationEventListener;
|
||||
|
@ -103,7 +102,6 @@ public final class LinphoneService extends Service {
|
|||
private NotificationsManager mNotificationManager;
|
||||
private LinphoneManager mLinphoneManager;
|
||||
private ContactsManager mContactsManager;
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private DeviceOrientationEventListener mOrientationHelper;
|
||||
|
||||
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
|
||||
|
@ -215,8 +213,6 @@ public final class LinphoneService extends Service {
|
|||
ContactsContract.Contacts.CONTENT_URI, true, mContactsManager);
|
||||
}
|
||||
|
||||
mBluetoothManager = new BluetoothManager();
|
||||
|
||||
Compatibility.createChatShortcuts(this);
|
||||
mOrientationHelper.enable();
|
||||
|
||||
|
@ -268,7 +264,6 @@ public final class LinphoneService extends Service {
|
|||
mNotificationManager.destroy();
|
||||
}
|
||||
mContactsManager.destroy();
|
||||
mBluetoothManager.destroy();
|
||||
|
||||
if (LinphonePreferences.instance().useJavaLogger()) {
|
||||
Factory.instance().getLoggingService().removeListener(mJavaLoggingService);
|
||||
|
@ -311,10 +306,6 @@ public final class LinphoneService extends Service {
|
|||
return mContactsManager;
|
||||
}
|
||||
|
||||
public BluetoothManager getBluetoothManager() {
|
||||
return mBluetoothManager;
|
||||
}
|
||||
|
||||
public void createOverlay() {
|
||||
if (mOverlay != null) destroyOverlay();
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ public class AboutActivity extends MainActivity {
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOnBackPressGoHome = false;
|
||||
mAlwaysHideTabBar = true;
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ public class DialerActivity extends MainActivity implements AddressText.AddressC
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -22,14 +22,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
import android.os.Bundle;
|
||||
import org.linphone.LinphoneService;
|
||||
|
||||
public abstract class LinphoneGenericActivity extends ThemableActivity {
|
||||
public abstract class LinphoneGenericActivity extends ThemeableActivity {
|
||||
protected boolean mAbortCreation;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
mAbortCreation = false;
|
||||
super.onCreate(savedInstanceState);
|
||||
// After a crash, Android restart the last Activity so we need to check
|
||||
// if all dependencies are loaded
|
||||
if (!LinphoneService.isReady()) {
|
||||
startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class));
|
||||
mAbortCreation = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ import org.linphone.core.ProxyConfig;
|
|||
import org.linphone.core.RegistrationState;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.fragments.EmptyFragment;
|
||||
import org.linphone.fragments.StatusFragment;
|
||||
import org.linphone.fragments.StatusBarFragment;
|
||||
import org.linphone.history.HistoryActivity;
|
||||
import org.linphone.menu.SideMenuFragment;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
@ -73,7 +73,7 @@ import org.linphone.utils.LinphoneUtils;
|
|||
import org.linphone.utils.PushNotificationUtils;
|
||||
|
||||
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 FRAGMENT_SPECIFIC_PERMISSION = 2;
|
||||
|
||||
|
@ -88,7 +88,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
|||
private LinearLayout mTabBar;
|
||||
|
||||
private SideMenuFragment mSideMenuFragment;
|
||||
private StatusFragment mStatusFragment;
|
||||
private StatusBarFragment mStatusBarFragment;
|
||||
|
||||
protected boolean mOnBackPressGoHome;
|
||||
protected boolean mAlwaysHideTabBar;
|
||||
|
@ -99,6 +99,9 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LinphoneService.isReady()) {
|
||||
finish();
|
||||
|
@ -171,8 +174,8 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
|||
}
|
||||
});
|
||||
|
||||
mStatusFragment =
|
||||
(StatusFragment) getFragmentManager().findFragmentById(R.id.status_fragment);
|
||||
mStatusBarFragment =
|
||||
(StatusBarFragment) getFragmentManager().findFragmentById(R.id.status_fragment);
|
||||
|
||||
DrawerLayout mSideMenu = findViewById(R.id.side_menu);
|
||||
RelativeLayout mSideMenuContent = findViewById(R.id.side_menu_content);
|
||||
|
@ -316,7 +319,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
|||
mDialerSelected.setVisibility(View.GONE);
|
||||
mChatSelected.setVisibility(View.GONE);
|
||||
|
||||
mStatusFragment.setMenuListener(this);
|
||||
mStatusBarFragment.setMenuListener(this);
|
||||
mSideMenuFragment.setQuitListener(this);
|
||||
mSideMenuFragment.displayAccountsInSideMenu();
|
||||
|
||||
|
@ -334,7 +337,7 @@ public abstract class MainActivity extends LinphoneGenericActivity
|
|||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
mStatusFragment.setMenuListener(null);
|
||||
mStatusBarFragment.setMenuListener(null);
|
||||
mSideMenuFragment.setQuitListener(null);
|
||||
|
||||
Core core = LinphoneManager.getCore();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.linphone.activities;
|
||||
|
||||
/*
|
||||
ThemableActivity.java
|
||||
ThemeableActivity.java
|
||||
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
||||
|
||||
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 androidx.appcompat.app.AppCompatActivity;
|
||||
import org.linphone.R;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
||||
public abstract class ThemableActivity extends AppCompatActivity {
|
||||
public abstract class ThemeableActivity extends AppCompatActivity {
|
||||
private int mTheme;
|
||||
|
||||
@Override
|
||||
|
@ -43,16 +44,30 @@ public abstract class ThemableActivity extends AppCompatActivity {
|
|||
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
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (LinphonePreferences.instance().isDarkModeEnabled()) {
|
||||
if (mTheme != R.style.LinphoneStyleDark) {
|
||||
Log.w("[Themeable Activity] Recreate Activity cause theme doesn't match");
|
||||
recreate();
|
||||
}
|
||||
} else {
|
||||
if (mTheme != R.style.LinphoneStyleLight) {
|
||||
Log.w("[Themeable Activity] Recreate Activity cause theme doesn't match");
|
||||
recreate();
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ import android.widget.ImageView;
|
|||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.R;
|
||||
import org.linphone.activities.DialerActivity;
|
||||
import org.linphone.activities.ThemableActivity;
|
||||
import org.linphone.activities.ThemeableActivity;
|
||||
import org.linphone.core.AccountCreator;
|
||||
import org.linphone.core.Core;
|
||||
import org.linphone.core.DialPlan;
|
||||
|
@ -39,7 +39,7 @@ import org.linphone.core.ProxyConfig;
|
|||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
||||
public abstract class AssistantActivity extends ThemableActivity
|
||||
public abstract class AssistantActivity extends ThemeableActivity
|
||||
implements CountryPicker.CountryPickedListener {
|
||||
static AccountCreator mAccountCreator;
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class CountryAdapter extends BaseAdapter implements Filterable {
|
|||
if (convertView != null) {
|
||||
view = convertView;
|
||||
} 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);
|
||||
|
|
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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
Compatibility.setShowWhenLocked(this, true);
|
||||
Compatibility.setTurnScreenOn(this, true);
|
||||
|
|
|
@ -44,8 +44,7 @@ import org.linphone.views.AddressType;
|
|||
/** Handle call updating, reinvites. */
|
||||
public class CallManager {
|
||||
private Context mContext;
|
||||
private boolean mHandsetON = false;
|
||||
private CallActivity.CallActivityInterface mCallInterface;
|
||||
private CallActivityInterface mCallInterface;
|
||||
private BandwidthManager mBandwidthManager;
|
||||
|
||||
public CallManager(Context context) {
|
||||
|
@ -57,90 +56,113 @@ public class CallManager {
|
|||
mBandwidthManager.destroy();
|
||||
}
|
||||
|
||||
public void inviteAddress(Address lAddress, boolean forceZRTP) {
|
||||
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();
|
||||
|
||||
CallParams params = core.createCallParams(null);
|
||||
mBandwidthManager.updateWithProfileSettings(params);
|
||||
|
||||
if (videoEnabled && params.videoEnabled()) {
|
||||
params.enableVideo(true);
|
||||
} else {
|
||||
params.enableVideo(false);
|
||||
}
|
||||
|
||||
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(), 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() {
|
||||
public void terminateCurrentCallOrConferenceOrAll() {
|
||||
Core core = LinphoneManager.getCore();
|
||||
Call call = core.getCurrentCall();
|
||||
if (call == null) {
|
||||
Log.e("[Call Manager] Trying to reinviteWithVideo while not in call: doing nothing");
|
||||
return false;
|
||||
if (call != null) {
|
||||
call.terminate();
|
||||
} else if (core.isInConference()) {
|
||||
core.terminateConference();
|
||||
} else {
|
||||
core.terminateAllCalls();
|
||||
}
|
||||
}
|
||||
|
||||
public void addVideo() {
|
||||
Call call = LinphoneManager.getCore().getCurrentCall();
|
||||
if (call.getState() == Call.State.End || call.getState() == Call.State.Released) return;
|
||||
if (!call.getCurrentParams().videoEnabled()) {
|
||||
enableCamera(call, true);
|
||||
reinviteWithVideo();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeVideo() {
|
||||
Core core = LinphoneManager.getCore();
|
||||
Call call = core.getCurrentCall();
|
||||
CallParams params = core.createCallParams(call);
|
||||
params.enableVideo(false);
|
||||
call.update(params);
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
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();
|
||||
if (call == null) {
|
||||
Log.e("[Call Manager] Trying to switch camera while not in call");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
||||
if (params.videoEnabled()) return false;
|
||||
boolean isLowBandwidthConnection =
|
||||
!LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance());
|
||||
|
||||
// Check if video possible regarding bandwidth limitations
|
||||
mBandwidthManager.updateWithProfileSettings(params);
|
||||
|
||||
// Abort if not enough bandwidth...
|
||||
if (!params.videoEnabled()) {
|
||||
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;
|
||||
}
|
||||
|
||||
// Not yet in video call: try to re-invite with video
|
||||
call.update(params);
|
||||
call.acceptWithParams(params);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
public void acceptCallUpdate(boolean accept) {
|
||||
Core core = LinphoneManager.getCore();
|
||||
Call call = core.getCurrentCall();
|
||||
if (call == null) {
|
||||
Log.e("[Call Manager] Trying to updateCall while not in call: doing nothing");
|
||||
return;
|
||||
}
|
||||
call.update(null);
|
||||
|
||||
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) {
|
||||
|
@ -149,10 +171,6 @@ public class CallManager {
|
|||
}
|
||||
|
||||
public void newOutgoingCall(String to, String displayName) {
|
||||
// if (mCore.inCall()) {
|
||||
// listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
|
||||
// return;
|
||||
// }
|
||||
if (to == null) return;
|
||||
|
||||
// If to is only a username, try to find the contact to get an alias if existing
|
||||
|
@ -184,8 +202,7 @@ public class CallManager {
|
|||
address.setDisplayName(displayName);
|
||||
|
||||
boolean isLowBandwidthConnection =
|
||||
!LinphoneUtils.isHighBandwidthConnection(
|
||||
LinphoneService.instance().getApplicationContext());
|
||||
!LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance());
|
||||
|
||||
if (core.isNetworkReachable()) {
|
||||
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) {
|
||||
try {
|
||||
if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) {
|
||||
|
@ -233,44 +240,20 @@ public class CallManager {
|
|||
LinphoneManager.getCore().playDtmf(dtmf, -1);
|
||||
}
|
||||
|
||||
private void terminateCall() {
|
||||
Core core = LinphoneManager.getCore();
|
||||
if (core.inCall()) {
|
||||
core.getCurrentCall().terminate();
|
||||
}
|
||||
public boolean shouldShowAcceptCallUpdateDialog(Call call) {
|
||||
if (call == null) return true;
|
||||
|
||||
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 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) {
|
||||
public void setCallInterface(CallActivityInterface callInterface) {
|
||||
mCallInterface = callInterface;
|
||||
}
|
||||
|
||||
|
@ -286,20 +269,102 @@ public class CallManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void setHandsetMode(Boolean on) {
|
||||
if (mHandsetON == on) return;
|
||||
public void removeCallFromConference(Call call) {
|
||||
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();
|
||||
|
||||
if (core.isIncomingInvitePending() && on) {
|
||||
mHandsetON = true;
|
||||
acceptCall(core.getCurrentCall());
|
||||
} else if (on && mCallInterface != null) {
|
||||
mHandsetON = true;
|
||||
mCallInterface.setSpeakerEnabled(true);
|
||||
mCallInterface.refreshInCallActions();
|
||||
} else if (!on) {
|
||||
mHandsetON = false;
|
||||
terminateCall();
|
||||
CallParams params = core.createCallParams(null);
|
||||
mBandwidthManager.updateWithProfileSettings(params);
|
||||
|
||||
if (videoEnabled && params.videoEnabled()) {
|
||||
params.enableVideo(true);
|
||||
} else {
|
||||
params.enableVideo(false);
|
||||
}
|
||||
|
||||
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.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
@ -63,6 +60,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
setContentView(R.layout.call_outgoing);
|
||||
|
@ -89,36 +89,49 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
|||
if (state == State.Error) {
|
||||
// Convert Core message for internalization
|
||||
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_call_declined),
|
||||
Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_call_declined),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
} else if (call.getErrorInfo().getReason() == Reason.NotFound) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_user_not_found),
|
||||
Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_user_not_found),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
} else if (call.getErrorInfo().getReason() == Reason.NotAcceptable) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_incompatible_media),
|
||||
Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_incompatible_media),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
} else if (call.getErrorInfo().getReason() == Reason.Busy) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_user_busy), Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_user_busy),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
} else if (message != null) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_unknown) + " - " + message,
|
||||
Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_unknown) + " - " + message,
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
}
|
||||
} else if (state == State.End) {
|
||||
// Convert Core message for internalization
|
||||
if (call.getErrorInfo().getReason() == Reason.Declined) {
|
||||
displayCustomToast(
|
||||
getString(R.string.error_call_declined),
|
||||
Toast.LENGTH_SHORT);
|
||||
Toast.makeText(
|
||||
CallOutgoingActivity.this,
|
||||
getString(R.string.error_call_declined),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
decline();
|
||||
}
|
||||
} else if (state == State.Connected) {
|
||||
|
@ -223,20 +236,6 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC
|
|||
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() {
|
||||
mCall.terminate();
|
||||
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
|
||||
Copyright (C) 2017 Belledonne Communications, Grenoble, France
|
||||
CallStatusBarFragment.java
|
||||
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
@ -18,7 +19,6 @@ along with this program; if not, write to the Free Software
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
|
@ -37,60 +37,47 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.LinphoneService;
|
||||
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.Content;
|
||||
import org.linphone.core.Core;
|
||||
import org.linphone.core.CoreListenerStub;
|
||||
import org.linphone.core.Event;
|
||||
import org.linphone.core.MediaEncryption;
|
||||
import org.linphone.core.ProxyConfig;
|
||||
import org.linphone.core.RegistrationState;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
||||
public class StatusFragment extends Fragment {
|
||||
public class CallStatusBarFragment extends Fragment {
|
||||
private final Handler mRefreshHandler = new Handler();
|
||||
private TextView mStatusText, mVoicemailCount;
|
||||
private ImageView mStatusLed, mCallQuality, mEncryption, mMenu, mVoicemail;
|
||||
private TextView mStatusText;
|
||||
private ImageView mStatusLed, mCallQuality, mEncryption;
|
||||
private Runnable mCallQualityUpdater;
|
||||
private boolean mIsInCall, mIsAttached = false;
|
||||
private CoreListenerStub mListener;
|
||||
private Dialog mZrtpDialog = null;
|
||||
private int mDisplayedQuality = -1;
|
||||
private MenuClikedListener mMenuListener;
|
||||
private StatsClikedListener mStatsListener;
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
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);
|
||||
mStatusLed = view.findViewById(R.id.status_led);
|
||||
mCallQuality = view.findViewById(R.id.call_quality);
|
||||
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;
|
||||
mMenu.setOnClickListener(
|
||||
mStatsListener = null;
|
||||
mCallQuality.setOnClickListener(
|
||||
new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mMenuListener != null) {
|
||||
mMenuListener.onMenuCliked();
|
||||
if (mStatsListener != null) {
|
||||
mStatsListener.onStatsClicked();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We create it once to not delay the first display
|
||||
populateSliderContent();
|
||||
|
||||
mListener =
|
||||
new CoreListenerStub() {
|
||||
@Override
|
||||
|
@ -98,11 +85,7 @@ public class StatusFragment extends Fragment {
|
|||
final Core core,
|
||||
final ProxyConfig proxy,
|
||||
final RegistrationState state,
|
||||
String smessage) {
|
||||
if (!mIsAttached || !LinphoneService.isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message) {
|
||||
if (core.getProxyConfigList() == null) {
|
||||
mStatusLed.setImageResource(R.drawable.led_disconnected);
|
||||
mStatusText.setText(getString(R.string.no_account));
|
||||
|
@ -136,171 +119,29 @@ public class StatusFragment extends Fragment {
|
|||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
public void onCallStateChanged(
|
||||
Core core, Call call, Call.State state, String message) {
|
||||
if (state == Call.State.Resuming || state == Call.State.StreamsRunning) {
|
||||
refreshStatusItems(call);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallEncryptionChanged(
|
||||
Core core, Call call, boolean on, String authenticationToken) {
|
||||
if (call.getCurrentParams()
|
||||
.getMediaEncryption()
|
||||
.equals(MediaEncryption.ZRTP)
|
||||
&& !call.getAuthenticationTokenVerified()) {
|
||||
showZRTPDialog(call);
|
||||
}
|
||||
refreshStatusItems(call);
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mIsAttached = false;
|
||||
}
|
||||
|
||||
public void setMenuListener(MenuClikedListener listener) {
|
||||
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
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
@ -314,14 +155,15 @@ public class StatusFragment extends Fragment {
|
|||
}
|
||||
|
||||
Call call = core.getCurrentCall();
|
||||
if (mIsInCall
|
||||
&& (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0)) {
|
||||
if (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0) {
|
||||
if (call != null) {
|
||||
startCallQuality();
|
||||
refreshStatusItems(call);
|
||||
|
||||
if (!call.getAuthenticationTokenVerified()) {
|
||||
showZRTPDialog(call);
|
||||
}
|
||||
}
|
||||
mMenu.setVisibility(View.INVISIBLE);
|
||||
mCallQuality.setVisibility(View.VISIBLE);
|
||||
|
||||
// We are obviously connected
|
||||
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) {
|
||||
if (call != null) {
|
||||
mVoicemailCount.setVisibility(View.GONE);
|
||||
MediaEncryption mediaEncryption = call.getCurrentParams().getMediaEncryption();
|
||||
|
||||
mEncryption.setVisibility(View.VISIBLE);
|
||||
|
@ -491,7 +423,7 @@ public class StatusFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
public interface MenuClikedListener {
|
||||
void onMenuCliked();
|
||||
public interface StatsClikedListener {
|
||||
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 android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
|
@ -30,10 +31,12 @@ import android.app.PendingIntent;
|
|||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import org.linphone.R;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.notifications.Notifiable;
|
||||
import org.linphone.notifications.NotifiableMessage;
|
||||
|
||||
|
@ -260,4 +263,14 @@ class ApiTwentySixPlus {
|
|||
FragmentTransaction transaction, boolean 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) {
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
boolean accessGranted = notificationManager.isNotificationPolicyAccessGranted();
|
||||
return accessGranted;
|
||||
return notificationManager.isNotificationPolicyAccessGranted();
|
||||
}
|
||||
|
||||
public static boolean isDoNotDisturbPolicyAllowingRinging(
|
||||
|
|
|
@ -256,4 +256,10 @@ public class Compatibility {
|
|||
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();
|
||||
for (LinphoneNumberOrAddress noa : mContact.getNumbersOrAddresses()) {
|
||||
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 displayedNumberOrAddress = value;
|
||||
|
|
|
@ -597,7 +597,7 @@ public class ContactEditorFragment extends Fragment {
|
|||
final LinphoneNumberOrAddress nounoa = tempNounoa;
|
||||
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);
|
||||
if (!isSIP) {
|
||||
|
@ -641,7 +641,7 @@ public class ContactEditorFragment extends Fragment {
|
|||
@SuppressLint("InflateParams")
|
||||
private void addEmptyRowToAllowNewNumberOrAddress(
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package org.linphone.receivers;
|
|||
|
||||
/*
|
||||
BootReceiver.java
|
||||
Copyright (C) 2017 Belledonne Communications, Grenoble, France
|
||||
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
|
||||
|
|
|
@ -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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAbortCreation) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOnBackPressGoHome = false;
|
||||
mAlwaysHideTabBar = true;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.linphone.core.TunnelConfig;
|
|||
import org.linphone.core.VideoActivationPolicy;
|
||||
import org.linphone.core.VideoDefinition;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.mediastream.Version;
|
||||
import org.linphone.purchase.Purchasable;
|
||||
import org.linphone.utils.LinphoneUtils;
|
||||
|
||||
|
@ -943,6 +944,11 @@ public class LinphonePreferences {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.linphone.core.Factory;
|
|||
import org.linphone.core.PayloadType;
|
||||
import org.linphone.core.VideoDefinition;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.mediastream.Version;
|
||||
import org.linphone.settings.widget.ListSetting;
|
||||
import org.linphone.settings.widget.SettingListenerBase;
|
||||
import org.linphone.settings.widget.SwitchSetting;
|
||||
|
@ -189,6 +190,11 @@ public class VideoSettingsFragment extends SettingsFragment {
|
|||
mAutoAccept.setChecked(mPrefs.shouldAutomaticallyAcceptVideoRequests());
|
||||
|
||||
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.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_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.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
|
@ -33,6 +39,7 @@ import android.telephony.TelephonyManager;
|
|||
import android.view.KeyEvent;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.R;
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
|
@ -42,7 +49,8 @@ import org.linphone.core.Core;
|
|||
import org.linphone.core.CoreListenerStub;
|
||||
import org.linphone.core.EcCalibratorStatus;
|
||||
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;
|
||||
|
||||
public class AndroidAudioManager {
|
||||
|
@ -53,10 +61,16 @@ public class AndroidAudioManager {
|
|||
private Call mRingingCall;
|
||||
private MediaPlayer mRingerPlayer;
|
||||
private final Vibrator mVibrator;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothHeadset mBluetoothHeadset;
|
||||
private BluetoothReceiver mBluetoothReceiver;
|
||||
private HeadsetReceiver mHeadsetReceiver;
|
||||
|
||||
private boolean mIsRinging;
|
||||
private boolean mAudioFocused;
|
||||
private boolean mEchoTesterIsRunning;
|
||||
private boolean mIsBluetoothHeadsetConnected;
|
||||
private boolean mIsBluetoothHeadsetScoConnected;
|
||||
|
||||
private CoreListenerStub mListener;
|
||||
|
||||
|
@ -66,6 +80,8 @@ public class AndroidAudioManager {
|
|||
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mEchoTesterIsRunning = false;
|
||||
|
||||
startBluetooth();
|
||||
|
||||
mListener =
|
||||
new CoreListenerStub() {
|
||||
@Override
|
||||
|
@ -103,6 +119,15 @@ public class AndroidAudioManager {
|
|||
// mAudioManager.abandonAudioFocus(null);
|
||||
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) {
|
||||
if (core.getCallsNb() == 0) {
|
||||
|
@ -118,6 +143,12 @@ public class AndroidAudioManager {
|
|||
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)
|
||||
mContext.getSystemService(
|
||||
|
@ -137,12 +168,16 @@ public class AndroidAudioManager {
|
|||
// ringback is heard normally in earpiece or bluetooth receiver.
|
||||
setAudioManagerInCallMode();
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
startBluetooth();
|
||||
if (mIsBluetoothHeadsetConnected) {
|
||||
routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
|
||||
if (state == Call.State.StreamsRunning) {
|
||||
startBluetooth();
|
||||
setAudioManagerInCallMode();
|
||||
if (mIsBluetoothHeadsetConnected) {
|
||||
routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,6 +197,16 @@ public class AndroidAudioManager {
|
|||
}
|
||||
|
||||
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();
|
||||
if (core != null) {
|
||||
core.removeListener(mListener);
|
||||
|
@ -183,7 +228,11 @@ public class AndroidAudioManager {
|
|||
}
|
||||
|
||||
public boolean isAudioRoutedToSpeaker() {
|
||||
return mAudioManager.isSpeakerphoneOn();
|
||||
return mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
||||
}
|
||||
|
||||
public boolean isAudioRoutedToEarpiece() {
|
||||
return !mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
||||
}
|
||||
|
||||
/* Echo cancellation */
|
||||
|
@ -263,12 +312,6 @@ public class AndroidAudioManager {
|
|||
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
}
|
||||
|
||||
private void startBluetooth() {
|
||||
if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
||||
BluetoothManager.getInstance().routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
|
||||
private void requestAudioFocus(int stream) {
|
||||
if (!mAudioFocused) {
|
||||
int res =
|
||||
|
@ -297,10 +340,7 @@ public class AndroidAudioManager {
|
|||
return;
|
||||
}
|
||||
|
||||
if (mContext.getResources().getBoolean(R.bool.allow_ringing_while_early_media)) {
|
||||
routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media
|
||||
}
|
||||
|
||||
routeAudioToSpeaker();
|
||||
mAudioManager.setMode(MODE_RINGTONE);
|
||||
|
||||
try {
|
||||
|
@ -354,23 +394,14 @@ public class AndroidAudioManager {
|
|||
}
|
||||
|
||||
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) {
|
||||
Log.w(
|
||||
"[Audio Manager] Routing audio to "
|
||||
+ (speakerOn ? "speaker" : "earpiece")
|
||||
+ ", disabling bluetooth audio route");
|
||||
BluetoothManager.getInstance().disableBluetoothSCO();
|
||||
Log.w("[Audio Manager] Routing audio to " + (speakerOn ? "speaker" : "earpiece"));
|
||||
if (mIsBluetoothHeadsetScoConnected) {
|
||||
Log.w("[Audio Manager] [Bluetooth] Disabling bluetooth audio route");
|
||||
changeBluetoothSco(false);
|
||||
}
|
||||
|
||||
mAudioManager.setSpeakerphoneOn(speakerOn);
|
||||
}
|
||||
|
@ -383,4 +414,187 @@ public class AndroidAudioManager {
|
|||
i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE,
|
||||
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.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.LinphoneService;
|
||||
import org.linphone.R;
|
||||
import org.linphone.core.Call;
|
||||
import org.linphone.core.Core;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
@ -95,12 +95,7 @@ public class Digit extends Button implements AddressAware {
|
|||
|
||||
private boolean linphoneServiceReady() {
|
||||
if (!LinphoneService.isReady()) {
|
||||
Log.w("Service is not ready while pressing digit");
|
||||
Toast.makeText(
|
||||
getContext(),
|
||||
getContext().getString(R.string.skipable_error_service_not_ready),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
Log.e("[Numpad] Service is not ready while pressing digit");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -112,18 +107,19 @@ public class Digit extends Button implements AddressAware {
|
|||
Core core = LinphoneManager.getCore();
|
||||
core.stopDtmf();
|
||||
mIsDtmfStarted = false;
|
||||
if (core.inCall()) {
|
||||
core.getCurrentCall().sendDtmf(mKeyCode);
|
||||
Call call = core.getCurrentCall();
|
||||
if (call != null) {
|
||||
call.sendDtmf(mKeyCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (mAddress != null) {
|
||||
int lBegin = mAddress.getSelectionStart();
|
||||
if (lBegin == -1) {
|
||||
lBegin = mAddress.length();
|
||||
int begin = mAddress.getSelectionStart();
|
||||
if (begin == -1) {
|
||||
begin = mAddress.length();
|
||||
}
|
||||
if (lBegin >= 0) {
|
||||
mAddress.getEditableText().insert(lBegin, String.valueOf(mKeyCode));
|
||||
if (begin >= 0) {
|
||||
mAddress.getEditableText().insert(begin, String.valueOf(mKeyCode));
|
||||
}
|
||||
|
||||
if (LinphonePreferences.instance().getDebugPopupAddress() != null
|
||||
|
@ -212,12 +208,12 @@ public class Digit extends Button implements AddressAware {
|
|||
|
||||
if (mAddress == null) return true;
|
||||
|
||||
int lBegin = mAddress.getSelectionStart();
|
||||
if (lBegin == -1) {
|
||||
lBegin = mAddress.getEditableText().length();
|
||||
int begin = mAddress.getSelectionStart();
|
||||
if (begin == -1) {
|
||||
begin = mAddress.getEditableText().length();
|
||||
}
|
||||
if (lBegin >= 0) {
|
||||
mAddress.getEditableText().insert(lBegin, "+");
|
||||
if (begin >= 0) {
|
||||
mAddress.getEditableText().insert(begin, "+");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package org.linphone.views;
|
|||
|
||||
/*
|
||||
NumpadView.java
|
||||
Copyright (C) 2017 Belledonne Communications, Grenoble, France
|
||||
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
|
||||
|
@ -31,21 +31,13 @@ import java.util.Collection;
|
|||
import org.linphone.R;
|
||||
|
||||
public class Numpad extends LinearLayout implements AddressAware {
|
||||
|
||||
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) {
|
||||
super(context, attrs);
|
||||
|
||||
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();
|
||||
LayoutInflater.from(context).inflate(R.layout.numpad, this);
|
||||
setLongClickable(true);
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_selected="true">
|
||||
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/route_bluetooth_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
<bitmap android:src="@drawable/route_earpiece_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_selected="true">
|
||||
<bitmap android:src="@drawable/route_earpiece_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/route_earpiece_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
<bitmap android:src="@drawable/route_speaker_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_selected="true">
|
||||
<bitmap android:src="@drawable/route_speaker_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/route_speaker_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
<bitmap android:src="@drawable/routes_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_selected="true">
|
||||
<bitmap android:src="@drawable/routes_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/routes_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
|
|
|
@ -8,21 +8,19 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:background="@color/dark_grey_color"
|
||||
android:baselineAligned="false"
|
||||
android:padding="20dp"
|
||||
android:orientation="horizontal">
|
||||
android:columnCount="2"
|
||||
android:padding="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
@ -53,10 +51,9 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
@ -75,9 +72,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/about_liblinphone_sdk_version" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</GridLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -10,66 +10,37 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fragmentContainer"
|
||||
<TextureView
|
||||
android:id="@+id/remote_video_texture"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<TextureView
|
||||
android:id="@+id/local_preview_texture"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/active_calls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="60dp"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_conference_header" android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/active_call"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="visible">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_active_header" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -83,30 +54,7 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_paused_by_remote" android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pause"
|
||||
|
@ -140,30 +88,6 @@
|
|||
android:background="@color/white_color"
|
||||
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
|
||||
android:id="@+id/recording"
|
||||
android:layout_width="40dp"
|
||||
|
@ -179,261 +103,45 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:baselineAligned="false"
|
||||
android:id="@+id/menu"
|
||||
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_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
|
||||
android:id="@+id/secondary_bar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.5"
|
||||
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_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="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:baselineAligned="false"
|
||||
android:id="@+id/buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="60dp">
|
||||
android:gravity="bottom">
|
||||
|
||||
<org.linphone.views.Numpad
|
||||
android:id="@+id/numpad"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@color/toolbar_color"
|
||||
android:contentDescription="@string/content_description_numpad"
|
||||
android:visibility="gone" />
|
||||
<!-- This is a better way of splitting screen 50/50 than using weights -->
|
||||
<View
|
||||
android:id="@+id/vertical_divider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<include layout="@layout/call_primary_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toLeftOf="@id/vertical_divider" />
|
||||
|
||||
<include layout="@layout/call_secondary_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toRightOf="@id/vertical_divider" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</FrameLayout>
|
||||
<org.linphone.views.Numpad
|
||||
android:id="@+id/numpad"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@color/toolbar_color"
|
||||
android:contentDescription="@string/content_description_numpad" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/side_menu_content"
|
||||
|
@ -443,19 +151,22 @@
|
|||
android:layout_marginTop="40dp"
|
||||
android:background="@color/white_color">
|
||||
|
||||
<include
|
||||
android:id="@+id/incall_stats"
|
||||
layout="@layout/incall_stats" />
|
||||
<fragment
|
||||
android:id="@+id/call_stats_fragment"
|
||||
android:name="org.linphone.call.CallStatsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout="@layout/call_stats" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:id="@+id/status_bar_fragment"
|
||||
android:name="org.linphone.call.CallStatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<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_height="35dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/side_menu"
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<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_height="35dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/side_menu"
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<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_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/side_menu"
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/backgroundContastColor"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
|
@ -59,7 +58,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:background="?attr/backgroundColor"
|
||||
android:padding="10dp">
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
@ -56,7 +56,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/answer_no"
|
||||
android:text="No"
|
||||
android:text="@string/no"
|
||||
android:textAllCaps="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -72,7 +72,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/answer_yes"
|
||||
android:text="Yes"
|
||||
android:text="@string/yes"
|
||||
android:textAllCaps="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<include
|
||||
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_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fragmentContainer"
|
||||
<TextureView
|
||||
android:id="@+id/remote_video_texture"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextureView
|
||||
android:id="@+id/local_preview_texture"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/active_calls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="120dp"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_conference_header" android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/active_call"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="visible">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_active_header" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -83,30 +54,7 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
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>
|
||||
<include layout="@layout/call_paused_by_remote" android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pause"
|
||||
|
@ -140,30 +88,6 @@
|
|||
android:background="?attr/backgroundColor"
|
||||
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
|
||||
android:id="@+id/recording"
|
||||
android:layout_width="50dp"
|
||||
|
@ -179,259 +103,37 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu"
|
||||
<RelativeLayout
|
||||
android:id="@+id/buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/secondary_bar"
|
||||
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_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="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"
|
||||
<include layout="@layout/call_primary_buttons"
|
||||
android:id="@+id/call_primary_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal">
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
<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_height="match_parent"
|
||||
android:layout_marginBottom="120dp">
|
||||
|
||||
<org.linphone.views.Numpad
|
||||
android:id="@+id/numpad"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@color/toolbar_color"
|
||||
android:contentDescription="@string/content_description_numpad"
|
||||
android:visibility="gone" />
|
||||
<include layout="@layout/call_secondary_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@id/call_primary_buttons" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</FrameLayout>
|
||||
<org.linphone.views.Numpad
|
||||
android:id="@+id/numpad"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@color/toolbar_color"
|
||||
android:contentDescription="@string/content_description_numpad" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/side_menu_content"
|
||||
|
@ -441,19 +143,22 @@
|
|||
android:layout_marginTop="40dp"
|
||||
android:background="?attr/backgroundColor">
|
||||
|
||||
<include
|
||||
android:id="@+id/incall_stats"
|
||||
layout="@layout/incall_stats" />
|
||||
<fragment
|
||||
android:id="@+id/call_stats_fragment"
|
||||
android:name="org.linphone.call.CallStatsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout="@layout/call_stats" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:id="@+id/status_bar_fragment"
|
||||
android:name="org.linphone.call.CallStatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
</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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_margin="2dp"
|
||||
android:alpha="0.5"
|
||||
android:background="?attr/accentColor"
|
||||
android:gravity="center_vertical"
|
||||
|
@ -10,13 +9,11 @@
|
|||
android:padding="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/contact_picture"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/conference_start" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contact_name"
|
||||
style="@style/call_contact_name_paused_font"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -28,7 +25,7 @@
|
|||
android:text="@string/conference" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/conference_pause"
|
||||
android:id="@+id/conference_resume"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:contentDescription="@string/content_description_pause"
|
|
@ -2,7 +2,8 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="?attr/accentColorLight30"
|
||||
android:alpha="0.5"
|
||||
android:background="?attr/accentColor"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dp">
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.call.CallStatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/top_bar"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.call.CallStatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<RelativeLayout
|
||||
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" />
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/edit_list" />
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
android:src="@drawable/delete" />
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/edit_list" />
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
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>
|
||||
|
||||
<include layout="@layout/edit_list" />
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:background="?attr/lighToolbarBackgroundColor"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
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>
|
||||
|
||||
<include layout="@layout/edit_list" />
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/history_list"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/status"
|
||||
android:name="org.linphone.fragments.StatusFragment"
|
||||
android:name="org.linphone.fragments.StatusBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topbar"
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<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_height="40dp"
|
||||
tools:layout="@layout/status" />
|
||||
tools:layout="@layout/status_bar" />
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
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" />
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/edit_list" />
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
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: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
|
||||
android:id="@+id/status_led"
|
||||
android:layout_width="20dp"
|
||||
|
@ -68,16 +57,4 @@
|
|||
android:paddingRight="10dp"
|
||||
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>
|
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue