From cb2e7abc68f5595cd53cdc89c0947017255a67e1 Mon Sep 17 00:00:00 2001 From: jiaoyang623 Date: Sun, 5 Aug 2018 21:27:29 +0800 Subject: [PATCH] init --- app/.gitignore | 1 + app/build.gradle | 47 +++ app/proguard-rules.pro | 21 ++ .../ioio/alpha/ExampleInstrumentedTest.java | 26 ++ app/src/main/AndroidManifest.xml | 32 +++ app/src/main/assets/channels.json | 94 ++++++ .../java/guru/ioio/alpha/BaseActivity.java | 10 + .../guru/ioio/alpha/ChannelListActivity.java | 72 +++++ .../java/guru/ioio/alpha/MainActivity.java | 24 ++ .../guru/ioio/alpha/model/ChannelBean.java | 8 + .../guru/ioio/alpha/model/ChannelRoot.java | 7 + .../ioio/alpha/player/PlayerActivity.java | 145 ++++++++++ .../guru/ioio/alpha/player/PlayerView.java | 272 ++++++++++++++++++ .../alpha/player/VideoPlayerListener.java | 31 ++ .../drawable-v24/ic_launcher_foreground.xml | 34 +++ .../res/drawable/ic_launcher_background.xml | 170 +++++++++++ .../main/res/layout/activity_channel_list.xml | 20 ++ app/src/main/res/layout/activity_main.xml | 25 ++ app/src/main/res/layout/activity_player.xml | 29 ++ app/src/main/res/layout/item_channel.xml | 26 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 17 ++ .../java/guru/ioio/alpha/ExampleUnitTest.java | 17 ++ base/.gitignore | 1 + base/build.gradle | 38 +++ base/proguard-rules.pro | 25 ++ .../ioio/base/ExampleInstrumentedTest.java | 26 ++ base/src/main/AndroidManifest.xml | 15 + .../ioio/base/AbsBindingListActivity.java | 78 +++++ .../guru/ioio/base/ActivityListActivity.java | 125 ++++++++ .../ioio/base/adapter/BindingBaseAdapter.java | 110 +++++++ .../guru/ioio/base/adapter/IDataLoader.java | 30 ++ .../base/adapter/RVBindingBaseAdapter.java | 194 +++++++++++++ .../java/guru/ioio/base/frame/BaseApp.java | 24 ++ .../guru/ioio/base/frame/BindingUtils.java | 9 + .../base/permission/PermissionsActivity.java | 153 ++++++++++ .../base/permission/PermissionsChecker.java | 51 ++++ base/src/main/res/layout/activity_abslist.xml | 38 +++ .../main/res/layout/activity_permissions.xml | 8 + base/src/main/res/layout/item_activity.xml | 23 ++ base/src/main/res/values/strings.xml | 10 + .../java/guru/ioio/base/ExampleUnitTest.java | 17 ++ bbtv.jks | Bin 0 -> 2182 bytes build.gradle | 27 ++ gradle.properties | 13 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 +++++++++++ gradlew.bat | 84 ++++++ local.properties | 9 + settings.gradle | 1 + 64 files changed, 2434 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/guru/ioio/alpha/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/channels.json create mode 100644 app/src/main/java/guru/ioio/alpha/BaseActivity.java create mode 100644 app/src/main/java/guru/ioio/alpha/ChannelListActivity.java create mode 100644 app/src/main/java/guru/ioio/alpha/MainActivity.java create mode 100644 app/src/main/java/guru/ioio/alpha/model/ChannelBean.java create mode 100644 app/src/main/java/guru/ioio/alpha/model/ChannelRoot.java create mode 100644 app/src/main/java/guru/ioio/alpha/player/PlayerActivity.java create mode 100644 app/src/main/java/guru/ioio/alpha/player/PlayerView.java create mode 100644 app/src/main/java/guru/ioio/alpha/player/VideoPlayerListener.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_channel_list.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_player.xml create mode 100644 app/src/main/res/layout/item_channel.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/guru/ioio/alpha/ExampleUnitTest.java create mode 100644 base/.gitignore create mode 100644 base/build.gradle create mode 100644 base/proguard-rules.pro create mode 100644 base/src/androidTest/java/guru/ioio/base/ExampleInstrumentedTest.java create mode 100644 base/src/main/AndroidManifest.xml create mode 100644 base/src/main/java/guru/ioio/base/AbsBindingListActivity.java create mode 100644 base/src/main/java/guru/ioio/base/ActivityListActivity.java create mode 100644 base/src/main/java/guru/ioio/base/adapter/BindingBaseAdapter.java create mode 100644 base/src/main/java/guru/ioio/base/adapter/IDataLoader.java create mode 100644 base/src/main/java/guru/ioio/base/adapter/RVBindingBaseAdapter.java create mode 100644 base/src/main/java/guru/ioio/base/frame/BaseApp.java create mode 100644 base/src/main/java/guru/ioio/base/frame/BindingUtils.java create mode 100644 base/src/main/java/guru/ioio/base/permission/PermissionsActivity.java create mode 100644 base/src/main/java/guru/ioio/base/permission/PermissionsChecker.java create mode 100644 base/src/main/res/layout/activity_abslist.xml create mode 100644 base/src/main/res/layout/activity_permissions.xml create mode 100644 base/src/main/res/layout/item_activity.xml create mode 100644 base/src/main/res/values/strings.xml create mode 100644 base/src/test/java/guru/ioio/base/ExampleUnitTest.java create mode 100644 bbtv.jks create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 local.properties create mode 100644 settings.gradle diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..c78ecea --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,47 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "guru.ioio.alpha" + minSdkVersion 21 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + dataBinding { + enabled true + } + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:28+' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + implementation 'io.reactivex.rxjava2:rxjava:2.2.0' + implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' + implementation 'com.squareup.retrofit2:retrofit:2.4.0' + implementation 'com.github.k0shk0sh:PermissionHelper:1.1.0' + implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8' + implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8' + implementation project(':base') +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -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 diff --git a/app/src/androidTest/java/guru/ioio/alpha/ExampleInstrumentedTest.java b/app/src/androidTest/java/guru/ioio/alpha/ExampleInstrumentedTest.java new file mode 100644 index 0000000..f3b9dfb --- /dev/null +++ b/app/src/androidTest/java/guru/ioio/alpha/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package guru.ioio.alpha; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.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 Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("guru.ioio.alpha", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9602ece --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/channels.json b/app/src/main/assets/channels.json new file mode 100644 index 0000000..1236e01 --- /dev/null +++ b/app/src/main/assets/channels.json @@ -0,0 +1,94 @@ +{ + "list": [ + { + "name": "中央1", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv1.m3u8" + ] + }, + { + "name": "中央2", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv2.m3u8" + ] + }, + { + "name": "中央3", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv3.m3u8" + ] + }, + { + "name": "中央4", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv4.m3u8" + ] + }, + { + "name": "中央5", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv5.m3u8" + ] + }, + { + "name": "中央6", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv6.m3u8" + ] + }, + { + "name": "中央7", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv7.m3u8" + ] + }, + { + "name": "中央8", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv8.m3u8" + ] + }, + { + "name": "中央9", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv9.m3u8" + ] + }, + { + "name": "中央10", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv10.m3u8" + ] + }, + { + "name": "中央11", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv11.m3u8" + ] + }, + { + "name": "中央12", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv12.m3u8" + ] + }, + { + "name": "中央13", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv13.m3u8" + ] + }, + { + "name": "中央14", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv14.m3u8" + ] + }, + { + "name": "中央15", + "uri": [ + "http://ivi.bupt.edu.cn/hls/cctv15.m3u8" + ] + } + ] +} diff --git a/app/src/main/java/guru/ioio/alpha/BaseActivity.java b/app/src/main/java/guru/ioio/alpha/BaseActivity.java new file mode 100644 index 0000000..c9c7cd1 --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/BaseActivity.java @@ -0,0 +1,10 @@ +package guru.ioio.alpha; + +import android.support.v7.app.AppCompatActivity; +import android.widget.Toast; + +public class BaseActivity extends AppCompatActivity { + protected void show(String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/java/guru/ioio/alpha/ChannelListActivity.java b/app/src/main/java/guru/ioio/alpha/ChannelListActivity.java new file mode 100644 index 0000000..2df4a2f --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/ChannelListActivity.java @@ -0,0 +1,72 @@ +package guru.ioio.alpha; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; + +import com.google.gson.Gson; + +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.util.List; + +import guru.ioio.alpha.databinding.ActivityChannelListBinding; +import guru.ioio.alpha.model.ChannelBean; +import guru.ioio.alpha.model.ChannelRoot; +import guru.ioio.alpha.player.PlayerActivity; +import guru.ioio.base.adapter.RVBindingBaseAdapter; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class ChannelListActivity extends BaseActivity { + private ActivityChannelListBinding mBinding; + private RVBindingBaseAdapter mAdapter; + + public static void launch(Context context) { + context.startActivity(new Intent(context, ChannelListActivity.class)); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_channel_list); + mBinding.setPresenter(this); + mAdapter = new RVBindingBaseAdapter<>(R.layout.item_channel, guru.ioio.alpha.BR.data); + mAdapter.addPresenter(guru.ioio.alpha.BR.presenter, this); + mBinding.recycler.setLayoutManager(new GridLayoutManager(this, 1, GridLayoutManager.VERTICAL, false)); + mBinding.recycler.setAdapter(mAdapter); + + loadChannels(); + } + + @SuppressLint("CheckResult") + private void loadChannels() { + Observable.create(s -> { + try (InputStream in = getAssets().open("channels.json")) { + String data = IOUtils.toString(in, "utf-8"); + Gson gson = new Gson(); + ChannelRoot root = gson.fromJson(data, ChannelRoot.class); + if (root != null && root.list != null) { + s.onNext(root.list); + } else { + s.onError(new Exception("no data")); + } + s.onComplete(); + } + }).subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(list -> mAdapter.add((List) list), e -> { + }); + } + + public boolean onItemClick(ChannelBean bean) { + PlayerActivity.launch(this, bean.uri.get(0)); + return true; + } +} diff --git a/app/src/main/java/guru/ioio/alpha/MainActivity.java b/app/src/main/java/guru/ioio/alpha/MainActivity.java new file mode 100644 index 0000000..a96b2b6 --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/MainActivity.java @@ -0,0 +1,24 @@ +package guru.ioio.alpha; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; + +import guru.ioio.alpha.databinding.ActivityMainBinding; + +public class MainActivity extends BaseActivity { + private ActivityMainBinding mBinding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); + mBinding.setPresenter(this); + ChannelListActivity.launch(this); + finish(); + } + + public boolean onPlayClick() { + ChannelListActivity.launch(this); + return true; + } +} diff --git a/app/src/main/java/guru/ioio/alpha/model/ChannelBean.java b/app/src/main/java/guru/ioio/alpha/model/ChannelBean.java new file mode 100644 index 0000000..5793f67 --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/model/ChannelBean.java @@ -0,0 +1,8 @@ +package guru.ioio.alpha.model; + +import java.util.List; + +public class ChannelBean { + public String name; + public List uri; +} diff --git a/app/src/main/java/guru/ioio/alpha/model/ChannelRoot.java b/app/src/main/java/guru/ioio/alpha/model/ChannelRoot.java new file mode 100644 index 0000000..e49d996 --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/model/ChannelRoot.java @@ -0,0 +1,7 @@ +package guru.ioio.alpha.model; + +import java.util.List; + +public class ChannelRoot { + public List list; +} diff --git a/app/src/main/java/guru/ioio/alpha/player/PlayerActivity.java b/app/src/main/java/guru/ioio/alpha/player/PlayerActivity.java new file mode 100644 index 0000000..588e7ab --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/player/PlayerActivity.java @@ -0,0 +1,145 @@ +package guru.ioio.alpha.player; + +import android.content.Context; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.databinding.ObservableBoolean; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.view.WindowManager; + +import com.fastaccess.permission.base.PermissionHelper; +import com.fastaccess.permission.base.callback.OnPermissionCallback; + +import guru.ioio.alpha.BaseActivity; +import guru.ioio.alpha.R; +import guru.ioio.alpha.databinding.ActivityPlayerBinding; +import tv.danmaku.ijk.media.player.IMediaPlayer; +import tv.danmaku.ijk.media.player.IjkMediaPlayer; + +public class PlayerActivity extends BaseActivity implements OnPermissionCallback { + public ObservableBoolean isLoading = new ObservableBoolean(true); + private ActivityPlayerBinding mBinding; + private static final String KEY_URI = "uri"; + private String mPlayUri = null; + + public static void launch(Context context, String uri) { + Intent intent = new Intent(context, PlayerActivity.class); + intent.putExtra(KEY_URI, uri); + context.startActivity(intent); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > 24) { + checkPermission(); + } else { + init(); + } + } + + private void init() { + Intent intent = getIntent(); + mPlayUri = intent.getStringExtra(KEY_URI); + if (TextUtils.isEmpty(mPlayUri)) { + finish(); + show("资源错误"); + return; + } + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_player); + mBinding.setPresenter(this); + + try { + IjkMediaPlayer.loadLibrariesOnce(null); + IjkMediaPlayer.native_profileBegin("libijkplayer.so"); + } catch (Exception e) { + this.finish(); + } + + mBinding.player.setListener(new VideoPlayerListener() { + @Override + public void onPrepared(IMediaPlayer iMediaPlayer) { + iMediaPlayer.start(); + isLoading.set(false); + } + + }); + + mBinding.player.setVideoPath(mPlayUri); + } + + private String[] PERMISSIONS = { + "android.permission.WRITE_EXTERNAL_STORAGE" + }; + + private void checkPermission() { + PermissionHelper.getInstance(this) + .setForceAccepting(false)// true if you had like force reshowing the permission dialog on Deny (not recommended) + .request(PERMISSIONS); + } + + @Override + protected void onPause() { + super.onPause(); + if (mBinding != null) { + mBinding.player.pause(); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (mBinding != null && mBinding.player.isPlaying()) { + mBinding.player.start(); + } + } + + @Override + protected void onStop() { + if (mBinding != null) { + IjkMediaPlayer.native_profileEnd(); + } + super.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mBinding != null) { + mBinding.player.release(); + } + } + + @Override + public void onPermissionGranted(@NonNull String[] permissionName) { + init(); + } + + @Override + public void onPermissionDeclined(@NonNull String[] permissionName) { + finish(); + } + + @Override + public void onPermissionPreGranted(@NonNull String permissionsName) { + } + + @Override + public void onPermissionNeedExplanation(@NonNull String permissionName) { + } + + @Override + public void onPermissionReallyDeclined(@NonNull String permissionName) { + } + + @Override + public void onNoPermissionNeeded() { + } +} diff --git a/app/src/main/java/guru/ioio/alpha/player/PlayerView.java b/app/src/main/java/guru/ioio/alpha/player/PlayerView.java new file mode 100644 index 0000000..ea2239c --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/player/PlayerView.java @@ -0,0 +1,272 @@ +package guru.ioio.alpha.player; + +import android.content.Context; +import android.support.annotation.AttrRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.widget.FrameLayout; + +import java.io.IOException; + +import tv.danmaku.ijk.media.player.IMediaPlayer; +import tv.danmaku.ijk.media.player.IjkMediaPlayer; + +public class PlayerView extends FrameLayout { + + /** + * 由ijkplayer提供,用于播放视频,需要给他传入一个surfaceView + */ + private IMediaPlayer mMediaPlayer = null; + + /** + * 视频文件地址 + */ + private String mPath = ""; + + private SurfaceView surfaceView; + + private VideoPlayerListener listener; + private Context mContext; + + public PlayerView(@NonNull Context context) { + super(context); + initVideoView(context); + } + + public PlayerView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initVideoView(context); + } + + public PlayerView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + initVideoView(context); + } + + private void initVideoView(Context context) { + mContext = context; + + //获取焦点,不知道有没有必要~。~ + setFocusable(true); + setBackgroundColor(0xff000000); + } + + /** + * 设置视频地址。 + * 根据是否第一次播放视频,做不同的操作。 + * + * @param path the path of the video. + */ + public void setVideoPath(String path) { + if (TextUtils.equals("", mPath)) { + //如果是第一次播放视频,那就创建一个新的surfaceView + mPath = path; + createSurfaceView(); + } else { + //否则就直接load + mPath = path; + load(); + } + } + + /** + * 新建一个surfaceview + */ + private void createSurfaceView() { + //生成一个新的surface view + surfaceView = new SurfaceView(mContext); + surfaceView.getHolder().addCallback(new LmnSurfaceCallback()); + LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT + , LayoutParams.MATCH_PARENT, Gravity.CENTER); + surfaceView.setLayoutParams(layoutParams); + this.addView(surfaceView); + } + + /** + * surfaceView的监听器 + */ + private class LmnSurfaceCallback implements SurfaceHolder.Callback { + @Override + public void surfaceCreated(SurfaceHolder holder) { + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + //surfaceview创建成功后,加载视频 + load(); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + } + } + + /** + * 加载视频 + */ + private void load() { + //每次都要重新创建IMediaPlayer + createPlayer(); + try { + mMediaPlayer.setDataSource(mPath); + } catch (IOException e) { + e.printStackTrace(); + } + //给mediaPlayer设置视图 + mMediaPlayer.setDisplay(surfaceView.getHolder()); + + mMediaPlayer.prepareAsync(); + } + + /** + * 创建一个新的player + */ + private void createPlayer() { + if (mMediaPlayer != null) { + mMediaPlayer.stop(); + mMediaPlayer.setDisplay(null); + mMediaPlayer.release(); + } + IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer(); + ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG); + +//开启硬解码 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); + + mMediaPlayer = ijkMediaPlayer; + + if (listener != null) { + mMediaPlayer.setOnPreparedListener(listener); + mMediaPlayer.setOnInfoListener(new IMediaPlayer.OnInfoListener() { + @Override + public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) { + if (listener != null) { + listener.onInfo(iMediaPlayer, i, i1); + } + + int w = mMediaPlayer.getVideoWidth(); + int h = mMediaPlayer.getVideoHeight(); + if (w + h != 0 && (mVideoWidth != w || mVideoHeight != h)) { + mVideoWidth = w; + mVideoHeight = h; + requestLayout(); + } + return false; + } + }); + mMediaPlayer.setOnSeekCompleteListener(listener); + mMediaPlayer.setOnBufferingUpdateListener(listener); + mMediaPlayer.setOnErrorListener(listener); + } + } + + private int mVideoWidth = 0; + private int mVideoHeight = 0; + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (mVideoHeight + mVideoWidth == 0) { + super.onLayout(changed, left, top, right, bottom); + } else { + int width = right - left; + int height = bottom - top; + + int w, h, dw, dh; + if (mVideoWidth * height > width * mVideoHeight) { + // more width + w = width; + dw = 0; + h = mVideoHeight * width / mVideoWidth; + dh = (height - h) / 2; + } else { + w = mVideoWidth * height / mVideoHeight; + dw = (width - w) / 2; + h = height; + dh = 0; + } + surfaceView.layout(dw, dh, w + dw, h + dh); + } + } + + public void setListener(VideoPlayerListener listener) { + this.listener = listener; + if (mMediaPlayer != null) { + mMediaPlayer.setOnPreparedListener(listener); + } + } + + /** + * -------======--------- 下面封装了一下控制视频的方法 + */ + + public void start() { + if (mMediaPlayer != null) { + mMediaPlayer.start(); + } + } + + public boolean isPlaying() { + if (mMediaPlayer != null) { + return mMediaPlayer.isPlaying(); + } else { + return false; + } + } + + public void release() { + if (mMediaPlayer != null) { + mMediaPlayer.reset(); + mMediaPlayer.release(); + mMediaPlayer = null; + } + } + + public void pause() { + if (mMediaPlayer != null) { + mMediaPlayer.pause(); + } + } + + public void stop() { + if (mMediaPlayer != null) { + mMediaPlayer.stop(); + } + } + + + public void reset() { + if (mMediaPlayer != null) { + mMediaPlayer.reset(); + } + } + + + public long getDuration() { + if (mMediaPlayer != null) { + return mMediaPlayer.getDuration(); + } else { + return 0; + } + } + + + public long getCurrentPosition() { + if (mMediaPlayer != null) { + return mMediaPlayer.getCurrentPosition(); + } else { + return 0; + } + } + + + public void seekTo(long l) { + if (mMediaPlayer != null) { + mMediaPlayer.seekTo(l); + } + } + +} diff --git a/app/src/main/java/guru/ioio/alpha/player/VideoPlayerListener.java b/app/src/main/java/guru/ioio/alpha/player/VideoPlayerListener.java new file mode 100644 index 0000000..508284b --- /dev/null +++ b/app/src/main/java/guru/ioio/alpha/player/VideoPlayerListener.java @@ -0,0 +1,31 @@ +package guru.ioio.alpha.player; + +import tv.danmaku.ijk.media.player.IMediaPlayer; + +public class VideoPlayerListener implements IMediaPlayer.OnPreparedListener, IMediaPlayer.OnInfoListener, + IMediaPlayer.OnSeekCompleteListener ,IMediaPlayer.OnBufferingUpdateListener,IMediaPlayer.OnErrorListener{ + @Override + public void onPrepared(IMediaPlayer iMediaPlayer) { + + } + + @Override + public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) { + return false; + } + + @Override + public void onSeekComplete(IMediaPlayer iMediaPlayer) { + + } + + @Override + public void onBufferingUpdate(IMediaPlayer iMediaPlayer, int i) { + + } + + @Override + public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) { + return false; + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_channel_list.xml b/app/src/main/res/layout/activity_channel_list.xml new file mode 100644 index 0000000..dd7a736 --- /dev/null +++ b/app/src/main/res/layout/activity_channel_list.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4a6a36b --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,25 @@ + + + + + + + + + + +