Fix controller ui toggling when using SphericalSurfaceView

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=209909845
This commit is contained in:
eguven 2018-08-23 03:19:30 -07:00 committed by Oliver Woodman
parent 74e2384fb6
commit 3f70454cc2
4 changed files with 115 additions and 38 deletions

View file

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

View file

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

View file

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

View file

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