Merge pull request #1655 from nextcloud/bugfix/1582/rewriteToggleChatEtc

Bugfix/1582/rewrite toggle chat etc
This commit is contained in:
Marcel Hibbe 2021-11-11 14:21:05 +01:00 committed by GitHub
commit d602bf3dfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1749 additions and 1759 deletions

View File

@ -41,7 +41,7 @@ import com.bluelinelabs.logansquare.LoganSquare
import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity import com.nextcloud.talk.activities.CallNotificationActivity
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
@ -178,7 +178,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
) )
} }
} else if (type == "call") { } else if (type == "call") {
val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java) val fullScreenIntent = Intent(applicationContext, CallNotificationActivity::class.java)
val bundle = Bundle() val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_ID, decryptedPushMessage!!.id) bundle.putString(BundleKeys.KEY_ROOM_ID, decryptedPushMessage!!.id)
bundle.putParcelable(KEY_USER_ENTITY, signatureVerification!!.userEntity) bundle.putParcelable(KEY_USER_ENTITY, signatureVerification!!.userEntity)

View File

@ -123,9 +123,24 @@
</activity> </activity>
<activity <activity
android:name=".activities.MagicCallActivity" android:name=".activities.CallActivity"
android:configChanges="orientation|screenSize" android:theme="@style/AppTheme.CallLauncher"
android:launchMode="singleTask" /> android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTask"
android:taskAffinity=".call"
android:excludeFromRecents="true"
android:showOnLockScreen="true"/>
<activity
android:name=".activities.CallNotificationActivity"
android:theme="@style/AppTheme.CallLauncher"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTask"
android:taskAffinity=".call"
android:excludeFromRecents="true"
android:showOnLockScreen="true" />
<activity <activity
android:name=".activities.FullScreenImageActivity" android:name=".activities.FullScreenImageActivity"

View File

@ -0,0 +1,131 @@
package com.nextcloud.talk.activities;
import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.Rational;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.nextcloud.talk.BuildConfig;
public abstract class CallBaseActivity extends BaseActivity {
public static final String TAG = "CallBaseActivity";
public PictureInPictureParams.Builder mPictureInPictureParamsBuilder;
public Boolean isInPipMode = false;
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
dismissKeyguard();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (isGreaterEqualOreo() && isPipModePossible()) {
mPictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
}
}
void hideNavigationIfNoPipAvailable(){
if (!isPipModePossible()) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
suppressFitsSystemWindows();
}
}
void dismissKeyguard() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
keyguardManager.requestDismissKeyguard(this, null);
} else {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
}
void enableKeyguard() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(false);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
}
@Override
public void onStop() {
super.onStop();
if (isInPipMode) {
finish();
}
}
@Override
public void onBackPressed() {
if (isPipModePossible()) {
enterPipMode();
}
}
@Override
protected void onUserLeaveHint() {
enterPipMode();
}
void enterPipMode() {
enableKeyguard();
if (isGreaterEqualOreo() && isPipModePossible()) {
Rational pipRatio = new Rational(300, 500);
mPictureInPictureParamsBuilder.setAspectRatio(pipRatio);
enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
} else {
// we don't support other solutions than PIP to have a call in the background.
// If PIP is not available the call is ended when user presses the home button.
Log.d(TAG, "Activity was finished because PIP is not available.");
finish();
}
}
boolean isPipModePossible() {
if (isGreaterEqualOreo()) {
boolean deviceHasPipFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
boolean isPipFeatureGranted = appOpsManager.checkOpNoThrow(
AppOpsManager.OPSTR_PICTURE_IN_PICTURE,
android.os.Process.myUid(),
BuildConfig.APPLICATION_ID) == AppOpsManager.MODE_ALLOWED;
return deviceHasPipFeature && isPipFeatureGranted;
}
return false;
}
boolean isGreaterEqualOreo(){
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
abstract void updateUiForPipMode();
abstract void updateUiForNormalMode();
abstract void suppressFitsSystemWindows();
}

View File

