From 3f70454cc2fdd80de30a40f55534322e94500092 Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 23 Aug 2018 03:19:30 -0700 Subject: [PATCH] Fix controller ui toggling when using SphericalSurfaceView ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=209909845 --- .../android/exoplayer2/ui/PlayerView.java | 33 ++++++-- .../ui/spherical/SingleTapListener.java | 29 +++++++ .../ui/spherical/SphericalSurfaceView.java | 8 +- .../exoplayer2/ui/spherical/TouchTracker.java | 83 ++++++++++++------- 4 files changed, 115 insertions(+), 38 deletions(-) create mode 100644 library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SingleTapListener.java diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java index 011976ad12..8ad8899216 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java @@ -59,6 +59,7 @@ import com.google.android.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode; +import com.google.android.exoplayer2.ui.spherical.SingleTapListener; import com.google.android.exoplayer2.ui.spherical.SphericalSurfaceView; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ErrorMessageProvider; @@ -390,6 +391,7 @@ public class PlayerView extends FrameLayout { Assertions.checkState(Util.SDK_INT >= 15); SphericalSurfaceView sphericalSurfaceView = new SphericalSurfaceView(context); sphericalSurfaceView.setSurfaceListener(componentListener); + sphericalSurfaceView.setSingleTapListener(componentListener); surfaceView = sphericalSurfaceView; break; default: @@ -1021,15 +1023,10 @@ public class PlayerView extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent ev) { - if (!useController || player == null || ev.getActionMasked() != MotionEvent.ACTION_DOWN) { + if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { return false; } - if (!controller.isVisible()) { - maybeShowController(true); - } else if (controllerHideOnTouch) { - controller.hide(); - } - return true; + return toggleControllerVisibility(); } @Override @@ -1067,6 +1064,18 @@ public class PlayerView extends FrameLayout { } } + private boolean toggleControllerVisibility() { + if (!useController || player == null) { + return false; + } + if (!controller.isVisible()) { + maybeShowController(true); + } else if (controllerHideOnTouch) { + controller.hide(); + } + return true; + } + /** Shows the playback controls, but only if forced or shown indefinitely. */ private void maybeShowController(boolean isForced) { if (isPlayingAd() && controllerHideDuringAds) { @@ -1286,7 +1295,8 @@ public class PlayerView extends FrameLayout { TextOutput, VideoListener, OnLayoutChangeListener, - SphericalSurfaceView.SurfaceListener { + SphericalSurfaceView.SurfaceListener, + SingleTapListener { // TextOutput implementation @@ -1391,5 +1401,12 @@ public class PlayerView extends FrameLayout { } } } + + // SingleTapListener implementation + + @Override + public boolean onSingleTapUp(MotionEvent e) { + return toggleControllerVisibility(); + } } } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SingleTapListener.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SingleTapListener.java new file mode 100644 index 0000000000..7328bdfcab --- /dev/null +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SingleTapListener.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ui.spherical; + +import android.view.MotionEvent; + +/** Listens tap events on a {@link android.view.View}. */ +public interface SingleTapListener { + /** + * Notified when a tap occurs with the up {@link MotionEvent} that triggered it. + * + * @param e The up motion event that completed the first tap. + * @return Whether the event is consumed. + */ + boolean onSingleTapUp(MotionEvent e); +} diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java index d90b1d31b3..483376dba4 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java @@ -91,6 +91,7 @@ public final class SphericalSurfaceView extends GLSurfaceView private final PhoneOrientationListener phoneOrientationListener; private final Renderer renderer; private final Handler mainHandler; + private final TouchTracker touchTracker; private @Nullable SurfaceListener surfaceListener; private @Nullable SurfaceTexture surfaceTexture; private @Nullable Surface surface; @@ -121,7 +122,7 @@ public final class SphericalSurfaceView extends GLSurfaceView renderer = new Renderer(); - TouchTracker touchTracker = new TouchTracker(renderer, PX_PER_DEGREES); + touchTracker = new TouchTracker(context, renderer, PX_PER_DEGREES); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = Assertions.checkNotNull(windowManager).getDefaultDisplay(); phoneOrientationListener = new PhoneOrientationListener(display, touchTracker, renderer); @@ -155,6 +156,11 @@ public final class SphericalSurfaceView extends GLSurfaceView surfaceListener = listener; } + /** Sets the {@link SingleTapListener} used to listen to single tap events on this view. */ + public void setSingleTapListener(@Nullable SingleTapListener listener) { + touchTracker.setSingleTapListener(listener); + } + @Override public void onVideoFrameAboutToBeRendered( long presentationTimeUs, long releaseTimeNs, Format format) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java index ea3a0b4e16..335f611b58 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java @@ -15,8 +15,11 @@ */ package com.google.android.exoplayer2.ui.spherical; +import android.content.Context; import android.graphics.PointF; import android.support.annotation.BinderThread; +import android.support.annotation.Nullable; +import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; @@ -42,7 +45,8 @@ import android.view.View; * Mesh as the user moves their finger. However, that requires quaternion interpolation. */ // @VisibleForTesting -/*package*/ class TouchTracker implements View.OnTouchListener { +/*package*/ class TouchTracker extends GestureDetector.SimpleOnGestureListener + implements View.OnTouchListener { /*package*/ interface Listener { void onScrollChange(PointF scrollOffsetDegrees); @@ -58,16 +62,27 @@ import android.view.View; private final Listener listener; private final float pxPerDegrees; + private final GestureDetector gestureDetector; // The conversion from touch to yaw & pitch requires compensating for device roll. This is set // on the sensor thread and read on the UI thread. private volatile float roll; + private @Nullable SingleTapListener singleTapListener; - public TouchTracker(Listener listener, float pxPerDegrees) { + @SuppressWarnings({ + "nullness:assignment.type.incompatible", + "nullness:argument.type.incompatible" + }) + public TouchTracker(Context context, Listener listener, float pxPerDegrees) { this.listener = listener; this.pxPerDegrees = pxPerDegrees; + gestureDetector = new GestureDetector(context, this); roll = SphericalSurfaceView.UPRIGHT_ROLL; } + public void setSingleTapListener(@Nullable SingleTapListener listener) { + singleTapListener = listener; + } + /** * Converts ACTION_MOVE events to pitch & yaw events while compensating for device roll. * @@ -75,36 +90,46 @@ import android.view.View; */ @Override public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - // Initialize drag gesture. - previousTouchPointPx.set(event.getX(), event.getY()); - return true; - case MotionEvent.ACTION_MOVE: - // Calculate the touch delta in screen space. - float touchX = (event.getX() - previousTouchPointPx.x) / pxPerDegrees; - float touchY = (event.getY() - previousTouchPointPx.y) / pxPerDegrees; - previousTouchPointPx.set(event.getX(), event.getY()); + return gestureDetector.onTouchEvent(event); + } - float r = roll; // Copy volatile state. - float cr = (float) Math.cos(r); - float sr = (float) Math.sin(r); - // To convert from screen space to the 3D space, we need to adjust the drag vector based - // on the roll of the phone. This is standard rotationMatrix(roll) * vector math but has - // an inverted y-axis due to the screen-space coordinates vs GL coordinates. - // Handle yaw. - accumulatedTouchOffsetDegrees.x -= cr * touchX - sr * touchY; - // Handle pitch and limit it to 45 degrees. - accumulatedTouchOffsetDegrees.y += sr * touchX + cr * touchY; - accumulatedTouchOffsetDegrees.y = - Math.max( - -MAX_PITCH_DEGREES, Math.min(MAX_PITCH_DEGREES, accumulatedTouchOffsetDegrees.y)); + @Override + public boolean onDown(MotionEvent e) { + // Initialize drag gesture. + previousTouchPointPx.set(e.getX(), e.getY()); + return true; + } - listener.onScrollChange(accumulatedTouchOffsetDegrees); - return true; - default: - return false; + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + // Calculate the touch delta in screen space. + float touchX = (e2.getX() - previousTouchPointPx.x) / pxPerDegrees; + float touchY = (e2.getY() - previousTouchPointPx.y) / pxPerDegrees; + previousTouchPointPx.set(e2.getX(), e2.getY()); + + float r = roll; // Copy volatile state. + float cr = (float) Math.cos(r); + float sr = (float) Math.sin(r); + // To convert from screen space to the 3D space, we need to adjust the drag vector based + // on the roll of the phone. This is standard rotationMatrix(roll) * vector math but has + // an inverted y-axis due to the screen-space coordinates vs GL coordinates. + // Handle yaw. + accumulatedTouchOffsetDegrees.x -= cr * touchX - sr * touchY; + // Handle pitch and limit it to 45 degrees. + accumulatedTouchOffsetDegrees.y += sr * touchX + cr * touchY; + accumulatedTouchOffsetDegrees.y = + Math.max(-MAX_PITCH_DEGREES, Math.min(MAX_PITCH_DEGREES, accumulatedTouchOffsetDegrees.y)); + + listener.onScrollChange(accumulatedTouchOffsetDegrees); + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (singleTapListener != null) { + return singleTapListener.onSingleTapUp(e); } + return false; } @BinderThread