Selaa lähdekoodia

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

Bugfix/1582/rewrite toggle chat etc
Marcel Hibbe 3 vuotta sitten
vanhempi
commit
d602bf3dfe
27 muutettua tiedostoa jossa 1058 lisäystä ja 1161 poistoa
  1. 2 2
      app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt
  2. 18 3
      app/src/main/AndroidManifest.xml
  3. 326 334
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.java
  4. 131 0
      app/src/main/java/com/nextcloud/talk/activities/CallBaseActivity.java
  5. 458 0
      app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java
  6. 0 158
      app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.kt
  7. 3 6
      app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt
  8. 12 3
      app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java
  9. 0 520
      app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java
  10. 15 24
      app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
  11. 0 6
      app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java
  12. 0 4
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java
  13. 0 5
      app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java
  14. 2 2
      app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java
  15. 10 0
      app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideCurrentRoomHolder.java
  16. 10 0
      app/src/main/res/drawable/ic_baseline_picture_in_picture_alt_24.xml
  17. 0 39
      app/src/main/res/layout/activity_magic_call.xml
  18. 47 15
      app/src/main/res/layout/call_activity.xml
  19. 9 16
      app/src/main/res/layout/call_notification_activity.xml
  20. 1 1
      app/src/main/res/layout/call_states.xml
  21. 0 13
      app/src/main/res/layout/controller_chat.xml
  22. 0 2
      app/src/main/res/values-land/dimens.xml
  23. 0 2
      app/src/main/res/values/dimens.xml
  24. 5 0
      app/src/main/res/values/strings.xml
  25. 7 4
      app/src/main/res/values/styles.xml
  26. 1 1
      scripts/analysis/findbugs-results.txt
  27. 1 1
      scripts/analysis/lint-results.txt

+ 2 - 2
app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt

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

+ 18 - 3
app/src/main/AndroidManifest.xml

@@ -123,9 +123,24 @@
         </activity>
 
         <activity
-            android:name=".activities.MagicCallActivity"
-            android:configChanges="orientation|screenSize"
-            android:launchMode="singleTask" />
+            android:name=".activities.CallActivity"
+            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
+            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
             android:name=".activities.FullScreenImageActivity"

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 326 - 334
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java


+ 131 - 0
app/src/main/java/com/nextcloud/talk/activities/CallBaseActivity.java

@@ -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();
+}

+ 458 - 0
app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java

@@ -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);
+    }
+}

+ 0 - 158
app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.kt

@@ -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
-            }
-    }
-}

+ 3 - 6
app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt

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

+ 12 - 3
app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java

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

+ 0 - 520
app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java

@@ -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");
-            }
-        }
-    }
-}

+ 15 - 24
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt

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

+ 0 - 6
app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java

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

+ 0 - 4
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java

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

+ 0 - 5
app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java

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

+ 2 - 2
app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java

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

+ 10 - 0
app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideCurrentRoomHolder.java

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

+ 10 - 0
app/src/main/res/drawable/ic_baseline_picture_in_picture_alt_24.xml

@@ -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>

+ 0 - 39
app/src/main/res/layout/activity_magic_call.xml

@@ -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>

+ 47 - 15
app/src/main/res/layout/controller_call.xml → app/src/main/res/layout/call_activity.xml

@@ -28,7 +28,7 @@
     android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     android:orientation="vertical"
-    tools:context=".activities.MagicCallActivity">
+    tools:context=".activities.CallActivity">
 
     <LinearLayout
         android:id="@+id/linearWrapperLayout"
@@ -37,7 +37,7 @@
         android:orientation="vertical">
 
         <RelativeLayout
-            android:id="@+id/conversationRelativeLayoutView"
+            android:id="@+id/conversationRelativeLayout"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"
@@ -55,12 +55,12 @@
                 android:stretchMode="columnWidth" />
 
             <FrameLayout
-                android:id="@+id/selfVideoView"
+                android:id="@+id/selfVideoViewWrapper"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content">
 
                 <org.webrtc.SurfaceViewRenderer
-                    android:id="@+id/pip_video_view"
+                    android:id="@+id/selfVideoRenderer"
                     android:layout_width="@dimen/large_preview_dimension"
                     android:layout_height="150dp"
                     android:layout_gravity="center"
@@ -70,7 +70,7 @@
                     tools:visibility="visible" />
 
                 <com.facebook.drawee.view.SimpleDraweeView
-                    android:id="@+id/call_control_switch_camera"
+                    android:id="@+id/switchSelfVideoButton"
                     android:layout_width="40dp"
                     android:layout_height="40dp"
                     android:layout_gravity="center_horizontal|bottom"
@@ -89,7 +89,7 @@
                 android:paddingTop="20dp">
 
                 <TextView
