New logic for handling global orientation

- added a button to manually change an orientation of a video
- adapted UI for an automatic global orientation too
This commit is contained in:
Avently 2020-01-16 14:20:22 +03:00
parent d1609cba90
commit 92ff98d99a
8 changed files with 106 additions and 67 deletions

View file

@ -4,6 +4,7 @@ import android.animation.ValueAnimator;
import android.app.Activity; import android.app.Activity;
import android.content.*; import android.content.*;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.database.ContentObserver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Build; import android.os.Build;
@ -69,7 +70,6 @@ import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.playqueue.*; import org.schabi.newpipe.player.playqueue.*;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.settings.SettingsContentObserver;
import org.schabi.newpipe.util.*; import org.schabi.newpipe.util.*;
import org.schabi.newpipe.views.AnimatedProgressBar; import org.schabi.newpipe.views.AnimatedProgressBar;
@ -97,8 +97,7 @@ public class VideoDetailFragment
View.OnClickListener, View.OnClickListener,
View.OnLongClickListener, View.OnLongClickListener,
PlayerEventListener, PlayerEventListener,
PlayerServiceEventListener, PlayerServiceEventListener {
SettingsContentObserver.OnChangeListener {
public static final String AUTO_PLAY = "auto_play"; public static final String AUTO_PLAY = "auto_play";
private boolean isFragmentStopped; private boolean isFragmentStopped;
@ -203,7 +202,7 @@ public class VideoDetailFragment
private TabLayout tabLayout; private TabLayout tabLayout;
private FrameLayout relatedStreamsLayout; private FrameLayout relatedStreamsLayout;
private SettingsContentObserver settingsContentObserver; private ContentObserver settingsContentObserver;
private ServiceConnection serviceConnection; private ServiceConnection serviceConnection;
private boolean bounded; private boolean bounded;
private MainPlayer playerService; private MainPlayer playerService;
@ -329,9 +328,15 @@ public class VideoDetailFragment
startService(false); startService(false);
setupBroadcastReceiver(); setupBroadcastReceiver();
settingsContentObserver = new SettingsContentObserver(new Handler(), this); settingsContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
if(activity != null && !PlayerHelper.globalScreenOrientationLocked(activity))
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
};
activity.getContentResolver().registerContentObserver( activity.getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true, Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
settingsContentObserver); settingsContentObserver);
} }
@ -1311,13 +1316,6 @@ public class VideoDetailFragment
// Orientation listener // Orientation listener
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
private boolean globalScreenOrientationLocked() {
// 1: Screen orientation changes using accelerometer
// 0: Screen orientation is locked
return !(android.provider.Settings.System.getInt(
activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
}
private void restoreDefaultOrientation() { private void restoreDefaultOrientation() {
if (player == null || !player.videoPlayerSelected() || activity == null) return; if (player == null || !player.videoPlayerSelected() || activity == null) return;
@ -1327,25 +1325,6 @@ public class VideoDetailFragment
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
} }
private void setupOrientation() {
if (player == null || !player.videoPlayerSelected() || activity == null) return;
int newOrientation;
if (globalScreenOrientationLocked())
newOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
else
newOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
if (newOrientation != activity.getRequestedOrientation())
activity.setRequestedOrientation(newOrientation);
}
@Override
public void onSettingsChanged() {
if(activity != null && !globalScreenOrientationLocked())
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Contract // Contract
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -1661,7 +1640,6 @@ public class VideoDetailFragment
animateView(positionView, true, 100); animateView(positionView, true, 100);
animateView(detailPositionView, true, 100); animateView(detailPositionView, true, 100);
} }
setupOrientation();
break; break;
} }
} }
@ -1742,6 +1720,15 @@ public class VideoDetailFragment
addVideoPlayerView(); addVideoPlayerView();
} }
@Override
public void onScreenRotationButtonClicked() {
int newOrientation = isLandscape() ?
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
activity.setRequestedOrientation(newOrientation);
}
/* /*
* Will scroll down to description view after long click on moreOptionsButton * Will scroll down to description view after long click on moreOptionsButton
* */ * */
@ -1828,9 +1815,15 @@ public class VideoDetailFragment
if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null) if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null)
setAutoplay(true); setAutoplay(true);
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
// Let's give a user time to look at video information page if video is not playing // Let's give a user time to look at video information page if video is not playing
if (player.isPlaying()) if (player.isPlaying()) {
player.checkLandscape(); player.checkLandscape();
} else if (orientationLocked) {
player.checkLandscape();
player.onPlay();
player.showControlsThenHide();
}
} }
private boolean isLandscape() { private boolean isLandscape() {

View file

@ -195,7 +195,7 @@ public final class MainPlayer extends Service {
boolean isLandscape() { boolean isLandscape() {
// DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't // DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't
final DisplayMetrics metrics = playerImpl.getParentActivity() != null ? final DisplayMetrics metrics = playerImpl != null && playerImpl.getParentActivity() != null ?
playerImpl.getParentActivity().getResources().getDisplayMetrics() playerImpl.getParentActivity().getResources().getDisplayMetrics()
: getResources().getDisplayMetrics(); : getResources().getDisplayMetrics();
return metrics.heightPixels < metrics.widthPixels; return metrics.heightPixels < metrics.widthPixels;

View file

@ -23,12 +23,15 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.*; import android.content.*;
import android.database.ContentObserver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point; import android.graphics.Point;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
@ -109,6 +112,7 @@ public class VideoPlayerImpl extends VideoPlayer
private ImageButton openInBrowser; private ImageButton openInBrowser;
private ImageButton fullscreenButton; private ImageButton fullscreenButton;
private ImageButton playerCloseButton; private ImageButton playerCloseButton;
private ImageButton screenRotationButton;
private ImageButton playPauseButton; private ImageButton playPauseButton;
private ImageButton playPreviousButton; private ImageButton playPreviousButton;
@ -139,6 +143,7 @@ public class VideoPlayerImpl extends VideoPlayer
private PlayerEventListener activityListener; private PlayerEventListener activityListener;
private GestureDetector gestureDetector; private GestureDetector gestureDetector;
private SharedPreferences defaultPreferences; private SharedPreferences defaultPreferences;
private ContentObserver settingsContentObserver;
@NonNull @NonNull
final private AudioPlaybackResolver resolver; final private AudioPlaybackResolver resolver;
@ -233,6 +238,7 @@ public class VideoPlayerImpl extends VideoPlayer
this.playWithKodi = rootView.findViewById(R.id.playWithKodi); this.playWithKodi = rootView.findViewById(R.id.playWithKodi);
this.openInBrowser = rootView.findViewById(R.id.openInBrowser); this.openInBrowser = rootView.findViewById(R.id.openInBrowser);
this.fullscreenButton = rootView.findViewById(R.id.fullScreenButton); this.fullscreenButton = rootView.findViewById(R.id.fullScreenButton);
this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton);
this.playerCloseButton = rootView.findViewById(R.id.playerCloseButton); this.playerCloseButton = rootView.findViewById(R.id.playerCloseButton);
this.playPauseButton = rootView.findViewById(R.id.playPauseButton); this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
@ -277,6 +283,7 @@ public class VideoPlayerImpl extends VideoPlayer
private void setupElementsVisibility() { private void setupElementsVisibility() {
if (popupPlayerSelected()) { if (popupPlayerSelected()) {
fullscreenButton.setVisibility(View.VISIBLE); fullscreenButton.setVisibility(View.VISIBLE);
screenRotationButton.setVisibility(View.GONE);
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE); getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE); getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE); queueButton.setVisibility(View.GONE);
@ -292,6 +299,7 @@ public class VideoPlayerImpl extends VideoPlayer
playerCloseButton.setVisibility(View.GONE); playerCloseButton.setVisibility(View.GONE);
} else { } else {
fullscreenButton.setVisibility(View.GONE); fullscreenButton.setVisibility(View.GONE);
setupScreenRotationButton(service.isLandscape());
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE); getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE); getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE); moreOptionsButton.setVisibility(View.VISIBLE);
@ -337,10 +345,19 @@ public class VideoPlayerImpl extends VideoPlayer
moreOptionsButton.setOnLongClickListener(this); moreOptionsButton.setOnLongClickListener(this);
shareButton.setOnClickListener(this); shareButton.setOnClickListener(this);
fullscreenButton.setOnClickListener(this); fullscreenButton.setOnClickListener(this);
screenRotationButton.setOnClickListener(this);
playWithKodi.setOnClickListener(this); playWithKodi.setOnClickListener(this);
openInBrowser.setOnClickListener(this); openInBrowser.setOnClickListener(this);
playerCloseButton.setOnClickListener(this); playerCloseButton.setOnClickListener(this);
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) { setupScreenRotationButton(service.isLandscape()); }
};
service.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
settingsContentObserver);
getRootView().addOnLayoutChangeListener((view, l, t, r, b, ol, ot, or, ob) -> { getRootView().addOnLayoutChangeListener((view, l, t, r, b, ol, ot, or, ob) -> {
if (l != ol || t != ot || r != or || b != ob) { if (l != ol || t != ot || r != or || b != ob) {
// Use smaller value to be consistent between screen orientations // Use smaller value to be consistent between screen orientations
@ -560,6 +577,7 @@ public class VideoPlayerImpl extends VideoPlayer
channelTextView.setVisibility(View.VISIBLE); channelTextView.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(View.GONE); playerCloseButton.setVisibility(View.GONE);
} }
setupScreenRotationButton(isInFullscreen());
} }
@Override @Override
@ -598,6 +616,9 @@ public class VideoPlayerImpl extends VideoPlayer
} else if (v.getId() == fullscreenButton.getId()) { } else if (v.getId() == fullscreenButton.getId()) {
toggleFullscreen(); toggleFullscreen();
} else if (v.getId() == screenRotationButton.getId()) {
fragmentListener.onScreenRotationButtonClicked();
} else if (v.getId() == playerCloseButton.getId()) { } else if (v.getId() == playerCloseButton.getId()) {
service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER)); service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
} }
@ -689,6 +710,13 @@ public class VideoPlayerImpl extends VideoPlayer
builder.create().show(); builder.create().show();
} }
private void setupScreenRotationButton(boolean landscape) {
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
screenRotationButton.setVisibility(orientationLocked && videoPlayerSelected() ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
landscape ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
}
@Override @Override
public void onPlaybackSpeedClicked() { public void onPlaybackSpeedClicked() {
if (videoPlayerSelected()) { if (videoPlayerSelected()) {
@ -880,6 +908,13 @@ public class VideoPlayerImpl extends VideoPlayer
super.onCompleted(); super.onCompleted();
} }
@Override
public void destroy() {
super.destroy();
service.getContentResolver().unregisterContentObserver(settingsContentObserver);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Broadcast Receiver // Broadcast Receiver
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -1282,7 +1317,7 @@ public class VideoPlayerImpl extends VideoPlayer
getLoadingPanel().setMinimumHeight(popupLayoutParams.height); getLoadingPanel().setMinimumHeight(popupLayoutParams.height);
service.removeViewFromParent(); service.removeViewFromParent();
windowManager.addView(service.getView(), popupLayoutParams); windowManager.addView(getRootView(), popupLayoutParams);
if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM) if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM)
onResizeClicked(); onResizeClicked();
@ -1313,7 +1348,7 @@ public class VideoPlayerImpl extends VideoPlayer
} }
private void initVideoPlayer() { private void initVideoPlayer() {
service.getView().setLayoutParams(new FrameLayout.LayoutParams( getRootView().setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
} }

View file

@ -5,6 +5,8 @@ import com.google.android.exoplayer2.ExoPlaybackException;
public interface PlayerServiceEventListener extends PlayerEventListener { public interface PlayerServiceEventListener extends PlayerEventListener {
void onFullscreenStateChanged(boolean fullscreen); void onFullscreenStateChanged(boolean fullscreen);
void onScreenRotationButtonClicked();
void onMoreOptionsLongClicked(); void onMoreOptionsLongClicked();
void onPlayerError(ExoPlaybackException error); void onPlayerError(ExoPlaybackException error);

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -321,6 +322,13 @@ public class PlayerHelper {
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis()); setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
} }
public static boolean globalScreenOrientationLocked(Context context) {
// 1: Screen orientation changes using accelerometer
// 0: Screen orientation is locked
return !(android.provider.Settings.System.getInt(
context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Private helpers // Private helpers
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View file

@ -1,29 +0,0 @@
package org.schabi.newpipe.settings;
import android.database.ContentObserver;
import android.os.Handler;
public class SettingsContentObserver extends ContentObserver {
private OnChangeListener listener;
public interface OnChangeListener {
void onSettingsChanged();
}
public SettingsContentObserver(Handler handler, OnChangeListener listener) {
super(handler);
this.listener = listener;
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (listener != null)
listener.onSettingsChanged();
}
}

View file

@ -466,6 +466,21 @@
android:visibility="gone" android:visibility="gone"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" /> tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
<ImageButton
android:id="@+id/screenRotationButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="4dp"
android:padding="6dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_fullscreen_white"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -464,6 +464,21 @@
android:visibility="gone" android:visibility="gone"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" /> tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
<ImageButton
android:id="@+id/screenRotationButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="4dp"
android:padding="6dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_fullscreen_white"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>