@ -0,0 +1,458 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.activities;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.bluelinelabs.logansquare.LoganSquare;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.databinding.CallNotificationActivityBinding;
import com.nextcloud.talk.events.CallNotificationClick;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomOverall;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import org.greenrobot.eventbus.EventBus;
import org.parceler.Parcels;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import autodagger.AutoInjector;
import butterknife.OnClick;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
@SuppressLint("LongLogTag")
@AutoInjector(NextcloudTalkApplication.class)
public class CallNotificationActivity extends CallBaseActivity {
public static final String TAG = "CallNotificationActivity";
@Inject
NcApi ncApi;
@Inject
AppPreferences appPreferences;
@Inject
Cache cache;
@Inject
EventBus eventBus;
@Inject
Context context;
private List<Disposable> disposablesList = new ArrayList<>();
private Bundle originalBundle;
private String roomId;
private UserEntity userBeingCalled;
private String credentials;
private Conversation currentConversation;
private MediaPlayer mediaPlayer;
private boolean leavingScreen = false;
private Handler handler;
private CallNotificationActivityBinding binding;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
binding = CallNotificationActivityBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
hideNavigationIfNoPipAvailable();
eventBus.post(new CallNotificationClick());
Bundle extras = getIntent().getExtras();
this.roomId = extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), "");
this.currentConversation = Parcels.unwrap(extras.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
this.userBeingCalled = extras.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY());
this.originalBundle = extras;
credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken());
setCallDescriptionText();
if (currentConversation == null) {
handleFromNotification();
} else {
setUpAfterConversationIsKnown();
}
if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) {
playRingtoneSound();
}
initClickListeners();
}
@Override
public void onStart() {
super.onStart();
if (handler == null) {
handler = new Handler();
try {
cache.evictAll();
} catch (IOException e) {
Log.e(TAG, "Failed to evict cache");
}
}
}
private void initClickListeners() {
binding.callAnswerVoiceOnlyView.setOnClickListener(l -> {
Log.d(TAG, "accept call (voice only)");
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), true);
proceedToCall();
});
binding.callAnswerCameraView.setOnClickListener(l -> {
Log.d(TAG, "accept call (with video)");
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false);
proceedToCall();
});
binding.hangupButton.setOnClickListener(l -> hangup());
}
private void setCallDescriptionText() {
String callDescriptionWithoutTypeInfo =
String.format(
getResources().getString(R.string.nc_call_unknown),
getResources().getString(R.string.nc_app_product_name));
binding.incomingCallVoiceOrVideoTextView.setText(callDescriptionWithoutTypeInfo);
}
private void showAnswerControls() {
binding.callAnswerCameraView.setVisibility(View.VISIBLE);
binding.callAnswerVoiceOnlyView.setVisibility(View.VISIBLE);
}
@OnClick(R.id.hangupButton)
void hangup() {
leavingScreen = true;
finish();
}
private void proceedToCall() {
originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken());
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
Intent intent = new Intent(this, CallActivity.class);
intent.putExtras(originalBundle);
startActivity(intent);
}
private void checkIfAnyParticipantsRemainInRoom() {
int apiVersion = ApiUtils.getCallApiVersion(userBeingCalled, new int[]{ApiUtils.APIv4, 1});
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, userBeingCalled.getBaseUrl(),
currentConversation.getToken()))
.subscribeOn(Schedulers.io())
.takeWhile(observable -> !leavingScreen)
.subscribe(new Observer<ParticipantsOverall>() {
@Override
public void onSubscribe(Disposable d) {
disposablesList.add(d);
}
@Override
public void onNext(ParticipantsOverall participantsOverall) {
boolean hasParticipantsInCall = false;
boolean inCallOnDifferentDevice = false;
List<Participant> participantList = participantsOverall.getOcs().getData();
hasParticipantsInCall = participantList.size() > 0;
if (hasParticipantsInCall) {
for (Participant participant : participantList) {
if (participant.getActorType() == Participant.ActorType.USERS &&
participant.getActorId().equals(userBeingCalled.getUserId())) {
inCallOnDifferentDevice = true;
break;
}
}
}
if (!hasParticipantsInCall || inCallOnDifferentDevice) {
runOnUiThread(() -> hangup());
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
if (!leavingScreen) {
handler.postDelayed(() -> checkIfAnyParticipantsRemainInRoom(), 5000);
}
}
});
}
private void handleFromNotification() {
int apiVersion = ApiUtils.getConversationApiVersion(userBeingCalled, new int[]{ApiUtils.APIv4,
ApiUtils.APIv3, 1});
ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, userBeingCalled.getBaseUrl(), roomId))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
disposablesList.add(d);
}
@Override
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
currentConversation = roomOverall.getOcs().data;
setUpAfterConversationIsKnown();
if (apiVersion >= 3) {
boolean hasCallFlags =
CapabilitiesUtil.hasSpreedFeatureCapability(userBeingCalled,
"conversation-call-flags");
if (hasCallFlags) {
if (isInCallWithVideo(currentConversation.callFlag)) {
binding.incomingCallVoiceOrVideoTextView.setText(
String.format(getResources().getString(R.string.nc_call_video),
getResources().getString(R.string.nc_app_product_name)));
} else {
binding.incomingCallVoiceOrVideoTextView.setText(
String.format(getResources().getString(R.string.nc_call_voice),
getResources().getString(R.string.nc_app_product_name)));
}
}
}
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
Log.e(TAG, e.getMessage(), e);
}
@Override
public void onComplete() {
}
});
}
private boolean isInCallWithVideo(int callFlag) {
return (Participant.ParticipantFlags.IN_CALL_WITH_VIDEO.getValue() == callFlag
|| Participant.ParticipantFlags.IN_CALL_WITH_AUDIO_AND_VIDEO.getValue() == callFlag);
}
private void setUpAfterConversationIsKnown() {
binding.conversationNameTextView.setText(currentConversation.getDisplayName());
if(currentConversation.getType() == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL){
setAvatarForOneToOneCall();
} else {
binding.avatarImageView.setImageResource(R.drawable.ic_circular_group);
}
checkIfAnyParticipantsRemainInRoom();
showAnswerControls();
}
private void setAvatarForOneToOneCall() {
ImageRequest imageRequest =
DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(),
R.dimen.avatar_size_big), null);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
binding.avatarImageView.getHierarchy().setImage(
new BitmapDrawable(getResources(), bitmap),
100,
true);
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
Log.e(TAG, "failed to load avatar");
}
}, UiThreadImmediateExecutorService.getInstance());
}
private void endMediaNotifications() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onDestroy() {
leavingScreen = true;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
dispose();
endMediaNotifications();
super.onDestroy();
}
private void dispose() {
if (disposablesList != null) {
for (Disposable disposable : disposablesList) {
if (!disposable.isDisposed()) {
disposable.dispose();
}
}
}
}
private void playRingtoneSound() {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(
callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(this, ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes = new AudioAttributes
.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
isInPipMode = isInPictureInPictureMode;
if (isInPictureInPictureMode) {
updateUiForPipMode();
} else {
updateUiForNormalMode();
}
}
public void updateUiForPipMode() {
binding.callAnswerButtons.setVisibility(View.INVISIBLE);
binding.incomingCallRelativeLayout.setVisibility(View.INVISIBLE);
}
public void updateUiForNormalMode() {
binding.callAnswerButtons.setVisibility(View.VISIBLE);
binding.incomingCallRelativeLayout.setVisibility(View.VISIBLE);
}
@Override
void suppressFitsSystemWindows() {
binding.controllerCallNotificationLayout.setFitsSystemWindows(false);
}
}

View File

@ -1,158 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger (infoi@andy-scherzinger.de)
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.activities
import android.app.KeyguardManager
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.Window
import android.view.WindowManager
import autodagger.AutoInjector
import com.bluelinelabs.conductor.Conductor
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.CallController
import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.ChatController
import com.nextcloud.talk.databinding.ActivityMagicCallBinding
import com.nextcloud.talk.events.ConfigurationChangeEvent
import com.nextcloud.talk.utils.bundle.BundleKeys
@AutoInjector(NextcloudTalkApplication::class)
class MagicCallActivity : BaseActivity() {
lateinit var binding: ActivityMagicCallBinding
private lateinit var chatController: ChatController
private var router: Router? = null
private var chatRouter: Router? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
setTheme(R.style.CallTheme)
requestWindowFeature(Window.FEATURE_NO_TITLE)
dismissKeyguard()
window.addFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN or
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
)
window.decorView.systemUiVisibility = systemUiVisibility
binding = ActivityMagicCallBinding.inflate(layoutInflater)
setContentView(binding.root)
router = Conductor.attachRouter(this, binding.controllerContainer, savedInstanceState)
router!!.setPopsLastView(false)
if (!router!!.hasRootController()) {
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
router!!.setRoot(
RouterTransaction.with(CallNotificationController(intent.extras))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else {
router!!.setRoot(
RouterTransaction.with(CallController(intent.extras))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
}
val extras = intent.extras ?: Bundle()
extras.putBoolean("showToggleChat", true)
chatController = ChatController(extras)
chatRouter = Conductor.attachRouter(this, binding.chatControllerView, savedInstanceState)
chatRouter!!.setRoot(
RouterTransaction.with(chatController)
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
fun showChat() {
enableKeyguard()
binding.chatControllerView.visibility = View.VISIBLE
binding.controllerContainer.visibility = View.GONE
chatController.wasDetached = false
chatController.pullChatMessages(1)
}
fun showCall() {
binding.controllerContainer.visibility = View.VISIBLE
binding.chatControllerView.visibility = View.GONE
chatController.wasDetached = true
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
eventBus.post(ConfigurationChangeEvent())
}
private fun dismissKeyguard() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
setTurnScreenOn(true)
val keyguardManager = getSystemService(KEYGUARD_SERVICE) as KeyguardManager
keyguardManager.requestDismissKeyguard(this, null)
} else {
window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}
}
private fun enableKeyguard() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(false)
} else {
window.clearFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}
}
companion object {
private val TAG = "MagicCallActivity"
private val systemUiVisibility: Int
get() {
var flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
flags = flags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
return flags
}
}
}

