Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fullscreen Optimization for Android #106

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5a9f1b9
Calling fullscreen activity bridge on android
ShariqMush Jul 18, 2017
d8a1edf
Update index.js
ShariqMush Jul 18, 2017
582dba1
Update README.md
ShariqMush Jul 18, 2017
8198002
Update README.md
ShariqMush Jul 18, 2017
bc255de
Update README.md
ShariqMush Jul 18, 2017
c9216e1
Files for fullscreen
ShariqMush Jul 18, 2017
e42c2d7
Merge branch 'master' of https://github.com/mrAlbert-development/reac…
ShariqMush Jul 18, 2017
28267f5
Update BridgeModule.java
ShariqMush Jul 18, 2017
d8a12a8
Update BridgePackage.java
ShariqMush Jul 18, 2017
fac09c2
Update VideoActivity.java
ShariqMush Jul 18, 2017
833df3e
Merge branch 'master' into master
ShariqMush Jul 25, 2017
84ce1a9
Fixed error on Android Nougat
Aug 10, 2017
39ca8ac
Update index.js
Sundin Aug 17, 2017
07fa303
Merged reaqdme
abrown1982 Sep 22, 2017
004703d
Fixed issue with RN 0.44, List @Override depricated
abrown1982 Sep 22, 2017
43bffe5
Added logic to retain position when moving between fullscreen and inl…
abrown1982 Sep 22, 2017
a961f1f
Cherry picked prop-types update
Traviskn Jul 4, 2017
e855bef
Merge pull request #2 from Misiur/bugfix/proptypes
abrown1982 Oct 19, 2017
b1ce46b
Change Image to ImageBackground for RN 50 support
abrown1982 Dec 7, 2017
cb0fcf3
Incrememnted version
abrown1982 Dec 7, 2017
f2af4ae
Added method to close fullscreen on end
abrown1982 Dec 12, 2017
8d1ec88
Merge branch 'master' of github.com:abrown1982/react-native-video-player
abrown1982 Dec 12, 2017
59eb23d
Added support for playing from OBB files in fullscreen
abrown1982 Feb 23, 2018
fa9810b
Add
xstable Feb 26, 2019
1f77c50
Merge remote-tracking branch 'project_initiator/master' into merge_wi…
xstable Feb 26, 2019
11fd8e8
Update react-native-video dependency to 4.4.0
xstable Feb 28, 2019
96841c0
Add Contributors to package.json
xstable Feb 28, 2019
63ae2f3
Fix Bug for missing "NativeModules"
xstable Feb 28, 2019
dfe7480
Fixed Play-Button on Non-Fullscreen Video doesn't work
xstable Feb 28, 2019
adf39ff
Fix Bug, that controls doesn't appear if tap on video (older Android-…
xstable Mar 6, 2019
1fc37b3
Increment Patch-Version
xstable Mar 6, 2019
b325619
Change Repository-Entry
xstable Mar 6, 2019
4de6899
Merge branch 'master' into merge_with_project_initiator
xstable Aug 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## 0.10.1
- Updated dependency of react-native-video to 4.4.0
- Added 'close'-Button on Fullscreen for Android
- Added duration/play time for IOS (with upgrading react-native-video)
- Fixed prop types issue on TouchableOpacity causing this package not to work on React Native v0.62.

## 0.9.1
Expand Down
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,45 @@ All other props are passed to the react-native-video component.
- [x] Make player customizable.
- [ ] Add volume control
- [X] Add fullscreen button
- [ ] Add fullscreen button for Android (See PR #38 if you need fullscreen in Android)
- [ ] Add loader
- [ ] Add video duration/play time
- [X] Add video duration/play time for IOS
- [ ] Add video duration/play time for Android

## Setting up fullscreen on Android

Step 1:

Go to your ```android\app\src\main\java\your\package\directory``` folder where you can find ```MainActivity.java```. Copy the java files from the repo's ```android\app\src\main\java``` folder and paste them there. Open those files in any editor(Android Studio recommended) and change the package names according to your project. After that, go to your ```MainApplication.java``` file
and under the ```new MainReactPackage()```, copy and paste this: ```new BridgePackage()``` and it should look similar to the code below if you do not have other packages.
```
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new BridgePackage()
);
}
```
Step 2:

Make a folder in your ```android\app\src\main\res``` directory and name it ```layout```, then copy the player_fullscreen.xml from the repo's ```android\app\src\main\res\layout``` directory and paste it into your directory and then go to your ```AndroidManifest.xml``` and add this before the ending application tag:
```
<activity android:name=".VideoActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="orientation|screenSize"
/>
```


If you want to remove the action bar, change your theme or change the theme for your activity from the manifest

If you want to load from an obb file, add the following to your AndroidManifext.xml file. Update the mainVersion and patchVersion to suit and remember to change for any updates:

<provider android:name="com.my.package.ZipFileContentProvider" android:authorities="com.my.package.provider">
<meta-data android:name="mainVersion" android:value="73"></meta-data>
<meta-data android:name="patchVersion" android:value="0"></meta-data>
</provider>

Then pass the mainVer and expVer in as usual for react-native-video.

And then your fullscreen should be working and ready to go!
74 changes: 74 additions & 0 deletions android/app/src/main/java/BridgeModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.my.package;

import android.os.Bundle;
import android.content.Context;
import android.content.Intent;
import android.app.Activity;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.Promise;

public class BridgeModule extends ReactContextBaseJavaModule {
static final int VIDEO_PROGRESS_REQUEST = 13214; // The request code
private static final String E_FAILED_TO_SHOW_VIDEO = "E_FAILED_TO_SHOW_VIDEO";

private Promise mBridgePromise;

private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
@Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
if (requestCode == VIDEO_PROGRESS_REQUEST) {
if (mBridgePromise != null) {
if (resultCode == Activity.RESULT_OK) {
int position = intent.getIntExtra("VIDEO_POSITION", -1);
Context context = getReactApplicationContext();
if (position <= 0) {
mBridgePromise.resolve(0);
} else {
mBridgePromise.resolve(position);
}
}
mBridgePromise = null;
}
}
}
};

