迁移项目

This commit is contained in:
2025-12-10 23:13:23 +08:00
parent 28fe161276
commit ea73fea4a5
67 changed files with 2459 additions and 997 deletions

21
.gitignore vendored
View File

@@ -1,12 +1,11 @@
/build
gen
.DS_Store
/obj
/ffmpeg_rtsp
.vscode
local.properties
gradle.properties
.gradle
.idea
*.iml
/exo-library
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/.kotlin

View File

@@ -1,16 +1,22 @@
apply plugin: 'com.android.application'
plugins {
alias(libs.plugins.android.application)
}
android {
compileSdkVersion 26
buildToolsVersion '28.0.3'
namespace "org.easydarwin.easyplayer"
compileSdk {
version = release(36)
}
defaultConfig {
applicationId "org.easydarwin.easyplayer"
minSdkVersion 19
targetSdkVersion 26
applicationId "org.easydarwin.easyplayer.pro"
minSdk 28
targetSdk 36
versionCode 14210703
versionName "1.4.21.0703"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
if (project.hasProperty('PLAYER_KEY')) {
buildConfigField 'String', 'PLAYER_KEY', PLAYER_KEY
} else {
@@ -19,44 +25,27 @@ android {
}
ndk {
//设置支持的SO库架构
// abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
abiFilters 'x86', 'armeabi-v7a'
abiFilters 'armeabi-v7a'/*, 'arm64-v8a'*/
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
dataBinding {
enabled = true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
flavorDimensions "prod"
productFlavors {
pro {
applicationId "org.easydarwin.easyplayer.pro"
dimension "prod"
}
/*fastPro {
applicationId "org.easydarwin.easyplayer.pro"
dimension "prod"
}*/
/*njjl {
applicationId "org.easydarwin.easyplayer.pro"
dimension "prod"
}*/
}
//签名配置
signingConfigs {
buildFeatures {
buildConfig true
viewBinding true
dataBinding true
}
android.applicationVariants.all { variant ->
@@ -66,32 +55,19 @@ android {
}
}
repositories {
flatDir {
dirs 'libs'
}
mavenCentral()
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/gson-2.1.jar')
implementation "com.android.support:appcompat-v7:${support_version}"
implementation "com.android.support:support-v4:${support_version}"
implementation "com.android.support:preference-v7:${support_version}"
implementation "com.android.support:design:${support_version}"
implementation "com.android.support:cardview-v7:${support_version}"
// implementation 'com.writingminds:FFmpegAndroid:0.3.2'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.github.chrisbanes:PhotoView:1.3.0'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.budiyev.android:code-scanner:1.9.4'
testImplementation 'junit:junit:4.12'
implementation libs.androidx.core.ktx
implementation libs.androidx.appcompat
implementation libs.androidx.constraintlayout
implementation libs.androidx.recyclerview
implementation libs.androidx.swiperefreshlayout
implementation libs.material.components
implementation libs.glide
implementation libs.code.scanner
implementation project(':ijkplayer-java')
implementation project(':photoview')
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
}

Binary file not shown.

View File

@@ -1,30 +1,21 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\software\adt-bundle-windows-x86_64-20140702\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# 忽略警告
-ignorewarning
-keepclassmembers class org.easydarwin.video.EasyRTSPClient {
public *;
}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
-keepclassmembers class org.easydarwin.video.RTSPClient {
private void onRTSPSourceCallBack(int, int, int, byte[], byte[]);
}
-keepclassmembers class org.easydarwin.video.RTSPClient$FrameInfo{
*;
}
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,13 +0,0 @@
package org.esaydarwin.rtsp.player;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@@ -33,10 +33,14 @@ import android.opengl.GLES20;
import android.opengl.Matrix;
import android.os.Build;
import android.os.Environment;
import android.test.AndroidTestCase;
import android.util.Log;
import android.view.Surface;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -66,8 +70,8 @@ import java.nio.FloatBuffer;
* (This was derived from bits and pieces of CTS tests, and is packaged as such, but is not
* currently part of CTS.)
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class CameraToMpegTest extends AndroidTestCase {
@RunWith(AndroidJUnit4.class)
public class CameraToMpegTest {
private static final String TAG = "CameraToMpegTest";
private static final boolean VERBOSE = false; // lots of logging
@@ -104,45 +108,41 @@ public class CameraToMpegTest extends AndroidTestCase {
// allocate one of these up front so we don't need to do it every time
private MediaCodec.BufferInfo mBufferInfo;
/** test entry point */
public void testEncodeCameraToMp4() throws Throwable {
CameraToMpegWrapper.runTest(this);
/**
* Attempts to find a preview size that matches the provided width and height (which
* specify the dimensions of the encoded video). If it fails to find a match it just
* uses the default preview size.
* <p>
* TODO: should do a best-fit match.
*/
private static void choosePreviewSize(Camera.Parameters parms, int width, int height) {
// We should make sure that the requested MPEG size is less than the preferred
// size, and has the same aspect ratio.
Camera.Size ppsfv = parms.getPreferredPreviewSizeForVideo();
if (VERBOSE && ppsfv != null) {
Log.d(TAG, "Camera preferred preview size for video is " +
ppsfv.width + "x" + ppsfv.height);
}
for (Camera.Size size : parms.getSupportedPreviewSizes()) {
if (size.width == width && size.height == height) {
parms.setPreviewSize(width, height);
return;
}
}
Log.w(TAG, "Unable to set preview size to " + width + "x" + height);
if (ppsfv != null) {
parms.setPreviewSize(ppsfv.width, ppsfv.height);
}
}
/**
* Wraps encodeCameraToMpeg(). This is necessary because SurfaceTexture will try to use
* the looper in the current thread if one exists, and the CTS tests create one on the
* test thread.
*
* The wrapper propagates exceptions thrown by the worker thread back to the caller.
* test entry point
*/
private static class CameraToMpegWrapper implements Runnable {
private Throwable mThrowable;
private CameraToMpegTest mTest;
private CameraToMpegWrapper(CameraToMpegTest test) {
mTest = test;
}
@Override
public void run() {
try {
mTest.encodeCameraToMpeg();
} catch (Throwable th) {
mThrowable = th;
}
}
/** Entry point. */
public static void runTest(CameraToMpegTest obj) throws Throwable {
CameraToMpegWrapper wrapper = new CameraToMpegWrapper(obj);
Thread th = new Thread(wrapper, "codec test");
th.start();
th.join();
if (wrapper.mThrowable != null) {
throw wrapper.mThrowable;
}
}
@Test
public void testEncodeCameraToMp4() throws Throwable {
CameraToMpegWrapper.runTest(this);
}
/**
@@ -261,35 +261,6 @@ public class CameraToMpegTest extends AndroidTestCase {
Log.d(TAG, "Camera preview size is " + size.width + "x" + size.height);
}
/**
* Attempts to find a preview size that matches the provided width and height (which
* specify the dimensions of the encoded video). If it fails to find a match it just
* uses the default preview size.
* <p>
* TODO: should do a best-fit match.
*/
private static void choosePreviewSize(Camera.Parameters parms, int width, int height) {
// We should make sure that the requested MPEG size is less than the preferred
// size, and has the same aspect ratio.
Camera.Size ppsfv = parms.getPreferredPreviewSizeForVideo();
if (VERBOSE && ppsfv != null) {
Log.d(TAG, "Camera preferred preview size for video is " +
ppsfv.width + "x" + ppsfv.height);
}
for (Camera.Size size : parms.getSupportedPreviewSizes()) {
if (size.width == width && size.height == height) {
parms.setPreviewSize(width, height);
return;
}
}
Log.w(TAG, "Unable to set preview size to " + width + "x" + height);
if (ppsfv != null) {
parms.setPreviewSize(ppsfv.width, ppsfv.height);
}
}
/**
* Stops camera preview, and releases the camera to the system.
*/
@@ -497,6 +468,43 @@ public class CameraToMpegTest extends AndroidTestCase {
}
}
/**
* Wraps encodeCameraToMpeg(). This is necessary because SurfaceTexture will try to use
* the looper in the current thread if one exists, and the CTS tests create one on the
* test thread.
* <p>
* The wrapper propagates exceptions thrown by the worker thread back to the caller.
*/
private static class CameraToMpegWrapper implements Runnable {
private Throwable mThrowable;
private CameraToMpegTest mTest;
private CameraToMpegWrapper(CameraToMpegTest test) {
mTest = test;
}
/**
* Entry point.
*/
public static void runTest(CameraToMpegTest obj) throws Throwable {
CameraToMpegWrapper wrapper = new CameraToMpegWrapper(obj);
Thread th = new Thread(wrapper, "codec test");
th.start();
th.join();
if (wrapper.mThrowable != null) {
throw wrapper.mThrowable;
}
}
@Override
public void run() {
try {
mTest.encodeCameraToMpeg();
} catch (Throwable th) {
mThrowable = th;
}
}
}
/**
* Holds state associated with a Surface used for MediaCodec encoder input.
@@ -754,16 +762,6 @@ public class CameraToMpegTest extends AndroidTestCase {
private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
-1.0f, -1.0f, 0, 0.f, 0.f,
1.0f, -1.0f, 0, 1.f, 0.f,
-1.0f, 1.0f, 0, 0.f, 1.f,
1.0f, 1.0f, 0, 1.f, 1.f,
};
private FloatBuffer mTriangleVertices;
private static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uSTMatrix;\n" +
@@ -774,7 +772,6 @@ public class CameraToMpegTest extends AndroidTestCase {
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
"}\n";
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" + // highp here doesn't seem to matter
@@ -783,7 +780,14 @@ public class CameraToMpegTest extends AndroidTestCase {
"void main() {\n" +
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
"}\n";
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
-1.0f, -1.0f, 0, 0.f, 0.f,
1.0f, -1.0f, 0, 1.f, 0.f,
-1.0f, 1.0f, 0, 0.f, 1.f,
1.0f, 1.0f, 0, 1.f, 1.f,
};
private FloatBuffer mTriangleVertices;
private float[] mMVPMatrix = new float[16];
private float[] mSTMatrix = new float[16];
@@ -796,13 +800,19 @@ public class CameraToMpegTest extends AndroidTestCase {
public STextureRender() {
mTriangleVertices = ByteBuffer.allocateDirect(
mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTriangleVertices.put(mTriangleVerticesData).position(0);
Matrix.setIdentityM(mSTMatrix, 0);
}
public static void checkLocation(int location, String label) {
if (location < 0) {
throw new RuntimeException("Unable to locate '" + label + "' in program");
}
}
public int getTextureId() {
return mTextureID;
}
@@ -952,11 +962,5 @@ public class CameraToMpegTest extends AndroidTestCase {
throw new RuntimeException(op + ": glError " + error);
}
}
public static void checkLocation(int location, String label) {
if (location < 0) {
throw new RuntimeException("Unable to locate '" + label + "' in program");
}
}
}
}

View File

@@ -1,18 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.easydarwin.easyplayer">
xmlns:tools="http://schemas.android.com/tools">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<application
android:name=".TheApp"
@@ -20,6 +27,7 @@
android:icon="@mipmap/ic_launcher_foreground"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<meta-data
@@ -31,6 +39,7 @@
<activity
android:name=".PlayListActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -50,15 +59,18 @@
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/FullscreenTheme" />
<activity
android:name=".AboutActivity" />
<activity android:name=".AboutActivity" />
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings" />
<activity android:name=".MediaFilesActivity" android:label="文件夹"/>
<activity android:name=".ScanQRActivity" android:label="扫码"/>
<activity
android:name=".MediaFilesActivity"
android:label="文件夹" />
<activity
android:name=".ScanQRActivity"
android:label="扫码" />
</application>

View File

@@ -1,17 +1,18 @@
package org.easydarwin.easyplayer;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import org.easydarwin.easyplayer.databinding.ActivityAboutBinding;
import org.easydarwin.easyplayer.views.ProVideoView;
@@ -43,7 +44,7 @@ public class AboutActivity extends AppCompatActivity implements View.OnClickList
binding.version.setText("EasyPlayer Pro播放器");
binding.version.append("(");
long activeDays = ProVideoView.getActiveDays(this,BuildConfig.PLAYER_KEY);
long activeDays = ProVideoView.getActiveDays(this, BuildConfig.PLAYER_KEY);
SpannableString ss;
if (activeDays >= 9999) {
@@ -76,20 +77,17 @@ public class AboutActivity extends AppCompatActivity implements View.OnClickList
@Override
public void onClick(View v) {
Intent intent= new Intent();
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
Uri content_url = Uri.parse("http://www.easydarwin.org");
switch (v.getId()) {
case R.id.darwin_content_tv:
content_url = Uri.parse("http://www.easydarwin.org");
break;
case R.id.dss_content_tv:
content_url = Uri.parse("http://www.easydss.com");
break;
case R.id.nvr_content_tv:
content_url = Uri.parse("http://www.easynvr.com");
break;
int id = v.getId();
if (id == R.id.darwin_content_tv) {
content_url = Uri.parse("http://www.easydarwin.org");
} else if (id == R.id.dss_content_tv) {
content_url = Uri.parse("http://www.easydss.com");
} else if (id == R.id.nvr_content_tv) {
content_url = Uri.parse("http://www.easynvr.com");
}
intent.setData(content_url);

View File

@@ -1,13 +1,8 @@
package org.easydarwin.easyplayer;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
@@ -15,12 +10,19 @@ import android.text.style.RelativeSizeSpan;
import android.view.MenuItem;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import org.easydarwin.easyplayer.databinding.ActivityMediaFilesBinding;
import org.easydarwin.easyplayer.fragments.LocalFileFragment;
/**
* 录像和截图
* */
*
*/
public class MediaFilesActivity extends AppCompatActivity {
private ActivityMediaFilesBinding mDataBinding;

View File

@@ -1,22 +1,17 @@
package org.easydarwin.easyplayer;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
@@ -27,8 +22,15 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.bumptech.glide.Glide;
import com.bumptech.glide.signature.StringSignature;
import org.easydarwin.easyplayer.data.VideoSource;
import org.easydarwin.easyplayer.databinding.ActivityPlayListBinding;
@@ -40,21 +42,18 @@ import org.easydarwin.easyplayer.views.ProVideoView;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
/**
* 视频广场
* */
*
*/
@SuppressLint("Range")
public class PlayListActivity extends AppCompatActivity implements View.OnClickListener, View.OnLongClickListener {
private static final int REQUEST_PLAY = 1000;
public static final int REQUEST_CAMERA_PERMISSION = 1001;
private static final int REQUEST_SCAN_TEXT_URL = 1003; // 扫描二维码
public static final String EXTRA_BOOLEAN_SELECT_ITEM_TO_PLAY = "extra-boolean-select-item-to-play";
private static final int REQUEST_PLAY = 1000;
private static final int REQUEST_SCAN_TEXT_URL = 1003; // 扫描二维码
private int mPos;
private ActivityPlayListBinding mBinding;
private RecyclerView mRecyclerView;
@@ -83,9 +82,7 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
mCursor = TheApp.sDB.query(VideoSource.TABLE_NAME, null, null, null, null, null, null);
if (!mCursor.moveToFirst()) {
List<String> urls = new ArrayList<>();
urls.add("rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov");
urls.add("rtmp://live.hkstv.hk.lxdns.com/live/hks2");
urls.add("http://www.easydarwin.org/public/video/3/video.m3u8");
urls.add("rtsp://77.110.228.219/axis-media/media.amp");
urls.add("http://m4.pptvyun.com/pvod/e11a0/ijblO6coKRX6a8NEQgg8LDZcqPY/eyJkbCI6MTUxNjYyNTM3NSwiZXMiOjYwNDgwMCwiaWQiOiIwYTJkbnEtWG82S2VvcTZMNEsyZG9hZmhvNkNjbTY2WXB3IiwidiI6IjEuMCJ9/0a2dnq-Xo6Keoq6L4K2doafho6Ccm66Ypw.mp4");
for (String url : urls) {
@@ -127,7 +124,6 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
Glide.with(PlayListActivity.this)
.load(file)
.signature(new StringSignature(UUID.randomUUID().toString()))
.placeholder(R.drawable.placeholder)
.centerCrop()
.into(plvh.mImageView);
@@ -192,9 +188,10 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CAMERA_PERMISSION: {
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
if (grantResults.length > 1 && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) {
toScanQRActivity();
}
@@ -310,9 +307,9 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
}
if (url.toLowerCase().indexOf("rtsp://") != 0 && url.toLowerCase().indexOf("rtmp://") != 0 &&
url.toLowerCase().indexOf("http://") != 0 && url.toLowerCase().indexOf("https://") != 0 &&
url.toLowerCase().indexOf("http://") != 0 && url.toLowerCase().indexOf("https://") != 0 &&
url.toLowerCase().indexOf("hls://") != 0) {
Toast.makeText(PlayListActivity.this,"不是合法的地址,请重新添加.",Toast.LENGTH_SHORT).show();
Toast.makeText(PlayListActivity.this, "不是合法的地址,请重新添加.", Toast.LENGTH_SHORT).show();
return;
}
@@ -361,7 +358,7 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
private void notifyAboutColorChange() {
//// !!!! important to set KEY !!!!
ProVideoView.setKey(BuildConfig.PLAYER_KEY);
long activeDays = ProVideoView.getActiveDays(this,BuildConfig.PLAYER_KEY);
long activeDays = ProVideoView.getActiveDays(this, BuildConfig.PLAYER_KEY);
ImageView iv = findViewById(R.id.toolbar_about);
@@ -379,9 +376,25 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
startActivity(i);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_SCAN_TEXT_URL) {
if (resultCode == RESULT_OK) {
String url = data.getStringExtra("text");
edit.setText(url);
}
} else {
// mRecyclerView.getAdapter().notifyItemChanged(mPos);
mRecyclerView.getAdapter().notifyDataSetChanged();
}
}
/**
* 视频源的item
* */
*
*/
class PlayListViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
private final TextView mAudienceNumber;
@@ -399,19 +412,4 @@ public class PlayListActivity extends AppCompatActivity implements View.OnClickL
itemView.setTag(this);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_SCAN_TEXT_URL) {
if (resultCode == RESULT_OK) {
String url = data.getStringExtra("text");
edit.setText(url);
}
} else {
// mRecyclerView.getAdapter().notifyItemChanged(mPos);
mRecyclerView.getAdapter().notifyDataSetChanged();
}
}
}

View File

@@ -16,24 +16,19 @@ package org.easydarwin.easyplayer;
* limitations under the License.
*/
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import android.Manifest;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
@@ -45,6 +40,13 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.ViewConfigurationCompat;
import androidx.databinding.DataBindingUtil;
import com.bumptech.glide.Glide;
import org.easydarwin.easyplayer.databinding.ActivityMainProBinding;
@@ -60,13 +62,9 @@ import java.util.Date;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
public class ProVideoActivity extends AppCompatActivity {
private static final String TAG = "ProVideoActivity";
public static final int REQUEST_WRITE_STORAGE = 111;
private static final String TAG = "ProVideoActivity";
private String mVideoPath;
private Uri mVideoUri;
@@ -315,8 +313,8 @@ public class ProVideoActivity extends AppCompatActivity {
TextView view = (TextView) findViewById(R.id.loading_speed);
view.setText(String.format("%3.01fKB/s", received * 1.0f / 1024));
if (findViewById(android.R.id.progress).getVisibility() == View.VISIBLE){
mVideoView.postDelayed(this,1000);
if (findViewById(android.R.id.progress).getVisibility() == View.VISIBLE) {
mVideoView.postDelayed(this, 1000);
}
}
};
@@ -368,7 +366,7 @@ public class ProVideoActivity extends AppCompatActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (REQUEST_WRITE_STORAGE == requestCode){
if (REQUEST_WRITE_STORAGE == requestCode) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
doTakePicture();
}
@@ -426,11 +424,11 @@ public class ProVideoActivity extends AppCompatActivity {
}
/*
* 截图
* */
* 截图
* */
public void onTakePicture(View view) {
if (mVideoView.isInPlaybackState()) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE);
} else {
doTakePicture();
@@ -446,7 +444,7 @@ public class ProVideoActivity extends AppCompatActivity {
final String picture = mVideoView.takePicture(file.getPath());
if (!TextUtils.isEmpty(picture)) {
Toast.makeText(ProVideoActivity.this,"图片已保存", Toast.LENGTH_SHORT).show();
Toast.makeText(ProVideoActivity.this, "图片已保存", Toast.LENGTH_SHORT).show();
if (mScanner == null) {
MediaScannerConnection connection = new MediaScannerConnection(ProVideoActivity.this, new MediaScannerConnection.MediaScannerConnectionClient() {

View File

@@ -2,11 +2,12 @@ package org.easydarwin.easyplayer;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.budiyev.android.codescanner.CodeScanner;
import com.budiyev.android.codescanner.CodeScannerView;
import com.budiyev.android.codescanner.DecodeCallback;

View File

@@ -1,13 +1,14 @@
package org.easydarwin.easyplayer;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.CompoundButton;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import org.easydarwin.easyplayer.databinding.ActivitySettingBinding;
import org.easydarwin.easyplayer.util.SPUtil;

View File

@@ -4,12 +4,13 @@ import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
/**
* 启动页
*/
@@ -53,7 +54,6 @@ public class SplashActivity extends AppCompatActivity {
}
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
@Override
public void run() {
@@ -74,6 +74,7 @@ public class SplashActivity extends AppCompatActivity {
return false;
}
};
private boolean mVisible;
@Override
protected void onCreate(Bundle savedInstanceState) {

View File

@@ -2,14 +2,8 @@ package org.easydarwin.easyplayer.fragments;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
@@ -20,9 +14,15 @@ import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import org.easydarwin.easyplayer.PlayListActivity;
import org.easydarwin.easyplayer.ProVideoActivity;
import org.easydarwin.easyplayer.R;
import org.easydarwin.easyplayer.databinding.FragmentMediaFileBinding;
@@ -34,16 +34,13 @@ import java.io.FilenameFilter;
public class LocalFileFragment extends Fragment implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
public static final String KEY_IS_RECORD = "key_last_selection";
private boolean mShowMp4File;
private FragmentMediaFileBinding mBinding;
SparseArray<Boolean> mImageChecked;
private String mSuffix;
File mRoot = null;
File[] mSubFiles;
int mImgHeight;
private boolean mShowMp4File;
private FragmentMediaFileBinding mBinding;
private String mSuffix;
@Override
public void onCreate(Bundle savedInstanceState) {

View File

@@ -1,13 +1,16 @@
package org.easydarwin.easyplayer.views;
import static tv.danmaku.ijk.media.player.IjkMediaPlayer.native_active_days;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.v4.app.ActivityCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.core.app.ActivityCompat;
import org.easydarwin.easyplayer.ProVideoActivity;
import org.easydarwin.easyplayer.util.FileUtil;
@@ -18,11 +21,9 @@ import java.util.Date;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.widget.media.IjkVideoView;
import static tv.danmaku.ijk.media.player.IjkMediaPlayer.native_active_days;
/**
* 播放器
*
* <p>
* Created by apple on 2017/2/11.
*/
public class ProVideoView extends IjkVideoView implements VideoControllerView.FullScreenAbleMediaPlayerControl {
@@ -53,19 +54,21 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
return native_active_days(context, key);
}
/** ================ super override ================ */
/**
* ================ super override ================
*/
public void startRecord(String path, int seconds) {
if (mMediaPlayer == null) {
return;
}
super.startRecord(path,seconds);
super.startRecord(path, seconds);
mRecordPath = path;
}
public void stopRecord() {
if (mMediaPlayer == null){
if (mMediaPlayer == null) {
return;
}
@@ -73,7 +76,9 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
mRecordPath = null;
}
/** ================ FullScreenAbleMediaPlayerControl ================ */
/**
* ================ FullScreenAbleMediaPlayerControl ================
*/
@Override
public boolean isFullScreen() {
@@ -131,7 +136,7 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
@Override
public void reStart() {
super.reStart();
if (mRecordPath != null){
if (mRecordPath != null) {
toggleRecord();
toggleRecord();
}
@@ -142,8 +147,8 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
if (getContext() instanceof ProVideoActivity) {
ProVideoActivity pro = (ProVideoActivity) getContext();
if (ActivityCompat.checkSelfPermission(pro, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(pro, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, ProVideoActivity.REQUEST_WRITE_STORAGE +1);
if (ActivityCompat.checkSelfPermission(pro, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(pro, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, ProVideoActivity.REQUEST_WRITE_STORAGE + 1);
return;
}
}
@@ -184,8 +189,8 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
@Override
public void setSpeed(float speed) {
if (mMediaPlayer == null ) {
return ;
if (mMediaPlayer == null) {
return;
}
if (mMediaPlayer instanceof IjkMediaPlayer) {
@@ -196,7 +201,7 @@ public class ProVideoView extends IjkVideoView implements VideoControllerView.Fu
@Override
public void takePicture() {
if (getContext() instanceof ProVideoActivity){
if (getContext() instanceof ProVideoActivity) {
ProVideoActivity pro = (ProVideoActivity) getContext();
pro.onTakePicture(null);
}

View File

@@ -3,12 +3,11 @@ package org.easydarwin.easyplayer.views;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by John on 2014/11/11.
*/
public class SquareImageView extends ImageView {
public class SquareImageView extends androidx.appcompat.widget.AppCompatImageView {
public SquareImageView(Context context) {
super(context);

View File

@@ -1,17 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorWhite">
android:background="@color/colorWhite"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="66dp"
@@ -24,33 +22,33 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="版本信息"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="18sp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="12dp"/>
android:layout_centerHorizontal="true"
android:layout_marginBottom="12dp"
android:gravity="center"
android:text="版本信息"
android:textColor="#ffffff"
android:textSize="18sp" />
<ImageButton
android:id="@+id/toolbar_back"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/new_nav_back"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"/>
android:layout_marginBottom="0dp"
android:src="@drawable/new_nav_back" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
</androidx.appcompat.widget.Toolbar>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.constraint.ConstraintLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -69,17 +67,17 @@
android:id="@+id/desc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/about_info"
android:textSize="15sp"
android:lineSpacingExtra="5dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/version"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp" />
android:layout_marginRight="16dp"
android:lineSpacingExtra="5dp"
android:text="@string/about_info"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/version" />
<TextView
android:id="@+id/darwin_tv"
@@ -102,8 +100,8 @@
android:layout_marginTop="5dp"
android:layout_marginRight="16dp"
android:text="http://www.easydarwin.org"
android:textSize="14sp"
android:textColor="@color/colorTheme2"
android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/darwin_tv" />
@@ -129,8 +127,8 @@
android:layout_marginTop="5dp"
android:layout_marginRight="16dp"
android:text="http://www.easydss.com"
android:textSize="14sp"
android:textColor="@color/colorTheme2"
android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/dss_tv" />
@@ -173,18 +171,18 @@
app:layout_constraintTop_toBottomOf="@+id/nvr_content_tv" />
<TextView
android:text="Copyright @ Open.TSINGSEE.com"
android:layout_height="40dp"
android:layout_width="0dp"
android:gravity="center"
android:id="@+id/textView3"
android:background="@color/colorTheme2"
android:textColor="#FFFFFF"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="30dp"
app:layout_constraintTop_toBottomOf="@+id/imageView"
android:background="@color/colorTheme2"
android:gravity="center"
android:text="Copyright @ Open.TSINGSEE.com"
android:textColor="#FFFFFF"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</LinearLayout>

View File

@@ -9,24 +9,24 @@
tools:context="org.easydarwin.easyplayer.PlayActivity">
<FrameLayout
android:id="@+id/render_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/render_container"
android:layout_gravity="center"
android:background="#000000">
<org.easydarwin.easyplayer.views.ProVideoView
android:id="@+id/video_view2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:visibility="gone"
android:layout_height="match_parent" />
android:visibility="gone" />
<org.easydarwin.easyplayer.views.ProVideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:keepScreenOn="true"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:keepScreenOn="true" />
<ImageView
android:id="@+id/surface_cover"
@@ -40,8 +40,8 @@
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_gravity="center"
android:gravity="center"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
@@ -51,12 +51,12 @@
android:indeterminateDrawable="@drawable/anim" />
<TextView
android:layout_width="wrap_content"
android:text="加载中"
android:id="@+id/loading_speed"
android:textColor="@color/colorTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_height="wrap_content" />
android:text="加载中"
android:textColor="@color/colorTheme" />
</LinearLayout>
@@ -77,16 +77,16 @@
android:id="@+id/player_container"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#fff"
android:layout_gravity="center"
android:background="#fff"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical">
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/new_lost"/>
android:src="@drawable/new_lost" />
</LinearLayout>

View File

@@ -6,10 +6,10 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorWhite">
android:background="@color/colorWhite"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="66dp"
@@ -22,42 +22,42 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件夹"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="18sp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="12dp"/>
android:layout_centerHorizontal="true"
android:layout_marginBottom="12dp"
android:gravity="center"
android:text="文件夹"
android:textColor="#ffffff"
android:textSize="18sp" />
<ImageButton
android:id="@+id/toolbar_back"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/new_nav_back"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"/>
android:layout_marginBottom="0dp"
android:src="@drawable/new_nav_back" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
</androidx.appcompat.widget.Toolbar>
<android.support.v4.view.ViewPager
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTitleStrip
<androidx.viewpager.widget.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f2f2f2"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="#f2f2f2"
android:textAlignment="center"
android:textSize="16sp" />
</android.support.v4.view.ViewPager>
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
</layout>

View File

@@ -1,17 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffffff"
android:orientation="vertical"
tools:context="org.easydarwin.easyplayer.activity.PlayListActivity">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="66dp"
@@ -24,27 +22,27 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="EasyPlayer Pro"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="18sp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="12dp"/>
android:layout_centerHorizontal="true"
android:layout_marginBottom="12dp"
android:gravity="center"
android:text="EasyPlayer Pro"
android:textColor="#ffffff"
android:textSize="18sp" />
<ImageButton
android:id="@+id/toolbar_about"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/new_version1"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"/>
android:layout_marginBottom="0dp"
android:src="@drawable/new_version1" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
</androidx.appcompat.widget.Toolbar>
<LinearLayout
android:id="@+id/bottom_ll"
@@ -56,64 +54,64 @@
<TextView
android:id="@+id/toolbar_add"
android:layout_height="match_parent"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:text="地址"
android:textColor="@drawable/new_color_text"
android:textSize="13sp"
android:drawableTop="@drawable/new_address_btn"
android:paddingTop="8dp"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_gravity="end" />
android:text="地址"
android:textColor="@drawable/new_color_text"
android:textSize="13sp" />
<TextView
android:id="@+id/toolbar_file"
android:layout_height="match_parent"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:drawableTop="@drawable/new_file_btn"
android:onClick="fileList"
android:paddingTop="8dp"
android:text="文件夹"
android:textColor="@drawable/new_color_text"
android:textSize="13sp"
android:drawableTop="@drawable/new_file_btn"
android:paddingTop="8dp"
android:onClick="fileList"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_gravity="end" />
android:textSize="13sp" />
<TextView
android:id="@+id/toolbar_setting"
android:layout_height="match_parent"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:text="设置"
android:textColor="@drawable/new_color_text"
android:textSize="13sp"
android:drawableTop="@drawable/new_setting_btn"
android:paddingTop="8dp"
style="@style/Base.Widget.AppCompat.ActionButton"
android:layout_gravity="end" />
android:text="设置"
android:textColor="@drawable/new_color_text"
android:textSize="13sp" />
</LinearLayout>
<android.support.v4.widget.SwipeRefreshLayout
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/pull_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:layout_above="@id/bottom_ll">
android:layout_above="@id/bottom_ll"
android:layout_below="@id/toolbar">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</RelativeLayout>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -13,19 +12,19 @@
app:autoFocusButtonVisible="false"
app:flashButtonColor="@android:color/white"
app:flashButtonVisible="true"
app:frameAspectRatioHeight="1"
app:frameAspectRatioWidth="1"
app:frameColor="@android:color/white"
app:frameCornersSize="50dp"
app:frameAspectRatioWidth="1"
app:frameAspectRatioHeight="1"
app:frameSize="0.75"
app:frameThickness="2dp"
app:maskColor="#66000000"/>
app:maskColor="#66000000" />
<ImageView
android:layout_width="56dp"
android:src="@drawable/new_nav_back"
android:padding="18dp"
android:layout_height="56dp"
android:onClick="onClose"
android:layout_height="56dp" />
android:padding="18dp"
android:src="@drawable/new_nav_back" />
</FrameLayout>

View File

@@ -9,7 +9,7 @@
android:background="@color/colorWhite"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="66dp"
@@ -42,7 +42,7 @@
</RelativeLayout>
</android.support.v7.widget.Toolbar>
</androidx.appcompat.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"

View File

@@ -14,13 +14,13 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="EasyPlayer Pro"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:text="EasyPlayer Pro" />
android:textSize="20sp" />
<TextView
android:id="@+id/txt_copyright"
@@ -30,21 +30,19 @@
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:gravity="center"
android:text="Copyright @ Open.TSINGSEE.com"
android:textColor="#666"
android:textSize="12sp"
android:text="Copyright @ Open.TSINGSEE.com" />
android:textSize="12sp" />
<TextView
android:id="@+id/txt_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/txt_copyright"
android:layout_marginBottom="10dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:text="EasyPlayer 1.0.0"
android:textColor="#666"
android:textSize="12sp"
android:text="EasyPlayer 1.0.0" />
android:textSize="12sp" />
</RelativeLayout>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@@ -10,8 +10,8 @@
android:layout_width="match_parent"
android:layout_height="128dp"
android:layout_margin="1dp"
android:background="#666"
android:adjustViewBounds="true"
android:background="#666"
android:scaleType="centerCrop" />
<ImageView
@@ -19,7 +19,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/new_player"/>
android:src="@drawable/new_player" />
<CheckBox
android:id="@+id/image_checkbox"

View File

@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/media_controller_ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/media_controller_ll"
android:background="#6000"
android:orientation="vertical">
@@ -17,26 +16,26 @@
android:id="@+id/tv_speed"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:visibility="gone"
android:textColor="@color/white" />
android:layout_weight="1"
android:textColor="@color/white"
android:visibility="gone" />
<TextView
android:id="@+id/tv_fps"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:visibility="gone"
android:layout_height="wrap_content"
android:textColor="@color/white" />
android:layout_weight="1"
android:textColor="@color/white"
android:visibility="gone" />
<TextView
android:id="@+id/tv_kbps"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/white"
android:visibility="gone" />
</LinearLayout>
@@ -49,38 +48,38 @@
<ImageButton
android:id="@+id/slow"
android:layout_weight="1"
style="@android:style/MediaButton.Next"
android:src="@drawable/new_slow_btn"
android:contentDescription="@string/description" />
android:layout_weight="1"
android:contentDescription="@string/description"
android:src="@drawable/new_slow_btn" />
<ImageButton
android:id="@+id/rewind"
android:layout_weight="1"
style="@android:style/MediaButton.Rew"
android:src="@drawable/new_moveback_btn"
android:contentDescription="@string/description" />
android:layout_weight="1"
android:contentDescription="@string/description"
android:src="@drawable/new_moveback_btn" />
<ImageButton
android:id="@+id/pause"
android:layout_weight="1"
style="@android:style/MediaButton.Play"
android:src="@drawable/new_stop_white"
android:contentDescription="@string/description" />
android:layout_weight="1"
android:contentDescription="@string/description"
android:src="@drawable/new_stop_white" />
<ImageButton
android:id="@+id/fast_forward"
android:layout_weight="1"
style="@android:style/MediaButton.Ffwd"
android:src="@drawable/new_forward_btn"
android:contentDescription="@string/description" />
android:layout_weight="1"
android:contentDescription="@string/description"
android:src="@drawable/new_forward_btn" />
<ImageButton
android:id="@+id/fast"
android:layout_weight="1"
style="@android:style/MediaButton.Ffwd"
android:src="@drawable/new_fast_btn"
android:contentDescription="@string/description" />
android:layout_weight="1"
android:contentDescription="@string/description"
android:src="@drawable/new_fast_btn" />
</LinearLayout>
@@ -95,52 +94,52 @@
android:id="@+id/action_take_picture"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/new_snapshot_btn" />
<ImageButton
android:id="@+id/action_record"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/new_videotape_btn" />
<TextView
android:id="@+id/tv_record_time"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
android:textColor="#ff0000"
android:drawablePadding="5dp"
android:layout_weight="1"
android:drawableLeft="@drawable/red_dot"
android:text="00:00" />
android:drawablePadding="5dp"
android:gravity="center"
android:text="00:00"
android:textColor="#ff0000"
android:visibility="gone" />
<ImageButton
android:id="@+id/action_change_mode"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/new_stretch_btn" />
<ImageButton
android:id="@+id/fullscreen"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/new_full" />
</LinearLayout>
<LinearLayout
android:id="@+id/seek_bar_container"
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="@+id/seek_bar_container"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -150,20 +149,20 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:paddingTop="4dip"
android:textSize="14sp"
android:paddingRight="4dip"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold" />
<SeekBar
android:id="@+id/media_controller_progress"
style="@style/CustomSeekbarStyle"
android:progress="10"
android:secondaryProgress="60"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
android:progress="10"
android:secondaryProgress="60" />
<TextView
android:id="@+id/total_time"
@@ -171,9 +170,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingLeft="4dip"
android:textColor="@color/white"
android:paddingRight="4dip"
android:paddingTop="4dip"
android:paddingRight="4dip"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold" />

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWhite">
@@ -11,12 +9,12 @@
android:id="@+id/new_media_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/new_scan_btn"
android:background="@null"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintTop_toTopOf="@id/new_media_source_url"
app:layout_constraintBottom_toBottomOf="@id/new_media_source_url" />
android:background="@null"
android:src="@drawable/new_scan_btn"
app:layout_constraintBottom_toBottomOf="@id/new_media_source_url"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/new_media_source_url" />
<EditText
@@ -32,4 +30,4 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin">
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin">
<FrameLayout
android:layout_width="match_parent"
@@ -32,10 +31,10 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxHeight="40dp"
android:minHeight="40dp"
android:ellipsize="end"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="9"
@@ -55,5 +54,5 @@
</LinearLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
</androidx.cardview.widget.CardView>
</layout>

View File

@@ -1,22 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
}
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
}
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
google()
}
}
ext{
support_version='26.1.0'
}

23
gradle.properties Normal file
View File

@@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

30
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,30 @@
[versions]
agp = "8.13.1"
coreKtx = "1.17.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
appcompat = "1.7.1"
constraintlayout = "2.2.1"
recyclerview = "1.4.0"
swiperefreshlayout = "1.2.0"
materialComponents = "1.13.0"
glide = "5.0.5"
code-scanner = "2.3.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
material-components = { group = "com.google.android.material", name = "material", version.ref = "materialComponents" }
glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
code-scanner = { group = "com.github.yuriy-budiyev", name = "code-scanner", version.ref = "code-scanner" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }

Binary file not shown.

View File

@@ -1,6 +1,7 @@
#Sat Apr 06 13:56:34 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

319
gradlew vendored
View File

@@ -1,74 +1,129 @@
#!/usr/bin/env bash
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Attempt to set APP_HOME
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn ( ) {
warn () {
echo "$*"
}
} >&2
die ( ) {
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH="\\\"\\\""
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -77,84 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

90
gradlew.bat vendored
View File

@@ -1,4 +1,22 @@
@if "%DEBUG%" == "" @echo off
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -8,26 +26,30 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -35,54 +57,36 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -1,27 +1,28 @@
apply plugin: 'com.android.library'
plugins {
alias(libs.plugins.android.library)
}
android {
compileSdkVersion 26
lintOptions {
abortOnError false
namespace "tv.danmaku.ijk.media.player"
compileSdk {
version = release(36)
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 26
consumerProguardFiles 'proguard-rules.pro'
versionCode 38
versionName "1.1.17.1124"
minSdk 28
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '28.0.3'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
}

View File

@@ -0,0 +1,11 @@
-keepparameternames
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,EnclosingMethod
-keep class tv.danmaku.ijk.media.widget.media.IjkVideoView {
public protected *;
}
-keep class tv.danmaku.ijk.media.widget.media.IMediaController {
public protected *;
}
-keep class tv.danmaku.ijk.media.player.** {
*;
}

View File

@@ -1,31 +1,21 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /opt/android/ADK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keepparameternames
-renamesourcefileattribute SourceFile
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep class tv.danmaku.ijk.media.widget.media.IjkVideoView {
public protected *;
}
-keep class tv.danmaku.ijk.media.widget.media.IMediaController {
public protected *;
}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
-keep class tv.danmaku.ijk.media.player.** {
*;
}
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,13 +0,0 @@
package tv.danmaku.ijk.media.player;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="java"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ijkplayer-java</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -1,4 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -1,4 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tv.danmaku.ijk.media.player" >
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -1,15 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-22
android.library=true

View File

@@ -1,203 +0,0 @@
ECLIPSE ANDROID PROJECT IMPORT SUMMARY
======================================
Manifest Merging:
-----------------
Your project uses libraries that provide manifests, and your Eclipse
project did not explicitly turn on manifest merging. In Android Gradle
projects, manifests are always merged (meaning that contents from your
libraries' manifests will be merged into the app manifest. If you had
manually copied contents from library manifests into your app manifest
you may need to remove these for the app to build correctly.
Ignored Files:
--------------
The following files were *not* copied into the new Gradle project; you
should evaluate whether these are still needed in your project and if
so manually move them:
From MediaUploader:
* .idea\
* .idea\.name
* .idea\MediaUploader.iml
* .idea\compiler.xml
* .idea\copyright\
* .idea\copyright\profiles_settings.xml
* .idea\encodings.xml
* .idea\misc.xml
* .idea\modules.xml
* .idea\vcs.xml
* .idea\workspace.xml
* ic_launcher-web.png
* proguard-project.txt
From libstreaming:
* .gitignore
* LICENSE
* README.md
* build.xml
* doc\
* doc\allclasses-frame.html
* doc\allclasses-noframe.html
* doc\constant-values.html
* doc\deprecated-list.html
* doc\help-doc.html
* doc\index-all.html
* doc\index.html
* doc\net\
* doc\net\majorkernelpanic\
* doc\net\majorkernelpanic\streaming\
* doc\net\majorkernelpanic\streaming\MediaStream.html
* doc\net\majorkernelpanic\streaming\Session.Callback.html
* doc\net\majorkernelpanic\streaming\Session.html
* doc\net\majorkernelpanic\streaming\SessionBuilder.html
* doc\net\majorkernelpanic\streaming\Stream.html
* doc\net\majorkernelpanic\streaming\audio\
* doc\net\majorkernelpanic\streaming\audio\AACStream.html
* doc\net\majorkernelpanic\streaming\audio\AMRNBStream.html
* doc\net\majorkernelpanic\streaming\audio\AudioQuality.html
* doc\net\majorkernelpanic\streaming\audio\AudioStream.html
* doc\net\majorkernelpanic\streaming\audio\package-frame.html
* doc\net\majorkernelpanic\streaming\audio\package-summary.html
* doc\net\majorkernelpanic\streaming\audio\package-tree.html
* doc\net\majorkernelpanic\streaming\exceptions\
* doc\net\majorkernelpanic\streaming\exceptions\CameraInUseException.html
* doc\net\majorkernelpanic\streaming\exceptions\ConfNotSupportedException.html
* doc\net\majorkernelpanic\streaming\exceptions\InvalidSurfaceException.html
* doc\net\majorkernelpanic\streaming\exceptions\StorageUnavailableException.html
* doc\net\majorkernelpanic\streaming\exceptions\package-frame.html
* doc\net\majorkernelpanic\streaming\exceptions\package-summary.html
* doc\net\majorkernelpanic\streaming\exceptions\package-tree.html
* doc\net\majorkernelpanic\streaming\gl\
* doc\net\majorkernelpanic\streaming\gl\SurfaceManager.html
* doc\net\majorkernelpanic\streaming\gl\SurfaceView.ViewAspectRatioMeasurer.html
* doc\net\majorkernelpanic\streaming\gl\SurfaceView.html
* doc\net\majorkernelpanic\streaming\gl\TextureManager.html
* doc\net\majorkernelpanic\streaming\gl\package-frame.html
* doc\net\majorkernelpanic\streaming\gl\package-summary.html
* doc\net\majorkernelpanic\streaming\gl\package-tree.html
* doc\net\majorkernelpanic\streaming\hw\
* doc\net\majorkernelpanic\streaming\hw\CodecManager.html
* doc\net\majorkernelpanic\streaming\hw\EncoderDebugger.html
* doc\net\majorkernelpanic\streaming\hw\NV21Convertor.html
* doc\net\majorkernelpanic\streaming\hw\package-frame.html
* doc\net\majorkernelpanic\streaming\hw\package-summary.html
* doc\net\majorkernelpanic\streaming\hw\package-tree.html
* doc\net\majorkernelpanic\streaming\mp4\
* doc\net\majorkernelpanic\streaming\mp4\MP4Config.html
* doc\net\majorkernelpanic\streaming\mp4\MP4Parser.html
* doc\net\majorkernelpanic\streaming\mp4\package-frame.html
* doc\net\majorkernelpanic\streaming\mp4\package-summary.html
* doc\net\majorkernelpanic\streaming\mp4\package-tree.html
* doc\net\majorkernelpanic\streaming\package-frame.html
* doc\net\majorkernelpanic\streaming\package-summary.html
* doc\net\majorkernelpanic\streaming\package-tree.html
* doc\net\majorkernelpanic\streaming\rtcp\
* doc\net\majorkernelpanic\streaming\rtcp\SenderReport.html
* doc\net\majorkernelpanic\streaming\rtcp\package-frame.html
* doc\net\majorkernelpanic\streaming\rtcp\package-summary.html
* doc\net\majorkernelpanic\streaming\rtcp\package-tree.html
* doc\net\majorkernelpanic\streaming\rtp\
* doc\net\majorkernelpanic\streaming\rtp\AACADTSPacketizer.html
* doc\net\majorkernelpanic\streaming\rtp\AACLATMPacketizer.html
* doc\net\majorkernelpanic\streaming\rtp\AMRNBPacketizer.html
* doc\net\majorkernelpanic\streaming\rtp\AbstractPacketizer.html
* doc\net\majorkernelpanic\streaming\rtp\H263Packetizer.html
* doc\net\majorkernelpanic\streaming\rtp\H264Packetizer.html
* doc\net\majorkernelpanic\streaming\rtp\MediaCodecInputStream.html
* doc\net\majorkernelpanic\streaming\rtp\RtpSocket.html
* doc\net\majorkernelpanic\streaming\rtp\package-frame.html
* doc\net\majorkernelpanic\streaming\rtp\package-summary.html
* doc\net\majorkernelpanic\streaming\rtp\package-tree.html
* doc\net\majorkernelpanic\streaming\rtsp\
* doc\net\majorkernelpanic\streaming\rtsp\RtspClient.Callback.html
* doc\net\majorkernelpanic\streaming\rtsp\RtspClient.html
* doc\net\majorkernelpanic\streaming\rtsp\RtspServer.CallbackListener.html
* doc\net\majorkernelpanic\streaming\rtsp\RtspServer.LocalBinder.html
* doc\net\majorkernelpanic\streaming\rtsp\RtspServer.html
* doc\net\majorkernelpanic\streaming\rtsp\UriParser.html
* doc\net\majorkernelpanic\streaming\rtsp\package-frame.html
* doc\net\majorkernelpanic\streaming\rtsp\package-summary.html
* doc\net\majorkernelpanic\streaming\rtsp\package-tree.html
* doc\net\majorkernelpanic\streaming\video\
* doc\net\majorkernelpanic\streaming\video\CodecManager.html
* doc\net\majorkernelpanic\streaming\video\H263Stream.html
* doc\net\majorkernelpanic\streaming\video\H264Stream.html
* doc\net\majorkernelpanic\streaming\video\VideoQuality.html
* doc\net\majorkernelpanic\streaming\video\VideoStream.html
* doc\net\majorkernelpanic\streaming\video\package-frame.html
* doc\net\majorkernelpanic\streaming\video\package-summary.html
* doc\net\majorkernelpanic\streaming\video\package-tree.html
* doc\overview-frame.html
* doc\overview-summary.html
* doc\overview-tree.html
* doc\package-list
* doc\resources\
* doc\resources\background.gif
* doc\resources\tab.gif
* doc\resources\titlebar.gif
* doc\resources\titlebar_end.gif
* doc\serialized-form.html
* doc\stylesheet.css
* pom.xml
* proguard-project.txt
Replaced Jars with Dependencies:
--------------------------------
The importer recognized the following .jar files as third party
libraries and replaced them with Gradle dependencies instead. This has
the advantage that more explicit version information is known, and the
libraries can be updated automatically. However, it is possible that
the .jar file in your project was of an older version than the
dependency we picked, which could render the project not compileable.
You can disable the jar replacement in the import wizard and try again:
android-support-v4.jar => com.android.support:support-v4:19.1.0
android-support-v7-appcompat.jar => com.android.support:appcompat-v7:19.1.0
gson-2.2.2_android.jar => com.google.code.gson:gson:2.3.1
Replaced Libraries with Dependencies:
-------------------------------------
The importer recognized the following library projects as third party
libraries and replaced them with Gradle dependencies instead. This has
the advantage that more explicit version information is known, and the
libraries can be updated automatically. However, it is possible that
the source files in your project were of an older version than the
dependency we picked, which could render the project not compileable.
You can disable the library replacement in the import wizard and try
again:
android-support-v7-appcompat => [com.android.support:appcompat-v7:19.1.0]
Moved Files:
------------
Android Gradle projects use a different directory structure than ADT
Eclipse projects. Here's how the projects were restructured:
In libstreaming:
* AndroidManifest.xml => libstreaming\src\main\AndroidManifest.xml
* assets\ => libstreaming\src\main\assets
* libs\android-logging-log4j-1.0.3.jar => libstreaming\libs\android-logging-log4j-1.0.3.jar
* libs\log4j-1.2.17.jar => libstreaming\libs\log4j-1.2.17.jar
* res\ => libstreaming\src\main\res
* src\ => libstreaming\src\main\java\
In MediaUploader:
* AndroidManifest.xml => mediaUploader\src\main\AndroidManifest.xml
* assets\ => mediaUploader\src\main\assets
* libs\armeabi\libUtils.so => mediaUploader\src\main\jniLibs\armeabi\libUtils.so
* res\ => mediaUploader\src\main\res\
* src\ => mediaUploader\src\main\java\
Next Steps:
-----------
You can now build the project. The Gradle project needs network
connectivity to download dependencies.
Bugs:
-----
If for some reason your project does not build, and you determine that
it is due to a bug or limitation of the Eclipse to Gradle importer,
please file a bug at http://b.android.com with category
Component-Tools.
(This import summary is for your information only, and can be deleted
after import once you are satisfied with the results.)

1
photoview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

36
photoview/build.gradle Normal file
View File

@@ -0,0 +1,36 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace 'com.github.chrisbanes.photoview'
compileSdk {
version = release(36)
}
defaultConfig {
minSdk 28
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation libs.androidx.appcompat
implementation libs.material.components
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
}

View File

21
photoview/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,26 @@
package com.github.chrisbanes.photoview;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.github.chrisbanes.photoview.test", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,39 @@
/*
Copyright 2011, 2012 Chris Banes.
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.
*/
package com.github.chrisbanes.photoview;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.View;
class Compat {
private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable);
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
}
}
@TargetApi(16)
private static void postOnAnimationJellyBean(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
}

View File

@@ -0,0 +1,214 @@
/*
Copyright 2011, 2012 Chris Banes.
<p/>
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
<p/>
http://www.apache.org/licenses/LICENSE-2.0
<p/>
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.
*/
package com.github.chrisbanes.photoview;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
/**
* Does a whole lot of gesture detecting.
*/
class CustomGestureDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;
private final ScaleGestureDetector mDetector;
private VelocityTracker mVelocityTracker;
private boolean mIsDragging;
private float mLastTouchX;
private float mLastTouchY;
private final float mTouchSlop;
private final float mMinimumVelocity;
private OnGestureListener mListener;
CustomGestureDetector(Context context, OnGestureListener listener) {
final ViewConfiguration configuration = ViewConfiguration
.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mTouchSlop = configuration.getScaledTouchSlop();
mListener = listener;
ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
private float lastFocusX, lastFocusY = 0;
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
return false;
if (scaleFactor >= 0) {
mListener.onScale(scaleFactor,
detector.getFocusX(),
detector.getFocusY(),
detector.getFocusX() - lastFocusX,
detector.getFocusY() - lastFocusY
);
lastFocusX = detector.getFocusX();
lastFocusY = detector.getFocusY();
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
lastFocusX = detector.getFocusX();
lastFocusY = detector.getFocusY();
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// NO-OP
}
};
mDetector = new ScaleGestureDetector(context, mScaleListener);
}
private float getActiveX(MotionEvent ev) {
try {
return ev.getX(mActivePointerIndex);
} catch (Exception e) {
return ev.getX();
}
}
private float getActiveY(MotionEvent ev) {
try {
return ev.getY(mActivePointerIndex);
} catch (Exception e) {
return ev.getY();
}
}
public boolean isScaling() {
return mDetector.isInProgress();
}
public boolean isDragging() {
return mIsDragging;
}
public boolean onTouchEvent(MotionEvent ev) {
try {
mDetector.onTouchEvent(ev);
return processTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is called
return true;
}
}
private boolean processTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mVelocityTracker = VelocityTracker.obtain();
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
mIsDragging = false;
break;
case MotionEvent.ACTION_MOVE:
final float x = getActiveX(ev);
final float y = getActiveY(ev);
final float dx = x - mLastTouchX, dy = y - mLastTouchY;
if (!mIsDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
if (mIsDragging) {
mListener.onDrag(dx, dy);
mLastTouchX = x;
mLastTouchY = y;
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
}
break;
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER_ID;
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
if (mIsDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
// Compute velocity within the last 1000ms
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
.getYVelocity();
// If the velocity is greater than minVelocity, call
// listener
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
mListener.onFling(mLastTouchX, mLastTouchY, -vX,
-vY);
}
}
}
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
case MotionEvent.ACTION_POINTER_UP:
final int pointerIndex = Util.getPointerIndex(ev.getAction());
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}
mActivePointerIndex = ev
.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
: 0);
return true;
}
}

View File

@@ -0,0 +1,28 @@
/*
Copyright 2011, 2012 Chris Banes.
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.
*/
package com.github.chrisbanes.photoview;
interface OnGestureListener {
void onDrag(float dx, float dy);
void onFling(float startX, float startY, float velocityX,
float velocityY);
void onScale(float scaleFactor, float focusX, float focusY);
void onScale(float scaleFactor, float focusX, float focusY, float dx, float dy);
}

View File

@@ -0,0 +1,18 @@
package com.github.chrisbanes.photoview;
import android.graphics.RectF;
/**
* Interface definition for a callback to be invoked when the internal Matrix has changed for
* this View.
*/
public interface OnMatrixChangedListener {
/**
* Callback for when the Matrix displaying the Drawable has changed. This could be because
* the View's bounds have changed, or the user has zoomed.
*
* @param rect - Rectangle displaying the Drawable's new bounds.
*/
void onMatrixChanged(RectF rect);
}

View File

@@ -0,0 +1,14 @@
package com.github.chrisbanes.photoview;
import android.widget.ImageView;
/**
* Callback when the user tapped outside of the photo
*/
public interface OnOutsidePhotoTapListener {
/**
* The outside of the photo has been tapped
*/
void onOutsidePhotoTap(ImageView imageView);
}

View File

@@ -0,0 +1,22 @@
package com.github.chrisbanes.photoview;
import android.widget.ImageView;
/**
* A callback to be invoked when the Photo is tapped with a single
* tap.
*/
public interface OnPhotoTapListener {
/**
* A callback to receive where the user taps on a photo. You will only receive a callback if
* the user taps on the actual photo, tapping on 'whitespace' will be ignored.
*
* @param view ImageView the user tapped.
* @param x where the user tapped from the of the Drawable, as percentage of the
* Drawable width.
* @param y where the user tapped from the top of the Drawable, as percentage of the
* Drawable height.
*/
void onPhotoTap(ImageView view, float x, float y);
}

View File

@@ -0,0 +1,17 @@
package com.github.chrisbanes.photoview;
/**
* Interface definition for callback to be invoked when attached ImageView scale changes
*/
public interface OnScaleChangedListener {
/**
* Callback for when the scale changes
*
* @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
* @param focusX focal point X position
* @param focusY focal point Y position
*/
void onScaleChange(float scaleFactor, float focusX, float focusY);
}

View File

@@ -0,0 +1,21 @@
package com.github.chrisbanes.photoview;
import android.view.MotionEvent;
/**
* A callback to be invoked when the ImageView is flung with a single
* touch
*/
public interface OnSingleFlingListener {
/**
* A callback to receive where the user flings on a ImageView. You will receive a callback if
* the user flings anywhere on the view.
*
* @param e1 MotionEvent the user first touch.
* @param e2 MotionEvent the user last touch.
* @param velocityX distance of user's horizontal fling.
* @param velocityY distance of user's vertical fling.
*/
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}

View File

@@ -0,0 +1,16 @@
package com.github.chrisbanes.photoview;
/**
* Interface definition for a callback to be invoked when the photo is experiencing a drag event
*/
public interface OnViewDragListener {
/**
* Callback for when the photo is experiencing a drag event. This cannot be invoked when the
* user is scaling.
*
* @param dx The change of the coordinates in the x-direction
* @param dy The change of the coordinates in the y-direction
*/
void onDrag(float dx, float dy);
}

View File

@@ -0,0 +1,16 @@
package com.github.chrisbanes.photoview;
import android.view.View;
public interface OnViewTapListener {
/**
* A callback to receive where the user taps on a ImageView. You will receive a callback if
* the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the left of the View.
* @param y - where the user tapped from the top of the View.
*/
void onViewTap(View view, float x, float y);
}

View File

@@ -0,0 +1,256 @@
/*
Copyright 2011, 2012 Chris Banes.
<p>
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
<p>
http://www.apache.org/licenses/LICENSE-2.0
<p>
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.
*/
package com.github.chrisbanes.photoview;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.GestureDetector;
import androidx.appcompat.widget.AppCompatImageView;
/**
* A zoomable ImageView. See {@link PhotoViewAttacher} for most of the details on how the zooming
* is accomplished
*/
@SuppressWarnings("unused")
public class PhotoView extends AppCompatImageView {
private PhotoViewAttacher attacher;
private ScaleType pendingScaleType;
public PhotoView(Context context) {
this(context, null);
}
public PhotoView(Context context, AttributeSet attr) {
this(context, attr, 0);
}
public PhotoView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
init();
}
private void init() {
attacher = new PhotoViewAttacher(this);
//We always pose as a Matrix scale type, though we can change to another scale type
//via the attacher
super.setScaleType(ScaleType.MATRIX);
//apply the previously applied scale type
if (pendingScaleType != null) {
setScaleType(pendingScaleType);
pendingScaleType = null;
}
}
/**
* Get the current {@link PhotoViewAttacher} for this view. Be wary of holding on to references
* to this attacher, as it has a reference to this view, which, if a reference is held in the
* wrong place, can cause memory leaks.
*
* @return the attacher.
*/
public PhotoViewAttacher getAttacher() {
return attacher;
}
@Override
public ScaleType getScaleType() {
return attacher.getScaleType();
}
@Override
public Matrix getImageMatrix() {
return attacher.getImageMatrix();
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
attacher.setOnLongClickListener(l);
}
@Override
public void setOnClickListener(OnClickListener l) {
attacher.setOnClickListener(l);
}
@Override
public void setScaleType(ScaleType scaleType) {
if (attacher == null) {
pendingScaleType = scaleType;
} else {
attacher.setScaleType(scaleType);
}
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
// setImageBitmap calls through to this method
if (attacher != null) {
attacher.update();
}
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
if (attacher != null) {
attacher.update();
}
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
if (attacher != null) {
attacher.update();
}
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
boolean changed = super.setFrame(l, t, r, b);
if (changed) {
attacher.update();
}
return changed;
}
public void setRotationTo(float rotationDegree) {
attacher.setRotationTo(rotationDegree);
}
public void setRotationBy(float rotationDegree) {
attacher.setRotationBy(rotationDegree);
}
public boolean isZoomable() {
return attacher.isZoomable();
}
public void setZoomable(boolean zoomable) {
attacher.setZoomable(zoomable);
}
public RectF getDisplayRect() {
return attacher.getDisplayRect();
}
public void getDisplayMatrix(Matrix matrix) {
attacher.getDisplayMatrix(matrix);
}
@SuppressWarnings("UnusedReturnValue") public boolean setDisplayMatrix(Matrix finalRectangle) {
return attacher.setDisplayMatrix(finalRectangle);
}
public void getSuppMatrix(Matrix matrix) {
attacher.getSuppMatrix(matrix);
}
public boolean setSuppMatrix(Matrix matrix) {
return attacher.setDisplayMatrix(matrix);
}
public float getMinimumScale() {
return attacher.getMinimumScale();
}
public float getMediumScale() {
return attacher.getMediumScale();
}
public float getMaximumScale() {
return attacher.getMaximumScale();
}
public float getScale() {
return attacher.getScale();
}
public void setAllowParentInterceptOnEdge(boolean allow) {
attacher.setAllowParentInterceptOnEdge(allow);
}
public void setMinimumScale(float minimumScale) {
attacher.setMinimumScale(minimumScale);
}
public void setMediumScale(float mediumScale) {
attacher.setMediumScale(mediumScale);
}
public void setMaximumScale(float maximumScale) {
attacher.setMaximumScale(maximumScale);
}
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
attacher.setScaleLevels(minimumScale, mediumScale, maximumScale);
}
public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
attacher.setOnMatrixChangeListener(listener);
}
public void setOnPhotoTapListener(OnPhotoTapListener listener) {
attacher.setOnPhotoTapListener(listener);
}
public void setOnOutsidePhotoTapListener(OnOutsidePhotoTapListener listener) {
attacher.setOnOutsidePhotoTapListener(listener);
}
public void setOnViewTapListener(OnViewTapListener listener) {
attacher.setOnViewTapListener(listener);
}
public void setOnViewDragListener(OnViewDragListener listener) {
attacher.setOnViewDragListener(listener);
}
public void setScale(float scale) {
attacher.setScale(scale);
}
public void setScale(float scale, boolean animate) {
attacher.setScale(scale, animate);
}
public void setScale(float scale, float focalX, float focalY, boolean animate) {
attacher.setScale(scale, focalX, focalY, animate);
}
public void setZoomTransitionDuration(int milliseconds) {
attacher.setZoomTransitionDuration(milliseconds);
}
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) {
attacher.setOnDoubleTapListener(onDoubleTapListener);
}
public void setOnScaleChangeListener(OnScaleChangedListener onScaleChangedListener) {
attacher.setOnScaleChangeListener(onScaleChangedListener);
}
public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) {
attacher.setOnSingleFlingListener(onSingleFlingListener);
}
}

View File

@@ -0,0 +1,823 @@
/*
Copyright 2011, 2012 Chris Banes.
<p>
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
<p>
http://www.apache.org/licenses/LICENSE-2.0
<p>
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.
*/
package com.github.chrisbanes.photoview;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.OverScroller;
/**
* The component of {@link PhotoView} which does the work allowing for zooming, scaling, panning, etc.
* It is made public in case you need to subclass something other than AppCompatImageView and still
* gain the functionality that {@link PhotoView} offers
*/
public class PhotoViewAttacher implements View.OnTouchListener,
View.OnLayoutChangeListener {
private static float DEFAULT_MAX_SCALE = 3.0f;
private static float DEFAULT_MID_SCALE = 1.75f;
private static float DEFAULT_MIN_SCALE = 1.0f;
private static int DEFAULT_ZOOM_DURATION = 200;
private static final int HORIZONTAL_EDGE_NONE = -1;
private static final int HORIZONTAL_EDGE_LEFT = 0;
private static final int HORIZONTAL_EDGE_RIGHT = 1;
private static final int HORIZONTAL_EDGE_BOTH = 2;
private static final int VERTICAL_EDGE_NONE = -1;
private static final int VERTICAL_EDGE_TOP = 0;
private static final int VERTICAL_EDGE_BOTTOM = 1;
private static final int VERTICAL_EDGE_BOTH = 2;
private static int SINGLE_TOUCH = 1;
private Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private int mZoomDuration = DEFAULT_ZOOM_DURATION;
private float mMinScale = DEFAULT_MIN_SCALE;
private float mMidScale = DEFAULT_MID_SCALE;
private float mMaxScale = DEFAULT_MAX_SCALE;
private boolean mAllowParentInterceptOnEdge = true;
private boolean mBlockParentIntercept = false;
private ImageView mImageView;
// Gesture Detectors
private GestureDetector mGestureDetector;
private CustomGestureDetector mScaleDragDetector;
// These are set so we don't keep allocating them on the heap
private final Matrix mBaseMatrix = new Matrix();
private final Matrix mDrawMatrix = new Matrix();
private final Matrix mSuppMatrix = new Matrix();
private final RectF mDisplayRect = new RectF();
private final float[] mMatrixValues = new float[9];
// Listeners
private OnMatrixChangedListener mMatrixChangeListener;
private OnPhotoTapListener mPhotoTapListener;
private OnOutsidePhotoTapListener mOutsidePhotoTapListener;
private OnViewTapListener mViewTapListener;
private View.OnClickListener mOnClickListener;
private OnLongClickListener mLongClickListener;
private OnScaleChangedListener mScaleChangeListener;
private OnSingleFlingListener mSingleFlingListener;
private OnViewDragListener mOnViewDragListener;
private FlingRunnable mCurrentFlingRunnable;
private int mHorizontalScrollEdge = HORIZONTAL_EDGE_BOTH;
private int mVerticalScrollEdge = VERTICAL_EDGE_BOTH;
private float mBaseRotation;
private boolean mZoomEnabled = true;
private ScaleType mScaleType = ScaleType.FIT_CENTER;
private OnGestureListener onGestureListener = new OnGestureListener() {
@Override
public void onDrag(float dx, float dy) {
if (mScaleDragDetector.isScaling()) {
return; // Do not drag if we are already scaling
}
if (mOnViewDragListener != null) {
mOnViewDragListener.onDrag(dx, dy);
}
mSuppMatrix.postTranslate(dx, dy);
checkAndDisplayMatrix();
/*
* Here we decide whether to let the ImageView's parent to start taking
* over the touch event.
*
* First we check whether this function is enabled. We never want the
* parent to take over if we're scaling. We then check the edge we're
* on, and the direction of the scroll (i.e. if we're pulling against
* the edge, aka 'overscrolling', let the parent take over).
*/
ViewParent parent = mImageView.getParent();
if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) {
if (mHorizontalScrollEdge == HORIZONTAL_EDGE_BOTH
|| (mHorizontalScrollEdge == HORIZONTAL_EDGE_LEFT && dx >= 1f)
|| (mHorizontalScrollEdge == HORIZONTAL_EDGE_RIGHT && dx <= -1f)
|| (mVerticalScrollEdge == VERTICAL_EDGE_TOP && dy >= 1f)
|| (mVerticalScrollEdge == VERTICAL_EDGE_BOTTOM && dy <= -1f)) {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(false);
}
}
} else {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
@Override
public void onFling(float startX, float startY, float velocityX, float velocityY) {
mCurrentFlingRunnable = new FlingRunnable(mImageView.getContext());
mCurrentFlingRunnable.fling(getImageViewWidth(mImageView),
getImageViewHeight(mImageView), (int) velocityX, (int) velocityY);
mImageView.post(mCurrentFlingRunnable);
}
@Override
public void onScale(float scaleFactor, float focusX, float focusY) {
onScale(scaleFactor, focusX, focusY, 0, 0);
}
@Override
public void onScale(float scaleFactor, float focusX, float focusY, float dx, float dy) {
if (getScale() < mMaxScale || scaleFactor < 1f) {
if (mScaleChangeListener != null) {
mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
}
mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
mSuppMatrix.postTranslate(dx, dy);
checkAndDisplayMatrix();
}
}
};
public PhotoViewAttacher(ImageView imageView) {
mImageView = imageView;
imageView.setOnTouchListener(this);
imageView.addOnLayoutChangeListener(this);
if (imageView.isInEditMode()) {
return;
}
mBaseRotation = 0.0f;
// Create Gesture Detectors...
mScaleDragDetector = new CustomGestureDetector(imageView.getContext(), onGestureListener);
mGestureDetector = new GestureDetector(imageView.getContext(), new GestureDetector.SimpleOnGestureListener() {
// forward long click listener
@Override
public void onLongPress(MotionEvent e) {
if (mLongClickListener != null) {
mLongClickListener.onLongClick(mImageView);
}
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (mSingleFlingListener != null) {
if (getScale() > DEFAULT_MIN_SCALE) {
return false;
}
if (e1.getPointerCount() > SINGLE_TOUCH
|| e2.getPointerCount() > SINGLE_TOUCH) {
return false;
}
return mSingleFlingListener.onFling(e1, e2, velocityX, velocityY);
}
return false;
}
});
mGestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mOnClickListener != null) {
mOnClickListener.onClick(mImageView);
}
final RectF displayRect = getDisplayRect();
final float x = e.getX(), y = e.getY();
if (mViewTapListener != null) {
mViewTapListener.onViewTap(mImageView, x, y);
}
if (displayRect != null) {
// Check to see if the user tapped on the photo
if (displayRect.contains(x, y)) {
float xResult = (x - displayRect.left)
/ displayRect.width();
float yResult = (y - displayRect.top)
/ displayRect.height();
if (mPhotoTapListener != null) {
mPhotoTapListener.onPhotoTap(mImageView, xResult, yResult);
}
return true;
} else {
if (mOutsidePhotoTapListener != null) {
mOutsidePhotoTapListener.onOutsidePhotoTap(mImageView);
}
}
}
return false;
}
@Override
public boolean onDoubleTap(MotionEvent ev) {
try {
float scale = getScale();
float x = ev.getX();
float y = ev.getY();
if (scale < getMediumScale()) {
setScale(getMediumScale(), x, y, true);
} else if (scale >= getMediumScale() && scale < getMaximumScale()) {
setScale(getMaximumScale(), x, y, true);
} else {
setScale(getMinimumScale(), x, y, true);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Can sometimes happen when getX() and getY() is called
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Wait for the confirmed onDoubleTap() instead
return false;
}
});
}
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
}
public void setOnScaleChangeListener(OnScaleChangedListener onScaleChangeListener) {
this.mScaleChangeListener = onScaleChangeListener;
}
public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) {
this.mSingleFlingListener = onSingleFlingListener;
}
@Deprecated
public boolean isZoomEnabled() {
return mZoomEnabled;
}
public RectF getDisplayRect() {
checkMatrixBounds();
return getDisplayRect(getDrawMatrix());
}
public boolean setDisplayMatrix(Matrix finalMatrix) {
if (finalMatrix == null) {
throw new IllegalArgumentException("Matrix cannot be null");
}
if (mImageView.getDrawable() == null) {
return false;
}
mSuppMatrix.set(finalMatrix);
checkAndDisplayMatrix();
return true;
}
public void setBaseRotation(final float degrees) {
mBaseRotation = degrees % 360;
update();
setRotationBy(mBaseRotation);
checkAndDisplayMatrix();
}
public void setRotationTo(float degrees) {
mSuppMatrix.setRotate(degrees % 360);
checkAndDisplayMatrix();
}
public void setRotationBy(float degrees) {
mSuppMatrix.postRotate(degrees % 360);
checkAndDisplayMatrix();
}
public float getMinimumScale() {
return mMinScale;
}
public float getMediumScale() {
return mMidScale;
}
public float getMaximumScale() {
return mMaxScale;
}
public float getScale() {
return (float) Math.sqrt((float) Math.pow(getValue(mSuppMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow
(getValue(mSuppMatrix, Matrix.MSKEW_Y), 2));
}
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int
oldRight, int oldBottom) {
// Update our base matrix, as the bounds have changed
if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
updateBaseMatrix(mImageView.getDrawable());
}
}
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean handled = false;
if (mZoomEnabled && Util.hasDrawable((ImageView) v)) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
ViewParent parent = v.getParent();
// First, disable the Parent from intercepting the touch
// event
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
// If we're flinging, and the user presses down, cancel
// fling
cancelFling();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
// If the user has zoomed less than min scale, zoom back
// to min scale
if (getScale() < mMinScale) {
RectF rect = getDisplayRect();
if (rect != null) {
v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
rect.centerX(), rect.centerY()));
handled = true;
}
} else if (getScale() > mMaxScale) {
RectF rect = getDisplayRect();
if (rect != null) {
v.post(new AnimatedZoomRunnable(getScale(), mMaxScale,
rect.centerX(), rect.centerY()));
handled = true;
}
}
break;
}
// Try the Scale/Drag detector
if (mScaleDragDetector != null) {
boolean wasScaling = mScaleDragDetector.isScaling();
boolean wasDragging = mScaleDragDetector.isDragging();
handled = mScaleDragDetector.onTouchEvent(ev);
boolean didntScale = !wasScaling && !mScaleDragDetector.isScaling();
boolean didntDrag = !wasDragging && !mScaleDragDetector.isDragging();
mBlockParentIntercept = didntScale && didntDrag;
}
// Check to see if the user double tapped
if (mGestureDetector != null && mGestureDetector.onTouchEvent(ev)) {
handled = true;
}
}
return handled;
}
public void setAllowParentInterceptOnEdge(boolean allow) {
mAllowParentInterceptOnEdge = allow;
}
public void setMinimumScale(float minimumScale) {
Util.checkZoomLevels(minimumScale, mMidScale, mMaxScale);
mMinScale = minimumScale;
}
public void setMediumScale(float mediumScale) {
Util.checkZoomLevels(mMinScale, mediumScale, mMaxScale);
mMidScale = mediumScale;
}
public void setMaximumScale(float maximumScale) {
Util.checkZoomLevels(mMinScale, mMidScale, maximumScale);
mMaxScale = maximumScale;
}
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
Util.checkZoomLevels(minimumScale, mediumScale, maximumScale);
mMinScale = minimumScale;
mMidScale = mediumScale;
mMaxScale = maximumScale;
}
public void setOnLongClickListener(OnLongClickListener listener) {
mLongClickListener = listener;
}
public void setOnClickListener(View.OnClickListener listener) {
mOnClickListener = listener;
}
public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
mMatrixChangeListener = listener;
}
public void setOnPhotoTapListener(OnPhotoTapListener listener) {
mPhotoTapListener = listener;
}
public void setOnOutsidePhotoTapListener(OnOutsidePhotoTapListener mOutsidePhotoTapListener) {
this.mOutsidePhotoTapListener = mOutsidePhotoTapListener;
}
public void setOnViewTapListener(OnViewTapListener listener) {
mViewTapListener = listener;
}
public void setOnViewDragListener(OnViewDragListener listener) {
mOnViewDragListener = listener;
}
public void setScale(float scale) {
setScale(scale, false);
}
public void setScale(float scale, boolean animate) {
setScale(scale,
(mImageView.getRight()) / 2,
(mImageView.getBottom()) / 2,
animate);
}
public void setScale(float scale, float focalX, float focalY,
boolean animate) {
// Check to see if the scale is within bounds
if (scale < mMinScale || scale > mMaxScale) {
throw new IllegalArgumentException("Scale must be within the range of minScale and maxScale");
}
if (animate) {
mImageView.post(new AnimatedZoomRunnable(getScale(), scale,
focalX, focalY));
} else {
mSuppMatrix.setScale(scale, scale, focalX, focalY);
checkAndDisplayMatrix();
}
}
/**
* Set the zoom interpolator
*
* @param interpolator the zoom interpolator
*/
public void setZoomInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
}
public void setScaleType(ScaleType scaleType) {
if (Util.isSupportedScaleType(scaleType) && scaleType != mScaleType) {
mScaleType = scaleType;
update();
}
}
public boolean isZoomable() {
return mZoomEnabled;
}
public void setZoomable(boolean zoomable) {
mZoomEnabled = zoomable;
update();
}
public void update() {
if (mZoomEnabled) {
// Update the base matrix using the current drawable
updateBaseMatrix(mImageView.getDrawable());
} else {
// Reset the Matrix...
resetMatrix();
}
}
/**
* Get the display matrix
*
* @param matrix target matrix to copy to
*/
public void getDisplayMatrix(Matrix matrix) {
matrix.set(getDrawMatrix());
}
/**
* Get the current support matrix
*/
public void getSuppMatrix(Matrix matrix) {
matrix.set(mSuppMatrix);
}
private Matrix getDrawMatrix() {
mDrawMatrix.set(mBaseMatrix);
mDrawMatrix.postConcat(mSuppMatrix);
return mDrawMatrix;
}
public Matrix getImageMatrix() {
return mDrawMatrix;
}
public void setZoomTransitionDuration(int milliseconds) {
this.mZoomDuration = milliseconds;
}
/**
* Helper method that 'unpacks' a Matrix and returns the required value
*
* @param matrix Matrix to unpack
* @param whichValue Which value from Matrix.M* to return
* @return returned value
*/
private float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
/**
* Resets the Matrix back to FIT_CENTER, and then displays its contents
*/
private void resetMatrix() {
mSuppMatrix.reset();
setRotationBy(mBaseRotation);
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
}
private void setImageViewMatrix(Matrix matrix) {
mImageView.setImageMatrix(matrix);
// Call MatrixChangedListener if needed
if (mMatrixChangeListener != null) {
RectF displayRect = getDisplayRect(matrix);
if (displayRect != null) {
mMatrixChangeListener.onMatrixChanged(displayRect);
}
}
}
/**
* Helper method that simply checks the Matrix, and then displays the result
*/
private void checkAndDisplayMatrix() {
if (checkMatrixBounds()) {
setImageViewMatrix(getDrawMatrix());
}
}
/**
* Helper method that maps the supplied Matrix to the current Drawable
*
* @param matrix - Matrix to map Drawable against
* @return RectF - Displayed Rectangle
*/
private RectF getDisplayRect(Matrix matrix) {
Drawable d = mImageView.getDrawable();
if (d != null) {
mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
matrix.mapRect(mDisplayRect);
return mDisplayRect;
}
return null;
}
/**
* Calculate Matrix for FIT_CENTER
*
* @param drawable - Drawable being displayed
*/
private void updateBaseMatrix(Drawable drawable) {
if (drawable == null) {
return;
}
final float viewWidth = getImageViewWidth(mImageView);
final float viewHeight = getImageViewHeight(mImageView);
final int drawableWidth = drawable.getIntrinsicWidth();
final int drawableHeight = drawable.getIntrinsicHeight();
mBaseMatrix.reset();
final float widthScale = viewWidth / drawableWidth;
final float heightScale = viewHeight / drawableHeight;
if (mScaleType == ScaleType.CENTER) {
mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
(viewHeight - drawableHeight) / 2F);
} else if (mScaleType == ScaleType.CENTER_CROP) {
float scale = Math.max(widthScale, heightScale);
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else if (mScaleType == ScaleType.CENTER_INSIDE) {
float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else {
RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
if ((int) mBaseRotation % 180 != 0) {
mTempSrc = new RectF(0, 0, drawableHeight, drawableWidth);
}
switch (mScaleType) {
case FIT_CENTER:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
break;
case FIT_START:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
break;
case FIT_END:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
break;
case FIT_XY:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
break;
default:
break;
}
}
resetMatrix();
}
private boolean checkMatrixBounds() {
final RectF rect = getDisplayRect(getDrawMatrix());
if (rect == null) {
return false;
}
final float height = rect.height(), width = rect.width();
float deltaX = 0, deltaY = 0;
final int viewHeight = getImageViewHeight(mImageView);
if (height <= viewHeight) {
switch (mScaleType) {
case FIT_START:
deltaY = -rect.top;
break;
case FIT_END:
deltaY = viewHeight - height - rect.top;
break;
default:
deltaY = (viewHeight - height) / 2 - rect.top;
break;
}
mVerticalScrollEdge = VERTICAL_EDGE_BOTH;
} else if (rect.top > 0) {
mVerticalScrollEdge = VERTICAL_EDGE_TOP;
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
mVerticalScrollEdge = VERTICAL_EDGE_BOTTOM;
deltaY = viewHeight - rect.bottom;
} else {
mVerticalScrollEdge = VERTICAL_EDGE_NONE;
}
final int viewWidth = getImageViewWidth(mImageView);
if (width <= viewWidth) {
switch (mScaleType) {
case FIT_START:
deltaX = -rect.left;
break;
case FIT_END:
deltaX = viewWidth - width - rect.left;
break;
default:
deltaX = (viewWidth - width) / 2 - rect.left;
break;
}
mHorizontalScrollEdge = HORIZONTAL_EDGE_BOTH;
} else if (rect.left > 0) {
mHorizontalScrollEdge = HORIZONTAL_EDGE_LEFT;
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
mHorizontalScrollEdge = HORIZONTAL_EDGE_RIGHT;
} else {
mHorizontalScrollEdge = HORIZONTAL_EDGE_NONE;
}
// Finally actually translate the matrix
mSuppMatrix.postTranslate(deltaX, deltaY);
return true;
}
private int getImageViewWidth(ImageView imageView) {
return imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
}
private int getImageViewHeight(ImageView imageView) {
return imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
}
private void cancelFling() {
if (mCurrentFlingRunnable != null) {
mCurrentFlingRunnable.cancelFling();
mCurrentFlingRunnable = null;
}
}
private class AnimatedZoomRunnable implements Runnable {
private final float mFocalX, mFocalY;
private final long mStartTime;
private final float mZoomStart, mZoomEnd;
public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
final float focalX, final float focalY) {
mFocalX = focalX;
mFocalY = focalY;
mStartTime = System.currentTimeMillis();
mZoomStart = currentZoom;
mZoomEnd = targetZoom;
}
@Override
public void run() {
float t = interpolate();
float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
float deltaScale = scale / getScale();
onGestureListener.onScale(deltaScale, mFocalX, mFocalY);
// We haven't hit our target scale yet, so post ourselves again
if (t < 1f) {
Compat.postOnAnimation(mImageView, this);
}
}
private float interpolate() {
float t = 1f * (System.currentTimeMillis() - mStartTime) / mZoomDuration;
t = Math.min(1f, t);
t = mInterpolator.getInterpolation(t);
return t;
}
}
private class FlingRunnable implements Runnable {
private final OverScroller mScroller;
private int mCurrentX, mCurrentY;
public FlingRunnable(Context context) {
mScroller = new OverScroller(context);
}
public void cancelFling() {
mScroller.forceFinished(true);
}
public void fling(int viewWidth, int viewHeight, int velocityX,
int velocityY) {
final RectF rect = getDisplayRect();
if (rect == null) {
return;
}
final int startX = Math.round(-rect.left);
final int minX, maxX, minY, maxY;
if (viewWidth < rect.width()) {
minX = 0;
maxX = Math.round(rect.width() - viewWidth);
} else {
minX = maxX = startX;
}
final int startY = Math.round(-rect.top);
if (viewHeight < rect.height()) {
minY = 0;
maxY = Math.round(rect.height() - viewHeight);
} else {
minY = maxY = startY;
}
mCurrentX = startX;
mCurrentY = startY;
// If we actually can move, fling the scroller
if (startX != maxX || startY != maxY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX,
maxX, minY, maxY, 0, 0);
}
}
@Override
public void run() {
if (mScroller.isFinished()) {
return; // remaining post that should not be handled
}
if (mScroller.computeScrollOffset()) {
final int newX = mScroller.getCurrX();
final int newY = mScroller.getCurrY();
mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
checkAndDisplayMatrix();
mCurrentX = newX;
mCurrentY = newY;
// Post On animation
Compat.postOnAnimation(mImageView, this);
}
}
}
}

View File

@@ -0,0 +1,37 @@
package com.github.chrisbanes.photoview;
import android.view.MotionEvent;
import android.widget.ImageView;
class Util {
static void checkZoomLevels(float minZoom, float midZoom,
float maxZoom) {
if (minZoom >= midZoom) {
throw new IllegalArgumentException(
"Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
} else if (midZoom >= maxZoom) {
throw new IllegalArgumentException(
"Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
}
}
static boolean hasDrawable(ImageView imageView) {
return imageView.getDrawable() != null;
}
static boolean isSupportedScaleType(final ImageView.ScaleType scaleType) {
if (scaleType == null) {
return false;
}
switch (scaleType) {
case MATRIX:
throw new IllegalStateException("Matrix scale type is not supported");
}
return true;
}
static int getPointerIndex(int action) {
return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
}

View File

@@ -0,0 +1,17 @@
package com.github.chrisbanes.photoview;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@@ -1,2 +1,25 @@
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
include ':EasyPlayerPro'
include ':ijkplayer-java'
include ':photoview'