From 32718be95130f0c15c1932d86687bff9a5f61f19 Mon Sep 17 00:00:00 2001 From: olivier bouillet Date: Wed, 15 Jun 2022 22:29:46 +0200 Subject: [PATCH] chore: remove MediaPlayer source --- android/build.gradle | 26 - android/src/main/AndroidManifest.xml | 3 - .../expansion/zipfile/APEZProvider.java | 287 ------- .../zipfile/APKExpansionSupport.java | 81 -- .../expansion/zipfile/ZipResourceFile.java | 428 ---------- .../brentvatne/react/ReactVideoPackage.java | 30 - .../com/brentvatne/react/ReactVideoView.java | 796 ------------------ .../react/ReactVideoViewManager.java | 172 ---- 8 files changed, 1823 deletions(-) delete mode 100644 android/build.gradle delete mode 100644 android/src/main/AndroidManifest.xml delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoPackage.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoView.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java 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); - } -}