Эх сурвалжийг харах

Fix #65

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 7 жил өмнө
parent
commit
58c2b1ba74

+ 1 - 0
app/src/main/AndroidManifest.xml

@@ -26,6 +26,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.permission.BATTERY_STATS"/>
     <uses-permission
     <uses-permission
         android:name="android.permission.USE_CREDENTIALS"
         android:name="android.permission.USE_CREDENTIALS"
         android:maxSdkVersion="22"/>
         android:maxSdkVersion="22"/>

+ 102 - 38
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -27,6 +27,7 @@ package com.nextcloud.talk.activities;
 import android.Manifest;
 import android.Manifest;
 import android.animation.Animator;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Intent;
@@ -40,6 +41,7 @@ import android.support.annotation.Nullable;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatActivity;
 import android.text.TextUtils;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View;
 import android.view.Window;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManager;
@@ -73,6 +75,7 @@ import com.nextcloud.talk.events.MediaStreamEvent;
 import com.nextcloud.talk.events.PeerConnectionEvent;
 import com.nextcloud.talk.events.PeerConnectionEvent;
 import com.nextcloud.talk.events.SessionDescriptionSendEvent;
 import com.nextcloud.talk.events.SessionDescriptionSendEvent;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 import com.nextcloud.talk.persistence.entities.UserEntity;
+import com.nextcloud.talk.utils.animations.PulseAnimation;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.webrtc.MagicAudioManager;
 import com.nextcloud.talk.webrtc.MagicAudioManager;
 import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
 import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
@@ -120,6 +123,7 @@ import autodagger.AutoInjector;
 import butterknife.BindView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import butterknife.ButterKnife;
 import butterknife.OnClick;
 import butterknife.OnClick;
+import butterknife.OnLongClick;
 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;
@@ -204,12 +208,16 @@ public class CallActivity extends AppCompatActivity {
 
 
     private Handler handler = new Handler();
     private Handler handler = new Handler();
 
 
+    private boolean isPTTActive = false;
+    private PulseAnimation pulseAnimation;
+
     private static int getSystemUiVisibility() {
     private static int getSystemUiVisibility() {
         int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
         int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
         flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
         flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
         return flags;
         return flags;
     }
     }
 
 
+    @SuppressLint("ClickableViewAccessibility")
     @Override
     @Override
     protected void onCreate(Bundle savedInstanceState) {
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         super.onCreate(savedInstanceState);
@@ -225,6 +233,12 @@ public class CallActivity extends AppCompatActivity {
         setContentView(R.layout.activity_call);
         setContentView(R.layout.activity_call);
         ButterKnife.bind(this);
         ButterKnife.bind(this);
 
 
+        microphoneControlButton.setOnTouchListener(new microphoneButtonTouchListener());
+        pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
+                .setDuration(310)
+                .setRepeatCount(PulseAnimation.INFINITE)
+                .setRepeatMode(PulseAnimation.REVERSE);
+
         roomToken = getIntent().getExtras().getString("roomToken", "");
         roomToken = getIntent().getExtras().getString("roomToken", "");
         userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable("userEntity"));
         userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable("userEntity"));
         callSession = "0";
         callSession = "0";
@@ -380,18 +394,37 @@ public class CallActivity extends AppCompatActivity {
         }
         }
     }
     }
 
 