View File

@ -40,7 +40,6 @@ import com.google.android.material.snackbar.Snackbar
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.ConversationsListController import com.nextcloud.talk.controllers.ConversationsListController
import com.nextcloud.talk.controllers.LockedController import com.nextcloud.talk.controllers.LockedController
import com.nextcloud.talk.controllers.ServerSelectionController import com.nextcloud.talk.controllers.ServerSelectionController
@ -310,11 +309,9 @@ class MainActivity : BaseActivity(), ActionBarProvider {
handleActionFromContact(intent) handleActionFromContact(intent)
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) { if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) { if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
router!!.pushController( val callNotificationIntent = Intent(this, CallNotificationActivity::class.java)
RouterTransaction.with(CallNotificationController(intent.extras)) intent.extras?.let { callNotificationIntent.putExtras(it) }
.pushChangeHandler(HorizontalChangeHandler()) startActivity(callNotificationIntent)
.popChangeHandler(HorizontalChangeHandler())
)
} else { } else {
ConductorRemapping.remapChatController( ConductorRemapping.remapChatController(
router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1), router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),

View File

@ -15,6 +15,7 @@ import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController; import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.CallActivity;
import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DisplayUtils;
import org.webrtc.MediaStream; import org.webrtc.MediaStream;
@ -79,6 +80,8 @@ public class ParticipantsAdapter extends BaseAdapter {
surfaceViewRenderer = convertView.findViewById(R.id.surface_view); surfaceViewRenderer = convertView.findViewById(R.id.surface_view);
try { try {
Log.d(TAG, "hasSurface: " + participantDisplayItem.getRootEglBase().hasSurface());
surfaceViewRenderer.setMirror(false); surfaceViewRenderer.setMirror(false);
surfaceViewRenderer.init(participantDisplayItem.getRootEglBase().getEglBaseContext(), null); surfaceViewRenderer.init(participantDisplayItem.getRootEglBase().getEglBaseContext(), null);
surfaceViewRenderer.setZOrderMediaOverlay(false); surfaceViewRenderer.setZOrderMediaOverlay(false);
@ -96,7 +99,6 @@ public class ParticipantsAdapter extends BaseAdapter {
layoutParams.height = scaleGridViewItemHeight(); layoutParams.height = scaleGridViewItemHeight();
convertView.setLayoutParams(layoutParams); convertView.setLayoutParams(layoutParams);
TextView nickTextView = convertView.findViewById(R.id.peer_nick_text_view); TextView nickTextView = convertView.findViewById(R.id.peer_nick_text_view);
SimpleDraweeView imageView = convertView.findViewById(R.id.avatarImageView); SimpleDraweeView imageView = convertView.findViewById(R.id.avatarImageView);
@ -110,8 +112,13 @@ public class ParticipantsAdapter extends BaseAdapter {
} else { } else {
imageView.setVisibility(View.VISIBLE); imageView.setVisibility(View.VISIBLE);
surfaceViewRenderer.setVisibility(View.INVISIBLE); surfaceViewRenderer.setVisibility(View.INVISIBLE);
nickTextView.setVisibility(View.VISIBLE);
nickTextView.setText(participantDisplayItem.getNick()); if (((CallActivity) mContext).isInPipMode) {
nickTextView.setVisibility(View.GONE);
} else {
nickTextView.setVisibility(View.VISIBLE);
nickTextView.setText(participantDisplayItem.getNick());
}
imageView.setController(null); imageView.setController(null);
DraweeController draweeController = Fresco.newDraweeControllerBuilder() DraweeController draweeController = Fresco.newDraweeControllerBuilder()
@ -127,7 +134,9 @@ public class ParticipantsAdapter extends BaseAdapter {
} else { } else {
audioOffView.setVisibility(View.INVISIBLE); audioOffView.setVisibility(View.INVISIBLE);
} }
return convertView; return convertView;
} }
private boolean hasVideoStream(ParticipantDisplayItem participantDisplayItem, MediaStream mediaStream) { private boolean hasVideoStream(ParticipantDisplayItem participantDisplayItem, MediaStream mediaStream) {

View File

@ -1,520 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.controllers;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.renderscript.RenderScript;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.postprocessors.BlurPostProcessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.CallNotificationClick;
import com.nextcloud.talk.events.ConfigurationChangeEvent;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomOverall;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.michaelevans.colorart.library.ColorArt;
import org.parceler.Parcels;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
@AutoInjector(NextcloudTalkApplication.class)
public class CallNotificationController extends BaseController {
private static final String TAG = "CallNotificationController";
@Inject
NcApi ncApi;
@Inject
AppPreferences appPreferences;
@Inject
Cache cache;
@Inject
EventBus eventBus;
@Inject
Context context;
@BindView(R.id.incomingCallVoiceOrVideoTextView)
TextView incomingCallVoiceOrVideoTextView;
@BindView(R.id.conversationNameTextView)
TextView conversationNameTextView;
@BindView(R.id.avatarImageView)
SimpleDraweeView avatarImageView;
@BindView(R.id.callAnswerVoiceOnlyView)
SimpleDraweeView callAnswerVoiceOnlyView;
@BindView(R.id.callAnswerCameraView)
SimpleDraweeView callAnswerCameraView;
@BindView(R.id.backgroundImageView)
ImageView backgroundImageView;
@BindView(R.id.incomingTextRelativeLayout)
RelativeLayout incomingTextRelativeLayout;
private List<Disposable> disposablesList = new ArrayList<>();
private Bundle originalBundle;
private String roomId;
private UserEntity userBeingCalled;
private String credentials;
private Conversation currentConversation;
private MediaPlayer mediaPlayer;
private boolean leavingScreen = false;
private RenderScript renderScript;
private Handler handler;
public CallNotificationController(Bundle args) {
super(args);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
eventBus.post(new CallNotificationClick());
this.roomId = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), "");
this.currentConversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
this.userBeingCalled = args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY());
this.originalBundle = args;
credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken());
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_call_notification, container, false);
}
private void showAnswerControls() {
callAnswerCameraView.setVisibility(View.VISIBLE);
callAnswerVoiceOnlyView.setVisibility(View.VISIBLE);
}
@OnClick(R.id.callControlHangupView)
void hangup() {
leavingScreen = true;
if (getActivity() != null) {
getActivity().finish();
}
}
@OnClick(R.id.callAnswerCameraView)
void answerWithCamera() {
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false);
proceedToCall();
}
@OnClick(R.id.callAnswerVoiceOnlyView)
void answerVoiceOnly() {
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), true);
proceedToCall();
}
private void proceedToCall() {
originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken());
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
.popChangeHandler(new HorizontalChangeHandler())
.pushChangeHandler(new HorizontalChangeHandler()));
}
private void checkIfAnyParticipantsRemainInRoom() {
int apiVersion = ApiUtils.getCallApiVersion(userBeingCalled, new int[] {ApiUtils.APIv4, 1});
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, userBeingCalled.getBaseUrl(),
currentConversation.getToken()))
.subscribeOn(Schedulers.io())
.takeWhile(observable -> !leavingScreen)
.subscribe(new Observer<ParticipantsOverall>() {
@Override
public void onSubscribe(Disposable d) {
disposablesList.add(d);
}
@Override
public void onNext(ParticipantsOverall participantsOverall) {
boolean hasParticipantsInCall = false;
boolean inCallOnDifferentDevice = false;
List<Participant> participantList = participantsOverall.getOcs().getData();
hasParticipantsInCall = participantList.size() > 0;
if (hasParticipantsInCall) {
for (Participant participant : participantList) {
if (participant.getActorType() == Participant.ActorType.USERS &&
participant.getActorId().equals(userBeingCalled.getUserId())) {
inCallOnDifferentDevice = true;
break;
}
}
}
if (!hasParticipantsInCall || inCallOnDifferentDevice) {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> hangup());
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
if (!leavingScreen) {
handler.postDelayed(() -> checkIfAnyParticipantsRemainInRoom(), 5000);
}
}
});
}
private void handleFromNotification() {
int apiVersion = ApiUtils.getConversationApiVersion(userBeingCalled, new int[] {ApiUtils.APIv4,
ApiUtils.APIv3, 1});
ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, userBeingCalled.getBaseUrl(), roomId))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
disposablesList.add(d);
}
@Override
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
currentConversation = roomOverall.getOcs().data;
runAllThings();
if (apiVersion >= 3) {
boolean hasCallFlags =
CapabilitiesUtil.hasSpreedFeatureCapability(userBeingCalled,
"conversation-call-flags");
if (hasCallFlags) {
if (isInCallWithVideo(currentConversation.callFlag)) {
incomingCallVoiceOrVideoTextView.setText(
String.format(getResources().getString(R.string.nc_call_video),
getResources().getString(R.string.nc_app_product_name)));
} else {
incomingCallVoiceOrVideoTextView.setText(
String.format(getResources().getString(R.string.nc_call_voice),
getResources().getString(R.string.nc_app_product_name)));
}
}
}
}
@SuppressLint("LongLogTag")
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
Log.e(TAG, e.getMessage(), e);
}
@Override
public void onComplete() {
}
});
}
private boolean isInCallWithVideo(int callFlag) {
return (Participant.ParticipantFlags.IN_CALL_WITH_VIDEO.getValue() == callFlag
|| Participant.ParticipantFlags.IN_CALL_WITH_AUDIO_AND_VIDEO.getValue() == callFlag);
}
private void runAllThings() {
if (conversationNameTextView != null) {
conversationNameTextView.setText(currentConversation.getDisplayName());
}
loadAvatar();
checkIfAnyParticipantsRemainInRoom();
showAnswerControls();
}
@SuppressLint({"LongLogTag"})
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
String callDescriptionWithoutTypeInfo =
String.format(
getResources().getString(R.string.nc_call_unknown),
getResources().getString(R.string.nc_app_product_name));
incomingCallVoiceOrVideoTextView.setText(callDescriptionWithoutTypeInfo);
renderScript = RenderScript.create(getActivity());
if (handler == null) {
handler = new Handler();
try {
cache.evictAll();
} catch (IOException e) {
Log.e(TAG, "Failed to evict cache");
}
}
if (currentConversation == null) {
handleFromNotification();
} else {
runAllThings();
}
if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) {
playRingtoneSound();
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) avatarImageView.getLayoutParams();
int dimen = (int) getResources().getDimension(R.dimen.avatar_size_very_big);
layoutParams.width = dimen;
layoutParams.height = dimen;
avatarImageView.setLayoutParams(layoutParams);
}
@Override
protected void onDetach(@NonNull View view) {
super.onDetach(view);
eventBus.unregister(this);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
eventBus.register(this);
}
private void loadAvatar() {
switch (currentConversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
avatarImageView.setVisibility(View.VISIBLE);
ImageRequest imageRequest =
DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(),
R.dimen.avatar_size_very_big),
null);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
if (avatarImageView != null) {
avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
true);
if (getResources() != null) {
incomingTextRelativeLayout.setBackground(
getResources().getDrawable(R.drawable.incoming_gradient));
}
if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 ||
AvatarStatusCodeHolder.getInstance().getStatusCode() == 0) {
if (getActivity() != null) {
Bitmap backgroundBitmap = bitmap.copy(bitmap.getConfig(), true);
new BlurPostProcessor(5, getActivity()).process(backgroundBitmap);
backgroundImageView.setImageDrawable(new BitmapDrawable(backgroundBitmap));
}
} else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
ColorArt colorArt = new ColorArt(bitmap);
int color = colorArt.getBackgroundColor();
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.75f;
color = Color.HSVToColor(hsv);
backgroundImageView.setImageDrawable(new ColorDrawable(color));
}
}
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
// unused atm
}
}, UiThreadImmediateExecutorService.getInstance());
break;
case ROOM_GROUP_CALL:
avatarImageView.setImageResource(R.drawable.ic_circular_group);
case ROOM_PUBLIC_CALL:
avatarImageView.setImageResource(R.drawable.ic_circular_group);
break;
default:
}
}
private void endMediaNotifications() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onDestroy() {
AvatarStatusCodeHolder.getInstance().setStatusCode(0);
leavingScreen = true;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
dispose();
endMediaNotifications();
super.onDestroy();
}
private void dispose() {
if (disposablesList != null) {
for (Disposable disposable : disposablesList) {
if (!disposable.isDisposed()) {
disposable.dispose();
}
}
}
}
@SuppressLint("LongLogTag")
private void playRingtoneSound() {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(
callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null && getActivity() != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getActivity(), ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes = new AudioAttributes
.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
}
}

View File

@ -94,7 +94,7 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage import com.facebook.imagepipeline.image.CloseableImage
import com.google.android.flexbox.FlexboxLayout import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder
@ -232,7 +232,6 @@ class ChatController(args: Bundle) :
val roomId: String val roomId: String
val voiceOnly: Boolean val voiceOnly: Boolean
var isFirstMessagesProcessing = true var isFirstMessagesProcessing = true
var isLeavingForConversation: Boolean = false
var wasDetached: Boolean = false var wasDetached: Boolean = false
var emojiPopup: EmojiPopup? = null var emojiPopup: EmojiPopup? = null
@ -270,6 +269,8 @@ class ChatController(args: Bundle) :
this.roomToken = args.getString(KEY_ROOM_TOKEN, "") this.roomToken = args.getString(KEY_ROOM_TOKEN, "")
this.sharedText = args.getString(BundleKeys.KEY_SHARED_TEXT, "") this.sharedText = args.getString(BundleKeys.KEY_SHARED_TEXT, "")
Log.d(TAG, "roomToken = " + roomToken)
if (args.containsKey(KEY_ACTIVE_CONVERSATION)) { if (args.containsKey(KEY_ACTIVE_CONVERSATION)) {
this.currentConversation = Parcels.unwrap<Conversation>(args.getParcelable(KEY_ACTIVE_CONVERSATION)) this.currentConversation = Parcels.unwrap<Conversation>(args.getParcelable(KEY_ACTIVE_CONVERSATION))
} }
@ -290,6 +291,7 @@ class ChatController(args: Bundle) :
} }
private fun getRoomInfo() { private fun getRoomInfo() {
Log.d(TAG, "getRoomInfo")
val shouldRepeat = CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") val shouldRepeat = CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "webinary-lobby")
if (shouldRepeat) { if (shouldRepeat) {
checkingLobbyStatus = true checkingLobbyStatus = true
@ -309,6 +311,8 @@ class ChatController(args: Bundle) :
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
override fun onNext(roomOverall: RoomOverall) { override fun onNext(roomOverall: RoomOverall) {
currentConversation = roomOverall.ocs.data currentConversation = roomOverall.ocs.data
Log.d(TAG, "currentConversation.toString : " + currentConversation.toString())
Log.d(TAG, "currentConversation.sessionId : " + currentConversation?.sessionId)
loadAvatarForStatusBar() loadAvatarForStatusBar()
setTitle() setTitle()
@ -420,6 +424,7 @@ class ChatController(args: Bundle) :
override fun onViewBound(view: View) { override fun onViewBound(view: View) {
actionBar?.show() actionBar?.show()
Log.d(TAG, "onViewBound")
var adapterWasNull = false var adapterWasNull = false
if (adapter == null) { if (adapter == null) {
@ -577,15 +582,6 @@ class ChatController(args: Bundle) :
binding.messageInputView.setPadding(0, 0, 0, 0) binding.messageInputView.setPadding(0, 0, 0, 0)
if (args.containsKey("showToggleChat") && args.getBoolean("showToggleChat")) {
binding.callControlToggleChat.visibility = View.VISIBLE
wasDetached = true
}
binding.callControlToggleChat.setOnClickListener {
(activity as MagicCallActivity).showCall()
}
binding.messagesListView.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.messagesListView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
@ -1376,10 +1372,8 @@ class ChatController(args: Bundle) :
activity?.findViewById<View>(R.id.toolbar)?.setOnClickListener { v -> showConversationInfoScreen() } activity?.findViewById<View>(R.id.toolbar)?.setOnClickListener { v -> showConversationInfoScreen() }
} }
isLeavingForConversation = false
ApplicationWideCurrentRoomHolder.getInstance().currentRoomId = roomId ApplicationWideCurrentRoomHolder.getInstance().currentRoomId = roomId
ApplicationWideCurrentRoomHolder.getInstance().currentRoomToken = roomId ApplicationWideCurrentRoomHolder.getInstance().currentRoomToken = roomToken
ApplicationWideCurrentRoomHolder.getInstance().isInCall = false
ApplicationWideCurrentRoomHolder.getInstance().userInRoom = conversationUser ApplicationWideCurrentRoomHolder.getInstance().userInRoom = conversationUser
val smileyButton = binding.messageInputView.findViewById<ImageButton>(R.id.smileyButton) val smileyButton = binding.messageInputView.findViewById<ImageButton>(R.id.smileyButton)
@ -1443,11 +1437,6 @@ class ChatController(args: Bundle) :
override fun onDetach(view: View) { override fun onDetach(view: View) {
super.onDetach(view) super.onDetach(view)
if (!isLeavingForConversation) {
// current room is still "active", we need the info
ApplicationWideCurrentRoomHolder.getInstance().clear()
}
eventBus?.unregister(this) eventBus?.unregister(this)
if (activity != null) { if (activity != null) {
@ -1457,8 +1446,10 @@ class ChatController(args: Bundle) :
if (conversationUser != null && if (conversationUser != null &&
activity != null && activity != null &&
!activity?.isChangingConfigurations!! && !activity?.isChangingConfigurations!! &&
!isLeavingForConversation !ApplicationWideCurrentRoomHolder.getInstance().isInCall &&
!ApplicationWideCurrentRoomHolder.getInstance().isDialing
) { ) {
ApplicationWideCurrentRoomHolder.getInstance().clear()
wasDetached = true wasDetached = true
leaveRoom() leaveRoom()
} }
@ -2129,7 +2120,7 @@ class ChatController(args: Bundle) :
} }
private fun startACall(isVoiceOnlyCall: Boolean) { private fun startACall(isVoiceOnlyCall: Boolean) {
isLeavingForConversation = true ApplicationWideCurrentRoomHolder.getInstance().isDialing = true
val callIntent = getIntentForCall(isVoiceOnlyCall) val callIntent = getIntentForCall(isVoiceOnlyCall)
if (callIntent != null) { if (callIntent != null) {
startActivity(callIntent) startActivity(callIntent)
@ -2151,7 +2142,7 @@ class ChatController(args: Bundle) :
} }
return if (activity != null) { return if (activity != null) {
val callIntent = Intent(activity, MagicCallActivity::class.java) val callIntent = Intent(activity, CallActivity::class.java)
callIntent.putExtras(bundle) callIntent.putExtras(bundle)
callIntent callIntent
} else { } else {
@ -2336,7 +2327,7 @@ class ChatController(args: Bundle) :
menu.findItem(R.id.action_forward_message).isVisible = menu.findItem(R.id.action_forward_message).isVisible =
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getMessageType() ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getMessageType()
if (menu.hasVisibleItems()) { if (menu.hasVisibleItems()) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
setForceShowIcon(true) setForceShowIcon(true)
} }
show() show()
@ -2509,7 +2500,7 @@ class ChatController(args: Bundle) :
} }
override fun onNext(roomOverall: RoomOverall) { override fun onNext(roomOverall: RoomOverall) {
val conversationIntent = Intent(activity, MagicCallActivity::class.java) val conversationIntent = Intent(activity, CallActivity::class.java)
val bundle = Bundle() val bundle = Bundle()
bundle.putParcelable(KEY_USER_ENTITY, conversationUser) bundle.putParcelable(KEY_USER_ENTITY, conversationUser)
bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token) bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token)

View File

@ -22,7 +22,6 @@ package com.nextcloud.talk.controllers;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
@ -45,7 +44,6 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.kennyc.bottomsheet.BottomSheet; import com.kennyc.bottomsheet.BottomSheet;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.MagicCallActivity;
import com.nextcloud.talk.adapters.items.GenericTextHeaderItem; import com.nextcloud.talk.adapters.items.GenericTextHeaderItem;
import com.nextcloud.talk.adapters.items.UserItem; import com.nextcloud.talk.adapters.items.UserItem;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
@ -106,7 +104,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.SelectableAdapter; import eu.davidea.flexibleadapter.SelectableAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible;
import io.reactivex.Observer; import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
@ -897,13 +894,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
@Override @Override
public void onNext(RoomOverall roomOverall) { public void onNext(RoomOverall roomOverall) {
if (getActivity() != null) { if (getActivity() != null) {
Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser);
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken()); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken());
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId()); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId());
conversationIntent.putExtras(bundle);
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(),
Parcels.wrap(roomOverall.getOcs().getData())); Parcels.wrap(roomOverall.getOcs().getData()));

View File

@ -38,7 +38,6 @@ import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.MagicCallActivity;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
@ -714,7 +713,6 @@ public class OperationsMenuController extends BaseController {
eventBus.post(new BottomSheetLockEvent(true, 0, eventBus.post(new BottomSheetLockEvent(true, 0,
true, true, dismissView)); true, true, dismissView));
Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken()); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken());
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId()); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId());
@ -723,8 +721,6 @@ public class OperationsMenuController extends BaseController {
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation)); bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation));
bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword); bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword);
conversationIntent.putExtras(bundle);
if (getParentController() != null) { if (getParentController() != null) {
ConductorRemapping.INSTANCE.remapChatController(getParentController().getRouter(), currentUser.getId(), ConductorRemapping.INSTANCE.remapChatController(getParentController().getRouter(), currentUser.getId(),
conversation.getToken(), bundle, true); conversation.getToken(), bundle, true);

View File

@ -33,7 +33,6 @@ import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.LoggingUtils; import com.nextcloud.talk.utils.LoggingUtils;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder;
import com.nextcloud.talk.utils.ssl.MagicKeyManager; import com.nextcloud.talk.utils.ssl.MagicKeyManager;
import com.nextcloud.talk.utils.ssl.MagicTrustManager; import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat; import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;
@ -253,10 +252,6 @@ public class RestModule {
Response response = chain.proceed(request); Response response = chain.proceed(request);
if (request.url().encodedPath().contains("/avatar/")) {
AvatarStatusCodeHolder.getInstance().setStatusCode(response.code());
}
return response; return response;
} }
} }