public BridgeModule(ReactApplicationContext reactContext) {
super(reactContext);

// Add the listener for `onActivityResult`
reactContext.addActivityEventListener(mActivityEventListener);
}

@Override
public String getName() {
return "BridgeModule";
}

@ReactMethod
public void showFullscreen(String videoUri, int position, final Promise promise) {
Activity currentActivity = getCurrentActivity();
Context context = getReactApplicationContext();

// Store the promise to resolve/reject when video returns data
mBridgePromise = promise;

try {
Intent intent = new Intent(context, VideoActivity.class); // mContext got from your overriden constructor
Bundle extras = new Bundle();
extras.putString("VIDEO_URL",videoUri);
extras.putInt("VIDEO_POSITION",position);
intent.putExtras(extras);
currentActivity.startActivityForResult(intent, VIDEO_PROGRESS_REQUEST);
} catch (Exception e) {
mBridgePromise.reject(E_FAILED_TO_SHOW_VIDEO, e);
mBridgePromise = null;
}
}
}
35 changes: 35 additions & 0 deletions android/app/src/main/java/BridgePackage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.my.package;


import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BridgePackage implements ReactPackage {

public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();

modules.add(new BridgeModule(reactContext));

return modules;
}

}
146 changes: 146 additions & 0 deletions android/app/src/main/java/VideoActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package com.my.package;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;
import android.view.View;
import android.view.MotionEvent;

public class VideoActivity extends AppCompatActivity {
private String videoPath;
private int videoPosition, clickCount = 0;
private long startTime, duration;
private Bundle extras;
private static final int MAX_DURATION = 500;
private static ProgressDialog progressDialog;
private static MediaController mediaController;

VideoView myVideoView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
setContentView(R.layout.player_fullscreen);
Intent i = getIntent();
if(i != null){
extras = i.getExtras();
videoPath = extras.getString("VIDEO_URL");
videoPosition = extras.getInt("VIDEO_POSITION");
myVideoView = (VideoView) findViewById(R.id.videoView);
progressDialog = ProgressDialog.show(VideoActivity.this, "", "Buffering video...", true);
progressDialog.setCancelable(true);
PlayVideo();
}
else{
Toast.makeText(VideoActivity.this, "VideoURL not found", Toast.LENGTH_SHORT).show();
}


// Touch listener to: show MediaControllers on singleclick & close fullscreen video on doubleclick
myVideoView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_UP:
clickCount++;
if(clickCount >= 2) {
duration = System.currentTimeMillis() - startTime;
if(duration<= MAX_DURATION) {
finishProgress(); // Close the fullscreen video view on doubleclick.
return true;
}
}
startTime = System.currentTimeMillis();
return false;
}
return true;
}
});
}

private void PlayVideo() {
try {
getWindow().setFormat(PixelFormat.TRANSLUCENT);
mediaController = new MediaController(VideoActivity.this);
mediaController.setAnchorView(myVideoView);

Uri video = Uri.parse(videoPath);
myVideoView.setMediaController(mediaController);
myVideoView.setVideoURI(video);
myVideoView.requestFocus();
myVideoView.setKeepScreenOn(true);
myVideoView.seekTo(videoPosition * 1000);
mediaController.setPrevNextListeners(new View.OnClickListener() {
@Override
public void onClick(View v) {
// next button clicked
mediaController.show();
}
}, new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
myVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
progressDialog.dismiss();
myVideoView.start();
}
});
myVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener () {
public void onCompletion(MediaPlayer mp) {
finishProgress(true);
}
});


} catch (Exception e) {
progressDialog.dismiss();
System.out.println("Video Play Error :" + e.toString());
finishProgress();
}

}

protected void finishProgress() {
this.finishProgress(false);
}

// Called instead of finish() to always send back the progress.
protected void finishProgress(Boolean isEnd) {
Intent resultIntent = new Intent(Intent.ACTION_PICK);
int position = myVideoView.getCurrentPosition();
if (isEnd) {
position = 0;
}
resultIntent.putExtra("VIDEO_POSITION", position);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}

// Pass the progress back on the user pressing the back button.
public void onBackPressed(){
finishProgress();
}
public void onClick(View v) {
switch(v.getId()) {
case R.id.closeBtn:
finishProgress();
break;
}
}
}
22 changes: 22 additions & 0 deletions android/app/src/main/java/ZipFileContentProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.my.package;

import com.android.vending.expansion.zipfile_sound.APEZProvider;
import android.net.Uri;
import java.io.File;

public class ZipFileContentProvider extends APEZProvider {
private static final String AUTHORITY = "com.my.package.provider";

@Override
public String getAuthority() {
return AUTHORITY;
}

public static Uri buildUri(String path) {
StringBuilder contentPath = new StringBuilder("content://");
contentPath.append(AUTHORITY);
contentPath.append(File.separator);
contentPath.append(path);
return Uri.parse(contentPath.toString());
}
}
31 changes: 31 additions & 0 deletions android/app/src/main/res/layout/player_fullscreen.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VideoActivity">

<Button
android:id="@+id/closeBtn"
style="@style/Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:background="@color/colorAccent"
android:onClick="onClick"
android:text="X"
android:textSize="24sp" />

<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
android:onClick="onClick"
android:padding="0dp" />
</RelativeLayout>
Loading