diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bf10d6e05..e4570133d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -76,14 +76,14 @@
-
0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- preparePlayer(true);
- } else {
- Toast.makeText(getApplicationContext(), R.string.storage_permission_denied,
- Toast.LENGTH_LONG).show();
- finish();
- }
- }
-
- // Permission management methods
-
- /**
- * Checks whether it is necessary to ask for permission to read storage. If necessary, it also
- * requests permission.
- *
- * @return true if a permission request is made. False if it is not necessary.
- */
- @TargetApi(23)
- private boolean maybeRequestPermission() {
- if (requiresPermission(contentUri)) {
- requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
- return true;
- } else {
- return false;
- }
- }
-
- @TargetApi(23)
- private boolean requiresPermission(Uri uri) {
- return Util.SDK_INT >= 23
- && Util.isLocalFileUri(uri)
- && checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED;
- }
-
- // Internal methods
-
- private RendererBuilder getRendererBuilder() {
- String userAgent = Util.getUserAgent(this, "NewPipeExoPlayer");
- switch (contentType) {
- case Util.TYPE_SS:
- return new SmoothStreamingRendererBuilder(this, userAgent, contentUri.toString(),
- new SmoothStreamingTestMediaDrmCallback());
- case Util.TYPE_DASH:
- return new DashRendererBuilder(this, userAgent, contentUri.toString(),
- new WidevineTestMediaDrmCallback(contentId, provider));
- case Util.TYPE_HLS:
- return new HlsRendererBuilder(this, userAgent, contentUri.toString());
- case Util.TYPE_OTHER:
- return new ExtractorRendererBuilder(this, userAgent, contentUri);
- default:
- throw new IllegalStateException("Unsupported type: " + contentType);
- }
- }
-
- private void preparePlayer(boolean playWhenReady) {
- if (player == null) {
- player = new NPExoPlayer(getRendererBuilder());
- player.addListener(this);
- player.setCaptionListener(this);
- player.setMetadataListener(this);
- player.seekTo(playerPosition);
- playerNeedsPrepare = true;
- mediaController.setMediaPlayer(player.getPlayerControl());
- mediaController.setEnabled(true);
- eventLogger = new EventLogger();
- eventLogger.startSession();
- player.addListener(eventLogger);
- player.setInfoListener(eventLogger);
- player.setInternalErrorListener(eventLogger);
- debugViewHelper = new DebugTextViewHelper(player, debugTextView);
- playerStateTextView.setVisibility(View.GONE);
- debugTextView.setVisibility(View.GONE);
- debugViewHelper.start();
- }
- if (playerNeedsPrepare) {
- player.prepare();
- playerNeedsPrepare = false;
- updateButtonVisibilities();
- }
- player.setSurface(surfaceView.getHolder().getSurface());
- player.setPlayWhenReady(playWhenReady);
- }
-
- private void releasePlayer() {
- if (player != null) {
- debugViewHelper.stop();
- debugViewHelper = null;
- playerPosition = player.getCurrentPosition();
- player.release();
- player = null;
- eventLogger.endSession();
- eventLogger = null;
- }
- }
-
- // NPExoPlayer.Listener implementation
-
- @Override
- public void onStateChanged(boolean playWhenReady, int playbackState) {
- if (playbackState == ExoPlayer.STATE_ENDED) {
- showControls();
- }
- String text = "playWhenReady=" + playWhenReady + ", playbackState=";
- switch(playbackState) {
- case ExoPlayer.STATE_BUFFERING:
- text += "buffering";
- break;
- case ExoPlayer.STATE_ENDED:
- text += "ended";
- break;
- case ExoPlayer.STATE_IDLE:
- text += "idle";
- break;
- case ExoPlayer.STATE_PREPARING:
- text += "preparing";
- break;
- case ExoPlayer.STATE_READY:
- text += "ready";
- break;
- default:
- text += "unknown";
- break;
- }
- playerStateTextView.setText(text);
- updateButtonVisibilities();
- }
-
- @Override
- public void onError(Exception e) {
- String errorString = null;
- if (e instanceof UnsupportedDrmException) {
- // Special case DRM failures.
- UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e;
- errorString = getString(Util.SDK_INT < 18 ? R.string.error_drm_not_supported
- : unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
- ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
- } else if (e instanceof ExoPlaybackException
- && e.getCause() instanceof DecoderInitializationException) {
- // Special case for decoder initialization failures.
- DecoderInitializationException decoderInitializationException =
- (DecoderInitializationException) e.getCause();
- if (decoderInitializationException.decoderName == null) {
- if (decoderInitializationException.getCause() instanceof DecoderQueryException) {
- errorString = getString(R.string.error_querying_decoders);
- } else if (decoderInitializationException.secureDecoderRequired) {
- errorString = getString(R.string.error_no_secure_decoder,
- decoderInitializationException.mimeType);
- } else {
- errorString = getString(R.string.error_no_decoder,
- decoderInitializationException.mimeType);
- }
- } else {
- errorString = getString(R.string.error_instantiating_decoder,
- decoderInitializationException.decoderName);
- }
- }
- if (errorString != null) {
- Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_LONG).show();
- }
- playerNeedsPrepare = true;
- updateButtonVisibilities();
- showControls();
- }
-
- @Override
- public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
- float pixelWidthAspectRatio) {
- shutterView.setVisibility(View.GONE);
- videoFrame.setAspectRatio(
- height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
- }
-
- // User controls
-
- private void updateButtonVisibilities() {
- retryButton.setVisibility(playerNeedsPrepare ? View.VISIBLE : View.GONE);
- videoButton.setVisibility(haveTracks(NPExoPlayer.TYPE_VIDEO) ? View.VISIBLE : View.GONE);
- audioButton.setVisibility(haveTracks(NPExoPlayer.TYPE_AUDIO) ? View.VISIBLE : View.GONE);
- textButton.setVisibility(haveTracks(NPExoPlayer.TYPE_TEXT) ? View.VISIBLE : View.GONE);
- }
-
- private boolean haveTracks(int type) {
- return player != null && player.getTrackCount(type) > 0;
- }
-
- public void showVideoPopup(View v) {
- PopupMenu popup = new PopupMenu(this, v);
- configurePopupWithTracks(popup, null, NPExoPlayer.TYPE_VIDEO);
- popup.show();
- }
-
- public void showAudioPopup(View v) {
- PopupMenu popup = new PopupMenu(this, v);
- Menu menu = popup.getMenu();
- menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.enable_background_audio);
- final MenuItem backgroundAudioItem = menu.findItem(0);
- backgroundAudioItem.setCheckable(true);
- backgroundAudioItem.setChecked(enableBackgroundAudio);
- OnMenuItemClickListener clickListener = new OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- if (item == backgroundAudioItem) {
- enableBackgroundAudio = !item.isChecked();
- return true;
- }
- return false;
- }
- };
- configurePopupWithTracks(popup, clickListener, NPExoPlayer.TYPE_AUDIO);
- popup.show();
- }
-
- public void showTextPopup(View v) {
- PopupMenu popup = new PopupMenu(this, v);
- configurePopupWithTracks(popup, null, NPExoPlayer.TYPE_TEXT);
- popup.show();
- }
-
- public void showVerboseLogPopup(View v) {
- PopupMenu popup = new PopupMenu(this, v);
- Menu menu = popup.getMenu();
- menu.add(Menu.NONE, 0, Menu.NONE, R.string.logging_normal);
- menu.add(Menu.NONE, 1, Menu.NONE, R.string.logging_verbose);
- menu.setGroupCheckable(Menu.NONE, true, true);
- menu.findItem((VerboseLogUtil.areAllTagsEnabled()) ? 1 : 0).setChecked(true);
- popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- if (item.getItemId() == 0) {
- VerboseLogUtil.setEnableAllTags(false);
- } else {
- VerboseLogUtil.setEnableAllTags(true);
- }
- return true;
- }
- });
- popup.show();
- }
-
- private void configurePopupWithTracks(PopupMenu popup,
- final OnMenuItemClickListener customActionClickListener,
- final int trackType) {
- if (player == null) {
- return;
- }
- int trackCount = player.getTrackCount(trackType);
- if (trackCount == 0) {
- return;
- }
- popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- return (customActionClickListener != null
- && customActionClickListener.onMenuItemClick(item))
- || onTrackItemClick(item, trackType);
- }
- });
- Menu menu = popup.getMenu();
- // ID_OFFSET ensures we avoid clashing with Menu.NONE (which equals 0).
- menu.add(MENU_GROUP_TRACKS, NPExoPlayer.TRACK_DISABLED + ID_OFFSET, Menu.NONE, R.string.off);
- for (int i = 0; i < trackCount; i++) {
- menu.add(MENU_GROUP_TRACKS, i + ID_OFFSET, Menu.NONE,
- buildTrackName(player.getTrackFormat(trackType, i)));
- }
- menu.setGroupCheckable(MENU_GROUP_TRACKS, true, true);
- menu.findItem(player.getSelectedTrack(trackType) + ID_OFFSET).setChecked(true);
- }
-
- private static String buildTrackName(MediaFormat format) {
- if (format.adaptive) {
- return "auto";
- }
- String trackName;
- if (MimeTypes.isVideo(format.mimeType)) {
- trackName = joinWithSeparator(joinWithSeparator(buildResolutionString(format),
- buildBitrateString(format)), buildTrackIdString(format));
- } else if (MimeTypes.isAudio(format.mimeType)) {
- trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
- buildAudioPropertyString(format)), buildBitrateString(format)),
- buildTrackIdString(format));
- } else {
- trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format),
- buildBitrateString(format)), buildTrackIdString(format));
- }
- return trackName.length() == 0 ? "unknown" : trackName;
- }
-
- private static String buildResolutionString(MediaFormat format) {
- return format.width == MediaFormat.NO_VALUE || format.height == MediaFormat.NO_VALUE
- ? "" : format.width + "x" + format.height;
- }
-
- private static String buildAudioPropertyString(MediaFormat format) {
- return format.channelCount == MediaFormat.NO_VALUE || format.sampleRate == MediaFormat.NO_VALUE
- ? "" : format.channelCount + "ch, " + format.sampleRate + "Hz";
- }
-
- private static String buildLanguageString(MediaFormat format) {
- return TextUtils.isEmpty(format.language) || "und".equals(format.language) ? ""
- : format.language;
- }
-
- private static String buildBitrateString(MediaFormat format) {
- return format.bitrate == MediaFormat.NO_VALUE ? ""
- : String.format(Locale.US, "%.2fMbit", format.bitrate / 1000000f);
- }
-
- private static String joinWithSeparator(String first, String second) {
- return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second);
- }
-
- private static String buildTrackIdString(MediaFormat format) {
- return format.trackId == null ? "" : " (" + format.trackId + ")";
- }
-
- private boolean onTrackItemClick(MenuItem item, int type) {
- if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) {
- return false;
- }
- player.setSelectedTrack(type, item.getItemId() - ID_OFFSET);
- return true;
- }
-
- private void toggleControlsVisibility() {
- if (mediaController.isShowing()) {
- mediaController.hide();
- debugRootView.setVisibility(View.GONE);
- playerStateTextView.setVisibility(View.GONE);
- debugTextView.setVisibility(View.GONE);
- } else {
- showControls();
- }
- }
-
- private void showControls() {
- mediaController.show(0);
- debugRootView.setVisibility(View.VISIBLE);
- playerStateTextView.setVisibility(View.VISIBLE);
- debugTextView.setVisibility(View.VISIBLE);
- }
-
- // NPExoPlayer.CaptionListener implementation
-
- @Override
- public void onCues(List cues) {
- subtitleLayout.setCues(cues);
- }
-
- // NPExoPlayer.MetadataListener implementation
-
- @Override
- public void onId3Metadata(Map metadata) {
- for (Map.Entry entry : metadata.entrySet()) {
- if (TxxxMetadata.TYPE.equals(entry.getKey())) {
- TxxxMetadata txxxMetadata = (TxxxMetadata) entry.getValue();
- Log.i(TAG, String.format("ID3 TimedMetadata %s: description=%s, value=%s",
- TxxxMetadata.TYPE, txxxMetadata.description, txxxMetadata.value));
- } else if (PrivMetadata.TYPE.equals(entry.getKey())) {
- PrivMetadata privMetadata = (PrivMetadata) entry.getValue();
- Log.i(TAG, String.format("ID3 TimedMetadata %s: owner=%s",
- PrivMetadata.TYPE, privMetadata.owner));
- } else if (GeobMetadata.TYPE.equals(entry.getKey())) {
- GeobMetadata geobMetadata = (GeobMetadata) entry.getValue();
- Log.i(TAG, String.format("ID3 TimedMetadata %s: mimeType=%s, filename=%s, description=%s",
- GeobMetadata.TYPE, geobMetadata.mimeType, geobMetadata.filename,
- geobMetadata.description));
- } else {
- Log.i(TAG, String.format("ID3 TimedMetadata %s", entry.getKey()));
- }
- }
- }
-
- // SurfaceHolder.Callback implementation
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- if (player != null) {
- player.setSurface(holder.getSurface());
- }
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- // Do nothing.
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- if (player != null) {
- player.blockingClearSurface();
- }
- }
-
- private void configureSubtitleView() {
- CaptionStyleCompat style;
- float fontScale;
- if (Util.SDK_INT >= 19) {
- style = getUserCaptionStyleV19();
- fontScale = getUserCaptionFontScaleV19();
- } else {
- style = CaptionStyleCompat.DEFAULT;
- fontScale = 1.0f;
- }
- subtitleLayout.setStyle(style);
- subtitleLayout.setFractionalTextSize(SubtitleLayout.DEFAULT_TEXT_SIZE_FRACTION * fontScale);
- }
-
- @TargetApi(19)
- private float getUserCaptionFontScaleV19() {
- CaptioningManager captioningManager =
- (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
- return captioningManager.getFontScale();
- }
-
- @TargetApi(19)
- private CaptionStyleCompat getUserCaptionStyleV19() {
- CaptioningManager captioningManager =
- (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
- return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
- }
-
- /**
- * Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
- * extension.
- *
- * @param uri The {@link Uri} of the media.
- * @param fileExtension An overriding file extension.
- * @return The inferred type.
- */
- private static int inferContentType(Uri uri, String fileExtension) {
- String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
- : uri.getLastPathSegment();
- return Util.inferContentType(lastPathSegment);
- }
-
- private static final class KeyCompatibleMediaController extends MediaController {
-
- private MediaController.MediaPlayerControl playerControl;
-
- public KeyCompatibleMediaController(Context context) {
- super(context);
- }
-
- @Override
- public void setMediaPlayer(MediaController.MediaPlayerControl playerControl) {
- super.setMediaPlayer(playerControl);
- this.playerControl = playerControl;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- int keyCode = event.getKeyCode();
- if (playerControl.canSeekForward() && keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- playerControl.seekTo(playerControl.getCurrentPosition() + 15000); // milliseconds
- show();
- }
- return true;
- } else if (playerControl.canSeekBackward() && keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- playerControl.seekTo(playerControl.getCurrentPosition() - 5000); // milliseconds
- show();
- }
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
- }
-
-}
diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
similarity index 98%
rename from app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java
rename to app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
index 47afac5b1..21d3d6e0d 100644
--- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
@@ -1,4 +1,4 @@
-package org.schabi.newpipe;
+package org.schabi.newpipe.player;
import android.app.Notification;
import android.app.NotificationManager;
@@ -20,6 +20,12 @@ import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
+import org.schabi.newpipe.ActivityCommunicator;
+import org.schabi.newpipe.BuildConfig;
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.VideoItemDetailActivity;
+import org.schabi.newpipe.VideoItemDetailFragment;
+
import java.io.IOException;
/**
diff --git a/app/src/main/java/org/schabi/newpipe/player/ExoPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ExoPlayerActivity.java
new file mode 100644
index 000000000..11e650cd6
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/ExoPlayerActivity.java
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+/**
+ * Created by Christian Schabesberger on 24.12.15.
+ *
+ * Copyright (C) Christian Schabesberger 2015
+ * ExoPlayerActivity.java is part of NewPipe. all changes are under GPL3
+ *
+ * NewPipe 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.
+ *
+ * NewPipe 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 NewPipe. If not, see .
+ */
+
+package org.schabi.newpipe.player;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.player.exoplayer.DashRendererBuilder;
+import org.schabi.newpipe.player.exoplayer.EventLogger;
+import org.schabi.newpipe.player.exoplayer.ExtractorRendererBuilder;
+import org.schabi.newpipe.player.exoplayer.HlsRendererBuilder;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer.RendererBuilder;
+import org.schabi.newpipe.player.exoplayer.SmoothStreamingRendererBuilder;
+import org.schabi.newpipe.player.exoplayer.SmoothStreamingTestMediaDrmCallback;
+import org.schabi.newpipe.player.exoplayer.WidevineTestMediaDrmCallback;
+
+import com.google.android.exoplayer.AspectRatioFrameLayout;
+import com.google.android.exoplayer.ExoPlaybackException;
+import com.google.android.exoplayer.ExoPlayer;
+import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
+import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
+import com.google.android.exoplayer.MediaFormat;
+import com.google.android.exoplayer.audio.AudioCapabilities;
+import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
+import com.google.android.exoplayer.drm.UnsupportedDrmException;
+import com.google.android.exoplayer.metadata.GeobMetadata;
+import com.google.android.exoplayer.metadata.PrivMetadata;
+import com.google.android.exoplayer.metadata.TxxxMetadata;
+import com.google.android.exoplayer.text.CaptionStyleCompat;
+import com.google.android.exoplayer.text.Cue;
+import com.google.android.exoplayer.text.SubtitleLayout;
+import com.google.android.exoplayer.util.DebugTextViewHelper;
+import com.google.android.exoplayer.util.MimeTypes;
+import com.google.android.exoplayer.util.Util;
+import com.google.android.exoplayer.util.VerboseLogUtil;
+
+import android.Manifest.permission;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnKeyListener;
+import android.view.View.OnTouchListener;
+import android.view.accessibility.CaptioningManager;
+import android.widget.Button;
+import android.widget.MediaController;
+import android.widget.PopupMenu;
+import android.widget.PopupMenu.OnMenuItemClickListener;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.CookiePolicy;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * An activity that plays media using {@link NPExoPlayer}.
+ */
+public class ExoPlayerActivity extends Activity {
+
+ // For use within demo app code.
+ public static final String CONTENT_ID_EXTRA = "content_id";
+ public static final String CONTENT_TYPE_EXTRA = "content_type";
+ public static final String PROVIDER_EXTRA = "provider";
+
+ // For use when launching the demo app using adb.
+ private static final String CONTENT_EXT_EXTRA = "type";
+
+ private static final String TAG = "PlayerActivity";
+ private static final int MENU_GROUP_TRACKS = 1;
+ private static final int ID_OFFSET = 2;
+
+ private static final CookieManager defaultCookieManager;
+ static {
+ defaultCookieManager = new CookieManager();
+ defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
+ }
+
+ private EventLogger eventLogger;
+ private MediaController mediaController;
+ private View debugRootView;
+ private View shutterView;
+ private AspectRatioFrameLayout videoFrame;
+ private SurfaceView surfaceView;
+ private TextView debugTextView;
+ private TextView playerStateTextView;
+ private SubtitleLayout subtitleLayout;
+ private Button videoButton;
+ private Button audioButton;
+ private Button textButton;
+ private Button retryButton;
+
+ private NPExoPlayer player;
+ private DebugTextViewHelper debugViewHelper;
+ private boolean playerNeedsPrepare;
+
+ private long playerPosition;
+ private boolean enableBackgroundAudio;
+
+ private Uri contentUri;
+ private int contentType;
+ private String contentId;
+ private String provider;
+
+ private AudioCapabilitiesReceiver audioCapabilitiesReceiver;
+
+
+ NPExoPlayer.Listener exoPlayerListener = new NPExoPlayer.Listener() {
+ @Override
+ public void onStateChanged(boolean playWhenReady, int playbackState) {
+ if (playbackState == ExoPlayer.STATE_ENDED) {
+ showControls();
+ }
+ String text = "playWhenReady=" + playWhenReady + ", playbackState=";
+ switch(playbackState) {
+ case ExoPlayer.STATE_BUFFERING:
+ text += "buffering";
+ break;
+ case ExoPlayer.STATE_ENDED:
+ text += "ended";
+ break;
+ case ExoPlayer.STATE_IDLE:
+ text += "idle";
+ break;
+ case ExoPlayer.STATE_PREPARING:
+ text += "preparing";
+ break;
+ case ExoPlayer.STATE_READY:
+ text += "ready";
+ break;
+ default:
+ text += "unknown";
+ break;
+ }
+ playerStateTextView.setText(text);
+ updateButtonVisibilities();
+ }
+
+ @Override
+ public void onError(Exception e) {
+ String errorString = null;
+ if (e instanceof UnsupportedDrmException) {
+ // Special case DRM failures.
+ UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e;
+ errorString = getString(Util.SDK_INT < 18 ? R.string.error_drm_not_supported
+ : unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
+ ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
+ } else if (e instanceof ExoPlaybackException
+ && e.getCause() instanceof DecoderInitializationException) {
+ // Special case for decoder initialization failures.
+ DecoderInitializationException decoderInitializationException =
+ (DecoderInitializationException) e.getCause();
+ if (decoderInitializationException.decoderName == null) {
+ if (decoderInitializationException.getCause() instanceof DecoderQueryException) {
+ errorString = getString(R.string.error_querying_decoders);
+ } else if (decoderInitializationException.secureDecoderRequired) {
+ errorString = getString(R.string.error_no_secure_decoder,
+ decoderInitializationException.mimeType);
+ } else {
+ errorString = getString(R.string.error_no_decoder,
+ decoderInitializationException.mimeType);
+ }
+ } else {
+ errorString = getString(R.string.error_instantiating_decoder,
+ decoderInitializationException.decoderName);
+ }
+ }
+ if (errorString != null) {
+ Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_LONG).show();
+ }
+ playerNeedsPrepare = true;
+ updateButtonVisibilities();
+ showControls();
+ }
+
+ @Override
+ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthAspectRatio) {
+ shutterView.setVisibility(View.GONE);
+ videoFrame.setAspectRatio(
+ height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
+ }
+ };
+
+ SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ if (player != null) {
+ player.setSurface(holder.getSurface());
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // Do nothing.
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ if (player != null) {
+ player.blockingClearSurface();
+ }
+ }
+ };
+
+ NPExoPlayer.CaptionListener captionListener = new NPExoPlayer.CaptionListener() {
+ @Override
+ public void onCues(List cues) {
+ subtitleLayout.setCues(cues);
+ }
+ };
+
+ NPExoPlayer.Id3MetadataListener id3MetadataListener = new NPExoPlayer.Id3MetadataListener() {
+ @Override
+ public void onId3Metadata(Map metadata) {
+ for (Map.Entry entry : metadata.entrySet()) {
+ if (TxxxMetadata.TYPE.equals(entry.getKey())) {
+ TxxxMetadata txxxMetadata = (TxxxMetadata) entry.getValue();
+ Log.i(TAG, String.format("ID3 TimedMetadata %s: description=%s, value=%s",
+ TxxxMetadata.TYPE, txxxMetadata.description, txxxMetadata.value));
+ } else if (PrivMetadata.TYPE.equals(entry.getKey())) {
+ PrivMetadata privMetadata = (PrivMetadata) entry.getValue();
+ Log.i(TAG, String.format("ID3 TimedMetadata %s: owner=%s",
+ PrivMetadata.TYPE, privMetadata.owner));
+ } else if (GeobMetadata.TYPE.equals(entry.getKey())) {
+ GeobMetadata geobMetadata = (GeobMetadata) entry.getValue();
+ Log.i(TAG, String.format("ID3 TimedMetadata %s: mimeType=%s, filename=%s, description=%s",
+ GeobMetadata.TYPE, geobMetadata.mimeType, geobMetadata.filename,
+ geobMetadata.description));
+ } else {
+ Log.i(TAG, String.format("ID3 TimedMetadata %s", entry.getKey()));
+ }
+ }
+ }
+ };
+
+ AudioCapabilitiesReceiver.Listener audioCapabilitiesListener = new AudioCapabilitiesReceiver.Listener() {
+ @Override
+ public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
+ if (player == null) {
+ return;
+ }
+ boolean backgrounded = player.getBackgrounded();
+ boolean playWhenReady = player.getPlayWhenReady();
+ releasePlayer();
+ preparePlayer(playWhenReady);
+ player.setBackgrounded(backgrounded);
+ }
+ };
+
+ // Activity lifecycle
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.exo_player_activity);
+ View root = findViewById(R.id.root);
+ root.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ toggleControlsVisibility();
+ } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
+ view.performClick();
+ }
+ return true;
+ }
+ });
+ root.setOnKeyListener(new OnKeyListener() {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE
+ || keyCode == KeyEvent.KEYCODE_MENU) {
+ return false;
+ }
+ return mediaController.dispatchKeyEvent(event);
+ }
+ });
+
+ shutterView = findViewById(R.id.shutter);
+ debugRootView = findViewById(R.id.controls_root);
+
+ videoFrame = (AspectRatioFrameLayout) findViewById(R.id.video_frame);
+ surfaceView = (SurfaceView) findViewById(R.id.surface_view);
+ surfaceView.getHolder().addCallback(surfaceHolderCallback);
+ debugTextView = (TextView) findViewById(R.id.debug_text_view);
+
+ playerStateTextView = (TextView) findViewById(R.id.player_state_view);
+ subtitleLayout = (SubtitleLayout) findViewById(R.id.subtitles);
+
+ mediaController = new KeyCompatibleMediaController(this);
+ mediaController.setAnchorView(root);
+ retryButton = (Button) findViewById(R.id.retry_button);
+ videoButton = (Button) findViewById(R.id.video_controls);
+ audioButton = (Button) findViewById(R.id.audio_controls);
+ textButton = (Button) findViewById(R.id.text_controls);
+
+ CookieHandler currentHandler = CookieHandler.getDefault();
+ if (currentHandler != defaultCookieManager) {
+ CookieHandler.setDefault(defaultCookieManager);
+ }
+
+ audioCapabilitiesReceiver = new AudioCapabilitiesReceiver(this, audioCapabilitiesListener);
+ audioCapabilitiesReceiver.register();
+
+
+ retryButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ preparePlayer(true);
+ }
+ });
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ releasePlayer();
+ playerPosition = 0;
+ setIntent(intent);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Intent intent = getIntent();
+ contentUri = intent.getData();
+ contentType = intent.getIntExtra(CONTENT_TYPE_EXTRA,
+ inferContentType(contentUri, intent.getStringExtra(CONTENT_EXT_EXTRA)));
+ contentId = intent.getStringExtra(CONTENT_ID_EXTRA);
+ provider = intent.getStringExtra(PROVIDER_EXTRA);
+ configureSubtitleView();
+ if (player == null) {
+ if (!maybeRequestPermission()) {
+ preparePlayer(true);
+ }
+ } else {
+ player.setBackgrounded(false);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (!enableBackgroundAudio) {
+ releasePlayer();
+ } else {
+ player.setBackgrounded(true);
+ }
+ shutterView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ audioCapabilitiesReceiver.unregister();
+ releasePlayer();
+ }
+
+
+ // Permission request listener method
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ preparePlayer(true);
+ } else {
+ Toast.makeText(getApplicationContext(), R.string.storage_permission_denied,
+ Toast.LENGTH_LONG).show();
+ finish();
+ }
+ }
+
+ // Permission management methods
+
+ /**
+ * Checks whether it is necessary to ask for permission to read storage. If necessary, it also
+ * requests permission.
+ *
+ * @return true if a permission request is made. False if it is not necessary.
+ */
+ @TargetApi(23)
+ private boolean maybeRequestPermission() {
+ if (requiresPermission(contentUri)) {
+ requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @TargetApi(23)
+ private boolean requiresPermission(Uri uri) {
+ return Util.SDK_INT >= 23
+ && Util.isLocalFileUri(uri)
+ && checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED;
+ }
+
+ // Internal methods
+
+ private RendererBuilder getRendererBuilder() {
+ String userAgent = Util.getUserAgent(this, "NewPipeExoPlayer");
+ switch (contentType) {
+ case Util.TYPE_SS:
+ return new SmoothStreamingRendererBuilder(this, userAgent, contentUri.toString(),
+ new SmoothStreamingTestMediaDrmCallback());
+ case Util.TYPE_DASH:
+ return new DashRendererBuilder(this, userAgent, contentUri.toString(),
+ new WidevineTestMediaDrmCallback(contentId, provider));
+ case Util.TYPE_HLS:
+ return new HlsRendererBuilder(this, userAgent, contentUri.toString());
+ case Util.TYPE_OTHER:
+ return new ExtractorRendererBuilder(this, userAgent, contentUri);
+ default:
+ throw new IllegalStateException("Unsupported type: " + contentType);
+ }
+ }
+
+ private void preparePlayer(boolean playWhenReady) {
+ if (player == null) {
+ player = new NPExoPlayer(getRendererBuilder());
+ player.addListener(exoPlayerListener);
+ player.setCaptionListener(captionListener);
+ player.setMetadataListener(id3MetadataListener);
+ player.seekTo(playerPosition);
+ playerNeedsPrepare = true;
+ mediaController.setMediaPlayer(player.getPlayerControl());
+ mediaController.setEnabled(true);
+ eventLogger = new EventLogger();
+ eventLogger.startSession();
+ player.addListener(eventLogger);
+ player.setInfoListener(eventLogger);
+ player.setInternalErrorListener(eventLogger);
+ debugViewHelper = new DebugTextViewHelper(player, debugTextView);
+ playerStateTextView.setVisibility(View.GONE);
+ debugTextView.setVisibility(View.GONE);
+ debugViewHelper.start();
+ }
+ if (playerNeedsPrepare) {
+ player.prepare();
+ playerNeedsPrepare = false;
+ updateButtonVisibilities();
+ }
+ player.setSurface(surfaceView.getHolder().getSurface());
+ player.setPlayWhenReady(playWhenReady);
+ }
+
+ private void releasePlayer() {
+ if (player != null) {
+ debugViewHelper.stop();
+ debugViewHelper = null;
+ playerPosition = player.getCurrentPosition();
+ player.release();
+ player = null;
+ eventLogger.endSession();
+ eventLogger = null;
+ }
+ }
+
+ // User controls
+
+ private void updateButtonVisibilities() {
+ retryButton.setVisibility(playerNeedsPrepare ? View.VISIBLE : View.GONE);
+ videoButton.setVisibility(haveTracks(NPExoPlayer.TYPE_VIDEO) ? View.VISIBLE : View.GONE);
+ audioButton.setVisibility(haveTracks(NPExoPlayer.TYPE_AUDIO) ? View.VISIBLE : View.GONE);
+ textButton.setVisibility(haveTracks(NPExoPlayer.TYPE_TEXT) ? View.VISIBLE : View.GONE);
+ }
+
+ private boolean haveTracks(int type) {
+ return player != null && player.getTrackCount(type) > 0;
+ }
+
+ public void showVideoPopup(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+ configurePopupWithTracks(popup, null, NPExoPlayer.TYPE_VIDEO);
+ popup.show();
+ }
+
+ public void showAudioPopup(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+ Menu menu = popup.getMenu();
+ menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.enable_background_audio);
+ final MenuItem backgroundAudioItem = menu.findItem(0);
+ backgroundAudioItem.setCheckable(true);
+ backgroundAudioItem.setChecked(enableBackgroundAudio);
+ OnMenuItemClickListener clickListener = new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item == backgroundAudioItem) {
+ enableBackgroundAudio = !item.isChecked();
+ return true;
+ }
+ return false;
+ }
+ };
+ configurePopupWithTracks(popup, clickListener, NPExoPlayer.TYPE_AUDIO);
+ popup.show();
+ }
+
+ public void showTextPopup(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+ configurePopupWithTracks(popup, null, NPExoPlayer.TYPE_TEXT);
+ popup.show();
+ }
+
+ public void showVerboseLogPopup(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+ Menu menu = popup.getMenu();
+ menu.add(Menu.NONE, 0, Menu.NONE, R.string.logging_normal);
+ menu.add(Menu.NONE, 1, Menu.NONE, R.string.logging_verbose);
+ menu.setGroupCheckable(Menu.NONE, true, true);
+ menu.findItem((VerboseLogUtil.areAllTagsEnabled()) ? 1 : 0).setChecked(true);
+ popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == 0) {
+ VerboseLogUtil.setEnableAllTags(false);
+ } else {
+ VerboseLogUtil.setEnableAllTags(true);
+ }
+ return true;
+ }
+ });
+ popup.show();
+ }
+
+ private void configurePopupWithTracks(PopupMenu popup,
+ final OnMenuItemClickListener customActionClickListener,
+ final int trackType) {
+ if (player == null) {
+ return;
+ }
+ int trackCount = player.getTrackCount(trackType);
+ if (trackCount == 0) {
+ return;
+ }
+ popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ return (customActionClickListener != null
+ && customActionClickListener.onMenuItemClick(item))
+ || onTrackItemClick(item, trackType);
+ }
+ });
+ Menu menu = popup.getMenu();
+ // ID_OFFSET ensures we avoid clashing with Menu.NONE (which equals 0).
+ menu.add(MENU_GROUP_TRACKS, NPExoPlayer.TRACK_DISABLED + ID_OFFSET, Menu.NONE, R.string.off);
+ for (int i = 0; i < trackCount; i++) {
+ menu.add(MENU_GROUP_TRACKS, i + ID_OFFSET, Menu.NONE,
+ buildTrackName(player.getTrackFormat(trackType, i)));
+ }
+ menu.setGroupCheckable(MENU_GROUP_TRACKS, true, true);
+ menu.findItem(player.getSelectedTrack(trackType) + ID_OFFSET).setChecked(true);
+ }
+
+ private static String buildTrackName(MediaFormat format) {
+ if (format.adaptive) {
+ return "auto";
+ }
+ String trackName;
+ if (MimeTypes.isVideo(format.mimeType)) {
+ trackName = joinWithSeparator(joinWithSeparator(buildResolutionString(format),
+ buildBitrateString(format)), buildTrackIdString(format));
+ } else if (MimeTypes.isAudio(format.mimeType)) {
+ trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
+ buildAudioPropertyString(format)), buildBitrateString(format)),
+ buildTrackIdString(format));
+ } else {
+ trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format),
+ buildBitrateString(format)), buildTrackIdString(format));
+ }
+ return trackName.length() == 0 ? "unknown" : trackName;
+ }
+
+ private static String buildResolutionString(MediaFormat format) {
+ return format.width == MediaFormat.NO_VALUE || format.height == MediaFormat.NO_VALUE
+ ? "" : format.width + "x" + format.height;
+ }
+
+ private static String buildAudioPropertyString(MediaFormat format) {
+ return format.channelCount == MediaFormat.NO_VALUE || format.sampleRate == MediaFormat.NO_VALUE
+ ? "" : format.channelCount + "ch, " + format.sampleRate + "Hz";
+ }
+
+ private static String buildLanguageString(MediaFormat format) {
+ return TextUtils.isEmpty(format.language) || "und".equals(format.language) ? ""
+ : format.language;
+ }
+
+ private static String buildBitrateString(MediaFormat format) {
+ return format.bitrate == MediaFormat.NO_VALUE ? ""
+ : String.format(Locale.US, "%.2fMbit", format.bitrate / 1000000f);
+ }
+
+ private static String joinWithSeparator(String first, String second) {
+ return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second);
+ }
+
+ private static String buildTrackIdString(MediaFormat format) {
+ return format.trackId == null ? "" : " (" + format.trackId + ")";
+ }
+
+ private boolean onTrackItemClick(MenuItem item, int type) {
+ if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) {
+ return false;
+ }
+ player.setSelectedTrack(type, item.getItemId() - ID_OFFSET);
+ return true;
+ }
+
+ private void toggleControlsVisibility() {
+ if (mediaController.isShowing()) {
+ mediaController.hide();
+ debugRootView.setVisibility(View.GONE);
+ playerStateTextView.setVisibility(View.GONE);
+ debugTextView.setVisibility(View.GONE);
+ } else {
+ showControls();
+ }
+ }
+
+ private void showControls() {
+ mediaController.show(0);
+ debugRootView.setVisibility(View.VISIBLE);
+ playerStateTextView.setVisibility(View.VISIBLE);
+ debugTextView.setVisibility(View.VISIBLE);
+ }
+
+ private void configureSubtitleView() {
+ CaptionStyleCompat style;
+ float fontScale;
+ if (Util.SDK_INT >= 19) {
+ style = getUserCaptionStyleV19();
+ fontScale = getUserCaptionFontScaleV19();
+ } else {
+ style = CaptionStyleCompat.DEFAULT;
+ fontScale = 1.0f;
+ }
+ subtitleLayout.setStyle(style);
+ subtitleLayout.setFractionalTextSize(SubtitleLayout.DEFAULT_TEXT_SIZE_FRACTION * fontScale);
+ }
+
+ @TargetApi(19)
+ private float getUserCaptionFontScaleV19() {
+ CaptioningManager captioningManager =
+ (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
+ return captioningManager.getFontScale();
+ }
+
+ @TargetApi(19)
+ private CaptionStyleCompat getUserCaptionStyleV19() {
+ CaptioningManager captioningManager =
+ (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
+ return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
+ }
+
+ /**
+ * Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
+ * extension.
+ *
+ * @param uri The {@link Uri} of the media.
+ * @param fileExtension An overriding file extension.
+ * @return The inferred type.
+ */
+ private static int inferContentType(Uri uri, String fileExtension) {
+ String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
+ : uri.getLastPathSegment();
+ return Util.inferContentType(lastPathSegment);
+ }
+
+ private static final class KeyCompatibleMediaController extends MediaController {
+
+ private MediaController.MediaPlayerControl playerControl;
+
+ public KeyCompatibleMediaController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setMediaPlayer(MediaController.MediaPlayerControl playerControl) {
+ super.setMediaPlayer(playerControl);
+ this.playerControl = playerControl;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ if (playerControl.canSeekForward() && keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ playerControl.seekTo(playerControl.getCurrentPosition() + 15000); // milliseconds
+ show();
+ }
+ return true;
+ } else if (playerControl.canSeekBackward() && keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ playerControl.seekTo(playerControl.getCurrentPosition() - 5000); // milliseconds
+ show();
+ }
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayVideoActivity.java
similarity index 99%
rename from app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java
rename to app/src/main/java/org/schabi/newpipe/player/PlayVideoActivity.java
index 823fb762c..91ba36f19 100644
--- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayVideoActivity.java
@@ -1,4 +1,4 @@
-package org.schabi.newpipe;
+package org.schabi.newpipe.player;
import android.content.Context;
import android.content.Intent;
@@ -27,6 +27,9 @@ import android.widget.MediaController;
import android.widget.ProgressBar;
import android.widget.VideoView;
+import org.schabi.newpipe.App;
+import org.schabi.newpipe.R;
+
/**
* Copyright (C) Christian Schabesberger 2015
* PlayVideoActivity.java is part of NewPipe.
@@ -191,7 +194,6 @@ public class PlayVideoActivity extends AppCompatActivity {
@Override
public void onResume() {
super.onResume();
- App.checkStartTor(this);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/DashRendererBuilder.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/DashRendererBuilder.java
similarity index 98%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/DashRendererBuilder.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/DashRendererBuilder.java
index 857af3a78..f12dc8975 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/DashRendererBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/DashRendererBuilder.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
-import org.schabi.newpipe.exoplayer.NPExoPlayer.RendererBuilder;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer.RendererBuilder;
import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/EventLogger.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/EventLogger.java
similarity index 99%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/EventLogger.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/EventLogger.java
index f2de9033e..62553ab3b 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/EventLogger.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/EventLogger.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/ExtractorRendererBuilder.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/ExtractorRendererBuilder.java
similarity index 96%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/ExtractorRendererBuilder.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/ExtractorRendererBuilder.java
index 0ba716bcb..a74c33bf8 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/ExtractorRendererBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/ExtractorRendererBuilder.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
-import org.schabi.newpipe.exoplayer.NPExoPlayer.RendererBuilder;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer.RendererBuilder;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/HlsRendererBuilder.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/HlsRendererBuilder.java
similarity index 98%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/HlsRendererBuilder.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/HlsRendererBuilder.java
index 8c0fae97d..8e6c2d9f5 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/HlsRendererBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/HlsRendererBuilder.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
-import org.schabi.newpipe.exoplayer.NPExoPlayer.RendererBuilder;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer.RendererBuilder;
import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/NPExoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/NPExoPlayer.java
similarity index 99%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/NPExoPlayer.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/NPExoPlayer.java
index 377e2e7b8..63a6a9261 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/NPExoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/NPExoPlayer.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
import com.google.android.exoplayer.CodecCounters;
import com.google.android.exoplayer.DummyTrackRenderer;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingRendererBuilder.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingRendererBuilder.java
similarity index 98%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingRendererBuilder.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingRendererBuilder.java
index 524e2d5c5..55b59c276 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingRendererBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingRendererBuilder.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
-import org.schabi.newpipe.exoplayer.NPExoPlayer.RendererBuilder;
+import org.schabi.newpipe.player.exoplayer.NPExoPlayer.RendererBuilder;
import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingTestMediaDrmCallback.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingTestMediaDrmCallback.java
similarity index 98%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingTestMediaDrmCallback.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingTestMediaDrmCallback.java
index 3fe1db139..ec9bf41a7 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/SmoothStreamingTestMediaDrmCallback.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/SmoothStreamingTestMediaDrmCallback.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
import com.google.android.exoplayer.drm.MediaDrmCallback;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
diff --git a/app/src/main/java/org/schabi/newpipe/exoplayer/WidevineTestMediaDrmCallback.java b/app/src/main/java/org/schabi/newpipe/player/exoplayer/WidevineTestMediaDrmCallback.java
similarity index 97%
rename from app/src/main/java/org/schabi/newpipe/exoplayer/WidevineTestMediaDrmCallback.java
rename to app/src/main/java/org/schabi/newpipe/player/exoplayer/WidevineTestMediaDrmCallback.java
index e23f3fc30..647e6599b 100644
--- a/app/src/main/java/org/schabi/newpipe/exoplayer/WidevineTestMediaDrmCallback.java
+++ b/app/src/main/java/org/schabi/newpipe/player/exoplayer/WidevineTestMediaDrmCallback.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.schabi.newpipe.exoplayer;
+package org.schabi.newpipe.player.exoplayer;
import com.google.android.exoplayer.drm.MediaDrmCallback;
import com.google.android.exoplayer.util.Util;
diff --git a/app/src/main/res/layout/activity_play_video.xml b/app/src/main/res/layout/activity_play_video.xml
index 117006a1a..bdedb2c2c 100644
--- a/app/src/main/res/layout/activity_play_video.xml
+++ b/app/src/main/res/layout/activity_play_video.xml
@@ -2,7 +2,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context="org.schabi.newpipe.PlayVideoActivity"
+ tools:context=".player.PlayVideoActivity"
android:gravity="center">