View File

@ -48,7 +48,7 @@ import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor; import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequest;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.activities.CallActivity;
import com.nextcloud.talk.activities.MainActivity; import com.nextcloud.talk.activities.MainActivity;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
@ -590,7 +590,7 @@ public class NotificationWorker extends Worker {
boolean startACall = decryptedPushMessage.getType().equals("call"); boolean startACall = decryptedPushMessage.getType().equals("call");
if (startACall) { if (startACall) {
intent = new Intent(context, MagicCallActivity.class); intent = new Intent(context, CallActivity.class);
} else { } else {
intent = new Intent(context, MainActivity.class); intent = new Intent(context, MainActivity.class);
} }

View File

@ -28,6 +28,7 @@ public class ApplicationWideCurrentRoomHolder {
private String currentRoomToken = ""; private String currentRoomToken = "";
private UserEntity userInRoom = new UserEntity(); private UserEntity userInRoom = new UserEntity();
private boolean inCall = false; private boolean inCall = false;
private boolean isDialing = false;
private String session = ""; private String session = "";
public static ApplicationWideCurrentRoomHolder getInstance() { public static ApplicationWideCurrentRoomHolder getInstance() {
@ -38,6 +39,7 @@ public class ApplicationWideCurrentRoomHolder {
currentRoomId = ""; currentRoomId = "";
userInRoom = new UserEntity(); userInRoom = new UserEntity();
inCall = false; inCall = false;
isDialing = false;
currentRoomToken = ""; currentRoomToken = "";
session = ""; session = "";
} }
@ -74,6 +76,14 @@ public class ApplicationWideCurrentRoomHolder {
this.inCall = inCall; this.inCall = inCall;
} }
public boolean isDialing() {
return isDialing;
}
public void setDialing(boolean dialing) {
isDialing = dialing;
}
public String getSession() { public String getSession() {
return session; return session;
} }

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<path
android:fillColor="#FF000000"
android:pathData="M19,11h-8v6h8v-6zM23,19L23,4.98C23,3.88 22.1,3 21,3L3,3c-1.1,0 -2,0.88 -2,1.98L1,19c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM21,19.02L3,19.02L3,4.97h18v14.05z"/>
</vector>

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ 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 3 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, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".activities.MagicCallActivity">
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="@+id/controller_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="@+id/chatControllerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</RelativeLayout>

View File

@ -28,7 +28,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:orientation="vertical" android:orientation="vertical"
tools:context=".activities.MagicCallActivity"> tools:context=".activities.CallActivity">
<LinearLayout <LinearLayout
android:id="@+id/linearWrapperLayout" android:id="@+id/linearWrapperLayout"
@ -37,7 +37,7 @@
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout <RelativeLayout
android:id="@+id/conversationRelativeLayoutView" android:id="@+id/conversationRelativeLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
@ -55,12 +55,12 @@
android:stretchMode="columnWidth" /> android:stretchMode="columnWidth" />
<FrameLayout <FrameLayout
android:id="@+id/selfVideoView" android:id="@+id/selfVideoViewWrapper"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<org.webrtc.SurfaceViewRenderer <org.webrtc.SurfaceViewRenderer
android:id="@+id/pip_video_view" android:id="@+id/selfVideoRenderer"
android:layout_width="@dimen/large_preview_dimension" android:layout_width="@dimen/large_preview_dimension"
android:layout_height="150dp" android:layout_height="150dp"
android:layout_gravity="center" android:layout_gravity="center"
@ -70,7 +70,7 @@
tools:visibility="visible" /> tools:visibility="visible" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/call_control_switch_camera" android:id="@+id/switchSelfVideoButton"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center_horizontal|bottom" android:layout_gravity="center_horizontal|bottom"
@ -89,7 +89,7 @@
android:paddingTop="20dp"> android:paddingTop="20dp">
<TextView <TextView
android:id="@+id/callVoiceOrVideoTextView" android:id="@+id/callModeTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAlignment="center" android:textAlignment="center"
@ -122,6 +122,7 @@
android:layout_centerVertical="true" /> android:layout_centerVertical="true" />
<include <include
android:id="@+id/callStates"
layout="@layout/call_states" layout="@layout/call_states"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -132,7 +133,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/callControlsLinearLayout" android:id="@+id/callControls"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/call_controls_height" android:layout_height="@dimen/call_controls_height"
android:layout_alignBottom="@id/linearWrapperLayout" android:layout_alignBottom="@id/linearWrapperLayout"
@ -142,18 +143,17 @@
android:orientation="horizontal"> android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlToggleChat" android:id="@+id/pictureInPictureButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="40dp"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:elevation="10dp" android:elevation="10dp"
app:backgroundImage="@color/call_buttons_background" app:backgroundImage="@color/call_buttons_background"
app:placeholderImage="@drawable/ic_comment_white" app:placeholderImage="@drawable/ic_baseline_picture_in_picture_alt_24"
app:roundAsCircle="true" /> app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlEnableSpeaker" android:id="@+id/speakerButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
@ -163,7 +163,7 @@
app:roundAsCircle="true" /> app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/call_control_camera" android:id="@+id/cameraButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
@ -174,7 +174,7 @@
app:roundAsCircle="true" /> app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/call_control_microphone" android:id="@+id/microphoneButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
@ -185,14 +185,46 @@
app:roundAsCircle="true" /> app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlHangupView" android:id="@+id/hangupButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="40dp" android:layout_marginEnd="10dp"
app:backgroundImage="@color/nc_darkRed" app:backgroundImage="@color/nc_darkRed"
app:placeholderImage="@drawable/ic_call_end_white_24px" app:placeholderImage="@drawable/ic_call_end_white_24px"
app:roundAsCircle="true" /> app:roundAsCircle="true" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/pipGroupCallOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/black"
android:gravity="center"
android:visibility="invisible">
<TextView
android:id="@+id/pipCallConversationNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-30dp"
android:layout_marginBottom="15dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:textAlignment="center"
android:maxLines="3"
android:ellipsize="end"
android:textColor="@color/white"
android:textSize="16sp"
tools:text="our group call" />
<com.facebook.drawee.view.SimpleDraweeView
android:layout_width="80dp"
android:layout_height="80dp"
app:backgroundImage="@drawable/ic_circular_group"
app:roundAsCircle="true" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -22,19 +22,13 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/controllerCallNotificationLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="@color/grey950">
<ImageView
android:id="@+id/backgroundImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="centerCrop"
android:src="@color/grey950"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<LinearLayout <LinearLayout
android:id="@+id/callAnswerButtons"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
@ -54,7 +48,7 @@
tools:visibility="visible" /> tools:visibility="visible" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlHangupView" android:id="@+id/hangupButton"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="24dp" android:layout_margin="24dp"
@ -75,7 +69,7 @@
</LinearLayout> </LinearLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/incomingTextRelativeLayout" android:id="@+id/incomingCallRelativeLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -119,10 +113,9 @@
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/avatarImageView" android:id="@+id/avatarImageView"
android:layout_width="@dimen/avatar_size_very_big" android:layout_width="@dimen/avatar_size_big"
android:layout_height="@dimen/avatar_size_very_big" android:layout_height="@dimen/avatar_size_big"
android:layout_centerInParent="true" android:layout_centerInParent="true"
app:roundAsCircle="true" app:roundAsCircle="true" />
tools:srcCompat="@tools:sample/avatars[0]" />
</RelativeLayout> </RelativeLayout>

View File

@ -21,7 +21,7 @@
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/callStateRelativeLayoutView" android:id="@+id/callStateRelativeLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">

View File

@ -40,19 +40,6 @@
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlToggleChat"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentEnd="true"
android:layout_margin="16dp"
android:elevation="10dp"
android:visibility="gone"
app:backgroundImage="@color/call_buttons_background"
app:placeholderImage="@drawable/ic_call_black_24dp"
app:roundAsCircle="true"
tools:visibility="visible" />
<LinearLayout <LinearLayout
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -21,6 +21,4 @@
<resources> <resources>
<!-- Default screen margins, per the Android Design guidelines. --> <!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">24dp</dimen> <dimen name="activity_horizontal_margin">24dp</dimen>
<dimen name="avatar_size_very_big">120dp</dimen>
</resources> </resources>

View File

@ -33,8 +33,6 @@
<dimen name="avatar_size">40dp</dimen> <dimen name="avatar_size">40dp</dimen>
<dimen name="avatar_size_app_bar">30dp</dimen> <dimen name="avatar_size_app_bar">30dp</dimen>
<dimen name="avatar_size_big">96dp</dimen> <dimen name="avatar_size_big">96dp</dimen>
<dimen name="avatar_size_very_big">@dimen/avatar_fetching_size_very_big</dimen>
<dimen name="avatar_fetching_size_very_big">180dp</dimen>
<dimen name="chat_text_size">14sp</dimen> <dimen name="chat_text_size">14sp</dimen>
<dimen name="message_bubble_corners_radius">6dp</dimen> <dimen name="message_bubble_corners_radius">6dp</dimen>

View File

@ -221,6 +221,10 @@
<string name="nc_call_state_with_phone">%1$s with phone</string> <string name="nc_call_state_with_phone">%1$s with phone</string>
<string name="nc_call_state_with_video">%1$s with video</string> <string name="nc_call_state_with_video">%1$s with video</string>
<!-- Picture in Picture -->
<string name="nc_pip_microphone_mute">Mute microphone</string>
<string name="nc_pip_microphone_unmute">Enable microphone</string>
<!-- Notification channels --> <!-- Notification channels -->
<string name="nc_notification_channel">%1$s on %2$s notification channel</string> <string name="nc_notification_channel">%1$s on %2$s notification channel</string>
<string name="nc_notification_channel_calls">Calls notification channel</string> <string name="nc_notification_channel_calls">Calls notification channel</string>
@ -468,4 +472,5 @@
<string name="filename_progress">%1$s (%2$d)</string> <string name="filename_progress">%1$s (%2$d)</string>
<string name="nc_dialog_invalid_password">Invalid password</string> <string name="nc_dialog_invalid_password">Invalid password</string>
<string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string> <string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string>
</resources> </resources>

View File

@ -51,10 +51,6 @@
<item name="iconTint">@color/fontAppbar</item> <item name="iconTint">@color/fontAppbar</item>
</style> </style>
<style name="CallTheme" parent="AppTheme">
<item name="android:navigationBarColor">@color/grey950</item>
</style>
<style name="BottomNavigationView" parent="@style/Widget.MaterialComponents.BottomNavigationView"> <style name="BottomNavigationView" parent="@style/Widget.MaterialComponents.BottomNavigationView">
<item name="elevation">1dp</item> <item name="elevation">1dp</item>
</style> </style>
@ -187,6 +183,13 @@
<item name="android:navigationBarColor">@color/colorPrimary</item> <item name="android:navigationBarColor">@color/colorPrimary</item>
</style> </style>
<!-- Call Launch screen -->
<style name="AppTheme.CallLauncher">
<item name="android:windowBackground">@color/grey950</item>
<item name="android:statusBarColor">@color/grey950</item>
<item name="android:navigationBarColor">@color/grey950</item>
</style>
<style name="Nextcloud.Material.TextButton" parent="Widget.MaterialComponents.Button.TextButton.Icon"> <style name="Nextcloud.Material.TextButton" parent="Widget.MaterialComponents.Button.TextButton.Icon">
<item name="android:typeface">sans</item> <item name="android:typeface">sans</item>
<item name="android:textStyle">bold</item> <item name="android:textStyle">bold</item>

View File

@ -1 +1 @@
569 568

View File

@ -1,2 +1,2 @@
DO NOT TOUCH; GENERATED BY DRONE DO NOT TOUCH; GENERATED BY DRONE
<span class="mdl-layout-title">Lint Report: 1 error and 269 warnings</span> <span class="mdl-layout-title">Lint Report: 1 error and 238 warnings</span>