-                    android:id="@+id/callVoiceOrVideoTextView"
+                    android:id="@+id/callModeTextView"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:textAlignment="center"
@@ -122,6 +122,7 @@
                 android:layout_centerVertical="true" />
 
             <include
+                android:id="@+id/callStates"
                 layout="@layout/call_states"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -132,7 +133,7 @@
     </LinearLayout>
 
     <LinearLayout
-        android:id="@+id/callControlsLinearLayout"
+        android:id="@+id/callControls"
         android:layout_width="match_parent"
         android:layout_height="@dimen/call_controls_height"
         android:layout_alignBottom="@id/linearWrapperLayout"
@@ -142,18 +143,17 @@
         android:orientation="horizontal">
 
         <com.facebook.drawee.view.SimpleDraweeView
-            android:id="@+id/callControlToggleChat"
+            android:id="@+id/pictureInPictureButton"
             android:layout_width="60dp"
             android:layout_height="match_parent"
-            android:layout_marginStart="40dp"
             android:layout_marginEnd="10dp"
             android:elevation="10dp"
             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" />
 
         <com.facebook.drawee.view.SimpleDraweeView
-            android:id="@+id/callControlEnableSpeaker"
+            android:id="@+id/speakerButton"
             android:layout_width="60dp"
             android:layout_height="match_parent"
             android:layout_marginStart="10dp"
@@ -163,7 +163,7 @@
             app:roundAsCircle="true" />
 
         <com.facebook.drawee.view.SimpleDraweeView
-            android:id="@+id/call_control_camera"
+            android:id="@+id/cameraButton"
             android:layout_width="60dp"
             android:layout_height="match_parent"
             android:layout_marginStart="10dp"
@@ -174,7 +174,7 @@
             app:roundAsCircle="true" />
 
         <com.facebook.drawee.view.SimpleDraweeView
-            android:id="@+id/call_control_microphone"
+            android:id="@+id/microphoneButton"
             android:layout_width="60dp"
             android:layout_height="match_parent"
             android:layout_marginStart="10dp"
@@ -185,14 +185,46 @@
             app:roundAsCircle="true" />
 
         <com.facebook.drawee.view.SimpleDraweeView
-            android:id="@+id/callControlHangupView"
+            android:id="@+id/hangupButton"
             android:layout_width="60dp"
             android:layout_height="match_parent"
             android:layout_marginStart="10dp"
-            android:layout_marginEnd="40dp"
+            android:layout_marginEnd="10dp"
             app:backgroundImage="@color/nc_darkRed"
             app:placeholderImage="@drawable/ic_call_end_white_24px"
             app:roundAsCircle="true" />
     </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>

+ 9 - 16
app/src/main/res/layout/controller_call_notification.xml → app/src/main/res/layout/call_notification_activity.xml

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

+ 1 - 1
app/src/main/res/layout/call_states.xml

@@ -21,7 +21,7 @@
   -->
 
 <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_height="wrap_content">
 

+ 0 - 13
app/src/main/res/layout/controller_chat.xml

@@ -40,19 +40,6 @@
             android:visibility="gone"
             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
             android:id="@+id/progressBar"
             android:layout_width="match_parent"

+ 0 - 2
app/src/main/res/values-land/dimens.xml

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

+ 0 - 2
app/src/main/res/values/dimens.xml

@@ -33,8 +33,6 @@
     <dimen name="avatar_size">40dp</dimen>
     <dimen name="avatar_size_app_bar">30dp</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="message_bubble_corners_radius">6dp</dimen>

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -221,6 +221,10 @@
     <string name="nc_call_state_with_phone">%1$s with phone</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 -->
     <string name="nc_notification_channel">%1$s on %2$s 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="nc_dialog_invalid_password">Invalid password</string>
     <string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string>
+
 </resources>

+ 7 - 4
app/src/main/res/values/styles.xml

@@ -51,10 +51,6 @@
         <item name="iconTint">@color/fontAppbar</item>
     </style>
 
-    <style name="CallTheme" parent="AppTheme">
-        <item name="android:navigationBarColor">@color/grey950</item>
-    </style>
-
     <style name="BottomNavigationView" parent="@style/Widget.MaterialComponents.BottomNavigationView">
         <item name="elevation">1dp</item>
     </style>
@@ -187,6 +183,13 @@
         <item name="android:navigationBarColor">@color/colorPrimary</item>
     </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">
         <item name="android:typeface">sans</item>
         <item name="android:textStyle">bold</item>

+ 1 - 1
scripts/analysis/findbugs-results.txt

@@ -1 +1 @@
-569
+568

+ 1 - 1
scripts/analysis/lint-results.txt

@@ -1,2 +1,2 @@
 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>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä