diff --git a/android/build.gradle b/android/build.gradle
deleted file mode 100644
index b382a85f..00000000
--- a/android/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-apply plugin: 'com.android.library'
-
-def safeExtGet(prop, fallback) {
- rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
-}
-
-android {
- compileSdkVersion safeExtGet('compileSdkVersion', 31)
- buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
-
- defaultConfig {
- minSdkVersion safeExtGet('minSdkVersion', 21)
- targetSdkVersion safeExtGet('targetSdkVersion', 28)
- versionCode 1
- versionName "1.0"
- ndk {
- abiFilters "armeabi-v7a", "x86"
- }
- }
-}
-
-dependencies {
- //noinspection GradleDynamicVersion
- implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
- implementation 'com.github.thang2162:Android-ScalableVideoView:v1.1.1'
-}
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
deleted file mode 100644
index 3535ad44..00000000
--- a/android/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java b/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java
deleted file mode 100644
index 1ba910bf..00000000
--- a/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java
+++ /dev/null
@@ -1,287 +0,0 @@
-package com.android.vending.expansion.zipfile;
-
-/*
- * Copyright (C) 2012 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.
- */
-
-//To implement APEZProvider in your application, you'll want to change
-//the AUTHORITY to match what you define in the manifest.
-
-import com.android.vending.expansion.zipfile.ZipResourceFile.ZipEntryRO;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.OperationApplicationException;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ProviderInfo;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.provider.BaseColumns;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * This content provider is an optional part of the library.
- *
- *
Most apps don't need to use this class. This defines a
- * ContentProvider that marshalls the data from the ZIP files through a
- * content provider Uri in order to provide file access for certain Android APIs
- * that expect Uri access to media files.
- *
- */
-public abstract class APEZProvider extends ContentProvider {
-
- private ZipResourceFile mAPKExtensionFile;
- private boolean mInit;
-
- public static final String FILEID = BaseColumns._ID;
- public static final String FILENAME = "ZPFN";
- public static final String ZIPFILE = "ZFIL";
- public static final String MODIFICATION = "ZMOD";
- public static final String CRC32 = "ZCRC";
- public static final String COMPRESSEDLEN = "ZCOL";
- public static final String UNCOMPRESSEDLEN = "ZUNL";
- public static final String COMPRESSIONTYPE = "ZTYP";
-
- public static final String[] ALL_FIELDS = {
- FILEID,
- FILENAME,
- ZIPFILE,
- MODIFICATION,
- CRC32,
- COMPRESSEDLEN,
- UNCOMPRESSEDLEN,
- COMPRESSIONTYPE
- };
-
- public static final int FILEID_IDX = 0;
- public static final int FILENAME_IDX = 1;
- public static final int ZIPFILE_IDX = 2;
- public static final int MOD_IDX = 3;
- public static final int CRC_IDX = 4;
- public static final int COMPLEN_IDX = 5;
- public static final int UNCOMPLEN_IDX = 6;
- public static final int COMPTYPE_IDX = 7;
-
- public static final int[] ALL_FIELDS_INT = {
- FILEID_IDX,
- FILENAME_IDX,
- ZIPFILE_IDX,
- MOD_IDX,
- CRC_IDX,
- COMPLEN_IDX,
- UNCOMPLEN_IDX,
- COMPTYPE_IDX
- };
-
- /**
- * This needs to match the authority in your manifest
- */
- public abstract String getAuthority();
-
- @Override
- public int delete(Uri arg0, String arg1, String[] arg2) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public String getType(Uri uri) {
- return "vnd.android.cursor.item/asset";
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- // TODO Auto-generated method stub
- return null;
- }
-
- static private final String NO_FILE = "N";
-
- private boolean initIfNecessary() {
- if ( !mInit ) {
- Context ctx = getContext();
- PackageManager pm = ctx.getPackageManager();
- ProviderInfo pi = pm.resolveContentProvider(getAuthority(), PackageManager.GET_META_DATA);
- PackageInfo packInfo;
- try {
- packInfo = pm.getPackageInfo(ctx.getPackageName(), 0);
- } catch (NameNotFoundException e1) {
- e1.printStackTrace();
- return false;
- }
- int patchFileVersion;
- int mainFileVersion;
- int appVersionCode = packInfo.versionCode;
- String[] resourceFiles = null;
- if ( null != pi.metaData ) {
- mainFileVersion = pi.metaData.getInt("mainVersion", appVersionCode);
- patchFileVersion = pi.metaData.getInt("patchVersion", appVersionCode);
- String mainFileName = pi.metaData.getString("mainFilename", NO_FILE);
- if ( NO_FILE != mainFileName ) {
- String patchFileName = pi.metaData.getString("patchFilename", NO_FILE);
- if ( NO_FILE != patchFileName ) {
- resourceFiles = new String[] { mainFileName, patchFileName };
- } else {
- resourceFiles = new String[] { mainFileName };
- }
- }
- } else {
- mainFileVersion = patchFileVersion = appVersionCode;
- }
- try {
- if ( null == resourceFiles ) {
- mAPKExtensionFile = APKExpansionSupport.getAPKExpansionZipFile(ctx, mainFileVersion, patchFileVersion);
- } else {
- mAPKExtensionFile = APKExpansionSupport.getResourceZipFile(resourceFiles);
- }
- mInit = true;
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return false;
- }
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode)
- throws FileNotFoundException {
- initIfNecessary();
- String path = uri.getEncodedPath();
- if ( path.startsWith("/") ) {
- path = path.substring(1);
- }
- return mAPKExtensionFile.getAssetFileDescriptor(path);
- }
-
- @Override
- public ContentProviderResult[] applyBatch(
- ArrayList operations)
- throws OperationApplicationException {
- initIfNecessary();
- return super.applyBatch(operations);
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode)
- throws FileNotFoundException {
- initIfNecessary();
- AssetFileDescriptor af = openAssetFile(uri, mode);
- if ( null != af ) {
- return af.getParcelFileDescriptor();
- }
- return null;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- initIfNecessary();
- // lists all of the items in the file that match
- ZipEntryRO[] zipEntries;
- if ( null == mAPKExtensionFile ) {
- zipEntries = new ZipEntryRO[0];
- } else {
- zipEntries = mAPKExtensionFile.getAllEntries();
- }
- int[] intProjection;
- if ( null == projection ) {
- intProjection = ALL_FIELDS_INT;
- projection = ALL_FIELDS;
- } else {
- int len = projection.length;
- intProjection = new int[len];
- for ( int i = 0; i < len; i++ ) {
- if ( projection[i].equals(FILEID) ) {
- intProjection[i] = FILEID_IDX;
- } else if ( projection[i].equals(FILENAME) ) {
- intProjection[i] = FILENAME_IDX;
- } else if ( projection[i].equals(ZIPFILE) ) {
- intProjection[i] = ZIPFILE_IDX;
- } else if ( projection[i].equals(MODIFICATION) ) {
- intProjection[i] = MOD_IDX;
- } else if ( projection[i].equals(CRC32) ) {
- intProjection[i] = CRC_IDX;
- } else if ( projection[i].equals(COMPRESSEDLEN) ) {
- intProjection[i] = COMPLEN_IDX;
- } else if ( projection[i].equals(UNCOMPRESSEDLEN) ) {
- intProjection[i] = UNCOMPLEN_IDX;
- } else if ( projection[i].equals(COMPRESSIONTYPE) ) {
- intProjection[i] = COMPTYPE_IDX;
- } else {
- throw new RuntimeException();
- }
- }
- }
- MatrixCursor mc = new MatrixCursor(projection, zipEntries.length);
- int len = intProjection.length;
- for ( ZipEntryRO zer : zipEntries ) {
- MatrixCursor.RowBuilder rb = mc.newRow();
- for ( int i = 0; i < len; i++ ) {
- switch (intProjection[i]) {
- case FILEID_IDX:
- rb.add(i);
- break;
- case FILENAME_IDX:
- rb.add(zer.mFileName);
- break;
- case ZIPFILE_IDX:
- rb.add(zer.getZipFileName());
- break;
- case MOD_IDX:
- rb.add(zer.mWhenModified);
- break;
- case CRC_IDX:
- rb.add(zer.mCRC32);
- break;
- case COMPLEN_IDX:
- rb.add(zer.mCompressedLength);
- break;
- case UNCOMPLEN_IDX:
- rb.add(zer.mUncompressedLength);
- break;
- case COMPTYPE_IDX:
- rb.add(zer.mMethod);
- break;
- }
- }
- }
- return mc;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
-
-}
diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java b/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java
deleted file mode 100644
index 34669c1d..00000000
--- a/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.vending.expansion.zipfile;
-/*
- * Copyright (C) 2012 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.
- */
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.util.Vector;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import android.content.Context;
-import android.os.Environment;
-import android.util.Log;
-
-public class APKExpansionSupport {
- // The shared path to all app expansion files
- private final static String EXP_PATH = "/Android/obb/";
-
- static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) {
- String packageName = ctx.getPackageName();
- Vector ret = new Vector();
- if (Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- // Build the full path to the app's expansion files
- File root = Environment.getExternalStorageDirectory();
- File expPath = new File(root.toString() + EXP_PATH + packageName);
-
- // Check that expansion file path exists
- if (expPath.exists()) {
- if ( mainVersion > 0 ) {
- String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb";
-// Log.d("APKEXPANSION", strMainPath);
- File main = new File(strMainPath);
- if ( main.isFile() ) {
- ret.add(strMainPath);
- }
- }
- if ( patchVersion > 0 ) {
- String strPatchPath = expPath + File.separator + "patch." + patchVersion + "." + packageName + ".obb";
- File main = new File(strPatchPath);
- if ( main.isFile() ) {
- ret.add(strPatchPath);
- }
- }
- }
- }
- String[] retArray = new String[ret.size()];
- ret.toArray(retArray);
- return retArray;
- }
-
- static public ZipResourceFile getResourceZipFile(String[] expansionFiles) throws IOException {
- ZipResourceFile apkExpansionFile = null;
- for (String expansionFilePath : expansionFiles) {
- if ( null == apkExpansionFile ) {
- apkExpansionFile = new ZipResourceFile(expansionFilePath);
- } else {
- apkExpansionFile.addPatchFile(expansionFilePath);
- }
- }
- return apkExpansionFile;
- }
-
- static public ZipResourceFile getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion) throws IOException{
- String[] expansionFiles = getAPKExpansionFiles(ctx, mainVersion, patchVersion);
- return getResourceZipFile(expansionFiles);
- }
-}
diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java b/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java
deleted file mode 100644
index 902af3c4..00000000
--- a/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java
+++ /dev/null
@@ -1,428 +0,0 @@
-
-package com.android.vending.expansion.zipfile;
-
-/*
- * Copyright (C) 2012 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.
- */
-import android.content.res.AssetFileDescriptor;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Vector;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-public class ZipResourceFile {
-
- //
- // Read-only access to Zip archives, with minimal heap allocation.
- //
- static final String LOG_TAG = "zipro";
- static final boolean LOGV = false;
-
- // 4-byte number
- static private int swapEndian(int i)
- {
- return ((i & 0xff) << 24) + ((i & 0xff00) << 8) + ((i & 0xff0000) >>> 8)
- + ((i >>> 24) & 0xff);
- }
-
- // 2-byte number
- static private int swapEndian(short i)
- {
- return ((i & 0x00FF) << 8 | (i & 0xFF00) >>> 8);
- }
-
- /*
- * Zip file constants.
- */
- static final int kEOCDSignature = 0x06054b50;
- static final int kEOCDLen = 22;
- static final int kEOCDNumEntries = 8; // offset to #of entries in file
- static final int kEOCDSize = 12; // size of the central directory
- static final int kEOCDFileOffset = 16; // offset to central directory
-
- static final int kMaxCommentLen = 65535; // longest possible in ushort
- static final int kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
-
- static final int kLFHSignature = 0x04034b50;
- static final int kLFHLen = 30; // excluding variable-len fields
- static final int kLFHNameLen = 26; // offset to filename length
- static final int kLFHExtraLen = 28; // offset to extra length
-
- static final int kCDESignature = 0x02014b50;
- static final int kCDELen = 46; // excluding variable-len fields
- static final int kCDEMethod = 10; // offset to compression method
- static final int kCDEModWhen = 12; // offset to modification timestamp
- static final int kCDECRC = 16; // offset to entry CRC
- static final int kCDECompLen = 20; // offset to compressed length
- static final int kCDEUncompLen = 24; // offset to uncompressed length
- static final int kCDENameLen = 28; // offset to filename length
- static final int kCDEExtraLen = 30; // offset to extra length
- static final int kCDECommentLen = 32; // offset to comment length
- static final int kCDELocalOffset = 42; // offset to local hdr
-
- static final int kCompressStored = 0; // no compression
- static final int kCompressDeflated = 8; // standard deflate
-
- /*
- * The values we return for ZipEntryRO use 0 as an invalid value, so we want
- * to adjust the hash table index by a fixed amount. Using a large value
- * helps insure that people don't mix & match arguments, e.g. to
- * findEntryByIndex().
- */
- static final int kZipEntryAdj = 10000;
-
- static public final class ZipEntryRO {
- public ZipEntryRO(final String zipFileName, final File file, final String fileName) {
- mFileName = fileName;
- mZipFileName = zipFileName;
- mFile = file;
- }
-
- public final File mFile;
- public final String mFileName;
- public final String mZipFileName;
- public long mLocalHdrOffset; // offset of local file header
-
- /* useful stuff from the directory entry */
- public int mMethod;
- public long mWhenModified;
- public long mCRC32;
- public long mCompressedLength;
- public long mUncompressedLength;
-
- public long mOffset = -1;
-
- public void setOffsetFromFile(RandomAccessFile f, ByteBuffer buf) throws IOException {
- long localHdrOffset = mLocalHdrOffset;
- try {
- f.seek(localHdrOffset);
- f.readFully(buf.array());
- if (buf.getInt(0) != kLFHSignature) {
- Log.w(LOG_TAG, "didn't find signature at start of lfh");
- throw new IOException();
- }
- int nameLen = buf.getShort(kLFHNameLen) & 0xFFFF;
- int extraLen = buf.getShort(kLFHExtraLen) & 0xFFFF;
- mOffset = localHdrOffset + kLFHLen + nameLen + extraLen;
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
-
- /**
- * Calculates the offset of the start of the Zip file entry within the
- * Zip file.
- *
- * @return the offset, in bytes from the start of the file of the entry
- */
- public long getOffset() {
- return mOffset;
- }
-
- /**
- * isUncompressed
- *
- * @return true if the file is stored in uncompressed form
- */
- public boolean isUncompressed() {
- return mMethod == kCompressStored;
- }
-
- public AssetFileDescriptor getAssetFileDescriptor() {
- if (mMethod == kCompressStored) {
- ParcelFileDescriptor pfd;
- try {
- pfd = ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_READ_ONLY);
- return new AssetFileDescriptor(pfd, getOffset(), mUncompressedLength);
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return null;
- }
-
- public String getZipFileName() {
- return mZipFileName;
- }
-
- public File getZipFile() {
- return mFile;
- }
-
- }
-
- private HashMap mHashMap = new HashMap();
-
- /* for reading compressed files */
- public HashMap mZipFiles = new HashMap();
-
- public ZipResourceFile(String zipFileName) throws IOException {
- addPatchFile(zipFileName);
- }
-
- ZipEntryRO[] getEntriesAt(String path) {
- Vector zev = new Vector();
- Collection values = mHashMap.values();
- if (null == path)
- path = "";
- int length = path.length();
- for (ZipEntryRO ze : values) {
- if (ze.mFileName.startsWith(path)) {
- if (-1 == ze.mFileName.indexOf('/', length)) {
- zev.add(ze);
- }
- }
- }
- ZipEntryRO[] entries = new ZipEntryRO[zev.size()];
- return zev.toArray(entries);
- }
-
- public ZipEntryRO[] getAllEntries() {
- Collection values = mHashMap.values();
- return values.toArray(new ZipEntryRO[values.size()]);
- }
-
- /**
- * getAssetFileDescriptor allows for ZipResourceFile to directly feed
- * Android API's that want an fd, offset, and length such as the
- * MediaPlayer. It also allows for the class to be used in a content
- * provider that can feed video players. The file must be stored
- * (non-compressed) in the Zip file for this to work.
- *
- * @param assetPath
- * @return the asset file descriptor for the file, or null if the file isn't
- * present or is stored compressed
- */
- public AssetFileDescriptor getAssetFileDescriptor(String assetPath) {
- ZipEntryRO entry = mHashMap.get(assetPath);
- if (null != entry) {
- return entry.getAssetFileDescriptor();
- }
- return null;
- }
-
- /**
- * getInputStream returns an AssetFileDescriptor.AutoCloseInputStream
- * associated with the asset that is contained in the Zip file, or a
- * standard ZipInputStream if necessary to uncompress the file
- *
- * @param assetPath
- * @return an input stream for the named asset path, or null if not found
- * @throws IOException
- */
- public InputStream getInputStream(String assetPath) throws IOException {
- ZipEntryRO entry = mHashMap.get(assetPath);
- if (null != entry) {
- if (entry.isUncompressed()) {
- return entry.getAssetFileDescriptor().createInputStream();
- } else {
- ZipFile zf = mZipFiles.get(entry.getZipFile());
- /** read compressed files **/
- if (null == zf) {
- zf = new ZipFile(entry.getZipFile(), ZipFile.OPEN_READ);
- mZipFiles.put(entry.getZipFile(), zf);
- }
- ZipEntry zi = zf.getEntry(assetPath);
- if (null != zi)
- return zf.getInputStream(zi);
- }
- }
- return null;
- }
-
- ByteBuffer mLEByteBuffer = ByteBuffer.allocate(4);
-
- static private int read4LE(RandomAccessFile f) throws EOFException, IOException {
- return swapEndian(f.readInt());
- }
-
- /*
- * Opens the specified file read-only. We memory-map the entire thing and
- * close the file before returning.
- */
- void addPatchFile(String zipFileName) throws IOException
- {
- File file = new File(zipFileName);
- RandomAccessFile f = new RandomAccessFile(file, "r");
- long fileLength = f.length();
-
- if (fileLength < kEOCDLen) {
- throw new java.io.IOException();
- }
-
- long readAmount = kMaxEOCDSearch;
- if (readAmount > fileLength)
- readAmount = fileLength;
-
- /*
- * Make sure this is a Zip archive.
- */
- f.seek(0);
-
- int header = read4LE(f);
- if (header == kEOCDSignature) {
- Log.i(LOG_TAG, "Found Zip archive, but it looks empty");
- throw new IOException();
- } else if (header != kLFHSignature) {
- Log.v(LOG_TAG, "Not a Zip archive");
- throw new IOException();
- }
-
- /*
- * Perform the traditional EOCD snipe hunt. We're searching for the End
- * of Central Directory magic number, which appears at the start of the
- * EOCD block. It's followed by 18 bytes of EOCD stuff and up to 64KB of
- * archive comment. We need to read the last part of the file into a
- * buffer, dig through it to find the magic number, parse some values
- * out, and use those to determine the extent of the CD. We start by
- * pulling in the last part of the file.
- */
- long searchStart = fileLength - readAmount;
-
- f.seek(searchStart);
- ByteBuffer bbuf = ByteBuffer.allocate((int) readAmount);
- byte[] buffer = bbuf.array();
- f.readFully(buffer);
- bbuf.order(ByteOrder.LITTLE_ENDIAN);
-
- /*
- * Scan backward for the EOCD magic. In an archive without a trailing
- * comment, we'll find it on the first try. (We may want to consider
- * doing an initial minimal read; if we don't find it, retry with a
- * second read as above.)
- */
-
- // EOCD == 0x50, 0x4b, 0x05, 0x06
- int eocdIdx;
- for (eocdIdx = buffer.length - kEOCDLen; eocdIdx >= 0; eocdIdx--) {
- if (buffer[eocdIdx] == 0x50 && bbuf.getInt(eocdIdx) == kEOCDSignature)
- {
- if (LOGV) {
- Log.v(LOG_TAG, "+++ Found EOCD at index: " + eocdIdx);
- }
- break;
- }
- }
-
- if (eocdIdx < 0) {
- Log.d(LOG_TAG, "Zip: EOCD not found, " + zipFileName + " is not zip");
- }
-
- /*
- * Grab the CD offset and size, and the number of entries in the
- * archive. After that, we can release our EOCD hunt buffer.
- */
-
- int numEntries = bbuf.getShort(eocdIdx + kEOCDNumEntries);
- long dirSize = bbuf.getInt(eocdIdx + kEOCDSize) & 0xffffffffL;
- long dirOffset = bbuf.getInt(eocdIdx + kEOCDFileOffset) & 0xffffffffL;
-
- // Verify that they look reasonable.
- if (dirOffset + dirSize > fileLength) {
- Log.w(LOG_TAG, "bad offsets (dir " + dirOffset + ", size " + dirSize + ", eocd "
- + eocdIdx + ")");
- throw new IOException();
- }
- if (numEntries == 0) {
- Log.w(LOG_TAG, "empty archive?");
- throw new IOException();
- }
-
- if (LOGV) {
- Log.v(LOG_TAG, "+++ numEntries=" + numEntries + " dirSize=" + dirSize + " dirOffset="
- + dirOffset);
- }
-
- MappedByteBuffer directoryMap = f.getChannel()
- .map(FileChannel.MapMode.READ_ONLY, dirOffset, dirSize);
- directoryMap.order(ByteOrder.LITTLE_ENDIAN);
-
- byte[] tempBuf = new byte[0xffff];
-
- /*
- * Walk through the central directory, adding entries to the hash table.
- */
-
- int currentOffset = 0;
-
- /*
- * Allocate the local directory information
- */
- ByteBuffer buf = ByteBuffer.allocate(kLFHLen);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
- for (int i = 0; i < numEntries; i++) {
- if (directoryMap.getInt(currentOffset) != kCDESignature) {
- Log.w(LOG_TAG, "Missed a central dir sig (at " + currentOffset + ")");
- throw new IOException();
- }
-
- /* useful stuff from the directory entry */
- int fileNameLen = directoryMap.getShort(currentOffset + kCDENameLen) & 0xffff;
- int extraLen = directoryMap.getShort(currentOffset + kCDEExtraLen) & 0xffff;
- int commentLen = directoryMap.getShort(currentOffset + kCDECommentLen) & 0xffff;
-
- /* get the CDE filename */
-
- directoryMap.position(currentOffset + kCDELen);
- directoryMap.get(tempBuf, 0, fileNameLen);
- directoryMap.position(0);
-
- /* UTF-8 on Android */
- String str = new String(tempBuf, 0, fileNameLen);
- if (LOGV) {
- Log.v(LOG_TAG, "Filename: " + str);
- }
-
- ZipEntryRO ze = new ZipEntryRO(zipFileName, file, str);
- ze.mMethod = directoryMap.getShort(currentOffset + kCDEMethod) & 0xffff;
- ze.mWhenModified = directoryMap.getInt(currentOffset + kCDEModWhen) & 0xffffffffL;
- ze.mCRC32 = directoryMap.getLong(currentOffset + kCDECRC) & 0xffffffffL;
- ze.mCompressedLength = directoryMap.getLong(currentOffset + kCDECompLen) & 0xffffffffL;
- ze.mUncompressedLength = directoryMap.getLong(currentOffset + kCDEUncompLen) & 0xffffffffL;
- ze.mLocalHdrOffset = directoryMap.getInt(currentOffset + kCDELocalOffset) & 0xffffffffL;
-
- // set the offsets
- buf.clear();
- ze.setOffsetFromFile(f, buf);
-
- // put file into hash
- mHashMap.put(str, ze);
-
- // go to next directory entry
- currentOffset += kCDELen + fileNameLen + extraLen + commentLen;
- }
- if (LOGV) {
- Log.v(LOG_TAG, "+++ zip good scan " + numEntries + " entries");
- }
- }
-}
diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java b/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java
deleted file mode 100644
index b09e9414..00000000
--- a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.brentvatne.react;
-
-import android.app.Activity;
-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.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-public class ReactVideoPackage implements ReactPackage {
-
- @Override
- public List createNativeModules(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
-
- // Deprecated RN 0.47
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
- @Override
- public List createViewManagers(ReactApplicationContext reactContext) {
- return Arrays.asList(new ReactVideoViewManager());
- }
-}
diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java
deleted file mode 100644
index 09285fb7..00000000
--- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java
+++ /dev/null
@@ -1,796 +0,0 @@
-package com.brentvatne.react;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.content.res.AssetFileDescriptor;
-import android.graphics.Matrix;
-import android.media.MediaPlayer;
-import android.media.TimedMetaData;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Handler;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.WindowManager;
-import android.view.View;
-import android.view.Window;
-import android.webkit.CookieManager;
-import android.widget.MediaController;
-
-import com.android.vending.expansion.zipfile.APKExpansionSupport;
-import com.android.vending.expansion.zipfile.ZipResourceFile;
-import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.LifecycleEventListener;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableArray;
-import com.facebook.react.bridge.WritableNativeArray;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.events.RCTEventEmitter;
-import com.yqritc.scalablevideoview.ScalableType;
-import com.yqritc.scalablevideoview.ScalableVideoView;
-import com.yqritc.scalablevideoview.ScaleManager;
-import com.yqritc.scalablevideoview.Size;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
-import java.util.Map;
-import java.lang.Math;
-import java.math.BigDecimal;
-
-import javax.annotation.Nullable;
-
-@SuppressLint("ViewConstructor")
-public class ReactVideoView extends ScalableVideoView implements
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnErrorListener,
- MediaPlayer.OnBufferingUpdateListener,
- MediaPlayer.OnSeekCompleteListener,
- MediaPlayer.OnCompletionListener,
- MediaPlayer.OnInfoListener,
- LifecycleEventListener,
- MediaController.MediaPlayerControl {
-
- public enum Events {
- EVENT_LOAD_START("onVideoLoadStart"),
- EVENT_LOAD("onVideoLoad"),
- EVENT_ERROR("onVideoError"),
- EVENT_PROGRESS("onVideoProgress"),
- EVENT_TIMED_METADATA("onTimedMetadata"),
- EVENT_SEEK("onVideoSeek"),
- EVENT_END("onVideoEnd"),
- EVENT_STALLED("onPlaybackStalled"),
- EVENT_RESUME("onPlaybackResume"),
- EVENT_READY_FOR_DISPLAY("onReadyForDisplay"),
- EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"),
- EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"),
- EVENT_FULLSCREEN_WILL_DISMISS("onVideoFullscreenPlayerWillDismiss"),
- EVENT_FULLSCREEN_DID_DISMISS("onVideoFullscreenPlayerDidDismiss");
-
- private final String mName;
-
- Events(final String name) {
- mName = name;
- }
-
- @Override
- public String toString() {
- return mName;
- }
- }
-
- public static final String EVENT_PROP_FAST_FORWARD = "canPlayFastForward";
- public static final String EVENT_PROP_SLOW_FORWARD = "canPlaySlowForward";
- public static final String EVENT_PROP_SLOW_REVERSE = "canPlaySlowReverse";
- public static final String EVENT_PROP_REVERSE = "canPlayReverse";
- public static final String EVENT_PROP_STEP_FORWARD = "canStepForward";
- public static final String EVENT_PROP_STEP_BACKWARD = "canStepBackward";
-
- public static final String EVENT_PROP_DURATION = "duration";
- public static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration";
- public static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration";
- public static final String EVENT_PROP_CURRENT_TIME = "currentTime";
- public static final String EVENT_PROP_SEEK_TIME = "seekTime";
- public static final String EVENT_PROP_NATURALSIZE = "naturalSize";
- public static final String EVENT_PROP_WIDTH = "width";
- public static final String EVENT_PROP_HEIGHT = "height";
- public static final String EVENT_PROP_ORIENTATION = "orientation";
- public static final String EVENT_PROP_METADATA = "metadata";
- public static final String EVENT_PROP_TARGET = "target";
- public static final String EVENT_PROP_METADATA_IDENTIFIER = "identifier";
- public static final String EVENT_PROP_METADATA_VALUE = "value";
-
- public static final String EVENT_PROP_ERROR = "error";
- public static final String EVENT_PROP_WHAT = "what";
- public static final String EVENT_PROP_EXTRA = "extra";
-
- private ThemedReactContext mThemedReactContext;
- private RCTEventEmitter mEventEmitter;
-
- private Handler mProgressUpdateHandler = new Handler();
- private Runnable mProgressUpdateRunnable = null;
- private Handler videoControlHandler = new Handler();
- private MediaController mediaController;
-
- private String mSrcUriString = null;
- private String mSrcType = "mp4";
- private ReadableMap mRequestHeaders = null;
- private boolean mSrcIsNetwork = false;
- private boolean mSrcIsAsset = false;
- private ScalableType mResizeMode = ScalableType.LEFT_TOP;
- private boolean mRepeat = false;
- private boolean mPaused = false;
- private boolean mMuted = false;
- private boolean mPreventsDisplaySleepDuringVideoPlayback = true;
- private float mVolume = 1.0f;
- private float mStereoPan = 0.0f;
- private float mProgressUpdateInterval = 250.0f;
- private float mRate = 1.0f;
- private float mActiveRate = 1.0f;
- private long mSeekTime = 0;
- private boolean mPlayInBackground = false;
- private boolean mBackgroundPaused = false;
- private boolean mIsFullscreen = false;
-
- private int mMainVer = 0;
- private int mPatchVer = 0;
-
- private boolean mMediaPlayerValid = false; // True if mMediaPlayer is in prepared, started, paused or completed state.
-
- private int mVideoDuration = 0;
- private int mVideoBufferedDuration = 0;
- private boolean isCompleted = false;
- private boolean mUseNativeControls = false;
-
- public ReactVideoView(ThemedReactContext themedReactContext) {
- super(themedReactContext);
-
- mThemedReactContext = themedReactContext;
- mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class);
- themedReactContext.addLifecycleEventListener(this);
-
- initializeMediaPlayerIfNeeded();
- setSurfaceTextureListener(this);
-
- mProgressUpdateRunnable = new Runnable() {
- @Override
- public void run() {
-
- if (mMediaPlayerValid && !isCompleted && !mPaused && !mBackgroundPaused) {
- WritableMap event = Arguments.createMap();
- event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0);
- event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mVideoBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable
- event.putDouble(EVENT_PROP_SEEKABLE_DURATION, mVideoDuration / 1000.0);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_PROGRESS.toString(), event);
-
- // Check for update after an interval
- mProgressUpdateHandler.postDelayed(mProgressUpdateRunnable, Math.round(mProgressUpdateInterval));
- }
- }
- };
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mUseNativeControls) {
- initializeMediaControllerIfNeeded();
- mediaController.show();
- }
-
- return super.onTouchEvent(event);
- }
-
- @Override
- @SuppressLint("DrawAllocation")
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (!changed || !mMediaPlayerValid) {
- return;
- }
-
- int videoWidth = getVideoWidth();
- int videoHeight = getVideoHeight();
-
- if (videoWidth == 0 || videoHeight == 0) {
- return;
- }
-
- Size viewSize = new Size(getWidth(), getHeight());
- Size videoSize = new Size(videoWidth, videoHeight);
- ScaleManager scaleManager = new ScaleManager(viewSize, videoSize);
- Matrix matrix = scaleManager.getScaleMatrix(mScalableType);
- if (matrix != null) {
- setTransform(matrix);
- }
- }
-
- private void initializeMediaPlayerIfNeeded() {
- if (mMediaPlayer == null) {
- mMediaPlayerValid = false;
- mMediaPlayer = new MediaPlayer();
- mMediaPlayer.setOnVideoSizeChangedListener(this);
- mMediaPlayer.setOnErrorListener(this);
- mMediaPlayer.setOnPreparedListener(this);
- mMediaPlayer.setOnBufferingUpdateListener(this);
- mMediaPlayer.setOnSeekCompleteListener(this);
- mMediaPlayer.setOnCompletionListener(this);
- mMediaPlayer.setOnInfoListener(this);
- if (Build.VERSION.SDK_INT >= 23) {
- mMediaPlayer.setOnTimedMetaDataAvailableListener(new TimedMetaDataAvailableListener());
- }
- }
- }
-
- private void initializeMediaControllerIfNeeded() {
- if (mediaController == null) {
- mediaController = new MediaController(this.getContext());
- }
- }
-
- public void cleanupMediaPlayerResources() {
- if ( mediaController != null ) {
- mediaController.hide();
- }
- if ( mMediaPlayer != null ) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- mMediaPlayer.setOnTimedMetaDataAvailableListener(null);
- }
- mMediaPlayerValid = false;
- release();
- }
- if (mIsFullscreen) {
- setFullscreen(false);
- }
- if (mThemedReactContext != null) {
- mThemedReactContext.removeLifecycleEventListener(this);
- mThemedReactContext = null;
- }
- }
-
- public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) {
- setSrc(uriString, type, isNetwork, isAsset, requestHeaders, 0, 0);
- }
-
- public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders, final int expansionMainVersion, final int expansionPatchVersion) {
-
- mSrcUriString = uriString;
- mSrcType = type;
- mSrcIsNetwork = isNetwork;
- mSrcIsAsset = isAsset;
- mRequestHeaders = requestHeaders;
- mMainVer = expansionMainVersion;
- mPatchVer = expansionPatchVersion;
-
-
- mMediaPlayerValid = false;
- mVideoDuration = 0;
- mVideoBufferedDuration = 0;
-
- initializeMediaPlayerIfNeeded();
- mMediaPlayer.reset();
-
- try {
- if (isNetwork) {
- // Use the shared CookieManager to access the cookies
- // set by WebViews inside the same app
- CookieManager cookieManager = CookieManager.getInstance();
-
- Uri parsedUrl = Uri.parse(uriString);
- Uri.Builder builtUrl = parsedUrl.buildUpon();
-
- String cookie = cookieManager.getCookie(builtUrl.build().toString());
-
- Map headers = new HashMap();
-
- if (cookie != null) {
- headers.put("Cookie", cookie);
- }
-
- if (mRequestHeaders != null) {
- headers.putAll(toStringMap(mRequestHeaders));
- }
-
- /* According to https://github.com/react-native-community/react-native-video/pull/537
- * there is an issue with this where it can cause a IOException.
- * TODO: diagnose this exception and fix it
- */
- setDataSource(mThemedReactContext, parsedUrl, headers);
- } else if (isAsset) {
- if (uriString.startsWith("content://")) {
- Uri parsedUrl = Uri.parse(uriString);
- setDataSource(mThemedReactContext, parsedUrl);
- } else {
- setDataSource(uriString);
- }
- } else {
- ZipResourceFile expansionFile= null;
- AssetFileDescriptor fd= null;
- if(mMainVer>0) {
- try {
- expansionFile = APKExpansionSupport.getAPKExpansionZipFile(mThemedReactContext, mMainVer, mPatchVer);
- fd = expansionFile.getAssetFileDescriptor(uriString.replace(".mp4","") + ".mp4");
- } catch (IOException e) {
- e.printStackTrace();
- } catch (NullPointerException e) {
- e.printStackTrace();
- }
- }
- if(fd==null) {
- int identifier = mThemedReactContext.getResources().getIdentifier(
- uriString,
- "drawable",
- mThemedReactContext.getPackageName()
- );
- if (identifier == 0) {
- identifier = mThemedReactContext.getResources().getIdentifier(
- uriString,
- "raw",
- mThemedReactContext.getPackageName()
- );
- }
- setRawData(identifier);
- }
- else {
- setDataSource(fd.getFileDescriptor(), fd.getStartOffset(),fd.getLength());
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
-
- WritableMap src = Arguments.createMap();
-
- WritableMap wRequestHeaders = Arguments.createMap();
- wRequestHeaders.merge(mRequestHeaders);
-
- src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString);
- src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type);
- src.putMap(ReactVideoViewManager.PROP_SRC_HEADERS, wRequestHeaders);
- src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork);
- if(mMainVer>0) {
- src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer);
- if(mPatchVer>0) {
- src.putInt(ReactVideoViewManager.PROP_SRC_PATCHVER, mPatchVer);
- }
- }
- WritableMap event = Arguments.createMap();
- event.putMap(ReactVideoViewManager.PROP_SRC, src);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD_START.toString(), event);
- isCompleted = false;
-
- try {
- prepareAsync(this);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void setResizeModeModifier(final ScalableType resizeMode) {
- mResizeMode = resizeMode;
-
- if (mMediaPlayerValid) {
- setScalableType(resizeMode);
- invalidate();
- }
- }
-
- public void setRepeatModifier(final boolean repeat) {
-
- mRepeat = repeat;
-
- if (mMediaPlayerValid) {
- setLooping(repeat);
- }
- }
-
- public void setPausedModifier(final boolean paused) {
- mPaused = paused;
-
- if (!mMediaPlayerValid) {
- return;
- }
-
- if (mPaused) {
- if (mMediaPlayer.isPlaying()) {
- pause();
- }
- } else {
- if (!mMediaPlayer.isPlaying()) {
- start();
- // Setting the rate unpauses, so we have to wait for an unpause
- if (mRate != mActiveRate) {
- setRateModifier(mRate);
- }
-
- // Also Start the Progress Update Handler
- mProgressUpdateHandler.post(mProgressUpdateRunnable);
- }
- }
- setKeepScreenOn(!mPaused && mPreventsDisplaySleepDuringVideoPlayback);
- }
-
- // reduces the volume based on stereoPan
- private float calulateRelativeVolume() {
- float relativeVolume = (mVolume * (1 - Math.abs(mStereoPan)));
- // only one decimal allowed
- BigDecimal roundRelativeVolume = new BigDecimal(relativeVolume).setScale(1, BigDecimal.ROUND_HALF_UP);
- return roundRelativeVolume.floatValue();
- }
-
- public void setPreventsDisplaySleepDuringVideoPlaybackModifier(final boolean preventsDisplaySleepDuringVideoPlayback) {
- mPreventsDisplaySleepDuringVideoPlayback = preventsDisplaySleepDuringVideoPlayback;
-
- if (!mMediaPlayerValid) {
- return;
- }
-
- mMediaPlayer.setScreenOnWhilePlaying(mPreventsDisplaySleepDuringVideoPlayback);
- setKeepScreenOn(mPreventsDisplaySleepDuringVideoPlayback);
- }
-
- public void setMutedModifier(final boolean muted) {
- mMuted = muted;
-
- if (!mMediaPlayerValid) {
- return;
- }
-
- if (mMuted) {
- setVolume(0, 0);
- } else if (mStereoPan < 0) {
- // louder on the left channel
- setVolume(mVolume, calulateRelativeVolume());
- } else if (mStereoPan > 0) {
- // louder on the right channel
- setVolume(calulateRelativeVolume(), mVolume);
- } else {
- // same volume on both channels
- setVolume(mVolume, mVolume);
- }
- }
-
- public void setVolumeModifier(final float volume) {
- mVolume = volume;
- setMutedModifier(mMuted);
- }
-
- public void setStereoPan(final float stereoPan) {
- mStereoPan = stereoPan;
- setMutedModifier(mMuted);
- }
-
- public void setProgressUpdateInterval(final float progressUpdateInterval) {
- mProgressUpdateInterval = progressUpdateInterval;
- }
-
- public void setRateModifier(final float rate) {
- mRate = rate;
-
- if (mMediaPlayerValid) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (!mPaused) { // Applying the rate while paused will cause the video to start
- /* Per https://stackoverflow.com/questions/39442522/setplaybackparams-causes-illegalstateexception
- * Some devices throw an IllegalStateException if you set the rate without first calling reset()
- * TODO: Call reset() then reinitialize the player
- */
- try {
- mMediaPlayer.setPlaybackParams(mMediaPlayer.getPlaybackParams().setSpeed(rate));
- mActiveRate = rate;
- } catch (Exception e) {
- Log.e(ReactVideoViewManager.REACT_CLASS, "Unable to set rate, unsupported on this device");
- }
- }
- } else {
- Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android versions below 6.0");
- }
- }
- }
-
- public void setFullscreen(boolean isFullscreen) {
- if (isFullscreen == mIsFullscreen) {
- return; // Avoid generating events when nothing is changing
- }
- mIsFullscreen = isFullscreen;
-
- Activity activity = mThemedReactContext.getCurrentActivity();
- if (activity == null) {
- return;
- }
- Window window = activity.getWindow();
- View decorView = window.getDecorView();
- int uiOptions;
- if (mIsFullscreen) {
- if (Build.VERSION.SDK_INT >= 19) { // 4.4+
- uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | SYSTEM_UI_FLAG_FULLSCREEN;
- } else {
- uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | SYSTEM_UI_FLAG_FULLSCREEN;
- }
- mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_WILL_PRESENT.toString(), null);
- decorView.setSystemUiVisibility(uiOptions);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_DID_PRESENT.toString(), null);
- } else {
- uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
- mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_WILL_DISMISS.toString(), null);
- decorView.setSystemUiVisibility(uiOptions);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_DID_DISMISS.toString(), null);
- }
- }
-
- public void applyModifiers() {
- setResizeModeModifier(mResizeMode);
- setRepeatModifier(mRepeat);
- setPausedModifier(mPaused);
- setMutedModifier(mMuted);
- setPreventsDisplaySleepDuringVideoPlaybackModifier(mPreventsDisplaySleepDuringVideoPlayback);
- setProgressUpdateInterval(mProgressUpdateInterval);
- setRateModifier(mRate);
- }
-
- public void setPlayInBackground(final boolean playInBackground) {
-
- mPlayInBackground = playInBackground;
- }
-
- public void setControls(boolean controls) {
- this.mUseNativeControls = controls;
- }
-
- @Override
- public void onPrepared(MediaPlayer mp) {
-
- mMediaPlayerValid = true;
- mVideoDuration = mp.getDuration();
-
- WritableMap naturalSize = Arguments.createMap();
- naturalSize.putInt(EVENT_PROP_WIDTH, mp.getVideoWidth());
- naturalSize.putInt(EVENT_PROP_HEIGHT, mp.getVideoHeight());
- if (mp.getVideoWidth() > mp.getVideoHeight())
- naturalSize.putString(EVENT_PROP_ORIENTATION, "landscape");
- else
- naturalSize.putString(EVENT_PROP_ORIENTATION, "portrait");
-
- WritableMap event = Arguments.createMap();
- event.putDouble(EVENT_PROP_DURATION, mVideoDuration / 1000.0);
- event.putDouble(EVENT_PROP_CURRENT_TIME, mp.getCurrentPosition() / 1000.0);
- event.putMap(EVENT_PROP_NATURALSIZE, naturalSize);
- // TODO: Actually check if you can.
- event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
- event.putBoolean(EVENT_PROP_SLOW_FORWARD, true);
- event.putBoolean(EVENT_PROP_SLOW_REVERSE, true);
- event.putBoolean(EVENT_PROP_REVERSE, true);
- event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
- event.putBoolean(EVENT_PROP_STEP_BACKWARD, true);
- event.putBoolean(EVENT_PROP_STEP_FORWARD, true);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD.toString(), event);
-
- applyModifiers();
-
- if (mUseNativeControls) {
- initializeMediaControllerIfNeeded();
- mediaController.setMediaPlayer(this);
- mediaController.setAnchorView(this);
-
- videoControlHandler.post(new Runnable() {
- @Override
- public void run() {
- mediaController.setEnabled(true);
- mediaController.show();
- }
- });
- }
-
- selectTimedMetadataTrack(mp);
- }
-
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
-
- WritableMap error = Arguments.createMap();
- error.putInt(EVENT_PROP_WHAT, what);
- error.putInt(EVENT_PROP_EXTRA, extra);
- WritableMap event = Arguments.createMap();
- event.putMap(EVENT_PROP_ERROR, error);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_ERROR.toString(), event);
- return true;
- }
-
- @Override
- public boolean onInfo(MediaPlayer mp, int what, int extra) {
- switch (what) {
- case MediaPlayer.MEDIA_INFO_BUFFERING_START:
- mEventEmitter.receiveEvent(getId(), Events.EVENT_STALLED.toString(), Arguments.createMap());
- break;
- case MediaPlayer.MEDIA_INFO_BUFFERING_END:
- mEventEmitter.receiveEvent(getId(), Events.EVENT_RESUME.toString(), Arguments.createMap());
- break;
- case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
- mEventEmitter.receiveEvent(getId(), Events.EVENT_READY_FOR_DISPLAY.toString(), Arguments.createMap());
- break;
-
- default:
- }
- return false;
- }
-
- @Override
- public void onBufferingUpdate(MediaPlayer mp, int percent) {
- selectTimedMetadataTrack(mp);
- mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0);
- }
-
- public void onSeekComplete(MediaPlayer mp) {
- WritableMap event = Arguments.createMap();
- event.putDouble(EVENT_PROP_CURRENT_TIME, getCurrentPosition() / 1000.0);
- event.putDouble(EVENT_PROP_SEEK_TIME, mSeekTime / 1000.0);
- mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event);
- mSeekTime = 0;
- }
-
- @Override
- public void seekTo(int msec) {
- if (mMediaPlayerValid) {
- mSeekTime = msec;
- mMediaPlayer.seekTo(msec, MediaPlayer.SEEK_CLOSEST);
- if (isCompleted && mVideoDuration != 0 && msec < mVideoDuration) {
- isCompleted = false;
- }
- }
- }
-
- @Override
- public int getBufferPercentage() {
- return 0;
- }
-
- @Override
- public boolean canPause() {
- return true;
- }
-
- @Override
- public boolean canSeekBackward() {
- return true;
- }
-
- @Override
- public boolean canSeekForward() {
- return true;
- }
-
- @Override
- public int getAudioSessionId() {
- return 0;
- }
-
- @Override
- public void onCompletion(MediaPlayer mp) {
- isCompleted = true;
- mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null);
- if (!mRepeat) {
- setKeepScreenOn(false);
- }
- }
-
- // This is not fully tested and does not work for all forms of timed metadata
- @TargetApi(23) // 6.0
- public class TimedMetaDataAvailableListener
- implements MediaPlayer.OnTimedMetaDataAvailableListener
- {
- public void onTimedMetaDataAvailable(MediaPlayer mp, TimedMetaData data) {
- WritableMap event = Arguments.createMap();
-
- try {
- String rawMeta = new String(data.getMetaData(), "UTF-8");
- WritableMap id3 = Arguments.createMap();
-
- id3.putString(EVENT_PROP_METADATA_VALUE, rawMeta.substring(rawMeta.lastIndexOf("\u0003") + 1));
- id3.putString(EVENT_PROP_METADATA_IDENTIFIER, "id3/TDEN");
-
- WritableArray metadata = new WritableNativeArray();
-
- metadata.pushMap(id3);
-
- event.putArray(EVENT_PROP_METADATA, metadata);
- event.putDouble(EVENT_PROP_TARGET, getId());
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
-
- mEventEmitter.receiveEvent(getId(), Events.EVENT_TIMED_METADATA.toString(), event);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- mMediaPlayerValid = false;
- super.onDetachedFromWindow();
- setKeepScreenOn(false);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if(mMainVer>0) {
- setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders, mMainVer, mPatchVer);
- }
- else {
- setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders);
- }
- setKeepScreenOn(mPreventsDisplaySleepDuringVideoPlayback);
- }
-
- @Override
- public void onHostPause() {
- if (mMediaPlayerValid && !mPaused && !mPlayInBackground) {
- /* Pause the video in background
- * Don't update the paused prop, developers should be able to update it on background
- * so that when you return to the app the video is paused
- */
- mBackgroundPaused = true;
- mMediaPlayer.pause();
- }
- }
-
- @Override
- public void onHostResume() {
- mBackgroundPaused = false;
- if (mMediaPlayerValid && !mPlayInBackground && !mPaused) {
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- // Restore original state
- setPausedModifier(false);
- }
- });
- }
- }
-
- @Override
- public void onHostDestroy() {
- }
-
- /**
- * toStringMap converts a {@link ReadableMap} into a HashMap.
- *
- * @param readableMap The ReadableMap to be conveted.
- * @return A HashMap containing the data that was in the ReadableMap.
- * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
- */
- public static Map toStringMap(@Nullable ReadableMap readableMap) {
- Map result = new HashMap<>();
- if (readableMap == null)
- return result;
-
- com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
- while (iterator.hasNextKey()) {
- String key = iterator.nextKey();
- result.put(key, readableMap.getString(key));
- }
-
- return result;
- }
-
- // Select track (so we can use it to listen to timed meta data updates)
- private void selectTimedMetadataTrack(MediaPlayer mp) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- return;
- }
- try { // It's possible this could throw an exception if the framework doesn't support getting track info
- MediaPlayer.TrackInfo[] trackInfo = mp.getTrackInfo();
- for (int i = 0; i < trackInfo.length; ++i) {
- if (trackInfo[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
- mp.selectTrack(i);
- break;
- }
- }
- } catch (Exception e) {}
- }
-}
diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java
deleted file mode 100644
index 59efab49..00000000
--- a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.brentvatne.react;
-
-import com.brentvatne.react.ReactVideoView.Events;
-import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.annotations.ReactProp;
-import com.facebook.react.uimanager.SimpleViewManager;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.events.RCTEventEmitter;
-import com.yqritc.scalablevideoview.ScalableType;
-
-import javax.annotation.Nullable;
-import java.util.Map;
-
-public class ReactVideoViewManager extends SimpleViewManager {
-
- public static final String REACT_CLASS = "RCTVideo";
-
- public static final String PROP_SRC = "src";
- public static final String PROP_SRC_URI = "uri";
- public static final String PROP_SRC_TYPE = "type";
- public static final String PROP_SRC_HEADERS = "requestHeaders";
- public static final String PROP_SRC_IS_NETWORK = "isNetwork";
- public static final String PROP_SRC_MAINVER = "mainVer";
- public static final String PROP_SRC_PATCHVER = "patchVer";
- public static final String PROP_SRC_IS_ASSET = "isAsset";
- public static final String PROP_RESIZE_MODE = "resizeMode";
- public static final String PROP_REPEAT = "repeat";
- public static final String PROP_PAUSED = "paused";
- public static final String PROP_MUTED = "muted";
- public static final String PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK = "preventsDisplaySleepDuringVideoPlayback";
- public static final String PROP_VOLUME = "volume";
- public static final String PROP_STEREO_PAN = "stereoPan";
- public static final String PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval";
- public static final String PROP_SEEK = "seek";
- public static final String PROP_RATE = "rate";
- public static final String PROP_FULLSCREEN = "fullscreen";
- public static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
- public static final String PROP_CONTROLS = "controls";
-
- @Override
- public String getName() {
- return REACT_CLASS;
- }
-
- @Override
- protected ReactVideoView createViewInstance(ThemedReactContext themedReactContext) {
- return new ReactVideoView(themedReactContext);
- }
-
- @Override
- public void onDropViewInstance(ReactVideoView view) {
- super.onDropViewInstance(view);
- view.cleanupMediaPlayerResources();
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- MapBuilder.Builder builder = MapBuilder.builder();
- for (Events event : Events.values()) {
- builder.put(event.toString(), MapBuilder.of("registrationName", event.toString()));
- }
- return builder.build();
- }
-
- @Override
- @Nullable
- public Map getExportedViewConstants() {
- return MapBuilder.of(
- "ScaleNone", Integer.toString(ScalableType.LEFT_TOP.ordinal()),
- "ScaleToFill", Integer.toString(ScalableType.FIT_XY.ordinal()),
- "ScaleAspectFit", Integer.toString(ScalableType.FIT_CENTER.ordinal()),
- "ScaleAspectFill", Integer.toString(ScalableType.CENTER_CROP.ordinal())
- );
- }
-
- @ReactProp(name = PROP_SRC)
- public void setSrc(final ReactVideoView videoView, @Nullable ReadableMap src) {
- int mainVer = src.getInt(PROP_SRC_MAINVER);
- int patchVer = src.getInt(PROP_SRC_PATCHVER);
- if(mainVer<0) { mainVer = 0; }
- if(patchVer<0) { patchVer = 0; }
- if(mainVer>0) {
- videoView.setSrc(
- src.getString(PROP_SRC_URI),
- src.getString(PROP_SRC_TYPE),
- src.getBoolean(PROP_SRC_IS_NETWORK),
- src.getBoolean(PROP_SRC_IS_ASSET),
- src.getMap(PROP_SRC_HEADERS),
- mainVer,
- patchVer
- );
- }
- else {
- videoView.setSrc(
- src.getString(PROP_SRC_URI),
- src.getString(PROP_SRC_TYPE),
- src.getBoolean(PROP_SRC_IS_NETWORK),
- src.getBoolean(PROP_SRC_IS_ASSET),
- src.getMap(PROP_SRC_HEADERS)
- );
- }
- }
-
- @ReactProp(name = PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK)
- public void setPropPreventsDisplaySleepDuringVideoPlayback(final ReactVideoView videoView, final boolean doPreventSleep) {
- videoView.setPreventsDisplaySleepDuringVideoPlaybackModifier(doPreventSleep);
- }
-
- @ReactProp(name = PROP_RESIZE_MODE)
- public void setResizeMode(final ReactVideoView videoView, final String resizeModeOrdinalString) {
- videoView.setResizeModeModifier(ScalableType.values()[Integer.parseInt(resizeModeOrdinalString)]);
- }
-
- @ReactProp(name = PROP_REPEAT, defaultBoolean = false)
- public void setRepeat(final ReactVideoView videoView, final boolean repeat) {
- videoView.setRepeatModifier(repeat);
- }
-
- @ReactProp(name = PROP_PAUSED, defaultBoolean = false)
- public void setPaused(final ReactVideoView videoView, final boolean paused) {
- videoView.setPausedModifier(paused);
- }
-
- @ReactProp(name = PROP_MUTED, defaultBoolean = false)
- public void setMuted(final ReactVideoView videoView, final boolean muted) {
- videoView.setMutedModifier(muted);
- }
-
- @ReactProp(name = PROP_VOLUME, defaultFloat = 1.0f)
- public void setVolume(final ReactVideoView videoView, final float volume) {
- videoView.setVolumeModifier(volume);
- }
-
- @ReactProp(name = PROP_STEREO_PAN)
- public void setStereoPan(final ReactVideoView videoView, final float stereoPan) {
- videoView.setStereoPan(stereoPan);
- }
-
- @ReactProp(name = PROP_PROGRESS_UPDATE_INTERVAL, defaultFloat = 250.0f)
- public void setProgressUpdateInterval(final ReactVideoView videoView, final float progressUpdateInterval) {
- videoView.setProgressUpdateInterval(progressUpdateInterval);
- }
-
- @ReactProp(name = PROP_SEEK)
- public void setSeek(final ReactVideoView videoView, final float seek) {
- videoView.seekTo(Math.round(seek * 1000.0f));
- }
-
- @ReactProp(name = PROP_RATE)
- public void setRate(final ReactVideoView videoView, final float rate) {
- videoView.setRateModifier(rate);
- }
-
- @ReactProp(name = PROP_FULLSCREEN, defaultBoolean = false)
- public void setFullscreen(final ReactVideoView videoView, final boolean fullscreen) {
- videoView.setFullscreen(fullscreen);
- }
-
- @ReactProp(name = PROP_PLAY_IN_BACKGROUND, defaultBoolean = false)
- public void setPlayInBackground(final ReactVideoView videoView, final boolean playInBackground) {
- videoView.setPlayInBackground(playInBackground);
- }
-
- @ReactProp(name = PROP_CONTROLS, defaultBoolean = false)
- public void setControls(final ReactVideoView videoView, final boolean controls) {
- videoView.setControls(controls);
- }
-}