+    @OnLongClick(R.id.call_control_microphone)
+    public boolean onMicrophoneLongClick() {
+        if (!audioOn) {
+            handler.removeCallbacksAndMessages(null);
+            isPTTActive = true;
+            callControls.setVisibility(View.VISIBLE);
+        }
+
+        onMicrophoneClick();
+        return true;
+    }
+
     @OnClick(R.id.call_control_microphone)
     @OnClick(R.id.call_control_microphone)
     public void onMicrophoneClick() {
     public void onMicrophoneClick() {
         if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
         if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
-            audioOn = !audioOn;
+            if (!isPTTActive) {
+                audioOn = !audioOn;
 
 
-            if (audioOn) {
-                microphoneControlButton.setImageResource(R.drawable.ic_mic_white_24px);
+                if (audioOn) {
+                    microphoneControlButton.setImageResource(R.drawable.ic_mic_white_24px);
+                } else {
+                    microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
+                }
+
+                toggleMedia(audioOn, false);
             } else {
             } else {
-                microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
+                microphoneControlButton.setImageResource(R.drawable.ic_mic_white_24px);
+                pulseAnimation.start();
+                toggleMedia(true, false);
             }
             }
 
 
-            toggleMedia(audioOn, false);
         } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) {
         } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) {
             // Microphone permission is permanently denied so we cannot request it normally.
             // Microphone permission is permanently denied so we cannot request it normally.
             OpenAppDetailsDialogFragment.show(
             OpenAppDetailsDialogFragment.show(
@@ -658,7 +691,9 @@ public class CallActivity extends AppCompatActivity {
 
 
     private void startCall() {
     private void startCall() {
         inCall = true;
         inCall = true;
-        animateCallControls(false, 7500);
+        if (!isPTTActive) {
+            animateCallControls(false, 7500);
+        }
         startPullingSignalingMessages(false);
         startPullingSignalingMessages(false);
         //registerNetworkReceiver();
         //registerNetworkReceiver();
     }
     }
@@ -1367,47 +1402,76 @@ public class CallActivity extends AppCompatActivity {
     }
     }
 
 
     private void animateCallControls(boolean show, long startDelay) {
     private void animateCallControls(boolean show, long startDelay) {
-        float alpha;
-        long duration;
-
-        if (show) {
-            handler.removeCallbacksAndMessages(null);
-            alpha = 1.0f;
-            duration = 1000;
-            if (callControls.getVisibility() != View.VISIBLE) {
-                callControls.setAlpha(0.0f);
-                callControls.setVisibility(View.VISIBLE);
+        if (!isPTTActive) {
+            float alpha;
+            long duration;
+
+            if (show) {
+                handler.removeCallbacksAndMessages(null);
+                alpha = 1.0f;
+                duration = 1000;
+                if (callControls.getVisibility() != View.VISIBLE) {
+                    callControls.setAlpha(0.0f);
+                    callControls.setVisibility(View.VISIBLE);
+                } else {
+                    handler.postDelayed(() -> animateCallControls(false, 0), 5000);
+                    return;
+                }
             } else {
             } else {
-                handler.postDelayed(() -> animateCallControls(false, 0), 5000);
-                return;
+                alpha = 0.0f;
+                duration = 1000;
             }
             }
-        } else {
-            alpha = 0.0f;
-            duration = 1000;
-        }
 
 
-        callControls.animate()
-                .translationY(0)
-                .alpha(alpha)
-                .setDuration(duration)
-                .setStartDelay(startDelay)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        super.onAnimationEnd(animation);
-                        if (callControls != null) {
-                            if (!show) {
-                                callControls.setVisibility(View.INVISIBLE);
-                            } else {
-                                handler.postDelayed(() -> animateCallControls(false, 0), 5000);
+            callControls.setEnabled(false);
+            callControls.animate()
+                    .translationY(0)
+                    .alpha(alpha)
+                    .setDuration(duration)
+                    .setStartDelay(startDelay)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            super.onAnimationEnd(animation);
+                            if (callControls != null) {
+                                if (!show) {
+                                    callControls.setVisibility(View.INVISIBLE);
+                                } else {
+                                    handler.postDelayed(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            if (!isPTTActive) {
+                                                animateCallControls(false, 0);
+                                            }
+                                        }
+                                    }, 7500);
+                                }
+
+                                callControls.setEnabled(true);
                             }
                             }
                         }
                         }
-                    }
-                });
+                    });
+        }
     }
     }
 
 
     @Override
     @Override
     public void onBackPressed() {
     public void onBackPressed() {
         hangup(false);
         hangup(false);
     }
     }
+
+    private class microphoneButtonTouchListener implements View.OnTouchListener {
+
+        @SuppressLint("ClickableViewAccessibility")
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            v.onTouchEvent(event);
+            if (event.getAction() == MotionEvent.ACTION_UP && isPTTActive) {
+                isPTTActive = false;
+                microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
+                pulseAnimation.stop();
+                toggleMedia(false, false);
+                animateCallControls(false, 5000);
+            }
+            return true;
+        }
+    }
 }
 }

+ 87 - 0
app/src/main/java/com/nextcloud/talk/utils/animations/PulseAnimation.java

@@ -0,0 +1,87 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 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/>.
+ *
+ * Original code taken from https://github.com/thunderrise/android-TNRAnimationHelper under MIT licence
+ * and modified by yours truly to fit the needs of this awesome app.
+ */
+
+package com.nextcloud.talk.utils.animations;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.support.annotation.NonNull;
+import android.view.View;
+
+public class PulseAnimation {
+
+    public static final int RESTART = 1;
+    public static final int REVERSE = 2;
+    public static final int INFINITE = -1;
+    private ObjectAnimator scaleDown;
+    private int duration = 310;
+    private View view;
+    private int repeatMode = ValueAnimator.RESTART;
+    private int repeatCount = INFINITE;
+
+    public static PulseAnimation create() {
+        return new PulseAnimation();
+    }
+
+    public PulseAnimation with(@NonNull View view) {
+        this.view = view;
+        return this;
+    }
+
+    public void start() {
+
+        if (view == null) throw new NullPointerException("View cant be null!");
+
+        scaleDown = ObjectAnimator.ofPropertyValuesHolder(view, PropertyValuesHolder.ofFloat("scaleX", 1.2f), PropertyValuesHolder.ofFloat("scaleY", 1.2f));
+        scaleDown.setDuration(duration);
+        scaleDown.setRepeatMode(repeatMode);
+        scaleDown.setRepeatCount(repeatCount);
+        scaleDown.setAutoCancel(true);
+        scaleDown.start();
+    }
+
+    public void stop() {
+        if (scaleDown != null && view != null) {
+            scaleDown.end();
+            scaleDown.cancel();
+            view.setScaleX(1.0f);
+            view.setScaleY(1.0f);
+        }
+    }
+
+    public PulseAnimation setDuration(int duration) {
+        this.duration = duration;
+        return this;
+    }
+
+    public PulseAnimation setRepeatMode(int repeatMode) {
+        this.repeatMode = repeatMode;
+        return this;
+    }
+
+    public PulseAnimation setRepeatCount(int repeatCount) {
+        this.repeatCount = repeatCount;
+        return this;
+    }
+}