Commit e3d87fb50a8f22e7e0fa002b3373b8c6de48e363
1 parent
146a809a
1 封装视频库
Showing
66 changed files
with
574 additions
and
4052 deletions
Too many changes to show.
To preserve performance only 66 of 72 files are displayed.
.idea/gradle.xml
| @@ -3,11 +3,33 @@ | @@ -3,11 +3,33 @@ | ||
| 3 | <component name="GradleSettings"> | 3 | <component name="GradleSettings"> |
| 4 | <option name="linkedExternalProjectsSettings"> | 4 | <option name="linkedExternalProjectsSettings"> |
| 5 | <GradleProjectSettings> | 5 | <GradleProjectSettings> |
| 6 | - <compositeConfiguration> | ||
| 7 | - <compositeBuild compositeDefinitionSource="SCRIPT" /> | ||
| 8 | - </compositeConfiguration> | ||
| 9 | <option name="distributionType" value="DEFAULT_WRAPPED" /> | 6 | <option name="distributionType" value="DEFAULT_WRAPPED" /> |
| 10 | <option name="externalProjectPath" value="$PROJECT_DIR$" /> | 7 | <option name="externalProjectPath" value="$PROJECT_DIR$" /> |
| 8 | + <option name="modules"> | ||
| 9 | + <set> | ||
| 10 | + <option value="$PROJECT_DIR$" /> | ||
| 11 | + <option value="$PROJECT_DIR$/app" /> | ||
| 12 | + <option value="$PROJECT_DIR$/app/strike" /> | ||
| 13 | + <option value="$PROJECT_DIR$/cloud" /> | ||
| 14 | + <option value="$PROJECT_DIR$/cloud/app_pay" /> | ||
| 15 | + <option value="$PROJECT_DIR$/cloud/pay" /> | ||
| 16 | + <option value="$PROJECT_DIR$/cloud/third_tool" /> | ||
| 17 | + <option value="$PROJECT_DIR$/cloud/user" /> | ||
| 18 | + <option value="$PROJECT_DIR$/cloud/video" /> | ||
| 19 | + <option value="$PROJECT_DIR$/core" /> | ||
| 20 | + <option value="$PROJECT_DIR$/core/app_qr" /> | ||
| 21 | + <option value="$PROJECT_DIR$/core/base" /> | ||
| 22 | + <option value="$PROJECT_DIR$/core/database" /> | ||
| 23 | + <option value="$PROJECT_DIR$/core/imageload" /> | ||
| 24 | + <option value="$PROJECT_DIR$/core/network" /> | ||
| 25 | + <option value="$PROJECT_DIR$/library_baidumap" /> | ||
| 26 | + <option value="$PROJECT_DIR$/module" /> | ||
| 27 | + <option value="$PROJECT_DIR$/module/pedometer" /> | ||
| 28 | + <option value="$PROJECT_DIR$/module/shanghaishop" /> | ||
| 29 | + <option value="$PROJECT_DIR$/module/shopcity" /> | ||
| 30 | + <option value="$PROJECT_DIR$/module/xiaojiasoundbox" /> | ||
| 31 | + </set> | ||
| 32 | + </option> | ||
| 11 | <option name="resolveModulePerSourceSet" value="false" /> | 33 | <option name="resolveModulePerSourceSet" value="false" /> |
| 12 | <option name="testRunner" value="PLATFORM" /> | 34 | <option name="testRunner" value="PLATFORM" /> |
| 13 | </GradleProjectSettings> | 35 | </GradleProjectSettings> |
app/strike/build.gradle
| @@ -182,7 +182,7 @@ dependencies { | @@ -182,7 +182,7 @@ dependencies { | ||
| 182 | implementation project(path: ':module:shopcity') | 182 | implementation project(path: ':module:shopcity') |
| 183 | // implementation project(path: ':module:shanghaishop') | 183 | // implementation project(path: ':module:shanghaishop') |
| 184 | implementation project(path: ':library_baidumap') | 184 | implementation project(path: ':library_baidumap') |
| 185 | - implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0' | 185 | +// implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0' |
| 186 | // implementation project(path: ':core:util') | 186 | // implementation project(path: ':core:util') |
| 187 | // implementation project(path: ':core:encipher') | 187 | // implementation project(path: ':core:encipher') |
| 188 | // implementation project(path: ':cloud:user') | 188 | // implementation project(path: ':cloud:user') |
app/strike/src/main/java/com/cnlive/strike/DemoApplication.java
| @@ -23,7 +23,6 @@ import com.baidu.mapapi.SDKInitializer; | @@ -23,7 +23,6 @@ import com.baidu.mapapi.SDKInitializer; | ||
| 23 | import com.cnlive.cloud.user.auth.UserService; | 23 | import com.cnlive.cloud.user.auth.UserService; |
| 24 | import com.cnlive.core.libs.base.application.AppConfig; | 24 | import com.cnlive.core.libs.base.application.AppConfig; |
| 25 | import com.cnlive.core.libs.base.application.BaseApplication; | 25 | import com.cnlive.core.libs.base.application.BaseApplication; |
| 26 | -import com.cnlive.strike.demo.exoplayer.demo.DownloadTracker; | ||
| 27 | import com.google.android.exoplayer2.BuildConfig; | 26 | import com.google.android.exoplayer2.BuildConfig; |
| 28 | import com.google.android.exoplayer2.DefaultRenderersFactory; | 27 | import com.google.android.exoplayer2.DefaultRenderersFactory; |
| 29 | import com.google.android.exoplayer2.RenderersFactory; | 28 | import com.google.android.exoplayer2.RenderersFactory; |
| @@ -72,7 +71,6 @@ public class DemoApplication extends BaseApplication { | @@ -72,7 +71,6 @@ public class DemoApplication extends BaseApplication { | ||
| 72 | private File downloadDirectory; | 71 | private File downloadDirectory; |
| 73 | private Cache downloadCache; | 72 | private Cache downloadCache; |
| 74 | private DownloadManager downloadManager; | 73 | private DownloadManager downloadManager; |
| 75 | - private DownloadTracker downloadTracker; | ||
| 76 | 74 | ||
| 77 | @Override | 75 | @Override |
| 78 | public void onCreate() { | 76 | public void onCreate() { |
| @@ -153,15 +151,7 @@ public class DemoApplication extends BaseApplication { | @@ -153,15 +151,7 @@ public class DemoApplication extends BaseApplication { | ||
| 153 | .setExtensionRendererMode(extensionRendererMode); | 151 | .setExtensionRendererMode(extensionRendererMode); |
| 154 | } | 152 | } |
| 155 | 153 | ||
| 156 | - public DownloadManager getDownloadManager() { | ||
| 157 | - initDownloadManager(); | ||
| 158 | - return downloadManager; | ||
| 159 | - } | ||
| 160 | 154 | ||
| 161 | - public DownloadTracker getDownloadTracker() { | ||
| 162 | - initDownloadManager(); | ||
| 163 | - return downloadTracker; | ||
| 164 | - } | ||
| 165 | 155 | ||
| 166 | protected synchronized Cache getDownloadCache() { | 156 | protected synchronized Cache getDownloadCache() { |
| 167 | if (downloadCache == null) { | 157 | if (downloadCache == null) { |
| @@ -172,23 +162,6 @@ public class DemoApplication extends BaseApplication { | @@ -172,23 +162,6 @@ public class DemoApplication extends BaseApplication { | ||
| 172 | return downloadCache; | 162 | return downloadCache; |
| 173 | } | 163 | } |
| 174 | 164 | ||
| 175 | - private synchronized void initDownloadManager() { | ||
| 176 | - if (downloadManager == null) { | ||
| 177 | - DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider()); | ||
| 178 | - upgradeActionFile( | ||
| 179 | - DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false); | ||
| 180 | - upgradeActionFile( | ||
| 181 | - DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ true); | ||
| 182 | - DownloaderConstructorHelper downloaderConstructorHelper = | ||
| 183 | - new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory()); | ||
| 184 | - downloadManager = | ||
| 185 | - new DownloadManager( | ||
| 186 | - this, downloadIndex, new DefaultDownloaderFactory(downloaderConstructorHelper)); | ||
| 187 | - downloadTracker = | ||
| 188 | - new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadManager); | ||
| 189 | - } | ||
| 190 | - } | ||
| 191 | - | ||
| 192 | private void upgradeActionFile( | 165 | private void upgradeActionFile( |
| 193 | String fileName, DefaultDownloadIndex downloadIndex, boolean addNewDownloadsAsCompleted) { | 166 | String fileName, DefaultDownloadIndex downloadIndex, boolean addNewDownloadsAsCompleted) { |
| 194 | try { | 167 | try { |
app/strike/src/main/java/com/cnlive/strike/demo/activity/DemoMvpActivity.java
| @@ -39,7 +39,6 @@ import com.cnlive.moudle.pedometer.commonInfo.CommonInfo; | @@ -39,7 +39,6 @@ import com.cnlive.moudle.pedometer.commonInfo.CommonInfo; | ||
| 39 | import com.cnlive.moudle.pedometer.ui.activity.RunLineActivity; | 39 | import com.cnlive.moudle.pedometer.ui.activity.RunLineActivity; |
| 40 | import com.cnlive.strike.demo.activity.presenter.DemoActivityPresenter; | 40 | import com.cnlive.strike.demo.activity.presenter.DemoActivityPresenter; |
| 41 | import com.cnlive.strike.demo.activity.view.DemoActivityView; | 41 | import com.cnlive.strike.demo.activity.view.DemoActivityView; |
| 42 | -import com.cnlive.strike.demo.exoplayer.demo.SampleChooserActivity; | ||
| 43 | import com.cnlive.strike.network.api.ApiService; | 42 | import com.cnlive.strike.network.api.ApiService; |
| 44 | import com.cnlive.strike.network.api.ApiTimeService; | 43 | import com.cnlive.strike.network.api.ApiTimeService; |
| 45 | import com.cnlive.strike.network.api.TimeServiceBean; | 44 | import com.cnlive.strike.network.api.TimeServiceBean; |
| @@ -434,8 +433,6 @@ public class DemoMvpActivity extends BaseActivity<DemoActivityView, DemoActivity | @@ -434,8 +433,6 @@ public class DemoMvpActivity extends BaseActivity<DemoActivityView, DemoActivity | ||
| 434 | binding.btnExoHome.setOnClickListener(new View.OnClickListener() { | 433 | binding.btnExoHome.setOnClickListener(new View.OnClickListener() { |
| 435 | @Override | 434 | @Override |
| 436 | public void onClick(View v) { | 435 | public void onClick(View v) { |
| 437 | - Intent intent=new Intent(me, SampleChooserActivity.class); | ||
| 438 | - startActivity(intent); | ||
| 439 | } | 436 | } |
| 440 | }); | 437 | }); |
| 441 | //获取uid | 438 | //获取uid |
app/strike/src/main/java/com/cnlive/strike/demo/activity/ExoPlayerActivity.java
| @@ -18,7 +18,9 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; | @@ -18,7 +18,9 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; | ||
| 18 | import com.google.android.exoplayer2.util.Util; | 18 | import com.google.android.exoplayer2.util.Util; |
| 19 | import com.google.android.exoplayer2.video.VideoListener; | 19 | import com.google.android.exoplayer2.video.VideoListener; |
| 20 | import com.libs.video.video.exoplayer.component.DefaultErrorView; | 20 | import com.libs.video.video.exoplayer.component.DefaultErrorView; |
| 21 | +import com.libs.video.video.exoplayer.component.DefaultYoukuPrepareView; | ||
| 21 | import com.libs.video.video.exoplayer.play.CNVideoView; | 22 | import com.libs.video.video.exoplayer.play.CNVideoView; |
| 23 | +import com.libs.video.video.test.CNLiveVideoView; | ||
| 22 | import com.libs.video.video.test.VideoPlayer; | 24 | import com.libs.video.video.test.VideoPlayer; |
| 23 | import com.libs.video.video.exoplayer.component.DefaultAdControlView; | 25 | import com.libs.video.video.exoplayer.component.DefaultAdControlView; |
| 24 | import com.libs.video.video.exoplayer.controller.StandardVideoController; | 26 | import com.libs.video.video.exoplayer.controller.StandardVideoController; |
| @@ -93,11 +95,13 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl | @@ -93,11 +95,13 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl | ||
| 93 | } | 95 | } |
| 94 | }); | 96 | }); |
| 95 | DefaultErrorView errorView=new DefaultErrorView(this); | 97 | DefaultErrorView errorView=new DefaultErrorView(this); |
| 96 | - mController.addControlComponent(adControlView, errorView); | 98 | + mController.addControlComponent(new DefaultYoukuPrepareView(me),errorView); |
| 97 | //直播 | 99 | //直播 |
| 98 | binding.playerView.setUrl("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8"); | 100 | binding.playerView.setUrl("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8"); |
| 99 | binding.playerView.setVideoController(mController); | 101 | binding.playerView.setVideoController(mController); |
| 102 | + binding.playerView.setScreenScaleType(CNVideoView.SCREEN_SCALE_16_9); | ||
| 100 | binding.playerView.start(); | 103 | binding.playerView.start(); |
| 104 | + | ||
| 101 | //监听播放结束 | 105 | //监听播放结束 |
| 102 | // binding.playerView.addOnStateChangeListener(new CNVideoView.SimpleOnStateChangeListener() { | 106 | // binding.playerView.addOnStateChangeListener(new CNVideoView.SimpleOnStateChangeListener() { |
| 103 | // @Override | 107 | // @Override |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/DemoDownloadService.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2017 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import android.app.Notification; | ||
| 19 | - | ||
| 20 | -import com.cnlive.cloud.R; | ||
| 21 | -import com.cnlive.strike.DemoApplication; | ||
| 22 | -import com.google.android.exoplayer2.offline.Download; | ||
| 23 | -import com.google.android.exoplayer2.offline.DownloadManager; | ||
| 24 | -import com.google.android.exoplayer2.offline.DownloadService; | ||
| 25 | -import com.google.android.exoplayer2.scheduler.PlatformScheduler; | ||
| 26 | -import com.google.android.exoplayer2.ui.DownloadNotificationHelper; | ||
| 27 | -import com.google.android.exoplayer2.util.NotificationUtil; | ||
| 28 | -import com.google.android.exoplayer2.util.Util; | ||
| 29 | -import java.util.List; | ||
| 30 | - | ||
| 31 | -/** A service for downloading media. */ | ||
| 32 | -public class DemoDownloadService extends DownloadService { | ||
| 33 | - | ||
| 34 | - private static final String CHANNEL_ID = "download_channel"; | ||
| 35 | - private static final int JOB_ID = 1; | ||
| 36 | - private static final int FOREGROUND_NOTIFICATION_ID = 1; | ||
| 37 | - | ||
| 38 | - private static int nextNotificationId = FOREGROUND_NOTIFICATION_ID + 1; | ||
| 39 | - | ||
| 40 | - private DownloadNotificationHelper notificationHelper; | ||
| 41 | - | ||
| 42 | - public DemoDownloadService() { | ||
| 43 | - super( | ||
| 44 | - FOREGROUND_NOTIFICATION_ID, | ||
| 45 | - DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL, | ||
| 46 | - CHANNEL_ID, | ||
| 47 | - R.string.exo_download_notification_channel_name, | ||
| 48 | - /* channelDescriptionResourceId= */ 0); | ||
| 49 | - nextNotificationId = FOREGROUND_NOTIFICATION_ID + 1; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - @Override | ||
| 53 | - public void onCreate() { | ||
| 54 | - super.onCreate(); | ||
| 55 | - notificationHelper = new DownloadNotificationHelper(this, CHANNEL_ID); | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - @Override | ||
| 59 | - protected DownloadManager getDownloadManager() { | ||
| 60 | - return ((DemoApplication) getApplication()).getDownloadManager(); | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - @Override | ||
| 64 | - protected PlatformScheduler getScheduler() { | ||
| 65 | - return Util.SDK_INT >= 21 ? new PlatformScheduler(this, JOB_ID) : null; | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - @Override | ||
| 69 | - protected Notification getForegroundNotification(List<Download> downloads) { | ||
| 70 | - return notificationHelper.buildProgressNotification( | ||
| 71 | - R.drawable.ic_download, /* contentIntent= */ null, /* message= */ null, downloads); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - @Override | ||
| 75 | - protected void onDownloadChanged(Download download) { | ||
| 76 | - Notification notification; | ||
| 77 | - if (download.state == Download.STATE_COMPLETED) { | ||
| 78 | - notification = | ||
| 79 | - notificationHelper.buildDownloadCompletedNotification( | ||
| 80 | - R.drawable.ic_download_done, | ||
| 81 | - /* contentIntent= */ null, | ||
| 82 | - Util.fromUtf8Bytes(download.request.data)); | ||
| 83 | - } else if (download.state == Download.STATE_FAILED) { | ||
| 84 | - notification = | ||
| 85 | - notificationHelper.buildDownloadFailedNotification( | ||
| 86 | - R.drawable.ic_download_done, | ||
| 87 | - /* contentIntent= */ null, | ||
| 88 | - Util.fromUtf8Bytes(download.request.data)); | ||
| 89 | - } else { | ||
| 90 | - return; | ||
| 91 | - } | ||
| 92 | - NotificationUtil.setNotification(this, nextNotificationId++, notification); | ||
| 93 | - } | ||
| 94 | -} |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/DownloadTracker.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2017 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import android.content.Context; | ||
| 19 | -import android.content.DialogInterface; | ||
| 20 | -import android.net.Uri; | ||
| 21 | -import android.widget.Toast; | ||
| 22 | -import androidx.annotation.Nullable; | ||
| 23 | -import androidx.fragment.app.FragmentManager; | ||
| 24 | - | ||
| 25 | -import com.cnlive.cloud.R; | ||
| 26 | -import com.google.android.exoplayer2.C; | ||
| 27 | -import com.google.android.exoplayer2.RenderersFactory; | ||
| 28 | -import com.google.android.exoplayer2.offline.Download; | ||
| 29 | -import com.google.android.exoplayer2.offline.DownloadCursor; | ||
| 30 | -import com.google.android.exoplayer2.offline.DownloadHelper; | ||
| 31 | -import com.google.android.exoplayer2.offline.DownloadIndex; | ||
| 32 | -import com.google.android.exoplayer2.offline.DownloadManager; | ||
| 33 | -import com.google.android.exoplayer2.offline.DownloadRequest; | ||
| 34 | -import com.google.android.exoplayer2.offline.DownloadService; | ||
| 35 | -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; | ||
| 36 | -import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; | ||
| 37 | -import com.google.android.exoplayer2.upstream.DataSource; | ||
| 38 | -import com.google.android.exoplayer2.util.Log; | ||
| 39 | -import com.google.android.exoplayer2.util.Util; | ||
| 40 | -import java.io.IOException; | ||
| 41 | -import java.util.HashMap; | ||
| 42 | -import java.util.concurrent.CopyOnWriteArraySet; | ||
| 43 | - | ||
| 44 | -/** Tracks media that has been downloaded. */ | ||
| 45 | -public class DownloadTracker { | ||
| 46 | - | ||
| 47 | - /** Listens for changes in the tracked downloads. */ | ||
| 48 | - public interface Listener { | ||
| 49 | - | ||
| 50 | - /** Called when the tracked downloads changed. */ | ||
| 51 | - void onDownloadsChanged(); | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - private static final String TAG = "DownloadTracker"; | ||
| 55 | - | ||
| 56 | - private final Context context; | ||
| 57 | - private final DataSource.Factory dataSourceFactory; | ||
| 58 | - private final CopyOnWriteArraySet<Listener> listeners; | ||
| 59 | - private final HashMap<Uri, Download> downloads; | ||
| 60 | - private final DownloadIndex downloadIndex; | ||
| 61 | - private final DefaultTrackSelector.Parameters trackSelectorParameters; | ||
| 62 | - | ||
| 63 | - @Nullable private StartDownloadDialogHelper startDownloadDialogHelper; | ||
| 64 | - | ||
| 65 | - public DownloadTracker( | ||
| 66 | - Context context, DataSource.Factory dataSourceFactory, DownloadManager downloadManager) { | ||
| 67 | - this.context = context.getApplicationContext(); | ||
| 68 | - this.dataSourceFactory = dataSourceFactory; | ||
| 69 | - listeners = new CopyOnWriteArraySet<>(); | ||
| 70 | - downloads = new HashMap<>(); | ||
| 71 | - downloadIndex = downloadManager.getDownloadIndex(); | ||
| 72 | - trackSelectorParameters = DownloadHelper.getDefaultTrackSelectorParameters(context); | ||
| 73 | - downloadManager.addListener(new DownloadManagerListener()); | ||
| 74 | - loadDownloads(); | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - public void addListener(Listener listener) { | ||
| 78 | - listeners.add(listener); | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - public void removeListener(Listener listener) { | ||
| 82 | - listeners.remove(listener); | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | - public boolean isDownloaded(Uri uri) { | ||
| 86 | - Download download = downloads.get(uri); | ||
| 87 | - return download != null && download.state != Download.STATE_FAILED; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - public DownloadRequest getDownloadRequest(Uri uri) { | ||
| 91 | - Download download = downloads.get(uri); | ||
| 92 | - return download != null && download.state != Download.STATE_FAILED ? download.request : null; | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - public void toggleDownload( | ||
| 96 | - FragmentManager fragmentManager, | ||
| 97 | - String name, | ||
| 98 | - Uri uri, | ||
| 99 | - String extension, | ||
| 100 | - RenderersFactory renderersFactory) { | ||
| 101 | - Download download = downloads.get(uri); | ||
| 102 | - if (download != null) { | ||
| 103 | - DownloadService.sendRemoveDownload( | ||
| 104 | - context, DemoDownloadService.class, download.request.id, /* foreground= */ false); | ||
| 105 | - } else { | ||
| 106 | - if (startDownloadDialogHelper != null) { | ||
| 107 | - startDownloadDialogHelper.release(); | ||
| 108 | - } | ||
| 109 | - startDownloadDialogHelper = | ||
| 110 | - new StartDownloadDialogHelper( | ||
| 111 | - fragmentManager, getDownloadHelper(uri, extension, renderersFactory), name); | ||
| 112 | - } | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | - private void loadDownloads() { | ||
| 116 | - try (DownloadCursor loadedDownloads = downloadIndex.getDownloads()) { | ||
| 117 | - while (loadedDownloads.moveToNext()) { | ||
| 118 | - Download download = loadedDownloads.getDownload(); | ||
| 119 | - downloads.put(download.request.uri, download); | ||
| 120 | - } | ||
| 121 | - } catch (IOException e) { | ||
| 122 | - Log.w(TAG, "Failed to query downloads", e); | ||
| 123 | - } | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - private DownloadHelper getDownloadHelper( | ||
| 127 | - Uri uri, String extension, RenderersFactory renderersFactory) { | ||
| 128 | - int type = Util.inferContentType(uri, extension); | ||
| 129 | - switch (type) { | ||
| 130 | - case C.TYPE_DASH: | ||
| 131 | - return DownloadHelper.forDash(context, uri, dataSourceFactory, renderersFactory); | ||
| 132 | - case C.TYPE_SS: | ||
| 133 | - return DownloadHelper.forSmoothStreaming(context, uri, dataSourceFactory, renderersFactory); | ||
| 134 | - case C.TYPE_HLS: | ||
| 135 | - return DownloadHelper.forHls(context, uri, dataSourceFactory, renderersFactory); | ||
| 136 | - case C.TYPE_OTHER: | ||
| 137 | - return DownloadHelper.forProgressive(context, uri); | ||
| 138 | - default: | ||
| 139 | - throw new IllegalStateException("Unsupported type: " + type); | ||
| 140 | - } | ||
| 141 | - } | ||
| 142 | - | ||
| 143 | - private class DownloadManagerListener implements DownloadManager.Listener { | ||
| 144 | - | ||
| 145 | - @Override | ||
| 146 | - public void onDownloadChanged(DownloadManager downloadManager, Download download) { | ||
| 147 | - downloads.put(download.request.uri, download); | ||
| 148 | - for (Listener listener : listeners) { | ||
| 149 | - listener.onDownloadsChanged(); | ||
| 150 | - } | ||
| 151 | - } | ||
| 152 | - | ||
| 153 | - @Override | ||
| 154 | - public void onDownloadRemoved(DownloadManager downloadManager, Download download) { | ||
| 155 | - downloads.remove(download.request.uri); | ||
| 156 | - for (Listener listener : listeners) { | ||
| 157 | - listener.onDownloadsChanged(); | ||
| 158 | - } | ||
| 159 | - } | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - private final class StartDownloadDialogHelper | ||
| 163 | - implements DownloadHelper.Callback, | ||
| 164 | - DialogInterface.OnClickListener, | ||
| 165 | - DialogInterface.OnDismissListener { | ||
| 166 | - | ||
| 167 | - private final FragmentManager fragmentManager; | ||
| 168 | - private final DownloadHelper downloadHelper; | ||
| 169 | - private final String name; | ||
| 170 | - | ||
| 171 | - private TrackSelectionDialog trackSelectionDialog; | ||
| 172 | - private MappedTrackInfo mappedTrackInfo; | ||
| 173 | - | ||
| 174 | - public StartDownloadDialogHelper( | ||
| 175 | - FragmentManager fragmentManager, DownloadHelper downloadHelper, String name) { | ||
| 176 | - this.fragmentManager = fragmentManager; | ||
| 177 | - this.downloadHelper = downloadHelper; | ||
| 178 | - this.name = name; | ||
| 179 | - downloadHelper.prepare(this); | ||
| 180 | - } | ||
| 181 | - | ||
| 182 | - public void release() { | ||
| 183 | - downloadHelper.release(); | ||
| 184 | - if (trackSelectionDialog != null) { | ||
| 185 | - trackSelectionDialog.dismiss(); | ||
| 186 | - } | ||
| 187 | - } | ||
| 188 | - | ||
| 189 | - // DownloadHelper.Callback implementation. | ||
| 190 | - | ||
| 191 | - @Override | ||
| 192 | - public void onPrepared(DownloadHelper helper) { | ||
| 193 | - if (helper.getPeriodCount() == 0) { | ||
| 194 | - Log.d(TAG, "No periods found. Downloading entire stream."); | ||
| 195 | - startDownload(); | ||
| 196 | - downloadHelper.release(); | ||
| 197 | - return; | ||
| 198 | - } | ||
| 199 | - mappedTrackInfo = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0); | ||
| 200 | - if (!TrackSelectionDialog.willHaveContent(mappedTrackInfo)) { | ||
| 201 | - Log.d(TAG, "No dialog content. Downloading entire stream."); | ||
| 202 | - startDownload(); | ||
| 203 | - downloadHelper.release(); | ||
| 204 | - return; | ||
| 205 | - } | ||
| 206 | - trackSelectionDialog = | ||
| 207 | - TrackSelectionDialog.createForMappedTrackInfoAndParameters( | ||
| 208 | - /* titleId= */ R.string.exo_download_description, | ||
| 209 | - mappedTrackInfo, | ||
| 210 | - trackSelectorParameters, | ||
| 211 | - /* allowAdaptiveSelections =*/ false, | ||
| 212 | - /* allowMultipleOverrides= */ true, | ||
| 213 | - /* onClickListener= */ this, | ||
| 214 | - /* onDismissListener= */ this); | ||
| 215 | - trackSelectionDialog.show(fragmentManager, /* tag= */ null); | ||
| 216 | - } | ||
| 217 | - | ||
| 218 | - @Override | ||
| 219 | - public void onPrepareError(DownloadHelper helper, IOException e) { | ||
| 220 | - Toast.makeText(context, R.string.download_start_error, Toast.LENGTH_LONG).show(); | ||
| 221 | - Log.e( | ||
| 222 | - TAG, | ||
| 223 | - e instanceof DownloadHelper.LiveContentUnsupportedException | ||
| 224 | - ? "Downloading live content unsupported" | ||
| 225 | - : "Failed to start download", | ||
| 226 | - e); | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - // DialogInterface.OnClickListener implementation. | ||
| 230 | - | ||
| 231 | - @Override | ||
| 232 | - public void onClick(DialogInterface dialog, int which) { | ||
| 233 | - for (int periodIndex = 0; periodIndex < downloadHelper.getPeriodCount(); periodIndex++) { | ||
| 234 | - downloadHelper.clearTrackSelections(periodIndex); | ||
| 235 | - for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) { | ||
| 236 | - if (!trackSelectionDialog.getIsDisabled(/* rendererIndex= */ i)) { | ||
| 237 | - downloadHelper.addTrackSelectionForSingleRenderer( | ||
| 238 | - periodIndex, | ||
| 239 | - /* rendererIndex= */ i, | ||
| 240 | - trackSelectorParameters, | ||
| 241 | - trackSelectionDialog.getOverrides(/* rendererIndex= */ i)); | ||
| 242 | - } | ||
| 243 | - } | ||
| 244 | - } | ||
| 245 | - DownloadRequest downloadRequest = buildDownloadRequest(); | ||
| 246 | - if (downloadRequest.streamKeys.isEmpty()) { | ||
| 247 | - // All tracks were deselected in the dialog. Don't start the download. | ||
| 248 | - return; | ||
| 249 | - } | ||
| 250 | - startDownload(downloadRequest); | ||
| 251 | - } | ||
| 252 | - | ||
| 253 | - // DialogInterface.OnDismissListener implementation. | ||
| 254 | - | ||
| 255 | - @Override | ||
| 256 | - public void onDismiss(DialogInterface dialogInterface) { | ||
| 257 | - trackSelectionDialog = null; | ||
| 258 | - downloadHelper.release(); | ||
| 259 | - } | ||
| 260 | - | ||
| 261 | - // Internal methods. | ||
| 262 | - | ||
| 263 | - private void startDownload() { | ||
| 264 | - startDownload(buildDownloadRequest()); | ||
| 265 | - } | ||
| 266 | - | ||
| 267 | - private void startDownload(DownloadRequest downloadRequest) { | ||
| 268 | - DownloadService.sendAddDownload( | ||
| 269 | - context, DemoDownloadService.class, downloadRequest, /* foreground= */ false); | ||
| 270 | - } | ||
| 271 | - | ||
| 272 | - private DownloadRequest buildDownloadRequest() { | ||
| 273 | - return downloadHelper.getDownloadRequest(Util.getUtf8Bytes(name)); | ||
| 274 | - } | ||
| 275 | - } | ||
| 276 | -} |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/PlayerActivity.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2016 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import android.content.Intent; | ||
| 19 | -import android.content.pm.PackageManager; | ||
| 20 | -import android.media.MediaDrm; | ||
| 21 | -import android.net.Uri; | ||
| 22 | -import android.os.Bundle; | ||
| 23 | -import android.util.Pair; | ||
| 24 | -import android.view.KeyEvent; | ||
| 25 | -import android.view.View; | ||
| 26 | -import android.view.View.OnClickListener; | ||
| 27 | -import android.widget.Button; | ||
| 28 | -import android.widget.LinearLayout; | ||
| 29 | -import android.widget.TextView; | ||
| 30 | -import android.widget.Toast; | ||
| 31 | -import androidx.annotation.NonNull; | ||
| 32 | -import androidx.annotation.Nullable; | ||
| 33 | -import androidx.appcompat.app.AppCompatActivity; | ||
| 34 | - | ||
| 35 | -import com.cnlive.cloud.R; | ||
| 36 | -import com.cnlive.strike.DemoApplication; | ||
| 37 | -import com.google.android.exoplayer2.C; | ||
| 38 | -import com.google.android.exoplayer2.C.ContentType; | ||
| 39 | -import com.google.android.exoplayer2.ExoPlaybackException; | ||
| 40 | -import com.google.android.exoplayer2.Format; | ||
| 41 | -import com.google.android.exoplayer2.PlaybackPreparer; | ||
| 42 | -import com.google.android.exoplayer2.Player; | ||
| 43 | -import com.google.android.exoplayer2.RenderersFactory; | ||
| 44 | -import com.google.android.exoplayer2.SimpleExoPlayer; | ||
| 45 | -import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; | ||
| 46 | -import com.google.android.exoplayer2.drm.DrmSessionManager; | ||
| 47 | -import com.google.android.exoplayer2.drm.ExoMediaCrypto; | ||
| 48 | -import com.google.android.exoplayer2.drm.FrameworkMediaDrm; | ||
| 49 | -import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; | ||
| 50 | -import com.google.android.exoplayer2.drm.MediaDrmCallback; | ||
| 51 | -import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException; | ||
| 52 | -import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; | ||
| 53 | -import com.google.android.exoplayer2.offline.DownloadHelper; | ||
| 54 | -import com.google.android.exoplayer2.offline.DownloadRequest; | ||
| 55 | -import com.google.android.exoplayer2.source.BehindLiveWindowException; | ||
| 56 | -import com.google.android.exoplayer2.source.ConcatenatingMediaSource; | ||
| 57 | -import com.google.android.exoplayer2.source.MediaSource; | ||
| 58 | -import com.google.android.exoplayer2.source.MediaSourceFactory; | ||
| 59 | -import com.google.android.exoplayer2.source.MergingMediaSource; | ||
| 60 | -import com.google.android.exoplayer2.source.ProgressiveMediaSource; | ||
| 61 | -import com.google.android.exoplayer2.source.SingleSampleMediaSource; | ||
| 62 | -import com.google.android.exoplayer2.source.TrackGroupArray; | ||
| 63 | -import com.google.android.exoplayer2.source.ads.AdsLoader; | ||
| 64 | -import com.google.android.exoplayer2.source.ads.AdsMediaSource; | ||
| 65 | -import com.google.android.exoplayer2.source.dash.DashMediaSource; | ||
| 66 | -import com.google.android.exoplayer2.source.hls.HlsMediaSource; | ||
| 67 | -import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; | ||
| 68 | -import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; | ||
| 69 | -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; | ||
| 70 | -import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; | ||
| 71 | -import com.google.android.exoplayer2.trackselection.RandomTrackSelection; | ||
| 72 | -import com.google.android.exoplayer2.trackselection.TrackSelection; | ||
| 73 | -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | ||
| 74 | -import com.google.android.exoplayer2.ui.DebugTextViewHelper; | ||
| 75 | -import com.google.android.exoplayer2.ui.PlayerControlView; | ||
| 76 | -import com.google.android.exoplayer2.ui.PlayerView; | ||
| 77 | -import com.google.android.exoplayer2.ui.spherical.SphericalGLSurfaceView; | ||
| 78 | -import com.google.android.exoplayer2.upstream.DataSource; | ||
| 79 | -import com.google.android.exoplayer2.upstream.HttpDataSource; | ||
| 80 | -import com.google.android.exoplayer2.util.ErrorMessageProvider; | ||
| 81 | -import com.google.android.exoplayer2.util.EventLogger; | ||
| 82 | -import com.google.android.exoplayer2.util.Util; | ||
| 83 | -import java.lang.reflect.Constructor; | ||
| 84 | -import java.net.CookieHandler; | ||
| 85 | -import java.net.CookieManager; | ||
| 86 | -import java.net.CookiePolicy; | ||
| 87 | - | ||
| 88 | -/** An activity that plays media using {@link SimpleExoPlayer}. */ | ||
| 89 | -public class PlayerActivity extends AppCompatActivity | ||
| 90 | - implements OnClickListener, PlaybackPreparer, PlayerControlView.VisibilityListener { | ||
| 91 | - | ||
| 92 | - // Activity extras. | ||
| 93 | - | ||
| 94 | - public static final String SPHERICAL_STEREO_MODE_EXTRA = "spherical_stereo_mode"; | ||
| 95 | - public static final String SPHERICAL_STEREO_MODE_MONO = "mono"; | ||
| 96 | - public static final String SPHERICAL_STEREO_MODE_TOP_BOTTOM = "top_bottom"; | ||
| 97 | - public static final String SPHERICAL_STEREO_MODE_LEFT_RIGHT = "left_right"; | ||
| 98 | - | ||
| 99 | - // Actions. | ||
| 100 | - | ||
| 101 | - public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW"; | ||
| 102 | - public static final String ACTION_VIEW_LIST = | ||
| 103 | - "com.google.android.exoplayer.demo.action.VIEW_LIST"; | ||
| 104 | - | ||
| 105 | - // Player configuration extras. | ||
| 106 | - | ||
| 107 | - public static final String ABR_ALGORITHM_EXTRA = "abr_algorithm"; | ||
| 108 | - public static final String ABR_ALGORITHM_DEFAULT = "default"; | ||
| 109 | - public static final String ABR_ALGORITHM_RANDOM = "random"; | ||
| 110 | - | ||
| 111 | - // Media item configuration extras. | ||
| 112 | - | ||
| 113 | - public static final String URI_EXTRA = "uri"; | ||
| 114 | - public static final String EXTENSION_EXTRA = "extension"; | ||
| 115 | - public static final String IS_LIVE_EXTRA = "is_live"; | ||
| 116 | - | ||
| 117 | - public static final String DRM_SCHEME_EXTRA = "drm_scheme"; | ||
| 118 | - public static final String DRM_LICENSE_URL_EXTRA = "drm_license_url"; | ||
| 119 | - public static final String DRM_KEY_REQUEST_PROPERTIES_EXTRA = "drm_key_request_properties"; | ||
| 120 | - public static final String DRM_MULTI_SESSION_EXTRA = "drm_multi_session"; | ||
| 121 | - public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders"; | ||
| 122 | - public static final String TUNNELING_EXTRA = "tunneling"; | ||
| 123 | - public static final String AD_TAG_URI_EXTRA = "ad_tag_uri"; | ||
| 124 | - public static final String SUBTITLE_URI_EXTRA = "subtitle_uri"; | ||
| 125 | - public static final String SUBTITLE_MIME_TYPE_EXTRA = "subtitle_mime_type"; | ||
| 126 | - public static final String SUBTITLE_LANGUAGE_EXTRA = "subtitle_language"; | ||
| 127 | - // For backwards compatibility only. | ||
| 128 | - public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid"; | ||
| 129 | - | ||
| 130 | - // Saved instance state keys. | ||
| 131 | - | ||
| 132 | - private static final String KEY_TRACK_SELECTOR_PARAMETERS = "track_selector_parameters"; | ||
| 133 | - private static final String KEY_WINDOW = "window"; | ||
| 134 | - private static final String KEY_POSITION = "position"; | ||
| 135 | - private static final String KEY_AUTO_PLAY = "auto_play"; | ||
| 136 | - | ||
| 137 | - private static final CookieManager DEFAULT_COOKIE_MANAGER; | ||
| 138 | - static { | ||
| 139 | - DEFAULT_COOKIE_MANAGER = new CookieManager(); | ||
| 140 | - DEFAULT_COOKIE_MANAGER.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); | ||
| 141 | - } | ||
| 142 | - | ||
| 143 | - private PlayerView playerView; | ||
| 144 | - private LinearLayout debugRootView; | ||
| 145 | - private Button selectTracksButton; | ||
| 146 | - private TextView debugTextView; | ||
| 147 | - private boolean isShowingTrackSelectionDialog; | ||
| 148 | - | ||
| 149 | - private DataSource.Factory dataSourceFactory; | ||
| 150 | - private SimpleExoPlayer player; | ||
| 151 | - private MediaSource mediaSource; | ||
| 152 | - private DefaultTrackSelector trackSelector; | ||
| 153 | - private DefaultTrackSelector.Parameters trackSelectorParameters; | ||
| 154 | - private DebugTextViewHelper debugViewHelper; | ||
| 155 | - private TrackGroupArray lastSeenTrackGroupArray; | ||
| 156 | - | ||
| 157 | - private boolean startAutoPlay; | ||
| 158 | - private int startWindow; | ||
| 159 | - private long startPosition; | ||
| 160 | - | ||
| 161 | - // Fields used only for ad playback. The ads loader is loaded via reflection. | ||
| 162 | - | ||
| 163 | - private AdsLoader adsLoader; | ||
| 164 | - private Uri loadedAdTagUri; | ||
| 165 | - | ||
| 166 | - // Activity lifecycle | ||
| 167 | - | ||
| 168 | - @Override | ||
| 169 | - public void onCreate(Bundle savedInstanceState) { | ||
| 170 | - Intent intent = getIntent(); | ||
| 171 | - String sphericalStereoMode = intent.getStringExtra(SPHERICAL_STEREO_MODE_EXTRA); | ||
| 172 | - if (sphericalStereoMode != null) { | ||
| 173 | - setTheme(R.style.PlayerTheme_Spherical); | ||
| 174 | - } | ||
| 175 | - super.onCreate(savedInstanceState); | ||
| 176 | - dataSourceFactory = buildDataSourceFactory(); | ||
| 177 | - if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) { | ||
| 178 | - CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER); | ||
| 179 | - } | ||
| 180 | - | ||
| 181 | - setContentView(R.layout.player_activity); | ||
| 182 | - debugRootView = findViewById(R.id.controls_root); | ||
| 183 | - debugTextView = findViewById(R.id.debug_text_view); | ||
| 184 | - selectTracksButton = findViewById(R.id.select_tracks_button); | ||
| 185 | - selectTracksButton.setOnClickListener(this); | ||
| 186 | - | ||
| 187 | - playerView = findViewById(R.id.player_view); | ||
| 188 | - playerView.setControllerVisibilityListener(this); | ||
| 189 | - playerView.setErrorMessageProvider(new PlayerErrorMessageProvider()); | ||
| 190 | - playerView.requestFocus(); | ||
| 191 | - if (sphericalStereoMode != null) { | ||
| 192 | - int stereoMode; | ||
| 193 | - if (SPHERICAL_STEREO_MODE_MONO.equals(sphericalStereoMode)) { | ||
| 194 | - stereoMode = C.STEREO_MODE_MONO; | ||
| 195 | - } else if (SPHERICAL_STEREO_MODE_TOP_BOTTOM.equals(sphericalStereoMode)) { | ||
| 196 | - stereoMode = C.STEREO_MODE_TOP_BOTTOM; | ||
| 197 | - } else if (SPHERICAL_STEREO_MODE_LEFT_RIGHT.equals(sphericalStereoMode)) { | ||
| 198 | - stereoMode = C.STEREO_MODE_LEFT_RIGHT; | ||
| 199 | - } else { | ||
| 200 | - showToast(R.string.error_unrecognized_stereo_mode); | ||
| 201 | - finish(); | ||
| 202 | - return; | ||
| 203 | - } | ||
| 204 | - ((SphericalGLSurfaceView) playerView.getVideoSurfaceView()).setDefaultStereoMode(stereoMode); | ||
| 205 | - } | ||
| 206 | - | ||
| 207 | - if (savedInstanceState != null) { | ||
| 208 | - trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS); | ||
| 209 | - startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY); | ||
| 210 | - startWindow = savedInstanceState.getInt(KEY_WINDOW); | ||
| 211 | - startPosition = savedInstanceState.getLong(KEY_POSITION); | ||
| 212 | - } else { | ||
| 213 | - DefaultTrackSelector.ParametersBuilder builder = | ||
| 214 | - new DefaultTrackSelector.ParametersBuilder(/* context= */ this); | ||
| 215 | - boolean tunneling = intent.getBooleanExtra(TUNNELING_EXTRA, false); | ||
| 216 | - if (Util.SDK_INT >= 21 && tunneling) { | ||
| 217 | - builder.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(/* context= */ this)); | ||
| 218 | - } | ||
| 219 | - trackSelectorParameters = builder.build(); | ||
| 220 | - clearStartPosition(); | ||
| 221 | - } | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - @Override | ||
| 225 | - public void onNewIntent(Intent intent) { | ||
| 226 | - super.onNewIntent(intent); | ||
| 227 | - releasePlayer(); | ||
| 228 | - releaseAdsLoader(); | ||
| 229 | - clearStartPosition(); | ||
| 230 | - setIntent(intent); | ||
| 231 | - } | ||
| 232 | - | ||
| 233 | - @Override | ||
| 234 | - public void onStart() { | ||
| 235 | - super.onStart(); | ||
| 236 | - if (Util.SDK_INT > 23) { | ||
| 237 | - initializePlayer(); | ||
| 238 | - if (playerView != null) { | ||
| 239 | - playerView.onResume(); | ||
| 240 | - } | ||
| 241 | - } | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - @Override | ||
| 245 | - public void onResume() { | ||
| 246 | - super.onResume(); | ||
| 247 | - if (Util.SDK_INT <= 23 || player == null) { | ||
| 248 | - initializePlayer(); | ||
| 249 | - if (playerView != null) { | ||
| 250 | - playerView.onResume(); | ||
| 251 | - } | ||
| 252 | - } | ||
| 253 | - } | ||
| 254 | - | ||
| 255 | - @Override | ||
| 256 | - public void onPause() { | ||
| 257 | - super.onPause(); | ||
| 258 | - if (Util.SDK_INT <= 23) { | ||
| 259 | - if (playerView != null) { | ||
| 260 | - playerView.onPause(); | ||
| 261 | - } | ||
| 262 | - releasePlayer(); | ||
| 263 | - } | ||
| 264 | - } | ||
| 265 | - | ||
| 266 | - @Override | ||
| 267 | - public void onStop() { | ||
| 268 | - super.onStop(); | ||
| 269 | - if (Util.SDK_INT > 23) { | ||
| 270 | - if (playerView != null) { | ||
| 271 | - playerView.onPause(); | ||
| 272 | - } | ||
| 273 | - releasePlayer(); | ||
| 274 | - } | ||
| 275 | - } | ||
| 276 | - | ||
| 277 | - @Override | ||
| 278 | - public void onDestroy() { | ||
| 279 | - super.onDestroy(); | ||
| 280 | - releaseAdsLoader(); | ||
| 281 | - } | ||
| 282 | - | ||
| 283 | - @Override | ||
| 284 | - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||
| 285 | - @NonNull int[] grantResults) { | ||
| 286 | - if (grantResults.length == 0) { | ||
| 287 | - // Empty results are triggered if a permission is requested while another request was already | ||
| 288 | - // pending and can be safely ignored in this case. | ||
| 289 | - return; | ||
| 290 | - } | ||
| 291 | - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||
| 292 | - initializePlayer(); | ||
| 293 | - } else { | ||
| 294 | - showToast(R.string.storage_permission_denied); | ||
| 295 | - finish(); | ||
| 296 | - } | ||
| 297 | - } | ||
| 298 | - | ||
| 299 | - @Override | ||
| 300 | - public void onSaveInstanceState(Bundle outState) { | ||
| 301 | - super.onSaveInstanceState(outState); | ||
| 302 | - updateTrackSelectorParameters(); | ||
| 303 | - updateStartPosition(); | ||
| 304 | - outState.putParcelable(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters); | ||
| 305 | - outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay); | ||
| 306 | - outState.putInt(KEY_WINDOW, startWindow); | ||
| 307 | - outState.putLong(KEY_POSITION, startPosition); | ||
| 308 | - } | ||
| 309 | - | ||
| 310 | - // Activity input | ||
| 311 | - | ||
| 312 | - @Override | ||
| 313 | - public boolean dispatchKeyEvent(KeyEvent event) { | ||
| 314 | - // See whether the player view wants to handle media or DPAD keys events. | ||
| 315 | - return playerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - // OnClickListener methods | ||
| 319 | - | ||
| 320 | - @Override | ||
| 321 | - public void onClick(View view) { | ||
| 322 | - if (view == selectTracksButton | ||
| 323 | - && !isShowingTrackSelectionDialog | ||
| 324 | - && TrackSelectionDialog.willHaveContent(trackSelector)) { | ||
| 325 | - isShowingTrackSelectionDialog = true; | ||
| 326 | - TrackSelectionDialog trackSelectionDialog = | ||
| 327 | - TrackSelectionDialog.createForTrackSelector( | ||
| 328 | - trackSelector, | ||
| 329 | - /* onDismissListener= */ dismissedDialog -> isShowingTrackSelectionDialog = false); | ||
| 330 | - trackSelectionDialog.show(getSupportFragmentManager(), /* tag= */ null); | ||
| 331 | - } | ||
| 332 | - } | ||
| 333 | - | ||
| 334 | - // PlaybackControlView.PlaybackPreparer implementation | ||
| 335 | - | ||
| 336 | - @Override | ||
| 337 | - public void preparePlayback() { | ||
| 338 | - player.retry(); | ||
| 339 | - } | ||
| 340 | - | ||
| 341 | - // PlaybackControlView.VisibilityListener implementation | ||
| 342 | - | ||
| 343 | - @Override | ||
| 344 | - public void onVisibilityChange(int visibility) { | ||
| 345 | - debugRootView.setVisibility(visibility); | ||
| 346 | - } | ||
| 347 | - | ||
| 348 | - // Internal methods | ||
| 349 | - | ||
| 350 | - private void initializePlayer() { | ||
| 351 | - if (player == null) { | ||
| 352 | - Intent intent = getIntent(); | ||
| 353 | - | ||
| 354 | - mediaSource = createTopLevelMediaSource(intent); | ||
| 355 | - if (mediaSource == null) { | ||
| 356 | - return; | ||
| 357 | - } | ||
| 358 | - | ||
| 359 | - TrackSelection.Factory trackSelectionFactory; | ||
| 360 | - String abrAlgorithm = intent.getStringExtra(ABR_ALGORITHM_EXTRA); | ||
| 361 | - if (abrAlgorithm == null || ABR_ALGORITHM_DEFAULT.equals(abrAlgorithm)) { | ||
| 362 | - trackSelectionFactory = new AdaptiveTrackSelection.Factory(); | ||
| 363 | - } else if (ABR_ALGORITHM_RANDOM.equals(abrAlgorithm)) { | ||
| 364 | - trackSelectionFactory = new RandomTrackSelection.Factory(); | ||
| 365 | - } else { | ||
| 366 | - showToast(R.string.error_unrecognized_abr_algorithm); | ||
| 367 | - finish(); | ||
| 368 | - return; | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - boolean preferExtensionDecoders = | ||
| 372 | - intent.getBooleanExtra(PREFER_EXTENSION_DECODERS_EXTRA, false); | ||
| 373 | - RenderersFactory renderersFactory = | ||
| 374 | - ((DemoApplication) getApplication()).buildRenderersFactory(preferExtensionDecoders); | ||
| 375 | - | ||
| 376 | - trackSelector = new DefaultTrackSelector(/* context= */ this, trackSelectionFactory); | ||
| 377 | - trackSelector.setParameters(trackSelectorParameters); | ||
| 378 | - lastSeenTrackGroupArray = null; | ||
| 379 | - | ||
| 380 | - player = | ||
| 381 | - new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) | ||
| 382 | - .setTrackSelector(trackSelector) | ||
| 383 | - .build(); | ||
| 384 | - player.addListener(new PlayerEventListener()); | ||
| 385 | - player.setPlayWhenReady(startAutoPlay); | ||
| 386 | - player.addAnalyticsListener(new EventLogger(trackSelector)); | ||
| 387 | - playerView.setPlayer(player); | ||
| 388 | - playerView.setPlaybackPreparer(this); | ||
| 389 | - debugViewHelper = new DebugTextViewHelper(player, debugTextView); | ||
| 390 | - debugViewHelper.start(); | ||
| 391 | - if (adsLoader != null) { | ||
| 392 | - adsLoader.setPlayer(player); | ||
| 393 | - } | ||
| 394 | - } | ||
| 395 | - boolean haveStartPosition = startWindow != C.INDEX_UNSET; | ||
| 396 | - if (haveStartPosition) { | ||
| 397 | - player.seekTo(startWindow, startPosition); | ||
| 398 | - } | ||
| 399 | - player.prepare(mediaSource, !haveStartPosition, false); | ||
| 400 | - updateButtonVisibility(); | ||
| 401 | - } | ||
| 402 | - | ||
| 403 | - @Nullable | ||
| 404 | - private MediaSource createTopLevelMediaSource(Intent intent) { | ||
| 405 | - String action = intent.getAction(); | ||
| 406 | - boolean actionIsListView = ACTION_VIEW_LIST.equals(action); | ||
| 407 | - if (!actionIsListView && !ACTION_VIEW.equals(action)) { | ||
| 408 | - showToast(getString(R.string.unexpected_intent_action, action)); | ||
| 409 | - finish(); | ||
| 410 | - return null; | ||
| 411 | - } | ||
| 412 | - | ||
| 413 | - Sample intentAsSample = Sample.createFromIntent(intent); | ||
| 414 | - Sample.UriSample[] samples = | ||
| 415 | - intentAsSample instanceof Sample.PlaylistSample | ||
| 416 | - ? ((Sample.PlaylistSample) intentAsSample).children | ||
| 417 | - : new Sample.UriSample[] {(Sample.UriSample) intentAsSample}; | ||
| 418 | - | ||
| 419 | - boolean seenAdsTagUri = false; | ||
| 420 | - for (Sample.UriSample sample : samples) { | ||
| 421 | - seenAdsTagUri |= sample.adTagUri != null; | ||
| 422 | - if (!Util.checkCleartextTrafficPermitted(sample.uri)) { | ||
| 423 | - showToast(R.string.error_cleartext_not_permitted); | ||
| 424 | - return null; | ||
| 425 | - } | ||
| 426 | - if (Util.maybeRequestReadExternalStoragePermission(/* activity= */ this, sample.uri)) { | ||
| 427 | - // The player will be reinitialized if the permission is granted. | ||
| 428 | - return null; | ||
| 429 | - } | ||
| 430 | - } | ||
| 431 | - | ||
| 432 | - MediaSource[] mediaSources = new MediaSource[samples.length]; | ||
| 433 | - for (int i = 0; i < samples.length; i++) { | ||
| 434 | - mediaSources[i] = createLeafMediaSource(samples[i]); | ||
| 435 | - Sample.SubtitleInfo subtitleInfo = samples[i].subtitleInfo; | ||
| 436 | - if (subtitleInfo != null) { | ||
| 437 | - Format subtitleFormat = | ||
| 438 | - Format.createTextSampleFormat( | ||
| 439 | - /* id= */ null, | ||
| 440 | - subtitleInfo.mimeType, | ||
| 441 | - C.SELECTION_FLAG_DEFAULT, | ||
| 442 | - subtitleInfo.language); | ||
| 443 | - MediaSource subtitleMediaSource = | ||
| 444 | - new SingleSampleMediaSource.Factory(dataSourceFactory) | ||
| 445 | - .createMediaSource(subtitleInfo.uri, subtitleFormat, C.TIME_UNSET); | ||
| 446 | - mediaSources[i] = new MergingMediaSource(mediaSources[i], subtitleMediaSource); | ||
| 447 | - } | ||
| 448 | - } | ||
| 449 | - MediaSource mediaSource = | ||
| 450 | - mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources); | ||
| 451 | - | ||
| 452 | - if (seenAdsTagUri) { | ||
| 453 | - Uri adTagUri = samples[0].adTagUri; | ||
| 454 | - if (actionIsListView) { | ||
| 455 | - showToast(R.string.unsupported_ads_in_concatenation); | ||
| 456 | - } else { | ||
| 457 | - if (!adTagUri.equals(loadedAdTagUri)) { | ||
| 458 | - releaseAdsLoader(); | ||
| 459 | - loadedAdTagUri = adTagUri; | ||
| 460 | - } | ||
| 461 | - MediaSource adsMediaSource = createAdsMediaSource(mediaSource, adTagUri); | ||
| 462 | - if (adsMediaSource != null) { | ||
| 463 | - mediaSource = adsMediaSource; | ||
| 464 | - } else { | ||
| 465 | - showToast(R.string.ima_not_loaded); | ||
| 466 | - } | ||
| 467 | - } | ||
| 468 | - } else { | ||
| 469 | - releaseAdsLoader(); | ||
| 470 | - } | ||
| 471 | - | ||
| 472 | - return mediaSource; | ||
| 473 | - } | ||
| 474 | - | ||
| 475 | - private MediaSource createLeafMediaSource(Sample.UriSample parameters) { | ||
| 476 | - Sample.DrmInfo drmInfo = parameters.drmInfo; | ||
| 477 | - int errorStringId = R.string.error_drm_unknown; | ||
| 478 | - DrmSessionManager<ExoMediaCrypto> drmSessionManager = null; | ||
| 479 | - if (drmInfo == null) { | ||
| 480 | - drmSessionManager = DrmSessionManager.getDummyDrmSessionManager(); | ||
| 481 | - } else if (Util.SDK_INT < 18) { | ||
| 482 | - errorStringId = R.string.error_drm_unsupported_before_api_18; | ||
| 483 | - } else if (!MediaDrm.isCryptoSchemeSupported(drmInfo.drmScheme)) { | ||
| 484 | - errorStringId = R.string.error_drm_unsupported_scheme; | ||
| 485 | - } else { | ||
| 486 | - MediaDrmCallback mediaDrmCallback = | ||
| 487 | - createMediaDrmCallback(drmInfo.drmLicenseUrl, drmInfo.drmKeyRequestProperties); | ||
| 488 | - drmSessionManager = | ||
| 489 | - new DefaultDrmSessionManager.Builder() | ||
| 490 | - .setUuidAndExoMediaDrmProvider(drmInfo.drmScheme, FrameworkMediaDrm.DEFAULT_PROVIDER) | ||
| 491 | - .setMultiSession(drmInfo.drmMultiSession) | ||
| 492 | - .build(mediaDrmCallback); | ||
| 493 | - } | ||
| 494 | - | ||
| 495 | - if (drmSessionManager == null) { | ||
| 496 | - showToast(errorStringId); | ||
| 497 | - finish(); | ||
| 498 | - return null; | ||
| 499 | - } | ||
| 500 | - | ||
| 501 | - DownloadRequest downloadRequest = | ||
| 502 | - ((DemoApplication) getApplication()) | ||
| 503 | - .getDownloadTracker() | ||
| 504 | - .getDownloadRequest(parameters.uri); | ||
| 505 | - if (downloadRequest != null) { | ||
| 506 | - return DownloadHelper.createMediaSource(downloadRequest, dataSourceFactory); | ||
| 507 | - } | ||
| 508 | - return createLeafMediaSource(parameters.uri, parameters.extension, drmSessionManager); | ||
| 509 | - } | ||
| 510 | - | ||
| 511 | - private MediaSource createLeafMediaSource( | ||
| 512 | - Uri uri, String extension, DrmSessionManager<ExoMediaCrypto> drmSessionManager) { | ||
| 513 | - @ContentType int type = Util.inferContentType(uri, extension); | ||
| 514 | - switch (type) { | ||
| 515 | - case C.TYPE_DASH: | ||
| 516 | - return new DashMediaSource.Factory(dataSourceFactory) | ||
| 517 | - .setDrmSessionManager(drmSessionManager) | ||
| 518 | - .createMediaSource(uri); | ||
| 519 | - case C.TYPE_SS: | ||
| 520 | - return new SsMediaSource.Factory(dataSourceFactory) | ||
| 521 | - .setDrmSessionManager(drmSessionManager) | ||
| 522 | - .createMediaSource(uri); | ||
| 523 | - case C.TYPE_HLS: | ||
| 524 | - return new HlsMediaSource.Factory(dataSourceFactory) | ||
| 525 | - .setDrmSessionManager(drmSessionManager) | ||
| 526 | - .createMediaSource(uri); | ||
| 527 | - case C.TYPE_OTHER: | ||
| 528 | - return new ProgressiveMediaSource.Factory(dataSourceFactory) | ||
| 529 | - .setDrmSessionManager(drmSessionManager) | ||
| 530 | - .createMediaSource(uri); | ||
| 531 | - default: | ||
| 532 | - throw new IllegalStateException("Unsupported type: " + type); | ||
| 533 | - } | ||
| 534 | - } | ||
| 535 | - | ||
| 536 | - private HttpMediaDrmCallback createMediaDrmCallback( | ||
| 537 | - String licenseUrl, String[] keyRequestPropertiesArray) { | ||
| 538 | - HttpDataSource.Factory licenseDataSourceFactory = | ||
| 539 | - ((DemoApplication) getApplication()).buildHttpDataSourceFactory(); | ||
| 540 | - HttpMediaDrmCallback drmCallback = | ||
| 541 | - new HttpMediaDrmCallback(licenseUrl, licenseDataSourceFactory); | ||
| 542 | - if (keyRequestPropertiesArray != null) { | ||
| 543 | - for (int i = 0; i < keyRequestPropertiesArray.length - 1; i += 2) { | ||
| 544 | - drmCallback.setKeyRequestProperty(keyRequestPropertiesArray[i], | ||
| 545 | - keyRequestPropertiesArray[i + 1]); | ||
| 546 | - } | ||
| 547 | - } | ||
| 548 | - return drmCallback; | ||
| 549 | - } | ||
| 550 | - | ||
| 551 | - private void releasePlayer() { | ||
| 552 | - if (player != null) { | ||
| 553 | - updateTrackSelectorParameters(); | ||
| 554 | - updateStartPosition(); | ||
| 555 | - debugViewHelper.stop(); | ||
| 556 | - debugViewHelper = null; | ||
| 557 | - player.release(); | ||
| 558 | - player = null; | ||
| 559 | - mediaSource = null; | ||
| 560 | - trackSelector = null; | ||
| 561 | - } | ||
| 562 | - if (adsLoader != null) { | ||
| 563 | - adsLoader.setPlayer(null); | ||
| 564 | - } | ||
| 565 | - } | ||
| 566 | - | ||
| 567 | - private void releaseAdsLoader() { | ||
| 568 | - if (adsLoader != null) { | ||
| 569 | - adsLoader.release(); | ||
| 570 | - adsLoader = null; | ||
| 571 | - loadedAdTagUri = null; | ||
| 572 | - playerView.getOverlayFrameLayout().removeAllViews(); | ||
| 573 | - } | ||
| 574 | - } | ||
| 575 | - | ||
| 576 | - private void updateTrackSelectorParameters() { | ||
| 577 | - if (trackSelector != null) { | ||
| 578 | - trackSelectorParameters = trackSelector.getParameters(); | ||
| 579 | - } | ||
| 580 | - } | ||
| 581 | - | ||
| 582 | - private void updateStartPosition() { | ||
| 583 | - if (player != null) { | ||
| 584 | - startAutoPlay = player.getPlayWhenReady(); | ||
| 585 | - startWindow = player.getCurrentWindowIndex(); | ||
| 586 | - startPosition = Math.max(0, player.getContentPosition()); | ||
| 587 | - } | ||
| 588 | - } | ||
| 589 | - | ||
| 590 | - private void clearStartPosition() { | ||
| 591 | - startAutoPlay = true; | ||
| 592 | - startWindow = C.INDEX_UNSET; | ||
| 593 | - startPosition = C.TIME_UNSET; | ||
| 594 | - } | ||
| 595 | - | ||
| 596 | - /** Returns a new DataSource factory. */ | ||
| 597 | - private DataSource.Factory buildDataSourceFactory() { | ||
| 598 | - return ((DemoApplication) getApplication()).buildDataSourceFactory(); | ||
| 599 | - } | ||
| 600 | - | ||
| 601 | - /** Returns an ads media source, reusing the ads loader if one exists. */ | ||
| 602 | - @Nullable | ||
| 603 | - private MediaSource createAdsMediaSource(MediaSource mediaSource, Uri adTagUri) { | ||
| 604 | - // Load the extension source using reflection so the demo app doesn't have to depend on it. | ||
| 605 | - // The ads loader is reused for multiple playbacks, so that ad playback can resume. | ||
| 606 | - try { | ||
| 607 | - Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader"); | ||
| 608 | - if (adsLoader == null) { | ||
| 609 | - // Full class names used so the LINT.IfChange rule triggers should any of the classes move. | ||
| 610 | - // LINT.IfChange | ||
| 611 | - Constructor<? extends AdsLoader> loaderConstructor = | ||
| 612 | - loaderClass | ||
| 613 | - .asSubclass(AdsLoader.class) | ||
| 614 | - .getConstructor(android.content.Context.class, Uri.class); | ||
| 615 | - // LINT.ThenChange(../../../../../../../../proguard-rules.txt) | ||
| 616 | - adsLoader = loaderConstructor.newInstance(this, adTagUri); | ||
| 617 | - } | ||
| 618 | - MediaSourceFactory adMediaSourceFactory = | ||
| 619 | - new MediaSourceFactory() { | ||
| 620 | - @Override | ||
| 621 | - public MediaSource createMediaSource(Uri uri) { | ||
| 622 | - return PlayerActivity.this.createLeafMediaSource( | ||
| 623 | - uri, /* extension=*/ null, DrmSessionManager.getDummyDrmSessionManager()); | ||
| 624 | - } | ||
| 625 | - | ||
| 626 | - @Override | ||
| 627 | - public int[] getSupportedTypes() { | ||
| 628 | - return new int[] {C.TYPE_DASH, C.TYPE_SS, C.TYPE_HLS, C.TYPE_OTHER}; | ||
| 629 | - } | ||
| 630 | - }; | ||
| 631 | - return new AdsMediaSource(mediaSource, adMediaSourceFactory, adsLoader, playerView); | ||
| 632 | - } catch (ClassNotFoundException e) { | ||
| 633 | - // IMA extension not loaded. | ||
| 634 | - return null; | ||
| 635 | - } catch (Exception e) { | ||
| 636 | - throw new RuntimeException(e); | ||
| 637 | - } | ||
| 638 | - } | ||
| 639 | - | ||
| 640 | - // User controls | ||
| 641 | - | ||
| 642 | - private void updateButtonVisibility() { | ||
| 643 | - selectTracksButton.setEnabled( | ||
| 644 | - player != null && TrackSelectionDialog.willHaveContent(trackSelector)); | ||
| 645 | - } | ||
| 646 | - | ||
| 647 | - private void showControls() { | ||
| 648 | - debugRootView.setVisibility(View.VISIBLE); | ||
| 649 | - } | ||
| 650 | - | ||
| 651 | - private void showToast(int messageId) { | ||
| 652 | - showToast(getString(messageId)); | ||
| 653 | - } | ||
| 654 | - | ||
| 655 | - private void showToast(String message) { | ||
| 656 | - Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); | ||
| 657 | - } | ||
| 658 | - | ||
| 659 | - private static boolean isBehindLiveWindow(ExoPlaybackException e) { | ||
| 660 | - if (e.type != ExoPlaybackException.TYPE_SOURCE) { | ||
| 661 | - return false; | ||
| 662 | - } | ||
| 663 | - Throwable cause = e.getSourceException(); | ||
| 664 | - while (cause != null) { | ||
| 665 | - if (cause instanceof BehindLiveWindowException) { | ||
| 666 | - return true; | ||
| 667 | - } | ||
| 668 | - cause = cause.getCause(); | ||
| 669 | - } | ||
| 670 | - return false; | ||
| 671 | - } | ||
| 672 | - | ||
| 673 | - private class PlayerEventListener implements Player.EventListener { | ||
| 674 | - | ||
| 675 | - @Override | ||
| 676 | - public void onPlayerStateChanged(boolean playWhenReady, @Player.State int playbackState) { | ||
| 677 | - if (playbackState == Player.STATE_ENDED) { | ||
| 678 | - showControls(); | ||
| 679 | - } | ||
| 680 | - updateButtonVisibility(); | ||
| 681 | - } | ||
| 682 | - | ||
| 683 | - @Override | ||
| 684 | - public void onPlayerError(ExoPlaybackException e) { | ||
| 685 | - if (isBehindLiveWindow(e)) { | ||
| 686 | - clearStartPosition(); | ||
| 687 | - initializePlayer(); | ||
| 688 | - } else { | ||
| 689 | - updateButtonVisibility(); | ||
| 690 | - showControls(); | ||
| 691 | - } | ||
| 692 | - } | ||
| 693 | - | ||
| 694 | - @Override | ||
| 695 | - @SuppressWarnings("ReferenceEquality") | ||
| 696 | - public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { | ||
| 697 | - updateButtonVisibility(); | ||
| 698 | - if (trackGroups != lastSeenTrackGroupArray) { | ||
| 699 | - MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); | ||
| 700 | - if (mappedTrackInfo != null) { | ||
| 701 | - if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO) | ||
| 702 | - == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { | ||
| 703 | - showToast(R.string.error_unsupported_video); | ||
| 704 | - } | ||
| 705 | - if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO) | ||
| 706 | - == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { | ||
| 707 | - showToast(R.string.error_unsupported_audio); | ||
| 708 | - } | ||
| 709 | - } | ||
| 710 | - lastSeenTrackGroupArray = trackGroups; | ||
| 711 | - } | ||
| 712 | - } | ||
| 713 | - } | ||
| 714 | - | ||
| 715 | - private class PlayerErrorMessageProvider implements ErrorMessageProvider<ExoPlaybackException> { | ||
| 716 | - | ||
| 717 | - @Override | ||
| 718 | - public Pair<Integer, String> getErrorMessage(ExoPlaybackException e) { | ||
| 719 | - String errorString = getString(R.string.error_generic); | ||
| 720 | - if (e.type == ExoPlaybackException.TYPE_RENDERER) { | ||
| 721 | - Exception cause = e.getRendererException(); | ||
| 722 | - if (cause instanceof DecoderInitializationException) { | ||
| 723 | - // Special case for decoder initialization failures. | ||
| 724 | - DecoderInitializationException decoderInitializationException = | ||
| 725 | - (DecoderInitializationException) cause; | ||
| 726 | - if (decoderInitializationException.codecInfo == null) { | ||
| 727 | - if (decoderInitializationException.getCause() instanceof DecoderQueryException) { | ||
| 728 | - errorString = getString(R.string.error_querying_decoders); | ||
| 729 | - } else if (decoderInitializationException.secureDecoderRequired) { | ||
| 730 | - errorString = | ||
| 731 | - getString( | ||
| 732 | - R.string.error_no_secure_decoder, decoderInitializationException.mimeType); | ||
| 733 | - } else { | ||
| 734 | - errorString = | ||
| 735 | - getString(R.string.error_no_decoder, decoderInitializationException.mimeType); | ||
| 736 | - } | ||
| 737 | - } else { | ||
| 738 | - errorString = | ||
| 739 | - getString( | ||
| 740 | - R.string.error_instantiating_decoder, | ||
| 741 | - decoderInitializationException.codecInfo.name); | ||
| 742 | - } | ||
| 743 | - } | ||
| 744 | - } | ||
| 745 | - return Pair.create(0, errorString); | ||
| 746 | - } | ||
| 747 | - } | ||
| 748 | -} |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/Sample.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2019 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.ACTION_VIEW_LIST; | ||
| 19 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.AD_TAG_URI_EXTRA; | ||
| 20 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.DRM_KEY_REQUEST_PROPERTIES_EXTRA; | ||
| 21 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.DRM_LICENSE_URL_EXTRA; | ||
| 22 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.DRM_MULTI_SESSION_EXTRA; | ||
| 23 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.DRM_SCHEME_EXTRA; | ||
| 24 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.DRM_SCHEME_UUID_EXTRA; | ||
| 25 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.EXTENSION_EXTRA; | ||
| 26 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.IS_LIVE_EXTRA; | ||
| 27 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.SUBTITLE_LANGUAGE_EXTRA; | ||
| 28 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.SUBTITLE_MIME_TYPE_EXTRA; | ||
| 29 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.SUBTITLE_URI_EXTRA; | ||
| 30 | -import static com.cnlive.strike.demo.exoplayer.demo.PlayerActivity.URI_EXTRA; | ||
| 31 | - | ||
| 32 | -import android.content.Intent; | ||
| 33 | -import android.net.Uri; | ||
| 34 | -import androidx.annotation.Nullable; | ||
| 35 | -import com.google.android.exoplayer2.util.Assertions; | ||
| 36 | -import com.google.android.exoplayer2.util.Util; | ||
| 37 | -import java.util.ArrayList; | ||
| 38 | -import java.util.UUID; | ||
| 39 | - | ||
| 40 | -/* package */public abstract class Sample { | ||
| 41 | - | ||
| 42 | - public static final class UriSample extends Sample { | ||
| 43 | - | ||
| 44 | - public static UriSample createFromIntent(Uri uri, Intent intent, String extrasKeySuffix) { | ||
| 45 | - String extension = intent.getStringExtra(EXTENSION_EXTRA + extrasKeySuffix); | ||
| 46 | - String adsTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA + extrasKeySuffix); | ||
| 47 | - boolean isLive = | ||
| 48 | - intent.getBooleanExtra(IS_LIVE_EXTRA + extrasKeySuffix, /* defaultValue= */ false); | ||
| 49 | - Uri adTagUri = adsTagUriString != null ? Uri.parse(adsTagUriString) : null; | ||
| 50 | - return new UriSample( | ||
| 51 | - /* name= */ null, | ||
| 52 | - uri, | ||
| 53 | - extension, | ||
| 54 | - isLive, | ||
| 55 | - DrmInfo.createFromIntent(intent, extrasKeySuffix), | ||
| 56 | - adTagUri, | ||
| 57 | - /* sphericalStereoMode= */ null, | ||
| 58 | - SubtitleInfo.createFromIntent(intent, extrasKeySuffix)); | ||
| 59 | - } | ||
| 60 | - | ||
| 61 | - public final Uri uri; | ||
| 62 | - public final String extension; | ||
| 63 | - public final boolean isLive; | ||
| 64 | - public final DrmInfo drmInfo; | ||
| 65 | - public final Uri adTagUri; | ||
| 66 | - @Nullable public final String sphericalStereoMode; | ||
| 67 | - @Nullable SubtitleInfo subtitleInfo; | ||
| 68 | - | ||
| 69 | - public UriSample( | ||
| 70 | - String name, | ||
| 71 | - Uri uri, | ||
| 72 | - String extension, | ||
| 73 | - boolean isLive, | ||
| 74 | - DrmInfo drmInfo, | ||
| 75 | - Uri adTagUri, | ||
| 76 | - @Nullable String sphericalStereoMode, | ||
| 77 | - @Nullable SubtitleInfo subtitleInfo) { | ||
| 78 | - super(name); | ||
| 79 | - this.uri = uri; | ||
| 80 | - this.extension = extension; | ||
| 81 | - this.isLive = isLive; | ||
| 82 | - this.drmInfo = drmInfo; | ||
| 83 | - this.adTagUri = adTagUri; | ||
| 84 | - this.sphericalStereoMode = sphericalStereoMode; | ||
| 85 | - this.subtitleInfo = subtitleInfo; | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - @Override | ||
| 89 | - public void addToIntent(Intent intent) { | ||
| 90 | - intent.setAction(PlayerActivity.ACTION_VIEW).setData(uri); | ||
| 91 | - intent.putExtra(IS_LIVE_EXTRA, isLive); | ||
| 92 | - intent.putExtra(PlayerActivity.SPHERICAL_STEREO_MODE_EXTRA, sphericalStereoMode); | ||
| 93 | - addPlayerConfigToIntent(intent, /* extrasKeySuffix= */ ""); | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - public void addToPlaylistIntent(Intent intent, String extrasKeySuffix) { | ||
| 97 | - intent.putExtra(URI_EXTRA + extrasKeySuffix, uri.toString()); | ||
| 98 | - intent.putExtra(IS_LIVE_EXTRA + extrasKeySuffix, isLive); | ||
| 99 | - addPlayerConfigToIntent(intent, extrasKeySuffix); | ||
| 100 | - } | ||
| 101 | - | ||
| 102 | - private void addPlayerConfigToIntent(Intent intent, String extrasKeySuffix) { | ||
| 103 | - intent | ||
| 104 | - .putExtra(EXTENSION_EXTRA + extrasKeySuffix, extension) | ||
| 105 | - .putExtra( | ||
| 106 | - AD_TAG_URI_EXTRA + extrasKeySuffix, adTagUri != null ? adTagUri.toString() : null); | ||
| 107 | - if (drmInfo != null) { | ||
| 108 | - drmInfo.addToIntent(intent, extrasKeySuffix); | ||
| 109 | - } | ||
| 110 | - if (subtitleInfo != null) { | ||
| 111 | - subtitleInfo.addToIntent(intent, extrasKeySuffix); | ||
| 112 | - } | ||
| 113 | - } | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - public static final class PlaylistSample extends Sample { | ||
| 117 | - | ||
| 118 | - public final UriSample[] children; | ||
| 119 | - | ||
| 120 | - public PlaylistSample(String name, UriSample... children) { | ||
| 121 | - super(name); | ||
| 122 | - this.children = children; | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | - @Override | ||
| 126 | - public void addToIntent(Intent intent) { | ||
| 127 | - intent.setAction(ACTION_VIEW_LIST); | ||
| 128 | - for (int i = 0; i < children.length; i++) { | ||
| 129 | - children[i].addToPlaylistIntent(intent, /* extrasKeySuffix= */ "_" + i); | ||
| 130 | - } | ||
| 131 | - } | ||
| 132 | - } | ||
| 133 | - | ||
| 134 | - public static final class DrmInfo { | ||
| 135 | - | ||
| 136 | - public static DrmInfo createFromIntent(Intent intent, String extrasKeySuffix) { | ||
| 137 | - String schemeKey = DRM_SCHEME_EXTRA + extrasKeySuffix; | ||
| 138 | - String schemeUuidKey = DRM_SCHEME_UUID_EXTRA + extrasKeySuffix; | ||
| 139 | - if (!intent.hasExtra(schemeKey) && !intent.hasExtra(schemeUuidKey)) { | ||
| 140 | - return null; | ||
| 141 | - } | ||
| 142 | - String drmSchemeExtra = | ||
| 143 | - intent.hasExtra(schemeKey) | ||
| 144 | - ? intent.getStringExtra(schemeKey) | ||
| 145 | - : intent.getStringExtra(schemeUuidKey); | ||
| 146 | - UUID drmScheme = Util.getDrmUuid(drmSchemeExtra); | ||
| 147 | - String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL_EXTRA + extrasKeySuffix); | ||
| 148 | - String[] keyRequestPropertiesArray = | ||
| 149 | - intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix); | ||
| 150 | - boolean drmMultiSession = | ||
| 151 | - intent.getBooleanExtra(DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, false); | ||
| 152 | - return new DrmInfo(drmScheme, drmLicenseUrl, keyRequestPropertiesArray, drmMultiSession); | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - public final UUID drmScheme; | ||
| 156 | - public final String drmLicenseUrl; | ||
| 157 | - public final String[] drmKeyRequestProperties; | ||
| 158 | - public final boolean drmMultiSession; | ||
| 159 | - | ||
| 160 | - public DrmInfo( | ||
| 161 | - UUID drmScheme, | ||
| 162 | - String drmLicenseUrl, | ||
| 163 | - String[] drmKeyRequestProperties, | ||
| 164 | - boolean drmMultiSession) { | ||
| 165 | - this.drmScheme = drmScheme; | ||
| 166 | - this.drmLicenseUrl = drmLicenseUrl; | ||
| 167 | - this.drmKeyRequestProperties = drmKeyRequestProperties; | ||
| 168 | - this.drmMultiSession = drmMultiSession; | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - public void addToIntent(Intent intent, String extrasKeySuffix) { | ||
| 172 | - Assertions.checkNotNull(intent); | ||
| 173 | - intent.putExtra(DRM_SCHEME_EXTRA + extrasKeySuffix, drmScheme.toString()); | ||
| 174 | - intent.putExtra(DRM_LICENSE_URL_EXTRA + extrasKeySuffix, drmLicenseUrl); | ||
| 175 | - intent.putExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix, drmKeyRequestProperties); | ||
| 176 | - intent.putExtra(DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, drmMultiSession); | ||
| 177 | - } | ||
| 178 | - } | ||
| 179 | - | ||
| 180 | - public static final class SubtitleInfo { | ||
| 181 | - | ||
| 182 | - @Nullable | ||
| 183 | - public static SubtitleInfo createFromIntent(Intent intent, String extrasKeySuffix) { | ||
| 184 | - if (!intent.hasExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)) { | ||
| 185 | - return null; | ||
| 186 | - } | ||
| 187 | - return new SubtitleInfo( | ||
| 188 | - Uri.parse(intent.getStringExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)), | ||
| 189 | - intent.getStringExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix), | ||
| 190 | - intent.getStringExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix)); | ||
| 191 | - } | ||
| 192 | - | ||
| 193 | - public final Uri uri; | ||
| 194 | - public final String mimeType; | ||
| 195 | - @Nullable public final String language; | ||
| 196 | - | ||
| 197 | - public SubtitleInfo(Uri uri, String mimeType, @Nullable String language) { | ||
| 198 | - this.uri = Assertions.checkNotNull(uri); | ||
| 199 | - this.mimeType = Assertions.checkNotNull(mimeType); | ||
| 200 | - this.language = language; | ||
| 201 | - } | ||
| 202 | - | ||
| 203 | - public void addToIntent(Intent intent, String extrasKeySuffix) { | ||
| 204 | - intent.putExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix, uri.toString()); | ||
| 205 | - intent.putExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix, mimeType); | ||
| 206 | - intent.putExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix, language); | ||
| 207 | - } | ||
| 208 | - } | ||
| 209 | - | ||
| 210 | - public static Sample createFromIntent(Intent intent) { | ||
| 211 | - if (ACTION_VIEW_LIST.equals(intent.getAction())) { | ||
| 212 | - ArrayList<String> intentUris = new ArrayList<>(); | ||
| 213 | - int index = 0; | ||
| 214 | - while (intent.hasExtra(URI_EXTRA + "_" + index)) { | ||
| 215 | - intentUris.add(intent.getStringExtra(URI_EXTRA + "_" + index)); | ||
| 216 | - index++; | ||
| 217 | - } | ||
| 218 | - UriSample[] children = new UriSample[intentUris.size()]; | ||
| 219 | - for (int i = 0; i < children.length; i++) { | ||
| 220 | - Uri uri = Uri.parse(intentUris.get(i)); | ||
| 221 | - children[i] = UriSample.createFromIntent(uri, intent, /* extrasKeySuffix= */ "_" + i); | ||
| 222 | - } | ||
| 223 | - return new PlaylistSample(/* name= */ null, children); | ||
| 224 | - } else { | ||
| 225 | - return UriSample.createFromIntent(intent.getData(), intent, /* extrasKeySuffix= */ ""); | ||
| 226 | - } | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - @Nullable public final String name; | ||
| 230 | - | ||
| 231 | - public Sample(String name) { | ||
| 232 | - this.name = name; | ||
| 233 | - } | ||
| 234 | - | ||
| 235 | - public abstract void addToIntent(Intent intent); | ||
| 236 | -} |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/SampleChooserActivity.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2016 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import android.content.Context; | ||
| 19 | -import android.content.Intent; | ||
| 20 | -import android.content.res.AssetManager; | ||
| 21 | -import android.net.Uri; | ||
| 22 | -import android.os.AsyncTask; | ||
| 23 | -import android.os.Bundle; | ||
| 24 | -import android.util.JsonReader; | ||
| 25 | -import android.view.Menu; | ||
| 26 | -import android.view.MenuInflater; | ||
| 27 | -import android.view.MenuItem; | ||
| 28 | -import android.view.View; | ||
| 29 | -import android.view.View.OnClickListener; | ||
| 30 | -import android.view.ViewGroup; | ||
| 31 | -import android.widget.BaseExpandableListAdapter; | ||
| 32 | -import android.widget.ExpandableListView; | ||
| 33 | -import android.widget.ExpandableListView.OnChildClickListener; | ||
| 34 | -import android.widget.ImageButton; | ||
| 35 | -import android.widget.TextView; | ||
| 36 | -import android.widget.Toast; | ||
| 37 | -import androidx.annotation.Nullable; | ||
| 38 | -import androidx.appcompat.app.AppCompatActivity; | ||
| 39 | - | ||
| 40 | -import com.cnlive.cloud.R; | ||
| 41 | -import com.cnlive.strike.DemoApplication; | ||
| 42 | -import com.google.android.exoplayer2.ParserException; | ||
| 43 | -import com.google.android.exoplayer2.RenderersFactory; | ||
| 44 | -import com.google.android.exoplayer2.offline.DownloadService; | ||
| 45 | -import com.google.android.exoplayer2.upstream.DataSource; | ||
| 46 | -import com.google.android.exoplayer2.upstream.DataSourceInputStream; | ||
| 47 | -import com.google.android.exoplayer2.upstream.DataSpec; | ||
| 48 | -import com.google.android.exoplayer2.upstream.DefaultDataSource; | ||
| 49 | -import com.google.android.exoplayer2.util.Assertions; | ||
| 50 | -import com.google.android.exoplayer2.util.Log; | ||
| 51 | -import com.google.android.exoplayer2.util.Util; | ||
| 52 | -import java.io.IOException; | ||
| 53 | -import java.io.InputStream; | ||
| 54 | -import java.io.InputStreamReader; | ||
| 55 | -import java.util.ArrayList; | ||
| 56 | -import java.util.Arrays; | ||
| 57 | -import java.util.Collections; | ||
| 58 | -import java.util.List; | ||
| 59 | - | ||
| 60 | -/** An activity for selecting from a list of media samples. */ | ||
| 61 | -public class SampleChooserActivity extends AppCompatActivity | ||
| 62 | - implements DownloadTracker.Listener, OnChildClickListener { | ||
| 63 | - | ||
| 64 | - private static final String TAG = "SampleChooserActivity"; | ||
| 65 | - | ||
| 66 | - private boolean useExtensionRenderers; | ||
| 67 | - private DownloadTracker downloadTracker; | ||
| 68 | - private SampleAdapter sampleAdapter; | ||
| 69 | - private MenuItem preferExtensionDecodersMenuItem; | ||
| 70 | - private MenuItem randomAbrMenuItem; | ||
| 71 | - private MenuItem tunnelingMenuItem; | ||
| 72 | - | ||
| 73 | - @Override | ||
| 74 | - public void onCreate(Bundle savedInstanceState) { | ||
| 75 | - super.onCreate(savedInstanceState); | ||
| 76 | - setContentView(R.layout.sample_chooser_activity); | ||
| 77 | - sampleAdapter = new SampleAdapter(); | ||
| 78 | - ExpandableListView sampleListView = findViewById(R.id.sample_list); | ||
| 79 | - sampleListView.setAdapter(sampleAdapter); | ||
| 80 | - sampleListView.setOnChildClickListener(this); | ||
| 81 | - | ||
| 82 | - Intent intent = getIntent(); | ||
| 83 | - String dataUri = intent.getDataString(); | ||
| 84 | - String[] uris; | ||
| 85 | - if (dataUri != null) { | ||
| 86 | - uris = new String[] {dataUri}; | ||
| 87 | - } else { | ||
| 88 | - ArrayList<String> uriList = new ArrayList<>(); | ||
| 89 | - AssetManager assetManager = getAssets(); | ||
| 90 | - try { | ||
| 91 | - for (String asset : assetManager.list("")) { | ||
| 92 | - if (asset.endsWith(".exolist.json")) { | ||
| 93 | - uriList.add("asset:///" + asset); | ||
| 94 | - } | ||
| 95 | - } | ||
| 96 | - } catch (IOException e) { | ||
| 97 | - Toast.makeText(getApplicationContext(), R.string.sample_list_load_error, Toast.LENGTH_LONG) | ||
| 98 | - .show(); | ||
| 99 | - } | ||
| 100 | - uris = new String[uriList.size()]; | ||
| 101 | - uriList.toArray(uris); | ||
| 102 | - Arrays.sort(uris); | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - DemoApplication application = (DemoApplication) getApplication(); | ||
| 106 | - useExtensionRenderers = application.useExtensionRenderers(); | ||
| 107 | - downloadTracker = application.getDownloadTracker(); | ||
| 108 | - SampleListLoader loaderTask = new SampleListLoader(); | ||
| 109 | - loaderTask.execute(uris); | ||
| 110 | - | ||
| 111 | - // Start the download service if it should be running but it's not currently. | ||
| 112 | - // Starting the service in the foreground causes notification flicker if there is no scheduled | ||
| 113 | - // action. Starting it in the background throws an exception if the app is in the background too | ||
| 114 | - // (e.g. if device screen is locked). | ||
| 115 | - try { | ||
| 116 | - DownloadService.start(this, DemoDownloadService.class); | ||
| 117 | - } catch (IllegalStateException e) { | ||
| 118 | - DownloadService.startForeground(this, DemoDownloadService.class); | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - @Override | ||
| 123 | - public boolean onCreateOptionsMenu(Menu menu) { | ||
| 124 | - MenuInflater inflater = getMenuInflater(); | ||
| 125 | - inflater.inflate(R.menu.sample_chooser_menu, menu); | ||
| 126 | - preferExtensionDecodersMenuItem = menu.findItem(R.id.prefer_extension_decoders); | ||
| 127 | - preferExtensionDecodersMenuItem.setVisible(useExtensionRenderers); | ||
| 128 | - randomAbrMenuItem = menu.findItem(R.id.random_abr); | ||
| 129 | - tunnelingMenuItem = menu.findItem(R.id.tunneling); | ||
| 130 | - if (Util.SDK_INT < 21) { | ||
| 131 | - tunnelingMenuItem.setEnabled(false); | ||
| 132 | - } | ||
| 133 | - return true; | ||
| 134 | - } | ||
| 135 | - | ||
| 136 | - @Override | ||
| 137 | - public boolean onOptionsItemSelected(MenuItem item) { | ||
| 138 | - item.setChecked(!item.isChecked()); | ||
| 139 | - return true; | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - @Override | ||
| 143 | - public void onStart() { | ||
| 144 | - super.onStart(); | ||
| 145 | - downloadTracker.addListener(this); | ||
| 146 | - sampleAdapter.notifyDataSetChanged(); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - @Override | ||
| 150 | - public void onStop() { | ||
| 151 | - downloadTracker.removeListener(this); | ||
| 152 | - super.onStop(); | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - @Override | ||
| 156 | - public void onDownloadsChanged() { | ||
| 157 | - sampleAdapter.notifyDataSetChanged(); | ||
| 158 | - } | ||
| 159 | - | ||
| 160 | - private void onSampleGroups(final List<SampleGroup> groups, boolean sawError) { | ||
| 161 | - if (sawError) { | ||
| 162 | - Toast.makeText(getApplicationContext(), R.string.sample_list_load_error, Toast.LENGTH_LONG) | ||
| 163 | - .show(); | ||
| 164 | - } | ||
| 165 | - sampleAdapter.setSampleGroups(groups); | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - @Override | ||
| 169 | - public boolean onChildClick( | ||
| 170 | - ExpandableListView parent, View view, int groupPosition, int childPosition, long id) { | ||
| 171 | - Sample sample = (Sample) view.getTag(); | ||
| 172 | - Intent intent = new Intent(this, PlayerActivity.class); | ||
| 173 | - intent.putExtra( | ||
| 174 | - PlayerActivity.PREFER_EXTENSION_DECODERS_EXTRA, | ||
| 175 | - isNonNullAndChecked(preferExtensionDecodersMenuItem)); | ||
| 176 | - String abrAlgorithm = | ||
| 177 | - isNonNullAndChecked(randomAbrMenuItem) | ||
| 178 | - ? PlayerActivity.ABR_ALGORITHM_RANDOM | ||
| 179 | - : PlayerActivity.ABR_ALGORITHM_DEFAULT; | ||
| 180 | - intent.putExtra(PlayerActivity.ABR_ALGORITHM_EXTRA, abrAlgorithm); | ||
| 181 | - intent.putExtra(PlayerActivity.TUNNELING_EXTRA, isNonNullAndChecked(tunnelingMenuItem)); | ||
| 182 | - sample.addToIntent(intent); | ||
| 183 | - startActivity(intent); | ||
| 184 | - return true; | ||
| 185 | - } | ||
| 186 | - | ||
| 187 | - private void onSampleDownloadButtonClicked(Sample sample) { | ||
| 188 | - int downloadUnsupportedStringId = getDownloadUnsupportedStringId(sample); | ||
| 189 | - if (downloadUnsupportedStringId != 0) { | ||
| 190 | - Toast.makeText(getApplicationContext(), downloadUnsupportedStringId, Toast.LENGTH_LONG) | ||
| 191 | - .show(); | ||
| 192 | - } else { | ||
| 193 | - Sample.UriSample UriSample = (Sample.UriSample) sample; | ||
| 194 | - RenderersFactory renderersFactory = | ||
| 195 | - ((DemoApplication) getApplication()) | ||
| 196 | - .buildRenderersFactory(isNonNullAndChecked(preferExtensionDecodersMenuItem)); | ||
| 197 | - downloadTracker.toggleDownload( | ||
| 198 | - getSupportFragmentManager(), | ||
| 199 | - sample.name, | ||
| 200 | - UriSample.uri, | ||
| 201 | - UriSample.extension, | ||
| 202 | - renderersFactory); | ||
| 203 | - } | ||
| 204 | - } | ||
| 205 | - | ||
| 206 | - private int getDownloadUnsupportedStringId(Sample sample) { | ||
| 207 | - if (sample instanceof Sample.PlaylistSample) { | ||
| 208 | - return R.string.download_playlist_unsupported; | ||
| 209 | - } | ||
| 210 | - Sample.UriSample UriSample = (Sample.UriSample) sample; | ||
| 211 | - if (UriSample.drmInfo != null) { | ||
| 212 | - return R.string.download_drm_unsupported; | ||
| 213 | - } | ||
| 214 | - if (UriSample.isLive) { | ||
| 215 | - return R.string.download_live_unsupported; | ||
| 216 | - } | ||
| 217 | - if (UriSample.adTagUri != null) { | ||
| 218 | - return R.string.download_ads_unsupported; | ||
| 219 | - } | ||
| 220 | - String scheme = UriSample.uri.getScheme(); | ||
| 221 | - if (!("http".equals(scheme) || "https".equals(scheme))) { | ||
| 222 | - return R.string.download_scheme_unsupported; | ||
| 223 | - } | ||
| 224 | - return 0; | ||
| 225 | - } | ||
| 226 | - | ||
| 227 | - private static boolean isNonNullAndChecked(@Nullable MenuItem menuItem) { | ||
| 228 | - // Temporary workaround for layouts that do not inflate the options menu. | ||
| 229 | - return menuItem != null && menuItem.isChecked(); | ||
| 230 | - } | ||
| 231 | - | ||
| 232 | - private final class SampleListLoader extends AsyncTask<String, Void, List<SampleGroup>> { | ||
| 233 | - | ||
| 234 | - private boolean sawError; | ||
| 235 | - | ||
| 236 | - @Override | ||
| 237 | - protected List<SampleGroup> doInBackground(String... uris) { | ||
| 238 | - List<SampleGroup> result = new ArrayList<>(); | ||
| 239 | - Context context = getApplicationContext(); | ||
| 240 | - String userAgent = Util.getUserAgent(context, "ExoPlayerDemo"); | ||
| 241 | - DataSource dataSource = | ||
| 242 | - new DefaultDataSource(context, userAgent, /* allowCrossProtocolRedirects= */ false); | ||
| 243 | - for (String uri : uris) { | ||
| 244 | - DataSpec dataSpec = new DataSpec(Uri.parse(uri)); | ||
| 245 | - InputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); | ||
| 246 | - try { | ||
| 247 | - readSampleGroups(new JsonReader(new InputStreamReader(inputStream, "UTF-8")), result); | ||
| 248 | - } catch (Exception e) { | ||
| 249 | - Log.e(TAG, "Error loading sample list: " + uri, e); | ||
| 250 | - sawError = true; | ||
| 251 | - } finally { | ||
| 252 | - Util.closeQuietly(dataSource); | ||
| 253 | - } | ||
| 254 | - } | ||
| 255 | - return result; | ||
| 256 | - } | ||
| 257 | - | ||
| 258 | - @Override | ||
| 259 | - protected void onPostExecute(List<SampleGroup> result) { | ||
| 260 | - onSampleGroups(result, sawError); | ||
| 261 | - } | ||
| 262 | - | ||
| 263 | - private void readSampleGroups(JsonReader reader, List<SampleGroup> groups) throws IOException { | ||
| 264 | - reader.beginArray(); | ||
| 265 | - while (reader.hasNext()) { | ||
| 266 | - readSampleGroup(reader, groups); | ||
| 267 | - } | ||
| 268 | - reader.endArray(); | ||
| 269 | - } | ||
| 270 | - | ||
| 271 | - private void readSampleGroup(JsonReader reader, List<SampleGroup> groups) throws IOException { | ||
| 272 | - String groupName = ""; | ||
| 273 | - ArrayList<Sample> samples = new ArrayList<>(); | ||
| 274 | - | ||
| 275 | - reader.beginObject(); | ||
| 276 | - while (reader.hasNext()) { | ||
| 277 | - String name = reader.nextName(); | ||
| 278 | - switch (name) { | ||
| 279 | - case "name": | ||
| 280 | - groupName = reader.nextString(); | ||
| 281 | - break; | ||
| 282 | - case "samples": | ||
| 283 | - reader.beginArray(); | ||
| 284 | - while (reader.hasNext()) { | ||
| 285 | - samples.add(readEntry(reader, false)); | ||
| 286 | - } | ||
| 287 | - reader.endArray(); | ||
| 288 | - break; | ||
| 289 | - case "_comment": | ||
| 290 | - reader.nextString(); // Ignore. | ||
| 291 | - break; | ||
| 292 | - default: | ||
| 293 | - throw new ParserException("Unsupported name: " + name); | ||
| 294 | - } | ||
| 295 | - } | ||
| 296 | - reader.endObject(); | ||
| 297 | - | ||
| 298 | - SampleGroup group = getGroup(groupName, groups); | ||
| 299 | - group.samples.addAll(samples); | ||
| 300 | - } | ||
| 301 | - | ||
| 302 | - private Sample readEntry(JsonReader reader, boolean insidePlaylist) throws IOException { | ||
| 303 | - String sampleName = null; | ||
| 304 | - Uri uri = null; | ||
| 305 | - String extension = null; | ||
| 306 | - boolean isLive = false; | ||
| 307 | - String drmScheme = null; | ||
| 308 | - String drmLicenseUrl = null; | ||
| 309 | - String[] drmKeyRequestProperties = null; | ||
| 310 | - boolean drmMultiSession = false; | ||
| 311 | - ArrayList<Sample.UriSample> playlistSamples = null; | ||
| 312 | - String adTagUri = null; | ||
| 313 | - String sphericalStereoMode = null; | ||
| 314 | - List<Sample.SubtitleInfo> subtitleInfos = new ArrayList<>(); | ||
| 315 | - Uri subtitleUri = null; | ||
| 316 | - String subtitleMimeType = null; | ||
| 317 | - String subtitleLanguage = null; | ||
| 318 | - | ||
| 319 | - reader.beginObject(); | ||
| 320 | - while (reader.hasNext()) { | ||
| 321 | - String name = reader.nextName(); | ||
| 322 | - switch (name) { | ||
| 323 | - case "name": | ||
| 324 | - sampleName = reader.nextString(); | ||
| 325 | - break; | ||
| 326 | - case "uri": | ||
| 327 | - uri = Uri.parse(reader.nextString()); | ||
| 328 | - break; | ||
| 329 | - case "extension": | ||
| 330 | - extension = reader.nextString(); | ||
| 331 | - break; | ||
| 332 | - case "drm_scheme": | ||
| 333 | - drmScheme = reader.nextString(); | ||
| 334 | - break; | ||
| 335 | - case "is_live": | ||
| 336 | - isLive = reader.nextBoolean(); | ||
| 337 | - break; | ||
| 338 | - case "drm_license_url": | ||
| 339 | - drmLicenseUrl = reader.nextString(); | ||
| 340 | - break; | ||
| 341 | - case "drm_key_request_properties": | ||
| 342 | - ArrayList<String> drmKeyRequestPropertiesList = new ArrayList<>(); | ||
| 343 | - reader.beginObject(); | ||
| 344 | - while (reader.hasNext()) { | ||
| 345 | - drmKeyRequestPropertiesList.add(reader.nextName()); | ||
| 346 | - drmKeyRequestPropertiesList.add(reader.nextString()); | ||
| 347 | - } | ||
| 348 | - reader.endObject(); | ||
| 349 | - drmKeyRequestProperties = drmKeyRequestPropertiesList.toArray(new String[0]); | ||
| 350 | - break; | ||
| 351 | - case "drm_multi_session": | ||
| 352 | - drmMultiSession = reader.nextBoolean(); | ||
| 353 | - break; | ||
| 354 | - case "playlist": | ||
| 355 | - Assertions.checkState(!insidePlaylist, "Invalid nesting of playlists"); | ||
| 356 | - playlistSamples = new ArrayList<Sample.UriSample>(); | ||
| 357 | - reader.beginArray(); | ||
| 358 | - while (reader.hasNext()) { | ||
| 359 | - playlistSamples.add((Sample.UriSample) readEntry(reader, /* insidePlaylist= */ true)); | ||
| 360 | - } | ||
| 361 | - reader.endArray(); | ||
| 362 | - break; | ||
| 363 | - case "ad_tag_uri": | ||
| 364 | - adTagUri = reader.nextString(); | ||
| 365 | - break; | ||
| 366 | - case "spherical_stereo_mode": | ||
| 367 | - Assertions.checkState( | ||
| 368 | - !insidePlaylist, "Invalid attribute on nested item: spherical_stereo_mode"); | ||
| 369 | - sphericalStereoMode = reader.nextString(); | ||
| 370 | - break; | ||
| 371 | - case "subtitle_uri": | ||
| 372 | - subtitleUri = Uri.parse(reader.nextString()); | ||
| 373 | - break; | ||
| 374 | - case "subtitle_mime_type": | ||
| 375 | - subtitleMimeType = reader.nextString(); | ||
| 376 | - break; | ||
| 377 | - case "subtitle_language": | ||
| 378 | - subtitleLanguage = reader.nextString(); | ||
| 379 | - break; | ||
| 380 | - default: | ||
| 381 | - throw new ParserException("Unsupported attribute name: " + name); | ||
| 382 | - } | ||
| 383 | - } | ||
| 384 | - reader.endObject(); | ||
| 385 | - Sample.DrmInfo drmInfo = | ||
| 386 | - drmScheme == null | ||
| 387 | - ? null | ||
| 388 | - : new Sample.DrmInfo( | ||
| 389 | - Util.getDrmUuid(drmScheme), | ||
| 390 | - drmLicenseUrl, | ||
| 391 | - drmKeyRequestProperties, | ||
| 392 | - drmMultiSession); | ||
| 393 | - Sample.SubtitleInfo subtitleInfo = | ||
| 394 | - subtitleUri == null | ||
| 395 | - ? null | ||
| 396 | - : new Sample.SubtitleInfo( | ||
| 397 | - subtitleUri, | ||
| 398 | - Assertions.checkNotNull( | ||
| 399 | - subtitleMimeType, "subtitle_mime_type is required if subtitle_uri is set."), | ||
| 400 | - subtitleLanguage); | ||
| 401 | - if (playlistSamples != null) { | ||
| 402 | - Sample.UriSample[] playlistSamplesArray = playlistSamples.toArray(new Sample.UriSample[0]); | ||
| 403 | - return new Sample.PlaylistSample(sampleName, playlistSamplesArray); | ||
| 404 | - } else { | ||
| 405 | - return new Sample.UriSample( | ||
| 406 | - sampleName, | ||
| 407 | - uri, | ||
| 408 | - extension, | ||
| 409 | - isLive, | ||
| 410 | - drmInfo, | ||
| 411 | - adTagUri != null ? Uri.parse(adTagUri) : null, | ||
| 412 | - sphericalStereoMode, | ||
| 413 | - subtitleInfo); | ||
| 414 | - } | ||
| 415 | - } | ||
| 416 | - | ||
| 417 | - private SampleGroup getGroup(String groupName, List<SampleGroup> groups) { | ||
| 418 | - for (int i = 0; i < groups.size(); i++) { | ||
| 419 | - if (Util.areEqual(groupName, groups.get(i).title)) { | ||
| 420 | - return groups.get(i); | ||
| 421 | - } | ||
| 422 | - } | ||
| 423 | - SampleGroup group = new SampleGroup(groupName); | ||
| 424 | - groups.add(group); | ||
| 425 | - return group; | ||
| 426 | - } | ||
| 427 | - | ||
| 428 | - } | ||
| 429 | - | ||
| 430 | - private final class SampleAdapter extends BaseExpandableListAdapter implements OnClickListener { | ||
| 431 | - | ||
| 432 | - private List<SampleGroup> sampleGroups; | ||
| 433 | - | ||
| 434 | - public SampleAdapter() { | ||
| 435 | - sampleGroups = Collections.emptyList(); | ||
| 436 | - } | ||
| 437 | - | ||
| 438 | - public void setSampleGroups(List<SampleGroup> sampleGroups) { | ||
| 439 | - this.sampleGroups = sampleGroups; | ||
| 440 | - notifyDataSetChanged(); | ||
| 441 | - } | ||
| 442 | - | ||
| 443 | - @Override | ||
| 444 | - public Sample getChild(int groupPosition, int childPosition) { | ||
| 445 | - return getGroup(groupPosition).samples.get(childPosition); | ||
| 446 | - } | ||
| 447 | - | ||
| 448 | - @Override | ||
| 449 | - public long getChildId(int groupPosition, int childPosition) { | ||
| 450 | - return childPosition; | ||
| 451 | - } | ||
| 452 | - | ||
| 453 | - @Override | ||
| 454 | - public View getChildView(int groupPosition, int childPosition, boolean isLastChild, | ||
| 455 | - View convertView, ViewGroup parent) { | ||
| 456 | - View view = convertView; | ||
| 457 | - if (view == null) { | ||
| 458 | - view = getLayoutInflater().inflate(R.layout.sample_list_item, parent, false); | ||
| 459 | - View downloadButton = view.findViewById(R.id.download_button); | ||
| 460 | - downloadButton.setOnClickListener(this); | ||
| 461 | - downloadButton.setFocusable(false); | ||
| 462 | - } | ||
| 463 | - initializeChildView(view, getChild(groupPosition, childPosition)); | ||
| 464 | - return view; | ||
| 465 | - } | ||
| 466 | - | ||
| 467 | - @Override | ||
| 468 | - public int getChildrenCount(int groupPosition) { | ||
| 469 | - return getGroup(groupPosition).samples.size(); | ||
| 470 | - } | ||
| 471 | - | ||
| 472 | - @Override | ||
| 473 | - public SampleGroup getGroup(int groupPosition) { | ||
| 474 | - return sampleGroups.get(groupPosition); | ||
| 475 | - } | ||
| 476 | - | ||
| 477 | - @Override | ||
| 478 | - public long getGroupId(int groupPosition) { | ||
| 479 | - return groupPosition; | ||
| 480 | - } | ||
| 481 | - | ||
| 482 | - @Override | ||
| 483 | - public View getGroupView(int groupPosition, boolean isExpanded, View convertView, | ||
| 484 | - ViewGroup parent) { | ||
| 485 | - View view = convertView; | ||
| 486 | - if (view == null) { | ||
| 487 | - view = | ||
| 488 | - getLayoutInflater() | ||
| 489 | - .inflate(android.R.layout.simple_expandable_list_item_1, parent, false); | ||
| 490 | - } | ||
| 491 | - ((TextView) view).setText(getGroup(groupPosition).title); | ||
| 492 | - return view; | ||
| 493 | - } | ||
| 494 | - | ||
| 495 | - @Override | ||
| 496 | - public int getGroupCount() { | ||
| 497 | - return sampleGroups.size(); | ||
| 498 | - } | ||
| 499 | - | ||
| 500 | - @Override | ||
| 501 | - public boolean hasStableIds() { | ||
| 502 | - return false; | ||
| 503 | - } | ||
| 504 | - | ||
| 505 | - @Override | ||
| 506 | - public boolean isChildSelectable(int groupPosition, int childPosition) { | ||
| 507 | - return true; | ||
| 508 | - } | ||
| 509 | - | ||
| 510 | - @Override | ||
| 511 | - public void onClick(View view) { | ||
| 512 | - onSampleDownloadButtonClicked((Sample) view.getTag()); | ||
| 513 | - } | ||
| 514 | - | ||
| 515 | - private void initializeChildView(View view, Sample sample) { | ||
| 516 | - view.setTag(sample); | ||
| 517 | - TextView sampleTitle = view.findViewById(R.id.sample_title); | ||
| 518 | - sampleTitle.setText(sample.name); | ||
| 519 | - | ||
| 520 | - boolean canDownload = getDownloadUnsupportedStringId(sample) == 0; | ||
| 521 | - boolean isDownloaded = canDownload && downloadTracker.isDownloaded(((Sample.UriSample) sample).uri); | ||
| 522 | - ImageButton downloadButton = view.findViewById(R.id.download_button); | ||
| 523 | - downloadButton.setTag(sample); | ||
| 524 | - downloadButton.setColorFilter( | ||
| 525 | - canDownload ? (isDownloaded ? 0xFF42A5F5 : 0xFFBDBDBD) : 0xFF666666); | ||
| 526 | - downloadButton.setImageResource( | ||
| 527 | - isDownloaded ? R.drawable.ic_download_done : R.drawable.ic_download); | ||
| 528 | - } | ||
| 529 | - } | ||
| 530 | - | ||
| 531 | - private static final class SampleGroup { | ||
| 532 | - | ||
| 533 | - public final String title; | ||
| 534 | - public final List<Sample> samples; | ||
| 535 | - | ||
| 536 | - public SampleGroup(String title) { | ||
| 537 | - this.title = title; | ||
| 538 | - this.samples = new ArrayList<>(); | ||
| 539 | - } | ||
| 540 | - | ||
| 541 | - } | ||
| 542 | -} |
app/strike/src/main/java/com/cnlive/strike/demo/exoplayer/demo/TrackSelectionDialog.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright (C) 2019 The Android Open Source Project | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | -package com.cnlive.strike.demo.exoplayer.demo; | ||
| 17 | - | ||
| 18 | -import android.app.Dialog; | ||
| 19 | -import android.content.DialogInterface; | ||
| 20 | -import android.content.res.Resources; | ||
| 21 | -import android.os.Bundle; | ||
| 22 | -import android.util.SparseArray; | ||
| 23 | -import android.view.LayoutInflater; | ||
| 24 | -import android.view.View; | ||
| 25 | -import android.view.ViewGroup; | ||
| 26 | -import android.widget.Button; | ||
| 27 | -import androidx.annotation.Nullable; | ||
| 28 | -import androidx.appcompat.app.AppCompatDialog; | ||
| 29 | -import androidx.fragment.app.DialogFragment; | ||
| 30 | -import androidx.fragment.app.Fragment; | ||
| 31 | -import androidx.fragment.app.FragmentManager; | ||
| 32 | -import androidx.fragment.app.FragmentPagerAdapter; | ||
| 33 | -import androidx.viewpager.widget.ViewPager; | ||
| 34 | - | ||
| 35 | -import com.cnlive.cloud.R; | ||
| 36 | -import com.google.android.exoplayer2.C; | ||
| 37 | -import com.google.android.exoplayer2.source.TrackGroupArray; | ||
| 38 | -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; | ||
| 39 | -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; | ||
| 40 | -import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; | ||
| 41 | -import com.google.android.exoplayer2.ui.TrackSelectionView; | ||
| 42 | -import com.google.android.exoplayer2.util.Assertions; | ||
| 43 | -import com.google.android.material.tabs.TabLayout; | ||
| 44 | -import java.util.ArrayList; | ||
| 45 | -import java.util.Collections; | ||
| 46 | -import java.util.List; | ||
| 47 | - | ||
| 48 | -/** Dialog to select tracks. */ | ||
| 49 | -public final class TrackSelectionDialog extends DialogFragment { | ||
| 50 | - | ||
| 51 | - private final SparseArray<TrackSelectionViewFragment> tabFragments; | ||
| 52 | - private final ArrayList<Integer> tabTrackTypes; | ||
| 53 | - | ||
| 54 | - private int titleId; | ||
| 55 | - private DialogInterface.OnClickListener onClickListener; | ||
| 56 | - private DialogInterface.OnDismissListener onDismissListener; | ||
| 57 | - | ||
| 58 | - /** | ||
| 59 | - * Returns whether a track selection dialog will have content to display if initialized with the | ||
| 60 | - * specified {@link DefaultTrackSelector} in its current state. | ||
| 61 | - */ | ||
| 62 | - public static boolean willHaveContent(DefaultTrackSelector trackSelector) { | ||
| 63 | - MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); | ||
| 64 | - return mappedTrackInfo != null && willHaveContent(mappedTrackInfo); | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - /** | ||
| 68 | - * Returns whether a track selection dialog will have content to display if initialized with the | ||
| 69 | - * specified {@link MappedTrackInfo}. | ||
| 70 | - */ | ||
| 71 | - public static boolean willHaveContent(MappedTrackInfo mappedTrackInfo) { | ||
| 72 | - for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) { | ||
| 73 | - if (showTabForRenderer(mappedTrackInfo, i)) { | ||
| 74 | - return true; | ||
| 75 | - } | ||
| 76 | - } | ||
| 77 | - return false; | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - /** | ||
| 81 | - * Creates a dialog for a given {@link DefaultTrackSelector}, whose parameters will be | ||
| 82 | - * automatically updated when tracks are selected. | ||
| 83 | - * | ||
| 84 | - * @param trackSelector The {@link DefaultTrackSelector}. | ||
| 85 | - * @param onDismissListener A {@link DialogInterface.OnDismissListener} to call when the dialog is | ||
| 86 | - * dismissed. | ||
| 87 | - */ | ||
| 88 | - public static TrackSelectionDialog createForTrackSelector( | ||
| 89 | - DefaultTrackSelector trackSelector, DialogInterface.OnDismissListener onDismissListener) { | ||
| 90 | - MappedTrackInfo mappedTrackInfo = | ||
| 91 | - Assertions.checkNotNull(trackSelector.getCurrentMappedTrackInfo()); | ||
| 92 | - TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog(); | ||
| 93 | - DefaultTrackSelector.Parameters parameters = trackSelector.getParameters(); | ||
| 94 | - trackSelectionDialog.init( | ||
| 95 | - /* titleId= */ R.string.track_selection_title, | ||
| 96 | - mappedTrackInfo, | ||
| 97 | - /* initialParameters = */ parameters, | ||
| 98 | - /* allowAdaptiveSelections =*/ true, | ||
| 99 | - /* allowMultipleOverrides= */ false, | ||
| 100 | - /* onClickListener= */ (dialog, which) -> { | ||
| 101 | - DefaultTrackSelector.ParametersBuilder builder = parameters.buildUpon(); | ||
| 102 | - for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) { | ||
| 103 | - builder | ||
| 104 | - .clearSelectionOverrides(/* rendererIndex= */ i) | ||
| 105 | - .setRendererDisabled( | ||
| 106 | - /* rendererIndex= */ i, | ||
| 107 | - trackSelectionDialog.getIsDisabled(/* rendererIndex= */ i)); | ||
| 108 | - List<SelectionOverride> overrides = | ||
| 109 | - trackSelectionDialog.getOverrides(/* rendererIndex= */ i); | ||
| 110 | - if (!overrides.isEmpty()) { | ||
| 111 | - builder.setSelectionOverride( | ||
| 112 | - /* rendererIndex= */ i, | ||
| 113 | - mappedTrackInfo.getTrackGroups(/* rendererIndex= */ i), | ||
| 114 | - overrides.get(0)); | ||
| 115 | - } | ||
| 116 | - } | ||
| 117 | - trackSelector.setParameters(builder); | ||
| 118 | - }, | ||
| 119 | - onDismissListener); | ||
| 120 | - return trackSelectionDialog; | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - /** | ||
| 124 | - * Creates a dialog for given {@link MappedTrackInfo} and {@link DefaultTrackSelector.Parameters}. | ||
| 125 | - * | ||
| 126 | - * @param titleId The resource id of the dialog title. | ||
| 127 | - * @param mappedTrackInfo The {@link MappedTrackInfo} to display. | ||
| 128 | - * @param initialParameters The {@link DefaultTrackSelector.Parameters} describing the initial | ||
| 129 | - * track selection. | ||
| 130 | - * @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track) | ||
| 131 | - * can be made. | ||
| 132 | - * @param allowMultipleOverrides Whether tracks from multiple track groups can be selected. | ||
| 133 | - * @param onClickListener {@link DialogInterface.OnClickListener} called when tracks are selected. | ||
| 134 | - * @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is | ||
| 135 | - * dismissed. | ||
| 136 | - */ | ||
| 137 | - public static TrackSelectionDialog createForMappedTrackInfoAndParameters( | ||
| 138 | - int titleId, | ||
| 139 | - MappedTrackInfo mappedTrackInfo, | ||
| 140 | - DefaultTrackSelector.Parameters initialParameters, | ||
| 141 | - boolean allowAdaptiveSelections, | ||
| 142 | - boolean allowMultipleOverrides, | ||
| 143 | - DialogInterface.OnClickListener onClickListener, | ||
| 144 | - DialogInterface.OnDismissListener onDismissListener) { | ||
| 145 | - TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog(); | ||
| 146 | - trackSelectionDialog.init( | ||
| 147 | - titleId, | ||
| 148 | - mappedTrackInfo, | ||
| 149 | - initialParameters, | ||
| 150 | - allowAdaptiveSelections, | ||
| 151 | - allowMultipleOverrides, | ||
| 152 | - onClickListener, | ||
| 153 | - onDismissListener); | ||
| 154 | - return trackSelectionDialog; | ||
| 155 | - } | ||
| 156 | - | ||
| 157 | - public TrackSelectionDialog() { | ||
| 158 | - tabFragments = new SparseArray<>(); | ||
| 159 | - tabTrackTypes = new ArrayList<>(); | ||
| 160 | - // Retain instance across activity re-creation to prevent losing access to init data. | ||
| 161 | - setRetainInstance(true); | ||
| 162 | - } | ||
| 163 | - | ||
| 164 | - private void init( | ||
| 165 | - int titleId, | ||
| 166 | - MappedTrackInfo mappedTrackInfo, | ||
| 167 | - DefaultTrackSelector.Parameters initialParameters, | ||
| 168 | - boolean allowAdaptiveSelections, | ||
| 169 | - boolean allowMultipleOverrides, | ||
| 170 | - DialogInterface.OnClickListener onClickListener, | ||
| 171 | - DialogInterface.OnDismissListener onDismissListener) { | ||
| 172 | - this.titleId = titleId; | ||
| 173 | - this.onClickListener = onClickListener; | ||
| 174 | - this.onDismissListener = onDismissListener; | ||
| 175 | - for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) { | ||
| 176 | - if (showTabForRenderer(mappedTrackInfo, i)) { | ||
| 177 | - int trackType = mappedTrackInfo.getRendererType(/* rendererIndex= */ i); | ||
| 178 | - TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i); | ||
| 179 | - TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment(); | ||
| 180 | - tabFragment.init( | ||
| 181 | - mappedTrackInfo, | ||
| 182 | - /* rendererIndex= */ i, | ||
| 183 | - initialParameters.getRendererDisabled(/* rendererIndex= */ i), | ||
| 184 | - initialParameters.getSelectionOverride(/* rendererIndex= */ i, trackGroupArray), | ||
| 185 | - allowAdaptiveSelections, | ||
| 186 | - allowMultipleOverrides); | ||
| 187 | - tabFragments.put(i, tabFragment); | ||
| 188 | - tabTrackTypes.add(trackType); | ||
| 189 | - } | ||
| 190 | - } | ||
| 191 | - } | ||
| 192 | - | ||
| 193 | - /** | ||
| 194 | - * Returns whether a renderer is disabled. | ||
| 195 | - * | ||
| 196 | - * @param rendererIndex Renderer index. | ||
| 197 | - * @return Whether the renderer is disabled. | ||
| 198 | - */ | ||
| 199 | - public boolean getIsDisabled(int rendererIndex) { | ||
| 200 | - TrackSelectionViewFragment rendererView = tabFragments.get(rendererIndex); | ||
| 201 | - return rendererView != null && rendererView.isDisabled; | ||
| 202 | - } | ||
| 203 | - | ||
| 204 | - /** | ||
| 205 | - * Returns the list of selected track selection overrides for the specified renderer. There will | ||
| 206 | - * be at most one override for each track group. | ||
| 207 | - * | ||
| 208 | - * @param rendererIndex Renderer index. | ||
| 209 | - * @return The list of track selection overrides for this renderer. | ||
| 210 | - */ | ||
| 211 | - public List<SelectionOverride> getOverrides(int rendererIndex) { | ||
| 212 | - TrackSelectionViewFragment rendererView = tabFragments.get(rendererIndex); | ||
| 213 | - return rendererView == null ? Collections.emptyList() : rendererView.overrides; | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - @Override | ||
| 217 | - public Dialog onCreateDialog(Bundle savedInstanceState) { | ||
| 218 | - // We need to own the view to let tab layout work correctly on all API levels. We can't use | ||
| 219 | - // AlertDialog because it owns the view itself, so we use AppCompatDialog instead, themed using | ||
| 220 | - // the AlertDialog theme overlay with force-enabled title. | ||
| 221 | - AppCompatDialog dialog = | ||
| 222 | - new AppCompatDialog(getActivity(), R.style.TrackSelectionDialogThemeOverlay); | ||
| 223 | - dialog.setTitle(titleId); | ||
| 224 | - return dialog; | ||
| 225 | - } | ||
| 226 | - | ||
| 227 | - @Override | ||
| 228 | - public void onDismiss(DialogInterface dialog) { | ||
| 229 | - super.onDismiss(dialog); | ||
| 230 | - onDismissListener.onDismiss(dialog); | ||
| 231 | - } | ||
| 232 | - | ||
| 233 | - @Nullable | ||
| 234 | - @Override | ||
| 235 | - public View onCreateView( | ||
| 236 | - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | ||
| 237 | - | ||
| 238 | - View dialogView = inflater.inflate(R.layout.track_selection_dialog, container, false); | ||
| 239 | - TabLayout tabLayout = dialogView.findViewById(R.id.track_selection_dialog_tab_layout); | ||
| 240 | - ViewPager viewPager = dialogView.findViewById(R.id.track_selection_dialog_view_pager); | ||
| 241 | - Button cancelButton = dialogView.findViewById(R.id.track_selection_dialog_cancel_button); | ||
| 242 | - Button okButton = dialogView.findViewById(R.id.track_selection_dialog_ok_button); | ||
| 243 | - viewPager.setAdapter(new FragmentAdapter(getChildFragmentManager())); | ||
| 244 | - tabLayout.setupWithViewPager(viewPager); | ||
| 245 | - tabLayout.setVisibility(tabFragments.size() > 1 ? View.VISIBLE : View.GONE); | ||
| 246 | - cancelButton.setOnClickListener(view -> dismiss()); | ||
| 247 | - okButton.setOnClickListener( | ||
| 248 | - view -> { | ||
| 249 | - onClickListener.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); | ||
| 250 | - dismiss(); | ||
| 251 | - }); | ||
| 252 | - return dialogView; | ||
| 253 | - } | ||
| 254 | - | ||
| 255 | - private static boolean showTabForRenderer(MappedTrackInfo mappedTrackInfo, int rendererIndex) { | ||
| 256 | - TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex); | ||
| 257 | - if (trackGroupArray.length == 0) { | ||
| 258 | - return false; | ||
| 259 | - } | ||
| 260 | - int trackType = mappedTrackInfo.getRendererType(rendererIndex); | ||
| 261 | - return isSupportedTrackType(trackType); | ||
| 262 | - } | ||
| 263 | - | ||
| 264 | - private static boolean isSupportedTrackType(int trackType) { | ||
| 265 | - switch (trackType) { | ||
| 266 | - case C.TRACK_TYPE_VIDEO: | ||
| 267 | - case C.TRACK_TYPE_AUDIO: | ||
| 268 | - case C.TRACK_TYPE_TEXT: | ||
| 269 | - return true; | ||
| 270 | - default: | ||
| 271 | - return false; | ||
| 272 | - } | ||
| 273 | - } | ||
| 274 | - | ||
| 275 | - private static String getTrackTypeString(Resources resources, int trackType) { | ||
| 276 | - switch (trackType) { | ||
| 277 | - case C.TRACK_TYPE_VIDEO: | ||
| 278 | - return resources.getString(R.string.exo_track_selection_title_video); | ||
| 279 | - case C.TRACK_TYPE_AUDIO: | ||
| 280 | - return resources.getString(R.string.exo_track_selection_title_audio); | ||
| 281 | - case C.TRACK_TYPE_TEXT: | ||
| 282 | - return resources.getString(R.string.exo_track_selection_title_text); | ||
| 283 | - default: | ||
| 284 | - throw new IllegalArgumentException(); | ||
| 285 | - } | ||
| 286 | - } | ||
| 287 | - | ||
| 288 | - private final class FragmentAdapter extends FragmentPagerAdapter { | ||
| 289 | - | ||
| 290 | - public FragmentAdapter(FragmentManager fragmentManager) { | ||
| 291 | - super(fragmentManager); | ||
| 292 | - } | ||
| 293 | - | ||
| 294 | - @Override | ||
| 295 | - public Fragment getItem(int position) { | ||
| 296 | - return tabFragments.valueAt(position); | ||
| 297 | - } | ||
| 298 | - | ||
| 299 | - @Override | ||
| 300 | - public int getCount() { | ||
| 301 | - return tabFragments.size(); | ||
| 302 | - } | ||
| 303 | - | ||
| 304 | - @Nullable | ||
| 305 | - @Override | ||
| 306 | - public CharSequence getPageTitle(int position) { | ||
| 307 | - return getTrackTypeString(getResources(), tabTrackTypes.get(position)); | ||
| 308 | - } | ||
| 309 | - } | ||
| 310 | - | ||
| 311 | - /** Fragment to show a track selection in tab of the track selection dialog. */ | ||
| 312 | - public static final class TrackSelectionViewFragment extends Fragment | ||
| 313 | - implements TrackSelectionView.TrackSelectionListener { | ||
| 314 | - | ||
| 315 | - private MappedTrackInfo mappedTrackInfo; | ||
| 316 | - private int rendererIndex; | ||
| 317 | - private boolean allowAdaptiveSelections; | ||
| 318 | - private boolean allowMultipleOverrides; | ||
| 319 | - | ||
| 320 | - /* package */ boolean isDisabled; | ||
| 321 | - /* package */ List<SelectionOverride> overrides; | ||
| 322 | - | ||
| 323 | - public TrackSelectionViewFragment() { | ||
| 324 | - // Retain instance across activity re-creation to prevent losing access to init data. | ||
| 325 | - setRetainInstance(true); | ||
| 326 | - } | ||
| 327 | - | ||
| 328 | - public void init( | ||
| 329 | - MappedTrackInfo mappedTrackInfo, | ||
| 330 | - int rendererIndex, | ||
| 331 | - boolean initialIsDisabled, | ||
| 332 | - @Nullable SelectionOverride initialOverride, | ||
| 333 | - boolean allowAdaptiveSelections, | ||
| 334 | - boolean allowMultipleOverrides) { | ||
| 335 | - this.mappedTrackInfo = mappedTrackInfo; | ||
| 336 | - this.rendererIndex = rendererIndex; | ||
| 337 | - this.isDisabled = initialIsDisabled; | ||
| 338 | - this.overrides = | ||
| 339 | - initialOverride == null | ||
| 340 | - ? Collections.emptyList() | ||
| 341 | - : Collections.singletonList(initialOverride); | ||
| 342 | - this.allowAdaptiveSelections = allowAdaptiveSelections; | ||
| 343 | - this.allowMultipleOverrides = allowMultipleOverrides; | ||
| 344 | - } | ||
| 345 | - | ||
| 346 | - @Nullable | ||
| 347 | - @Override | ||
| 348 | - public View onCreateView( | ||
| 349 | - LayoutInflater inflater, | ||
| 350 | - @Nullable ViewGroup container, | ||
| 351 | - @Nullable Bundle savedInstanceState) { | ||
| 352 | - View rootView = | ||
| 353 | - inflater.inflate( | ||
| 354 | - R.layout.exo_track_selection_dialog, container, /* attachToRoot= */ false); | ||
| 355 | - TrackSelectionView trackSelectionView = rootView.findViewById(R.id.exo_track_selection_view); | ||
| 356 | - trackSelectionView.setShowDisableOption(true); | ||
| 357 | - trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides); | ||
| 358 | - trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections); | ||
| 359 | - trackSelectionView.init( | ||
| 360 | - mappedTrackInfo, rendererIndex, isDisabled, overrides, /* listener= */ this); | ||
| 361 | - return rootView; | ||
| 362 | - } | ||
| 363 | - | ||
| 364 | - @Override | ||
| 365 | - public void onTrackSelectionChanged(boolean isDisabled, List<SelectionOverride> overrides) { | ||
| 366 | - this.isDisabled = isDisabled; | ||
| 367 | - this.overrides = overrides; | ||
| 368 | - } | ||
| 369 | - } | ||
| 370 | -} |
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DefaultErrorView.java
| 1 | package com.libs.video.video.exoplayer.component; | 1 | package com.libs.video.video.exoplayer.component; |
| 2 | 2 | ||
| 3 | import android.content.Context; | 3 | import android.content.Context; |
| 4 | +import android.content.res.Configuration; | ||
| 4 | import android.util.AttributeSet; | 5 | import android.util.AttributeSet; |
| 5 | import android.util.Log; | 6 | import android.util.Log; |
| 6 | import android.view.LayoutInflater; | 7 | import android.view.LayoutInflater; |
| @@ -17,6 +18,7 @@ import com.cnlive.core.libs.base.util.NetworkUtil; | @@ -17,6 +18,7 @@ import com.cnlive.core.libs.base.util.NetworkUtil; | ||
| 17 | import com.libs.video.video.exoplayer.PlayErrorException; | 18 | import com.libs.video.video.exoplayer.PlayErrorException; |
| 18 | import com.libs.video.video.exoplayer.controller.ControlWrapper; | 19 | import com.libs.video.video.exoplayer.controller.ControlWrapper; |
| 19 | import com.libs.video.video.exoplayer.controller.IControlComponent; | 20 | import com.libs.video.video.exoplayer.controller.IControlComponent; |
| 21 | +import com.libs.video.video.exoplayer.controller.OrientationHelper; | ||
| 20 | import com.libs.video.video.exoplayer.play.AbstractPlayer; | 22 | import com.libs.video.video.exoplayer.play.AbstractPlayer; |
| 21 | import com.libs.video.video.exoplayer.play.CNVideoView; | 23 | import com.libs.video.video.exoplayer.play.CNVideoView; |
| 22 | 24 | ||
| @@ -140,5 +142,17 @@ public class DefaultErrorView extends LinearLayout implements IControlComponent | @@ -140,5 +142,17 @@ public class DefaultErrorView extends LinearLayout implements IControlComponent | ||
| 140 | } | 142 | } |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | - | 145 | + /** |
| 146 | + * @param newConfig | ||
| 147 | + */ | ||
| 148 | + @Override | ||
| 149 | + protected void onConfigurationChanged(Configuration newConfig) { | ||
| 150 | + super.onConfigurationChanged(newConfig); | ||
| 151 | + //新状态为横屏 | ||
| 152 | + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { | ||
| 153 | + Log.e(TAG, "onConfigurationChanged: 横屏" ); | ||
| 154 | + }else { | ||
| 155 | + Log.e(TAG, "onConfigurationChanged: 竖屏" ); | ||
| 156 | + } | ||
| 157 | + } | ||
| 144 | } | 158 | } |
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DefaultYoukuErrorView.java
0 → 100644
| 1 | +package com.libs.video.video.exoplayer.component; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.content.res.Configuration; | ||
| 5 | +import android.util.AttributeSet; | ||
| 6 | +import android.util.Log; | ||
| 7 | +import android.view.LayoutInflater; | ||
| 8 | +import android.view.MotionEvent; | ||
| 9 | +import android.view.View; | ||
| 10 | +import android.view.ViewConfiguration; | ||
| 11 | +import android.view.animation.Animation; | ||
| 12 | +import android.widget.Button; | ||
| 13 | +import android.widget.LinearLayout; | ||
| 14 | +import android.widget.TextView; | ||
| 15 | + | ||
| 16 | +import com.cnlive.cloud.video.R; | ||
| 17 | +import com.libs.video.video.exoplayer.PlayErrorException; | ||
| 18 | +import com.libs.video.video.exoplayer.controller.ControlWrapper; | ||
| 19 | +import com.libs.video.video.exoplayer.controller.IControlComponent; | ||
| 20 | +import com.libs.video.video.exoplayer.play.CNVideoView; | ||
| 21 | + | ||
| 22 | +import androidx.annotation.NonNull; | ||
| 23 | +import androidx.annotation.Nullable; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 播放出错提示界面 | ||
| 27 | + */ | ||
| 28 | +public class DefaultYoukuErrorView extends LinearLayout implements IControlComponent { | ||
| 29 | + | ||
| 30 | + private float mDownX; | ||
| 31 | + private float mDownY; | ||
| 32 | + private Button btnRetry; | ||
| 33 | + private TextView tvMessage; | ||
| 34 | + private ControlWrapper mControlWrapper;//公共控制接口 | ||
| 35 | + private String TAG = this.getClass().getName(); | ||
| 36 | + | ||
| 37 | + public DefaultYoukuErrorView(Context context) { | ||
| 38 | + this(context, null); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public DefaultYoukuErrorView(Context context, @Nullable AttributeSet attrs) { | ||
| 42 | + super(context, attrs); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public DefaultYoukuErrorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | ||
| 46 | + super(context, attrs, defStyleAttr); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + { | ||
| 50 | + setVisibility(GONE); | ||
| 51 | + LayoutInflater.from(getContext()).inflate(R.layout.cnvideo_layout_error_view, this, true); | ||
| 52 | + btnRetry = findViewById(R.id.btn_retry); | ||
| 53 | + tvMessage=findViewById(R.id.tv_message); | ||
| 54 | + btnRetry.setOnClickListener(new OnClickListener() { | ||
| 55 | + @Override | ||
| 56 | + public void onClick(View v) { | ||
| 57 | + setVisibility(GONE); | ||
| 58 | + mControlWrapper.replay(false); | ||
| 59 | + } | ||
| 60 | + }); | ||
| 61 | + setClickable(true); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @Override | ||
| 65 | + public void attach(@NonNull ControlWrapper controlWrapper) { | ||
| 66 | + mControlWrapper = controlWrapper; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public View getView() { | ||
| 71 | + return this; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public void onPlayStateChanged(int playState) { | ||
| 77 | + if (playState == CNVideoView.STATE_ERROR) { | ||
| 78 | + //将view的z轴改变,置于父view的最上方。这个方法会将view从父view中移除,再添加到父view中。 | ||
| 79 | + bringToFront(); | ||
| 80 | + setVisibility(VISIBLE); | ||
| 81 | + } else if (playState == CNVideoView.STATE_IDLE) { | ||
| 82 | + setVisibility(GONE); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + @Override | ||
| 88 | + public boolean dispatchTouchEvent(MotionEvent ev) { | ||
| 89 | + switch (ev.getAction()) { | ||
| 90 | + case MotionEvent.ACTION_DOWN: | ||
| 91 | + mDownX = ev.getX(); | ||
| 92 | + mDownY = ev.getY(); | ||
| 93 | + // True if the child does not want the parent to intercept touch events. | ||
| 94 | + getParent().requestDisallowInterceptTouchEvent(true); | ||
| 95 | + break; | ||
| 96 | + case MotionEvent.ACTION_MOVE: | ||
| 97 | + float absDeltaX = Math.abs(ev.getX() - mDownX); | ||
| 98 | + float absDeltaY = Math.abs(ev.getY() - mDownY); | ||
| 99 | + if (absDeltaX > ViewConfiguration.get(getContext()).getScaledTouchSlop() || | ||
| 100 | + absDeltaY > ViewConfiguration.get(getContext()).getScaledTouchSlop()) { | ||
| 101 | + getParent().requestDisallowInterceptTouchEvent(false); | ||
| 102 | + } | ||
| 103 | + case MotionEvent.ACTION_UP: | ||
| 104 | + break; | ||
| 105 | + } | ||
| 106 | + return super.dispatchTouchEvent(ev); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + @Override | ||
| 110 | + public void onVisibilityChanged(boolean isVisible, Animation anim) { | ||
| 111 | + | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + @Override | ||
| 115 | + public void onPlayerStateChanged(int playerState) { | ||
| 116 | + | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public void setProgress(int duration, int position) { | ||
| 121 | + | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + @Override | ||
| 125 | + public void onLockStateChanged(boolean isLock) { | ||
| 126 | + | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + @Override | ||
| 130 | + public void onPlayError(PlayErrorException exception) { | ||
| 131 | + //获取当前类型 | ||
| 132 | + if (null == tvMessage) { | ||
| 133 | + return; | ||
| 134 | + } | ||
| 135 | + switch (exception.getErrorType()) { | ||
| 136 | + case PlayErrorException.TYPE_NETWORK_ERROR: | ||
| 137 | + tvMessage.setText(exception.getErrorMsg()); | ||
| 138 | + break; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * @param newConfig | ||
| 144 | + */ | ||
| 145 | + @Override | ||
| 146 | + protected void onConfigurationChanged(Configuration newConfig) { | ||
| 147 | + super.onConfigurationChanged(newConfig); | ||
| 148 | + //新状态为横屏 | ||
| 149 | + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { | ||
| 150 | + Log.e(TAG, "onConfigurationChanged: 横屏" ); | ||
| 151 | + }else { | ||
| 152 | + Log.e(TAG, "onConfigurationChanged: 竖屏" ); | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | +} |
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DefaultYoukuPrepareView.java
0 → 100644
| 1 | +package com.libs.video.video.exoplayer.component; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.graphics.drawable.AnimationDrawable; | ||
| 5 | +import android.util.AttributeSet; | ||
| 6 | +import android.view.LayoutInflater; | ||
| 7 | +import android.view.View; | ||
| 8 | +import android.view.animation.Animation; | ||
| 9 | +import android.widget.FrameLayout; | ||
| 10 | +import android.widget.ImageView; | ||
| 11 | +import android.widget.ProgressBar; | ||
| 12 | + | ||
| 13 | +import com.cnlive.cloud.video.R; | ||
| 14 | +import com.libs.video.video.exoplayer.PlayErrorException; | ||
| 15 | +import com.libs.video.video.exoplayer.controller.ControlWrapper; | ||
| 16 | +import com.libs.video.video.exoplayer.controller.IControlComponent; | ||
| 17 | +import com.libs.video.video.exoplayer.play.CNVideoView; | ||
| 18 | +import com.libs.video.video.exoplayer.play.VideoViewManager; | ||
| 19 | + | ||
| 20 | +import androidx.annotation.NonNull; | ||
| 21 | +import androidx.annotation.Nullable; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * 准备播放界面 | ||
| 25 | + */ | ||
| 26 | +public class DefaultYoukuPrepareView extends FrameLayout implements IControlComponent { | ||
| 27 | + | ||
| 28 | + private ControlWrapper mControlWrapper; | ||
| 29 | + | ||
| 30 | + // private ImageView mStartPlay; | ||
| 31 | + private FrameLayout mNetWarning; | ||
| 32 | + private View youkuLoading; | ||
| 33 | + | ||
| 34 | + public DefaultYoukuPrepareView(@NonNull Context context) { | ||
| 35 | + super(context); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public DefaultYoukuPrepareView(@NonNull Context context, @Nullable AttributeSet attrs) { | ||
| 39 | + super(context, attrs); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + public DefaultYoukuPrepareView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | ||
| 43 | + super(context, attrs, defStyleAttr); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + { | ||
| 47 | + LayoutInflater.from(getContext()).inflate(R.layout.cnvideo_layout_youku_prepare_view, this, true); | ||
| 48 | +// mStartPlay = findViewById(R.id.start_play); | ||
| 49 | + youkuLoading= findViewById(R.id.view_youku_loading); | ||
| 50 | + mNetWarning = findViewById(R.id.net_warning_layout); | ||
| 51 | + AnimationDrawable animationDrawable = (AnimationDrawable) youkuLoading.getBackground(); | ||
| 52 | + animationDrawable.start(); | ||
| 53 | + findViewById(R.id.status_btn).setOnClickListener(new OnClickListener() { | ||
| 54 | + @Override | ||
| 55 | + public void onClick(View v) { | ||
| 56 | + mNetWarning.setVisibility(GONE); | ||
| 57 | + VideoViewManager.instance().setPlayOnMobileNetwork(true); | ||
| 58 | + mControlWrapper.start(); | ||
| 59 | + } | ||
| 60 | + }); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 设置点击此界面开始播放 | ||
| 65 | + */ | ||
| 66 | + public void setClickStart() { | ||
| 67 | + setOnClickListener(new OnClickListener() { | ||
| 68 | + @Override | ||
| 69 | + public void onClick(View v) { | ||
| 70 | + mControlWrapper.start(); | ||
| 71 | + } | ||
| 72 | + }); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public void attach(@NonNull ControlWrapper controlWrapper) { | ||
| 77 | + mControlWrapper = controlWrapper; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public View getView() { | ||
| 82 | + return this; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Override | ||
| 86 | + public void onVisibilityChanged(boolean isVisible, Animation anim) { | ||
| 87 | + | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public void onPlayStateChanged(int playState) { | ||
| 92 | + switch (playState) { | ||
| 93 | + case CNVideoView.STATE_PREPARING: | ||
| 94 | + bringToFront(); | ||
| 95 | + setVisibility(VISIBLE); | ||
| 96 | +// mStartPlay.setVisibility(View.GONE); | ||
| 97 | + mNetWarning.setVisibility(GONE); | ||
| 98 | + break; | ||
| 99 | + case CNVideoView.STATE_PLAYING: | ||
| 100 | + case CNVideoView.STATE_PAUSED: | ||
| 101 | + case CNVideoView.STATE_ERROR: | ||
| 102 | + case CNVideoView.STATE_BUFFERING: | ||
| 103 | + case CNVideoView.STATE_BUFFERED: | ||
| 104 | + case CNVideoView.STATE_PLAYBACK_COMPLETED: | ||
| 105 | + setVisibility(GONE); | ||
| 106 | + break; | ||
| 107 | + case CNVideoView.STATE_IDLE: | ||
| 108 | + setVisibility(VISIBLE); | ||
| 109 | + bringToFront(); | ||
| 110 | + mNetWarning.setVisibility(GONE); | ||
| 111 | +// mStartPlay.setVisibility(View.VISIBLE); | ||
| 112 | + break; | ||
| 113 | + case CNVideoView.STATE_START_ABORT: | ||
| 114 | + setVisibility(VISIBLE); | ||
| 115 | + mNetWarning.setVisibility(VISIBLE); | ||
| 116 | + mNetWarning.bringToFront(); | ||
| 117 | + break; | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + @Override | ||
| 122 | + public void onPlayerStateChanged(int playerState) { | ||
| 123 | + | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + @Override | ||
| 127 | + public void setProgress(int duration, int position) { | ||
| 128 | + | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + @Override | ||
| 132 | + public void onLockStateChanged(boolean isLocked) { | ||
| 133 | + | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + @Override | ||
| 137 | + public void onPlayError(PlayErrorException exception) { | ||
| 138 | + | ||
| 139 | + } | ||
| 140 | +} |
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/ControlWrapper.java
| @@ -31,10 +31,10 @@ public class ControlWrapper implements MediaPlayerControl, IVideoController { | @@ -31,10 +31,10 @@ public class ControlWrapper implements MediaPlayerControl, IVideoController { | ||
| 31 | return abstractPlayer; | 31 | return abstractPlayer; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | - @Override | ||
| 35 | - public int getMediaCount() { | ||
| 36 | - return mPlayerControl.getMediaCount(); | ||
| 37 | - } | 34 | +// @Override |
| 35 | +// public int getMediaCount() { | ||
| 36 | +// return mPlayerControl.getMediaCount(); | ||
| 37 | +// } | ||
| 38 | 38 | ||
| 39 | @Override | 39 | @Override |
| 40 | public void start() { | 40 | public void start() { |
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/IControlComponent.java
| @@ -65,4 +65,9 @@ public interface IControlComponent { | @@ -65,4 +65,9 @@ public interface IControlComponent { | ||
| 65 | * @param exception | 65 | * @param exception |
| 66 | */ | 66 | */ |
| 67 | void onPlayError(PlayErrorException exception); | 67 | void onPlayError(PlayErrorException exception); |
| 68 | + | ||
| 69 | + /**屏幕方向改变 | ||
| 70 | + * @param orientation | ||
| 71 | + */ | ||
| 72 | +// void onScreenOrientationChanged(int orientation); | ||
| 68 | } | 73 | } |
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/MediaPlayerControl.java
| @@ -9,7 +9,7 @@ import com.libs.video.video.exoplayer.play.AbstractPlayer; | @@ -9,7 +9,7 @@ import com.libs.video.video.exoplayer.play.AbstractPlayer; | ||
| 9 | */ | 9 | */ |
| 10 | public interface MediaPlayerControl { | 10 | public interface MediaPlayerControl { |
| 11 | 11 | ||
| 12 | - int getMediaCount(); | 12 | +// int getMediaCount(); |
| 13 | 13 | ||
| 14 | void start(); | 14 | void start(); |
| 15 | 15 |
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/StandardVideoController.java
| @@ -16,6 +16,7 @@ import com.cnlive.cloud.video.R; | @@ -16,6 +16,7 @@ import com.cnlive.cloud.video.R; | ||
| 16 | import com.libs.video.video.exoplayer.PlayErrorException; | 16 | import com.libs.video.video.exoplayer.PlayErrorException; |
| 17 | import com.libs.video.video.exoplayer.component.DefaultCompleteView; | 17 | import com.libs.video.video.exoplayer.component.DefaultCompleteView; |
| 18 | import com.libs.video.video.exoplayer.component.DefaultErrorView; | 18 | import com.libs.video.video.exoplayer.component.DefaultErrorView; |
| 19 | +import com.libs.video.video.exoplayer.component.DefaultYoukuPrepareView; | ||
| 19 | import com.libs.video.video.exoplayer.component.GestureView; | 20 | import com.libs.video.video.exoplayer.component.GestureView; |
| 20 | import com.libs.video.video.exoplayer.component.LiveControlView; | 21 | import com.libs.video.video.exoplayer.component.LiveControlView; |
| 21 | import com.libs.video.video.exoplayer.component.DefaultPrepareView; | 22 | import com.libs.video.video.exoplayer.component.DefaultPrepareView; |
| @@ -37,7 +38,7 @@ public class StandardVideoController extends GestureVideoController implements V | @@ -37,7 +38,7 @@ public class StandardVideoController extends GestureVideoController implements V | ||
| 37 | 38 | ||
| 38 | protected ImageView mLockButton;//锁屏按钮 | 39 | protected ImageView mLockButton;//锁屏按钮 |
| 39 | 40 | ||
| 40 | - protected ProgressBar mLoadingProgress; | 41 | +// protected ProgressBar mLoadingProgress; |
| 41 | 42 | ||
| 42 | public StandardVideoController(@NonNull Context context) { | 43 | public StandardVideoController(@NonNull Context context) { |
| 43 | this(context, null); | 44 | this(context, null); |
| @@ -61,7 +62,7 @@ public class StandardVideoController extends GestureVideoController implements V | @@ -61,7 +62,7 @@ public class StandardVideoController extends GestureVideoController implements V | ||
| 61 | super.initView(); | 62 | super.initView(); |
| 62 | mLockButton = findViewById(R.id.lock); | 63 | mLockButton = findViewById(R.id.lock); |
| 63 | mLockButton.setOnClickListener(this); | 64 | mLockButton.setOnClickListener(this); |
| 64 | - mLoadingProgress = findViewById(R.id.loading); | 65 | +// mLoadingProgress = findViewById(R.id.loading); |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | 68 | ||
| @@ -170,21 +171,21 @@ public class StandardVideoController extends GestureVideoController implements V | @@ -170,21 +171,21 @@ public class StandardVideoController extends GestureVideoController implements V | ||
| 170 | //调用release方法会回到此状态 | 171 | //调用release方法会回到此状态 |
| 171 | case CNVideoView.STATE_IDLE: | 172 | case CNVideoView.STATE_IDLE: |
| 172 | mLockButton.setSelected(false); | 173 | mLockButton.setSelected(false); |
| 173 | - mLoadingProgress.setVisibility(GONE); | 174 | +// mLoadingProgress.setVisibility(GONE); |
| 174 | break; | 175 | break; |
| 175 | case CNVideoView.STATE_PLAYING: | 176 | case CNVideoView.STATE_PLAYING: |
| 176 | case CNVideoView.STATE_PAUSED: | 177 | case CNVideoView.STATE_PAUSED: |
| 177 | case CNVideoView.STATE_PREPARED: | 178 | case CNVideoView.STATE_PREPARED: |
| 178 | case CNVideoView.STATE_ERROR: | 179 | case CNVideoView.STATE_ERROR: |
| 179 | case CNVideoView.STATE_BUFFERED: | 180 | case CNVideoView.STATE_BUFFERED: |
| 180 | - mLoadingProgress.setVisibility(GONE); | 181 | +// mLoadingProgress.setVisibility(GONE); |
| 181 | break; | 182 | break; |
| 182 | case CNVideoView.STATE_PREPARING: | 183 | case CNVideoView.STATE_PREPARING: |
| 183 | case CNVideoView.STATE_BUFFERING: | 184 | case CNVideoView.STATE_BUFFERING: |
| 184 | - mLoadingProgress.setVisibility(VISIBLE); | 185 | +// mLoadingProgress.setVisibility(VISIBLE); |
| 185 | break; | 186 | break; |
| 186 | case CNVideoView.STATE_PLAYBACK_COMPLETED: | 187 | case CNVideoView.STATE_PLAYBACK_COMPLETED: |
| 187 | - mLoadingProgress.setVisibility(GONE); | 188 | +// mLoadingProgress.setVisibility(GONE); |
| 188 | mLockButton.setVisibility(GONE); | 189 | mLockButton.setVisibility(GONE); |
| 189 | mLockButton.setSelected(false); | 190 | mLockButton.setSelected(false); |
| 190 | break; | 191 | break; |
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/CNVideoView.java
| @@ -28,10 +28,13 @@ import com.libs.video.video.exoplayer.render.IRenderView; | @@ -28,10 +28,13 @@ import com.libs.video.video.exoplayer.render.IRenderView; | ||
| 28 | import com.libs.video.video.exoplayer.render.RenderViewFactory; | 28 | import com.libs.video.video.exoplayer.render.RenderViewFactory; |
| 29 | 29 | ||
| 30 | import java.io.IOException; | 30 | import java.io.IOException; |
| 31 | +import java.lang.annotation.Retention; | ||
| 32 | +import java.lang.annotation.RetentionPolicy; | ||
| 31 | import java.util.ArrayList; | 33 | import java.util.ArrayList; |
| 32 | import java.util.List; | 34 | import java.util.List; |
| 33 | import java.util.Map; | 35 | import java.util.Map; |
| 34 | 36 | ||
| 37 | +import androidx.annotation.IntDef; | ||
| 35 | import androidx.annotation.NonNull; | 38 | import androidx.annotation.NonNull; |
| 36 | import androidx.annotation.Nullable; | 39 | import androidx.annotation.Nullable; |
| 37 | 40 | ||
| @@ -125,8 +128,8 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -125,8 +128,8 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 125 | */ | 128 | */ |
| 126 | private int mPlayerBackgroundColor; | 129 | private int mPlayerBackgroundColor; |
| 127 | 130 | ||
| 128 | - private List<String> dataSource; | ||
| 129 | - private int curentPlayIndex; | 131 | +// private List<String> dataSource; |
| 132 | +// private int curentPlayIndex; | ||
| 130 | 133 | ||
| 131 | public CNVideoView(@NonNull Context context) { | 134 | public CNVideoView(@NonNull Context context) { |
| 132 | this(context, null); | 135 | this(context, null); |
| @@ -138,7 +141,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -138,7 +141,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 138 | 141 | ||
| 139 | public CNVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | 142 | public CNVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { |
| 140 | super(context, attrs, defStyleAttr); | 143 | super(context, attrs, defStyleAttr); |
| 141 | - dataSource = new ArrayList<>(); | 144 | +// dataSource = new ArrayList<>(); |
| 142 | //读取全局配置 | 145 | //读取全局配置 |
| 143 | VideoViewConfig config = VideoViewManager.getConfig(); | 146 | VideoViewConfig config = VideoViewManager.getConfig(); |
| 144 | mEnableAudioFocus = config.mEnableAudioFocus; | 147 | mEnableAudioFocus = config.mEnableAudioFocus; |
| @@ -184,16 +187,16 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -184,16 +187,16 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 184 | } | 187 | } |
| 185 | 188 | ||
| 186 | 189 | ||
| 187 | - | ||
| 188 | - /** | ||
| 189 | - * 当前媒体数量 | ||
| 190 | - * | ||
| 191 | - * @return | ||
| 192 | - */ | ||
| 193 | - @Override | ||
| 194 | - public int getMediaCount() { | ||
| 195 | - return dataSource.size(); | ||
| 196 | - } | 190 | +// |
| 191 | +// /** | ||
| 192 | +// * 当前媒体数量 | ||
| 193 | +// * | ||
| 194 | +// * @return | ||
| 195 | +// */ | ||
| 196 | +// @Override | ||
| 197 | +// public int getMediaCount() { | ||
| 198 | +// return dataSource.size(); | ||
| 199 | +// } | ||
| 197 | 200 | ||
| 198 | /** | 201 | /** |
| 199 | * 开始播放,注意:调用此方法后必须调用{@link #release()}释放播放器,否则会导致内存泄漏 | 202 | * 开始播放,注意:调用此方法后必须调用{@link #release()}释放播放器,否则会导致内存泄漏 |
| @@ -579,11 +582,11 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -579,11 +582,11 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 579 | } | 582 | } |
| 580 | setPlayState(STATE_PLAYBACK_COMPLETED); | 583 | setPlayState(STATE_PLAYBACK_COMPLETED); |
| 581 | 584 | ||
| 582 | - if (curentPlayIndex + 1 <= dataSource.size() - 1) { | ||
| 583 | - curentPlayIndex += 1; | ||
| 584 | - mUrl = dataSource.get(curentPlayIndex); | ||
| 585 | - replay(true); | ||
| 586 | - } | 585 | +// if (curentPlayIndex + 1 <= dataSource.size() - 1) { |
| 586 | +// curentPlayIndex += 1; | ||
| 587 | +// mUrl = dataSource.get(curentPlayIndex); | ||
| 588 | +// replay(true); | ||
| 589 | +// } | ||
| 587 | } | 590 | } |
| 588 | 591 | ||
| 589 | @Override | 592 | @Override |
| @@ -655,19 +658,19 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -655,19 +658,19 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 655 | * 设置视频地址 | 658 | * 设置视频地址 |
| 656 | */ | 659 | */ |
| 657 | public void setUrl(String url) { | 660 | public void setUrl(String url) { |
| 658 | - dataSource.clear(); | ||
| 659 | - dataSource.add(url); | ||
| 660 | - curentPlayIndex = 0; | ||
| 661 | - setUrl(dataSource.get(0), null); | 661 | +// dataSource.clear(); |
| 662 | +// dataSource.add(url); | ||
| 663 | +// curentPlayIndex = 0; | ||
| 664 | + setUrl(url, null); | ||
| 662 | } | 665 | } |
| 663 | 666 | ||
| 664 | - public void setDataSource(List<String> url) { | ||
| 665 | - dataSource.clear(); | ||
| 666 | - dataSource.addAll(url); | ||
| 667 | - curentPlayIndex = 0; | ||
| 668 | - setUrl(dataSource.get(0), null); | ||
| 669 | - | ||
| 670 | - } | 667 | +// public void setDataSource(List<String> url) { |
| 668 | +// dataSource.clear(); | ||
| 669 | +// dataSource.addAll(url); | ||
| 670 | +// curentPlayIndex = 0; | ||
| 671 | +// setUrl(dataSource.get(0), null); | ||
| 672 | +// | ||
| 673 | +// } | ||
| 671 | 674 | ||
| 672 | /** | 675 | /** |
| 673 | * 设置包含请求头信息的视频地址 | 676 | * 设置包含请求头信息的视频地址 |
| @@ -960,7 +963,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -960,7 +963,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 960 | * 设置视频比例 | 963 | * 设置视频比例 |
| 961 | */ | 964 | */ |
| 962 | @Override | 965 | @Override |
| 963 | - public void setScreenScaleType(int screenScaleType) { | 966 | + public void setScreenScaleType(@CNVideoView.screenScalType int screenScaleType) { |
| 964 | mCurrentScreenScaleType = screenScaleType; | 967 | mCurrentScreenScaleType = screenScaleType; |
| 965 | if (mRenderView != null) { | 968 | if (mRenderView != null) { |
| 966 | mRenderView.setScaleType(screenScaleType); | 969 | mRenderView.setScaleType(screenScaleType); |
| @@ -1144,4 +1147,11 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | @@ -1144,4 +1147,11 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout | ||
| 1144 | } | 1147 | } |
| 1145 | 1148 | ||
| 1146 | 1149 | ||
| 1150 | + /** | ||
| 1151 | + * 视频缩放类型 | ||
| 1152 | + */ | ||
| 1153 | + @IntDef({SCREEN_SCALE_DEFAULT,SCREEN_SCALE_16_9,SCREEN_SCALE_4_3,SCREEN_SCALE_MATCH_PARENT,SCREEN_SCALE_ORIGINAL,SCREEN_SCALE_CENTER_CROP}) | ||
| 1154 | + @Retention(RetentionPolicy.SOURCE) | ||
| 1155 | + public @interface screenScalType { | ||
| 1156 | + } | ||
| 1147 | } | 1157 | } |
cloud/video/src/main/res/drawable-hdpi/loading_00.png
0 → 100644
390 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_01.png
0 → 100644
363 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_02.png
0 → 100644
378 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_03.png
0 → 100644
379 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_04.png
0 → 100644
384 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_05.png
0 → 100644
419 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_06.png
0 → 100644
404 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_07.png
0 → 100644
372 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_08.png
0 → 100644
369 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_09.png
0 → 100644
408 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_10.png
0 → 100644
419 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_11.png
0 → 100644
388 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_12.png
0 → 100644
382 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_13.png
0 → 100644
386 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_14.png
0 → 100644
363 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_15.png
0 → 100644
385 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_16.png
0 → 100644
375 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_17.png
0 → 100644
383 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_18.png
0 → 100644
387 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_19.png
0 → 100644
389 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_20.png
0 → 100644
429 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_21.png
0 → 100644
411 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_22.png
0 → 100644
369 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_23.png
0 → 100644
375 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_24.png
0 → 100644
403 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_25.png
0 → 100644
425 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_26.png
0 → 100644
390 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_27.png
0 → 100644
382 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_28.png
0 → 100644
374 Bytes
cloud/video/src/main/res/drawable-hdpi/loading_29.png
0 → 100644
367 Bytes
cloud/video/src/main/res/drawable-hdpi/player_small_loading_view_bg.png
0 → 100644
11.7 KB
cloud/video/src/main/res/drawable-hdpi/xadsdk_youku_logo.png
0 → 100644
3.05 KB
cloud/video/src/main/res/drawable/anim_youku_prepare.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | + android:oneshot="false"> | ||
| 4 | + <item | ||
| 5 | + android:drawable="@drawable/loading_00" | ||
| 6 | + android:duration="100" /> | ||
| 7 | + <item | ||
| 8 | + android:drawable="@drawable/loading_01" | ||
| 9 | + android:duration="100" /> | ||
| 10 | + <item | ||
| 11 | + android:drawable="@drawable/loading_02" | ||
| 12 | + android:duration="100" /> | ||
| 13 | + <item | ||
| 14 | + android:drawable="@drawable/loading_03" | ||
| 15 | + android:duration="100" /> | ||
| 16 | + <item | ||
| 17 | + android:drawable="@drawable/loading_04" | ||
| 18 | + android:duration="100" /> | ||
| 19 | + <item | ||
| 20 | + android:drawable="@drawable/loading_05" | ||
| 21 | + android:duration="100" /> | ||
| 22 | + <item | ||
| 23 | + android:drawable="@drawable/loading_06" | ||
| 24 | + android:duration="100" /> | ||
| 25 | + <item | ||
| 26 | + android:drawable="@drawable/loading_07" | ||
| 27 | + android:duration="100" /> | ||
| 28 | + <item | ||
| 29 | + android:drawable="@drawable/loading_08" | ||
| 30 | + android:duration="100" /> | ||
| 31 | + <item | ||
| 32 | + android:drawable="@drawable/loading_09" | ||
| 33 | + android:duration="100" /> | ||
| 34 | + <item | ||
| 35 | + android:drawable="@drawable/loading_10" | ||
| 36 | + android:duration="100" /> | ||
| 37 | + <item | ||
| 38 | + android:drawable="@drawable/loading_11" | ||
| 39 | + android:duration="100" /> | ||
| 40 | + <item | ||
| 41 | + android:drawable="@drawable/loading_12" | ||
| 42 | + android:duration="100" /> | ||
| 43 | + <item | ||
| 44 | + android:drawable="@drawable/loading_13" | ||
| 45 | + android:duration="100" /> | ||
| 46 | + <item | ||
| 47 | + android:drawable="@drawable/loading_14" | ||
| 48 | + android:duration="100" /> | ||
| 49 | + <item | ||
| 50 | + android:drawable="@drawable/loading_15" | ||
| 51 | + android:duration="100" /> | ||
| 52 | + <item | ||
| 53 | + android:drawable="@drawable/loading_16" | ||
| 54 | + android:duration="100" /> | ||
| 55 | + <item | ||
| 56 | + android:drawable="@drawable/loading_17" | ||
| 57 | + android:duration="100" /> | ||
| 58 | + <item | ||
| 59 | + android:drawable="@drawable/loading_18" | ||
| 60 | + android:duration="100" /> | ||
| 61 | + <item | ||
| 62 | + android:drawable="@drawable/loading_19" | ||
| 63 | + android:duration="100" /> | ||
| 64 | + <item | ||
| 65 | + android:drawable="@drawable/loading_20" | ||
| 66 | + android:duration="100" /> | ||
| 67 | + <item | ||
| 68 | + android:drawable="@drawable/loading_21" | ||
| 69 | + android:duration="100" /> | ||
| 70 | + <item | ||
| 71 | + android:drawable="@drawable/loading_22" | ||
| 72 | + android:duration="100" /> | ||
| 73 | + <item | ||
| 74 | + android:drawable="@drawable/loading_23" | ||
| 75 | + android:duration="100" /> | ||
| 76 | + <item | ||
| 77 | + android:drawable="@drawable/loading_24" | ||
| 78 | + android:duration="100" /> | ||
| 79 | + <item | ||
| 80 | + android:drawable="@drawable/loading_25" | ||
| 81 | + android:duration="100" /> | ||
| 82 | + <item | ||
| 83 | + android:drawable="@drawable/loading_26" | ||
| 84 | + android:duration="100" /> | ||
| 85 | + <item | ||
| 86 | + android:drawable="@drawable/loading_27" | ||
| 87 | + android:duration="100" /> | ||
| 88 | + <item | ||
| 89 | + android:drawable="@drawable/loading_28" | ||
| 90 | + android:duration="100" /> | ||
| 91 | + <item | ||
| 92 | + android:drawable="@drawable/loading_29" | ||
| 93 | + android:duration="100" /> | ||
| 94 | +</animation-list> | ||
| 0 | \ No newline at end of file | 95 | \ No newline at end of file |
cloud/video/src/main/res/layout/cnvideo_layout_youku_prepare_view.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | + xmlns:tools="http://schemas.android.com/tools" | ||
| 4 | + android:layout_width="match_parent" | ||
| 5 | + android:layout_height="match_parent" | ||
| 6 | + android:background="@drawable/player_small_loading_view_bg"> | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + <LinearLayout | ||
| 10 | + android:layout_width="match_parent" | ||
| 11 | + android:layout_height="match_parent" | ||
| 12 | + android:gravity="center" | ||
| 13 | + android:orientation="vertical"> | ||
| 14 | + | ||
| 15 | + <ImageView | ||
| 16 | + android:layout_width="120dp" | ||
| 17 | + android:layout_height="50dp" | ||
| 18 | + android:background="@drawable/xadsdk_youku_logo" /> | ||
| 19 | + | ||
| 20 | + <TextView | ||
| 21 | + android:layout_width="wrap_content" | ||
| 22 | + android:layout_height="wrap_content" | ||
| 23 | + android:text="加载中" | ||
| 24 | + android:textColor="@color/my_dialog_line" | ||
| 25 | + android:textSize="15sp" /> | ||
| 26 | + | ||
| 27 | + <View | ||
| 28 | + android:id="@+id/view_youku_loading" | ||
| 29 | + android:layout_width="30dp" | ||
| 30 | + android:layout_height="30dp" | ||
| 31 | + android:background="@drawable/anim_youku_prepare" /> | ||
| 32 | + </LinearLayout> | ||
| 33 | + | ||
| 34 | + <FrameLayout | ||
| 35 | + android:id="@+id/net_warning_layout" | ||
| 36 | + android:layout_width="match_parent" | ||
| 37 | + android:layout_height="match_parent" | ||
| 38 | + android:background="@android:color/black" | ||
| 39 | + android:clickable="true" | ||
| 40 | + android:focusable="true" | ||
| 41 | + android:visibility="gone"> | ||
| 42 | + | ||
| 43 | + <LinearLayout | ||
| 44 | + android:layout_width="match_parent" | ||
| 45 | + android:layout_height="match_parent" | ||
| 46 | + android:gravity="center" | ||
| 47 | + android:orientation="vertical"> | ||
| 48 | + | ||
| 49 | + <TextView | ||
| 50 | + android:id="@+id/message" | ||
| 51 | + android:layout_width="wrap_content" | ||
| 52 | + android:layout_height="wrap_content" | ||
| 53 | + android:gravity="center" | ||
| 54 | + android:text="@string/cnvideo_wifi_tip" | ||
| 55 | + android:textColor="@android:color/white" /> | ||
| 56 | + | ||
| 57 | + <TextView | ||
| 58 | + android:id="@+id/status_btn" | ||
| 59 | + android:layout_width="wrap_content" | ||
| 60 | + android:layout_height="wrap_content" | ||
| 61 | + android:layout_marginTop="16dp" | ||
| 62 | + android:background="@drawable/cnvideo_shape_status_view_btn" | ||
| 63 | + android:gravity="center" | ||
| 64 | + android:paddingLeft="16dp" | ||
| 65 | + android:paddingTop="4dp" | ||
| 66 | + android:paddingRight="16dp" | ||
| 67 | + android:paddingBottom="4dp" | ||
| 68 | + android:text="@string/cnvideo_continue_play" | ||
| 69 | + android:textColor="@android:color/white" /> | ||
| 70 | + | ||
| 71 | + </LinearLayout> | ||
| 72 | + </FrameLayout> | ||
| 73 | + | ||
| 74 | +</FrameLayout> | ||
| 0 | \ No newline at end of file | 75 | \ No newline at end of file |
config.gradle
| @@ -80,10 +80,10 @@ ext { | @@ -80,10 +80,10 @@ ext { | ||
| 80 | // //权限 | 80 | // //权限 |
| 81 | easypermissions : 'pub.devrel:easypermissions:1.0.0', | 81 | easypermissions : 'pub.devrel:easypermissions:1.0.0', |
| 82 | //MVP | 82 | //MVP |
| 83 | - mvp : 'com.hannesdorfmann.mosby3:mvp:3.0.4', | ||
| 84 | - mvp_viewstate : 'com.hannesdorfmann.mosby3:viewstate:3.0.4', | ||
| 85 | - mvp_lce : 'com.hannesdorfmann.mosby3:mvp-lce:3.0.4', | ||
| 86 | - mvp_nullobject_presenter: 'com.hannesdorfmann.mosby3:mvp-nullobject-presenter:3.0.4', | 83 | + mvp : 'com.hannesdorfmann.mosby3:mvp:3.1.1', |
| 84 | + mvp_viewstate : 'com.hannesdorfmann.mosby3:viewstate:3.1.1', | ||
| 85 | + mvp_lce : 'com.hannesdorfmann.mosby3:mvp-lce:3.1.1', | ||
| 86 | + mvp_nullobject_presenter: 'com.hannesdorfmann.mosby3:mvp-nullobject-presenter:3.1.1', | ||
| 87 | //UI框架库 | 87 | //UI框架库 |
| 88 | qmui : 'com.qmuiteam:qmui:1.4.0', | 88 | qmui : 'com.qmuiteam:qmui:1.4.0', |
| 89 | qmui_arch : 'com.qmuiteam:arch:0.6.1', | 89 | qmui_arch : 'com.qmuiteam:arch:0.6.1', |
| @@ -136,10 +136,10 @@ ext { | @@ -136,10 +136,10 @@ ext { | ||
| 136 | library.qmui, | 136 | library.qmui, |
| 137 | library.qmui_arch, | 137 | library.qmui_arch, |
| 138 | //mvp | 138 | //mvp |
| 139 | -// library.mvp, | ||
| 140 | -// library.mvp_lce, | ||
| 141 | -// library.mvp_nullobject_presenter, | ||
| 142 | -// library.mvp_viewstate, | 139 | + library.mvp, |
| 140 | + library.mvp_lce, | ||
| 141 | + library.mvp_nullobject_presenter, | ||
| 142 | + library.mvp_viewstate, | ||
| 143 | //图片加载Glide | 143 | //图片加载Glide |
| 144 | glide.api, | 144 | glide.api, |
| 145 | glide.transformations, | 145 | glide.transformations, |
core/base/src/main/java/com/hannesdorfmann/mosby3/ActivityScopedCache.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2017 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - * | ||
| 16 | - */ | ||
| 17 | - | ||
| 18 | -package com.hannesdorfmann.mosby3; | ||
| 19 | - | ||
| 20 | -import android.os.Build; | ||
| 21 | -import android.util.ArrayMap; | ||
| 22 | - | ||
| 23 | -import androidx.annotation.NonNull; | ||
| 24 | -import androidx.annotation.Nullable; | ||
| 25 | -import androidx.annotation.RequiresApi; | ||
| 26 | - | ||
| 27 | -import com.hannesdorfmann.mosby3.mvp.MvpPresenter; | ||
| 28 | -import com.hannesdorfmann.mosby3.mvp.MvpView; | ||
| 29 | -import java.util.Map; | ||
| 30 | - | ||
| 31 | -/** | ||
| 32 | - * This class basically represents a Map for View Id to the Presenter / ViewState. | ||
| 33 | - * One instance of this class is also associated by {@link PresenterManager} to one Activity (kept | ||
| 34 | - * across screen orientation changes) | ||
| 35 | - * | ||
| 36 | - * @author Hannes Dorfmann | ||
| 37 | - * @since 3.0.0 | ||
| 38 | - */ | ||
| 39 | -@RequiresApi(api = Build.VERSION_CODES.KITKAT) | ||
| 40 | -class ActivityScopedCache { | ||
| 41 | - | ||
| 42 | - private final Map<String, PresenterHolder> presenterMap = new ArrayMap<>(); | ||
| 43 | - | ||
| 44 | - ActivityScopedCache() { | ||
| 45 | - // package private | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - public void clear() { | ||
| 49 | - /* | ||
| 50 | - // TODO: can this check if there are still Presenters in the internal cache that must be detached? Maybe post() / postDelayed() on the MainThreadLooper() | ||
| 51 | - // it doesnt work out that well, because super.onDestroy() which then invokes PresenterManager.clear() might be called before the MviDelegates did their job to remove the Presenter from cache and detach the view permanently | ||
| 52 | - | ||
| 53 | - for (PresenterHolder holder : presenterMap.values()) { | ||
| 54 | - // This should never be the case: If there were some presenters left in the internal cache, | ||
| 55 | - // a delegate didn't work correctly as expected | ||
| 56 | - if (holder.presenter != null) { | ||
| 57 | - holder.presenter.detachView(false); | ||
| 58 | - if (PresenterManager.DEBUG) { | ||
| 59 | - Log.w(PresenterManager.DEBUG_TAG, | ||
| 60 | - "Found a Presenter that is still alive. This should never happen. It seems that a MvpDelegate / MviDelegate didn't work correctly because this Delegate should have removed the presenter. The Presenter was " | ||
| 61 | - + holder.presenter); | ||
| 62 | - } | ||
| 63 | - } | ||
| 64 | - } | ||
| 65 | - */ | ||
| 66 | - presenterMap.clear(); | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - /** | ||
| 70 | - * Get the Presenter for a given {@link MvpView} if exists or <code>null</code> | ||
| 71 | - * | ||
| 72 | - * @param viewId The mosby internal view id | ||
| 73 | - * @param <P> The type tof the {@link MvpPresenter} | ||
| 74 | - * @return The Presenter for the given view id or <code>null</code> | ||
| 75 | - */ | ||
| 76 | - @Nullable | ||
| 77 | - public <P> P getPresenter(@NonNull String viewId) { | ||
| 78 | - PresenterHolder holder = presenterMap.get(viewId); | ||
| 79 | - return holder == null ? null : (P) holder.presenter; | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - /** | ||
| 83 | - * Get the ViewState for a given {@link MvpView} if exists or <code>null</code> | ||
| 84 | - * | ||
| 85 | - * @param viewId The mosby internal view id | ||
| 86 | - * @param <VS> The type tof the {@link MvpPresenter} | ||
| 87 | - * @return The ViewState for the given view id or <code>null</code> | ||
| 88 | - */ | ||
| 89 | - @Nullable public <VS> VS getViewState(@NonNull String viewId) { | ||
| 90 | - PresenterHolder holder = presenterMap.get(viewId); | ||
| 91 | - return holder == null ? null : (VS) holder.viewState; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - /** | ||
| 95 | - * Put the presenter in the internal cache | ||
| 96 | - * | ||
| 97 | - * @param viewId The mosby internal View id of the {@link MvpView} which the presenter is | ||
| 98 | - * associated to. | ||
| 99 | - * @param presenter The Presenter | ||
| 100 | - */ | ||
| 101 | - public void putPresenter(@NonNull String viewId, | ||
| 102 | - @NonNull MvpPresenter<? extends MvpView> presenter) { | ||
| 103 | - | ||
| 104 | - if (viewId == null) { | ||
| 105 | - throw new NullPointerException("ViewId is null"); | ||
| 106 | - } | ||
| 107 | - | ||
| 108 | - if (presenter == null) { | ||
| 109 | - throw new NullPointerException("Presenter is null"); | ||
| 110 | - } | ||
| 111 | - | ||
| 112 | - PresenterHolder presenterHolder = presenterMap.get(viewId); | ||
| 113 | - if (presenterHolder == null) { | ||
| 114 | - presenterHolder = new PresenterHolder(); | ||
| 115 | - presenterHolder.presenter = presenter; | ||
| 116 | - presenterMap.put(viewId, presenterHolder); | ||
| 117 | - } else { | ||
| 118 | - presenterHolder.presenter = presenter; | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - | ||
| 123 | - /** | ||
| 124 | - * Put the viewstate in the internal cache | ||
| 125 | - * | ||
| 126 | - * @param viewId The mosby internal View id of the {@link MvpView} which the presenter is | ||
| 127 | - * associated to. | ||
| 128 | - * @param viewState The Viewstate | ||
| 129 | - */ | ||
| 130 | - public void putViewState(@NonNull String viewId, | ||
| 131 | - @NonNull Object viewState) { | ||
| 132 | - | ||
| 133 | - if (viewId == null) { | ||
| 134 | - throw new NullPointerException("ViewId is null"); | ||
| 135 | - } | ||
| 136 | - | ||
| 137 | - if (viewState == null) { | ||
| 138 | - throw new NullPointerException("ViewState is null"); | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - PresenterHolder presenterHolder = presenterMap.get(viewId); | ||
| 142 | - if (presenterHolder == null) { | ||
| 143 | - presenterHolder = new PresenterHolder(); | ||
| 144 | - presenterHolder.viewState = viewState; | ||
| 145 | - presenterMap.put(viewId, presenterHolder); | ||
| 146 | - } else { | ||
| 147 | - presenterHolder.viewState = viewState; | ||
| 148 | - } | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - /** | ||
| 152 | - * Removes the Presenter (and ViewState) from the internal storage | ||
| 153 | - * | ||
| 154 | - * @param viewId The msoby internal view id | ||
| 155 | - */ | ||
| 156 | - public void remove(@NonNull String viewId) { | ||
| 157 | - | ||
| 158 | - if (viewId == null) { | ||
| 159 | - throw new NullPointerException("View Id is null"); | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - presenterMap.remove(viewId); | ||
| 163 | - } | ||
| 164 | - | ||
| 165 | - /** | ||
| 166 | - * Internal config change Cache entry | ||
| 167 | - */ | ||
| 168 | - static final class PresenterHolder { | ||
| 169 | - private MvpPresenter<?> presenter; | ||
| 170 | - private Object viewState; // workaround: didn't want to introduce dependency to viewstate module | ||
| 171 | - } | ||
| 172 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/MosbySavedState.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2016 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - * | ||
| 16 | - */ | ||
| 17 | -package com.hannesdorfmann.mosby3; | ||
| 18 | - | ||
| 19 | -import android.os.Build; | ||
| 20 | -import android.os.Parcel; | ||
| 21 | -import android.os.Parcelable; | ||
| 22 | -import android.view.AbsSavedState; | ||
| 23 | - | ||
| 24 | -import androidx.annotation.RequiresApi; | ||
| 25 | -import androidx.core.os.ParcelableCompat; | ||
| 26 | -import androidx.core.os.ParcelableCompatCreatorCallbacks; | ||
| 27 | - | ||
| 28 | -/** | ||
| 29 | - * The SavedState implementation to store the view's internal id to | ||
| 30 | - * | ||
| 31 | - * @author Hannes Dorfmann | ||
| 32 | - * @since 3.0 | ||
| 33 | - */ | ||
| 34 | -public class MosbySavedState extends AbsSavedState { | ||
| 35 | - | ||
| 36 | - public static final Creator<MosbySavedState> CREATOR = | ||
| 37 | - ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<MosbySavedState>() { | ||
| 38 | - public MosbySavedState createFromParcel(Parcel in, ClassLoader loader) { | ||
| 39 | - if (loader == null) { | ||
| 40 | - loader = MosbySavedState.class.getClassLoader(); | ||
| 41 | - } | ||
| 42 | - return new MosbySavedState(in, loader); | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - public MosbySavedState[] newArray(int size) { | ||
| 46 | - return new MosbySavedState[size]; | ||
| 47 | - } | ||
| 48 | - }); | ||
| 49 | - | ||
| 50 | - private String mosbyViewId; | ||
| 51 | - | ||
| 52 | - public MosbySavedState(Parcelable superState, String mosbyViewId) { | ||
| 53 | - super(superState); | ||
| 54 | - this.mosbyViewId = mosbyViewId; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - protected MosbySavedState(Parcel in, ClassLoader loader) { | ||
| 58 | - super(in, loader); | ||
| 59 | - this.mosbyViewId = in.readString(); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - @Override public void writeToParcel(Parcel out, int flags) { | ||
| 63 | - super.writeToParcel(out, flags); | ||
| 64 | - out.writeString(mosbyViewId); | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - public String getMosbyViewId() { | ||
| 68 | - return mosbyViewId; | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/PresenterManager.java deleted
100644 → 0
| 1 | -package com.hannesdorfmann.mosby3; | ||
| 2 | - | ||
| 3 | -import android.app.Activity; | ||
| 4 | -import android.app.Application; | ||
| 5 | -import android.content.Context; | ||
| 6 | -import android.content.ContextWrapper; | ||
| 7 | -import android.os.Build; | ||
| 8 | -import android.os.Bundle; | ||
| 9 | -import android.util.ArrayMap; | ||
| 10 | -import android.util.Log; | ||
| 11 | -import android.view.View; | ||
| 12 | - | ||
| 13 | -import androidx.annotation.MainThread; | ||
| 14 | -import androidx.annotation.NonNull; | ||
| 15 | -import androidx.annotation.Nullable; | ||
| 16 | -import androidx.annotation.RequiresApi; | ||
| 17 | - | ||
| 18 | -import com.hannesdorfmann.mosby3.mvp.MvpPresenter; | ||
| 19 | -import com.hannesdorfmann.mosby3.mvp.MvpView; | ||
| 20 | -import java.util.Map; | ||
| 21 | -import java.util.UUID; | ||
| 22 | - | ||
| 23 | -/** | ||
| 24 | - * A internal class responsible to save internal presenter instances during screen orientation | ||
| 25 | - * changes and reattach the presenter afterwards. | ||
| 26 | - * | ||
| 27 | - * <p> | ||
| 28 | - * The idea is that each MVP View (like a Activity, Fragment, ViewGroup) will get a unique view id. | ||
| 29 | - * This view id is | ||
| 30 | - * used to store the presenter and viewstate in it. After screen orientation changes we can reuse | ||
| 31 | - * the presenter and viewstate by querying for the given view id (must be saved in view's state | ||
| 32 | - * somehow). | ||
| 33 | - * </p> | ||
| 34 | - * | ||
| 35 | - * @author Hannes Dorfmann | ||
| 36 | - * @since 3.0 | ||
| 37 | - */ | ||
| 38 | -@RequiresApi(api = Build.VERSION_CODES.KITKAT) | ||
| 39 | -final public class PresenterManager { | ||
| 40 | - | ||
| 41 | - public static boolean DEBUG = false; | ||
| 42 | - public static final String DEBUG_TAG = "PresenterManager"; | ||
| 43 | - final static String KEY_ACTIVITY_ID = "com.hannesdorfmann.mosby3.MosbyPresenterManagerActivityId"; | ||
| 44 | - | ||
| 45 | - private final static Map<Activity, String> activityIdMap = new ArrayMap<>(); | ||
| 46 | - private final static Map<String, ActivityScopedCache> activityScopedCacheMap = new ArrayMap<>(); | ||
| 47 | - | ||
| 48 | - static final Application.ActivityLifecycleCallbacks activityLifecycleCallbacks = | ||
| 49 | - new Application.ActivityLifecycleCallbacks() { | ||
| 50 | - @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { | ||
| 51 | - if (savedInstanceState != null) { | ||
| 52 | - String activityId = savedInstanceState.getString(KEY_ACTIVITY_ID); | ||
| 53 | - if (activityId != null) { | ||
| 54 | - // After a screen orientation change we map the newly created Activity to the same | ||
| 55 | - // Activity ID as the previous activity has had (before screen orientation change) | ||
| 56 | - activityIdMap.put(activity, activityId); | ||
| 57 | - } | ||
| 58 | - } | ||
| 59 | - } | ||
| 60 | - | ||
| 61 | - @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { | ||
| 62 | - // Save the activityId into bundle so that the other | ||
| 63 | - String activityId = activityIdMap.get(activity); | ||
| 64 | - if (activityId != null) { | ||
| 65 | - outState.putString(KEY_ACTIVITY_ID, activityId); | ||
| 66 | - } | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - @Override public void onActivityStarted(Activity activity) { | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - @Override public void onActivityResumed(Activity activity) { | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - @Override public void onActivityPaused(Activity activity) { | ||
| 76 | - | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - @Override public void onActivityStopped(Activity activity) { | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - @Override public void onActivityDestroyed(Activity activity) { | ||
| 83 | - if (!activity.isChangingConfigurations()) { | ||
| 84 | - // Activity will be destroyed permanently, so reset the cache | ||
| 85 | - String activityId = activityIdMap.get(activity); | ||
| 86 | - if (activityId != null) { | ||
| 87 | - ActivityScopedCache scopedCache = activityScopedCacheMap.get(activityId); | ||
| 88 | - if (scopedCache != null) { | ||
| 89 | - scopedCache.clear(); | ||
| 90 | - activityScopedCacheMap.remove(activityId); | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - // No Activity Scoped cache available, so unregister | ||
| 94 | - if (activityScopedCacheMap.isEmpty()) { | ||
| 95 | - // All Mosby related activities are destroyed, so we can remove the activity lifecylce listener | ||
| 96 | - activity.getApplication() | ||
| 97 | - .unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks); | ||
| 98 | - if (DEBUG) { | ||
| 99 | - Log.d(DEBUG_TAG, "Unregistering ActivityLifecycleCallbacks"); | ||
| 100 | - } | ||
| 101 | - } | ||
| 102 | - } | ||
| 103 | - } | ||
| 104 | - activityIdMap.remove(activity); | ||
| 105 | - } | ||
| 106 | - }; | ||
| 107 | - | ||
| 108 | - private PresenterManager() { | ||
| 109 | - throw new RuntimeException("Not instantiatable!"); | ||
| 110 | - } | ||
| 111 | - | ||
| 112 | - /** | ||
| 113 | - * Get an already existing {@link ActivityScopedCache} or creates a new one if not existing yet | ||
| 114 | - * | ||
| 115 | - * @param activity The Activitiy for which you want to get the activity scope for | ||
| 116 | - * @return The {@link ActivityScopedCache} for the given Activity | ||
| 117 | - */ | ||
| 118 | - @NonNull | ||
| 119 | - @MainThread | ||
| 120 | - static ActivityScopedCache getOrCreateActivityScopedCache( | ||
| 121 | - @NonNull Activity activity) { | ||
| 122 | - if (activity == null) { | ||
| 123 | - throw new NullPointerException("Activity is null"); | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - String activityId = activityIdMap.get(activity); | ||
| 127 | - if (activityId == null) { | ||
| 128 | - // Activity not registered yet | ||
| 129 | - activityId = UUID.randomUUID().toString(); | ||
| 130 | - activityIdMap.put(activity, activityId); | ||
| 131 | - | ||
| 132 | - if (activityIdMap.size() == 1) { | ||
| 133 | - // Added the an Activity for the first time so register Activity LifecycleListener | ||
| 134 | - activity.getApplication().registerActivityLifecycleCallbacks(activityLifecycleCallbacks); | ||
| 135 | - if (DEBUG) { | ||
| 136 | - Log.d(DEBUG_TAG, "Registering ActivityLifecycleCallbacks"); | ||
| 137 | - } | ||
| 138 | - } | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - ActivityScopedCache activityScopedCache = activityScopedCacheMap.get(activityId); | ||
| 142 | - if (activityScopedCache == null) { | ||
| 143 | - activityScopedCache = new ActivityScopedCache(); | ||
| 144 | - activityScopedCacheMap.put(activityId, activityScopedCache); | ||
| 145 | - } | ||
| 146 | - | ||
| 147 | - return activityScopedCache; | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - /** | ||
| 151 | - * Get the {@link ActivityScopedCache} for the given Activity or <code>null</code> if no {@link | ||
| 152 | - * ActivityScopedCache} exists for the given Activity | ||
| 153 | - * | ||
| 154 | - * @param activity The activity | ||
| 155 | - * @return The {@link ActivityScopedCache} or null | ||
| 156 | - * @see #getOrCreateActivityScopedCache(Activity) | ||
| 157 | - */ | ||
| 158 | - @Nullable | ||
| 159 | - @MainThread static ActivityScopedCache getActivityScope(@NonNull Activity activity) { | ||
| 160 | - if (activity == null) { | ||
| 161 | - throw new NullPointerException("Activity is null"); | ||
| 162 | - } | ||
| 163 | - String activityId = activityIdMap.get(activity); | ||
| 164 | - if (activityId == null) { | ||
| 165 | - return null; | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - return activityScopedCacheMap.get(activityId); | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - /** | ||
| 172 | - * Get the presenter for the View with the given (Mosby - internal) view Id or <code>null</code> | ||
| 173 | - * if no presenter for the given view (via view id) exists. | ||
| 174 | - * | ||
| 175 | - * @param activity The Activity (used for scoping) | ||
| 176 | - * @param viewId The mosby internal View Id (unique among all {@link MvpView} | ||
| 177 | - * @param <P> The Presenter type | ||
| 178 | - * @return The Presenter or <code>null</code> | ||
| 179 | - */ | ||
| 180 | - @Nullable public static <P> P getPresenter(@NonNull Activity activity, @NonNull String viewId) { | ||
| 181 | - if (activity == null) { | ||
| 182 | - throw new NullPointerException("Activity is null"); | ||
| 183 | - } | ||
| 184 | - | ||
| 185 | - if (viewId == null) { | ||
| 186 | - throw new NullPointerException("View id is null"); | ||
| 187 | - } | ||
| 188 | - | ||
| 189 | - ActivityScopedCache scopedCache = getActivityScope(activity); | ||
| 190 | - return scopedCache == null ? null : (P) scopedCache.getPresenter(viewId); | ||
| 191 | - } | ||
| 192 | - | ||
| 193 | - /** | ||
| 194 | - * Get the ViewState (see mosby viestate modlue) for the View with the given (Mosby - internal) | ||
| 195 | - * view Id or <code>null</code> | ||
| 196 | - * if no viewstate for the given view exists. | ||
| 197 | - * | ||
| 198 | - * @param activity The Activity (used for scoping) | ||
| 199 | - * @param viewId The mosby internal View Id (unique among all {@link MvpView} | ||
| 200 | - * @param <VS> The type of the ViewState type | ||
| 201 | - * @return The Presenter or <code>null</code> | ||
| 202 | - */ | ||
| 203 | - @Nullable public static <VS> VS getViewState(@NonNull Activity activity, @NonNull String viewId) { | ||
| 204 | - if (activity == null) { | ||
| 205 | - throw new NullPointerException("Activity is null"); | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - if (viewId == null) { | ||
| 209 | - throw new NullPointerException("View id is null"); | ||
| 210 | - } | ||
| 211 | - | ||
| 212 | - ActivityScopedCache scopedCache = getActivityScope(activity); | ||
| 213 | - return scopedCache == null ? null : (VS) scopedCache.getViewState(viewId); | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - /** | ||
| 217 | - * Get the Activity of a context. This is typically used to determine the hosting activity of a | ||
| 218 | - * {@link View} | ||
| 219 | - * | ||
| 220 | - * @param context The context | ||
| 221 | - * @return The Activity or throws an Exception if Activity couldnt be determined | ||
| 222 | - */ | ||
| 223 | - @NonNull public static Activity getActivity(@NonNull Context context) { | ||
| 224 | - if (context == null) { | ||
| 225 | - throw new NullPointerException("context == null"); | ||
| 226 | - } | ||
| 227 | - if (context instanceof Activity) { | ||
| 228 | - return (Activity) context; | ||
| 229 | - } | ||
| 230 | - | ||
| 231 | - while (context instanceof ContextWrapper) { | ||
| 232 | - if (context instanceof Activity) { | ||
| 233 | - return (Activity) context; | ||
| 234 | - } | ||
| 235 | - context = ((ContextWrapper) context).getBaseContext(); | ||
| 236 | - } | ||
| 237 | - throw new IllegalStateException("Could not find the surrounding Activity"); | ||
| 238 | - } | ||
| 239 | - | ||
| 240 | - /** | ||
| 241 | - * Clears the internal (static) state. Used for testing. | ||
| 242 | - */ | ||
| 243 | - static void reset() { | ||
| 244 | - activityIdMap.clear(); | ||
| 245 | - for (ActivityScopedCache scopedCache : activityScopedCacheMap.values()) { | ||
| 246 | - scopedCache.clear(); | ||
| 247 | - } | ||
| 248 | - | ||
| 249 | - activityScopedCacheMap.clear(); | ||
| 250 | - } | ||
| 251 | - | ||
| 252 | - /** | ||
| 253 | - * Puts the presenter into the internal cache | ||
| 254 | - * | ||
| 255 | - * @param activity The parent activity | ||
| 256 | - * @param viewId the view id (mosby internal) | ||
| 257 | - * @param presenter the presenter | ||
| 258 | - */ | ||
| 259 | - public static void putPresenter(@NonNull Activity activity, @NonNull String viewId, | ||
| 260 | - @NonNull MvpPresenter<? extends MvpView> presenter) { | ||
| 261 | - if (activity == null) { | ||
| 262 | - throw new NullPointerException("Activity is null"); | ||
| 263 | - } | ||
| 264 | - | ||
| 265 | - ActivityScopedCache scopedCache = getOrCreateActivityScopedCache(activity); | ||
| 266 | - scopedCache.putPresenter(viewId, presenter); | ||
| 267 | - } | ||
| 268 | - | ||
| 269 | - /** | ||
| 270 | - * Puts the presenter into the internal cache | ||
| 271 | - * | ||
| 272 | - * @param activity The parent activity | ||
| 273 | - * @param viewId the view id (mosby internal) | ||
| 274 | - * @param viewState the presenter | ||
| 275 | - */ | ||
| 276 | - public static void putViewState(@NonNull Activity activity, @NonNull String viewId, | ||
| 277 | - @NonNull Object viewState) { | ||
| 278 | - if (activity == null) { | ||
| 279 | - throw new NullPointerException("Activity is null"); | ||
| 280 | - } | ||
| 281 | - | ||
| 282 | - ActivityScopedCache scopedCache = getOrCreateActivityScopedCache(activity); | ||
| 283 | - scopedCache.putViewState(viewId, viewState); | ||
| 284 | - } | ||
| 285 | - | ||
| 286 | - /** | ||
| 287 | - * Removes the Presenter (and ViewState) for the given View. Does nothing if no Presenter is | ||
| 288 | - * stored internally with the given viewId | ||
| 289 | - * | ||
| 290 | - * @param activity The activity | ||
| 291 | - * @param viewId The mosby internal view id | ||
| 292 | - */ | ||
| 293 | - public static void remove(@NonNull Activity activity, @NonNull String viewId) { | ||
| 294 | - if (activity == null) { | ||
| 295 | - throw new NullPointerException("Activity is null"); | ||
| 296 | - } | ||
| 297 | - | ||
| 298 | - ActivityScopedCache activityScope = getActivityScope(activity); | ||
| 299 | - if (activityScope != null) { | ||
| 300 | - activityScope.remove(viewId); | ||
| 301 | - } | ||
| 302 | - } | ||
| 303 | -} | ||
| 304 | - | ||
| 305 | - | ||
| 306 | - |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpActivity.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 18 | - | ||
| 19 | -import android.os.Bundle; | ||
| 20 | - | ||
| 21 | -import androidx.annotation.NonNull; | ||
| 22 | -import androidx.appcompat.app.AppCompatActivity; | ||
| 23 | - | ||
| 24 | -import com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegate; | ||
| 25 | -import com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl; | ||
| 26 | - | ||
| 27 | -/** | ||
| 28 | - * An Activity that uses a {@link MvpPresenter} to implement a Model-View-Presenter | ||
| 29 | - * architecture. | ||
| 30 | - * | ||
| 31 | - * @author Hannes Dorfmann | ||
| 32 | - * @since 1.0.0 | ||
| 33 | - */ | ||
| 34 | -public abstract class MvpActivity<V extends MvpView, P extends MvpPresenter<V>> | ||
| 35 | - extends AppCompatActivity implements MvpView, | ||
| 36 | - com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback<V,P> { | ||
| 37 | - | ||
| 38 | - protected ActivityMvpDelegate mvpDelegate; | ||
| 39 | - protected P presenter; | ||
| 40 | - protected boolean retainInstance; | ||
| 41 | - | ||
| 42 | - @Override protected void onCreate(Bundle savedInstanceState) { | ||
| 43 | - super.onCreate(savedInstanceState); | ||
| 44 | - getMvpDelegate().onCreate(savedInstanceState); | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - @Override protected void onDestroy() { | ||
| 48 | - super.onDestroy(); | ||
| 49 | - getMvpDelegate().onDestroy(); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - @Override protected void onSaveInstanceState(Bundle outState) { | ||
| 53 | - super.onSaveInstanceState(outState); | ||
| 54 | - getMvpDelegate().onSaveInstanceState(outState); | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - @Override protected void onPause() { | ||
| 58 | - super.onPause(); | ||
| 59 | - getMvpDelegate().onPause(); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - @Override protected void onResume() { | ||
| 63 | - super.onResume(); | ||
| 64 | - getMvpDelegate().onResume(); | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - @Override protected void onStart() { | ||
| 68 | - super.onStart(); | ||
| 69 | - getMvpDelegate().onStart(); | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - @Override protected void onStop() { | ||
| 73 | - super.onStop(); | ||
| 74 | - getMvpDelegate().onStop(); | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - @Override protected void onRestart() { | ||
| 78 | - super.onRestart(); | ||
| 79 | - getMvpDelegate().onRestart(); | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - @Override public void onContentChanged() { | ||
| 83 | - super.onContentChanged(); | ||
| 84 | - getMvpDelegate().onContentChanged(); | ||
| 85 | - } | ||
| 86 | - | ||
| 87 | - @Override protected void onPostCreate(Bundle savedInstanceState) { | ||
| 88 | - super.onPostCreate(savedInstanceState); | ||
| 89 | - getMvpDelegate().onPostCreate(savedInstanceState); | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - /** | ||
| 93 | - * Instantiate a presenter instance | ||
| 94 | - * | ||
| 95 | - * @return The {@link MvpPresenter} for this view | ||
| 96 | - */ | ||
| 97 | - @NonNull | ||
| 98 | - public abstract P createPresenter(); | ||
| 99 | - | ||
| 100 | - /** | ||
| 101 | - * Get the mvp delegate. This is internally used for creating presenter, attaching and detaching | ||
| 102 | - * view from presenter. | ||
| 103 | - * | ||
| 104 | - * <p><b>Please note that only one instance of mvp delegate should be used per Activity | ||
| 105 | - * instance</b>. | ||
| 106 | - * </p> | ||
| 107 | - * | ||
| 108 | - * <p> | ||
| 109 | - * Only override this method if you really know what you are doing. | ||
| 110 | - * </p> | ||
| 111 | - * | ||
| 112 | - * @return {@link ActivityMvpDelegateImpl} | ||
| 113 | - */ | ||
| 114 | - @NonNull protected ActivityMvpDelegate<V, P> getMvpDelegate() { | ||
| 115 | - if (mvpDelegate == null) { | ||
| 116 | - mvpDelegate = new ActivityMvpDelegateImpl(this, this, true); | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - return mvpDelegate; | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - @NonNull @Override public P getPresenter() { | ||
| 123 | - return presenter; | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - @Override public void setPresenter(@NonNull P presenter) { | ||
| 127 | - this.presenter = presenter; | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - @NonNull @Override public V getMvpView() { | ||
| 131 | - return (V) this; | ||
| 132 | - } | ||
| 133 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpBasePresenter.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 18 | - | ||
| 19 | - | ||
| 20 | -import androidx.annotation.NonNull; | ||
| 21 | -import androidx.annotation.UiThread; | ||
| 22 | - | ||
| 23 | -import java.lang.ref.WeakReference; | ||
| 24 | - | ||
| 25 | -/** | ||
| 26 | - * A base implementation of a {@link MvpPresenter} that uses a <b>WeakReference</b> for referring | ||
| 27 | - * to the attached view. | ||
| 28 | - * <p> | ||
| 29 | - * Use {@link #ifViewAttached(ViewAction)} to interact with the view. Since the view is passive, | ||
| 30 | - * usually a Presenter should not get any data from View: so calls like view.getUserId() should not be done. | ||
| 31 | - * Rather write a method in your Presenter that takes the user id as parameter like this: | ||
| 32 | - * {@code | ||
| 33 | - * void doSomething(int userId){ | ||
| 34 | - * // do something | ||
| 35 | - * ... | ||
| 36 | - * <p> | ||
| 37 | - * ifViewAttached( view -> view.showSuccessful()) | ||
| 38 | - * } | ||
| 39 | - * <p> | ||
| 40 | - * } | ||
| 41 | - * </p> | ||
| 42 | - * | ||
| 43 | - * @param <V> type of the {@link MvpView} | ||
| 44 | - * @author Hannes Dorfmann | ||
| 45 | - * @since 1.0.0 | ||
| 46 | - */ | ||
| 47 | -public class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> { | ||
| 48 | - | ||
| 49 | - /** | ||
| 50 | - * An Action that is executed to interact with the view. | ||
| 51 | - * Usually a Presenter should not get any data from View: so calls like view.getUserId() should not be done. | ||
| 52 | - * Rather write a method in your Presenter that takes the user id as parameter like this: | ||
| 53 | - * {@code | ||
| 54 | - * void doSomething(int userId){ | ||
| 55 | - * // do something | ||
| 56 | - * ... | ||
| 57 | - * <p> | ||
| 58 | - * ifViewAttached( view -> view.showSuccessful()) | ||
| 59 | - * } | ||
| 60 | - * | ||
| 61 | - * @param <V> The Type of the View | ||
| 62 | - */ | ||
| 63 | - public interface ViewAction<V> { | ||
| 64 | - | ||
| 65 | - /** | ||
| 66 | - * This method will be invoked to run the action. Implement this method to interact with the view. | ||
| 67 | - * | ||
| 68 | - * @param view The reference to the view. Not null. | ||
| 69 | - */ | ||
| 70 | - void run(@NonNull V view); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - private WeakReference<V> viewRef; | ||
| 74 | - private boolean presenterDestroyed = false; | ||
| 75 | - | ||
| 76 | - @UiThread | ||
| 77 | - @Override | ||
| 78 | - public void attachView(V view) { | ||
| 79 | - viewRef = new WeakReference<V>(view); | ||
| 80 | - presenterDestroyed = false; | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - /** | ||
| 84 | - * Gets the attached view. You should always call {@link #isViewAttached()} to check if the view | ||
| 85 | - * is attached to avoid NullPointerExceptions. | ||
| 86 | - * | ||
| 87 | - * @return <code>null</code>, if view is not attached, otherwise the concrete view instance | ||
| 88 | - * @deprecated Use {@link #ifViewAttached(ViewAction)} | ||
| 89 | - */ | ||
| 90 | - @Deprecated | ||
| 91 | - @UiThread | ||
| 92 | - public V getView() { | ||
| 93 | - return viewRef == null ? null : viewRef.get(); | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - /** | ||
| 97 | - * Checks if a view is attached to this presenter. You should always call this method before | ||
| 98 | - * calling {@link #getView()} to get the view instance. | ||
| 99 | - * | ||
| 100 | - * @deprecated Use {@link #ifViewAttached(ViewAction)} | ||
| 101 | - */ | ||
| 102 | - @Deprecated | ||
| 103 | - @UiThread | ||
| 104 | - public boolean isViewAttached() { | ||
| 105 | - return viewRef != null && viewRef.get() != null; | ||
| 106 | - } | ||
| 107 | - | ||
| 108 | - /** | ||
| 109 | - * {@inheritDoc} | ||
| 110 | - */ | ||
| 111 | - @Deprecated | ||
| 112 | - @UiThread | ||
| 113 | - @Override | ||
| 114 | - public void detachView(boolean retainInstance) { | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - /** | ||
| 118 | - * Executes the passed Action only if the View is attached. | ||
| 119 | - * If no View is attached, either an exception is thrown (if parameter exceptionIfViewNotAttached | ||
| 120 | - * is true) or the action is just not executed (no exception thrown). | ||
| 121 | - * Note that if no view is attached, this will not re-execute the given action if the View gets | ||
| 122 | - * re-attached. | ||
| 123 | - * | ||
| 124 | - * @param exceptionIfViewNotAttached true, if an exception should be thrown if no view is | ||
| 125 | - * attached while trying to execute the action. false, if no exception should be thrown (the action | ||
| 126 | - * will not be executed since no view is attached) | ||
| 127 | - * @param action The {@link ViewAction} that will be executed if a view is attached. This is | ||
| 128 | - * where you call view.isLoading etc. Use the view reference passed as parameter to {@link | ||
| 129 | - * ViewAction#run(Object)} and not deprecated method {@link #getView()} | ||
| 130 | - */ | ||
| 131 | - protected final void ifViewAttached(boolean exceptionIfViewNotAttached, ViewAction<V> action) { | ||
| 132 | - final V view = viewRef == null ? null : viewRef.get(); | ||
| 133 | - if (view != null) { | ||
| 134 | - action.run(view); | ||
| 135 | - } else if (exceptionIfViewNotAttached) { | ||
| 136 | - throw new IllegalStateException( | ||
| 137 | - "No View attached to Presenter. Presenter destroyed = " + presenterDestroyed); | ||
| 138 | - } | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - /** | ||
| 142 | - * Calls {@link #ifViewAttached(boolean, ViewAction)} with false as first parameter (don't throw | ||
| 143 | - * exception if view not attached). | ||
| 144 | - * | ||
| 145 | - * @see #ifViewAttached(boolean, ViewAction) | ||
| 146 | - */ | ||
| 147 | - protected final void ifViewAttached(ViewAction<V> action) { | ||
| 148 | - ifViewAttached(false, action); | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - /** | ||
| 152 | - * {@inheritDoc} | ||
| 153 | - */ | ||
| 154 | - public void detachView() { | ||
| 155 | - detachView(true); | ||
| 156 | - if (viewRef != null) { | ||
| 157 | - viewRef.clear(); | ||
| 158 | - viewRef = null; | ||
| 159 | - } | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - /** | ||
| 163 | - * {@inheritDoc} | ||
| 164 | - */ | ||
| 165 | - public void destroy() { | ||
| 166 | -// detachView(false); | ||
| 167 | - presenterDestroyed = true; | ||
| 168 | - } | ||
| 169 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpDialogFragment.java deleted
100644 → 0
| 1 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 2 | - | ||
| 3 | -import android.app.Activity; | ||
| 4 | -import android.app.Dialog; | ||
| 5 | -import android.content.Context; | ||
| 6 | -import android.os.Bundle; | ||
| 7 | -import android.view.View; | ||
| 8 | - | ||
| 9 | -import androidx.annotation.NonNull; | ||
| 10 | -import androidx.annotation.Nullable; | ||
| 11 | -import androidx.fragment.app.DialogFragment; | ||
| 12 | - | ||
| 13 | -import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegate; | ||
| 14 | -import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl; | ||
| 15 | -import com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback; | ||
| 16 | - | ||
| 17 | -/** | ||
| 18 | - * A DialogFragment that uses an {@link MvpPresenter} to implement a Model-View-Presenter | ||
| 19 | - * architecture | ||
| 20 | - * | ||
| 21 | - * @author Hannes Dorfmann | ||
| 22 | - * @author Michał Seroczyński | ||
| 23 | - * @since 3.1.1 | ||
| 24 | - */ | ||
| 25 | -public abstract class MvpDialogFragment<V extends MvpView, P extends MvpPresenter<V>> extends DialogFragment | ||
| 26 | - implements MvpDelegateCallback<V, P>, MvpView { | ||
| 27 | - | ||
| 28 | - protected FragmentMvpDelegate<V, P> mvpDelegate; | ||
| 29 | - | ||
| 30 | - /** | ||
| 31 | - * The presenter for this view. Will be instantiated with {@link #createPresenter()} | ||
| 32 | - */ | ||
| 33 | - protected P presenter; | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * Creates a new presenter instance, if needed. Will reuse the previous presenter instance if | ||
| 37 | - * {@link #setRetainInstance(boolean)} is set to true. This method will be called from | ||
| 38 | - * {@link #onViewCreated(View, Bundle)} | ||
| 39 | - */ | ||
| 40 | - public abstract P createPresenter(); | ||
| 41 | - | ||
| 42 | - /** | ||
| 43 | - * * Get the mvp delegate. This is internally used for creating presenter, attaching and | ||
| 44 | - * detaching view from presenter. | ||
| 45 | - * | ||
| 46 | - * <p> | ||
| 47 | - * <b>Please note that only one instance of mvp delegate should be used per fragment | ||
| 48 | - * instance</b>. | ||
| 49 | - * </p> | ||
| 50 | - * | ||
| 51 | - * <p> | ||
| 52 | - * Only override this method if you really know what you are doing. | ||
| 53 | - * </p> | ||
| 54 | - * | ||
| 55 | - * @return {@link FragmentMvpDelegateImpl} | ||
| 56 | - */ | ||
| 57 | - @NonNull | ||
| 58 | - protected FragmentMvpDelegate<V, P> getMvpDelegate() { | ||
| 59 | - if (mvpDelegate == null) { | ||
| 60 | - mvpDelegate = new FragmentMvpDelegateImpl<>(this, this, true, true); | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - return mvpDelegate; | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - @NonNull @Override public P getPresenter() { | ||
| 67 | - return presenter; | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - @Override public void setPresenter(@NonNull P presenter) { | ||
| 71 | - this.presenter = presenter; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - @NonNull @Override public V getMvpView() { | ||
| 75 | - return (V) this; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - @Override | ||
| 79 | - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { | ||
| 80 | - super.onViewCreated(view, savedInstanceState); | ||
| 81 | - getMvpDelegate().onViewCreated(view, savedInstanceState); | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - @Override public void onDestroyView() { | ||
| 85 | - Dialog dialog = getDialog(); | ||
| 86 | - // Handles https://code.google.com/p/android/issues/detail?id=17423 | ||
| 87 | - if (dialog != null && getRetainInstance()) { | ||
| 88 | - dialog.setDismissMessage(null); | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - super.onDestroyView(); | ||
| 92 | - getMvpDelegate().onDestroyView(); | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - @Override public void onCreate(Bundle savedInstanceState) { | ||
| 96 | - super.onCreate(savedInstanceState); | ||
| 97 | - getMvpDelegate().onCreate(savedInstanceState); | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - @Override public void onDestroy() { | ||
| 101 | - super.onDestroy(); | ||
| 102 | - getMvpDelegate().onDestroy(); | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - @Override public void onPause() { | ||
| 106 | - super.onPause(); | ||
| 107 | - getMvpDelegate().onPause(); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - @Override public void onResume() { | ||
| 111 | - super.onResume(); | ||
| 112 | - getMvpDelegate().onResume(); | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | - @Override public void onStart() { | ||
| 116 | - super.onStart(); | ||
| 117 | - getMvpDelegate().onStart(); | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - @Override public void onStop() { | ||
| 121 | - super.onStop(); | ||
| 122 | - getMvpDelegate().onStop(); | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | - @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { | ||
| 126 | - super.onActivityCreated(savedInstanceState); | ||
| 127 | - getMvpDelegate().onActivityCreated(savedInstanceState); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - @Override public void onAttach(Activity activity) { | ||
| 131 | - super.onAttach(activity); | ||
| 132 | - getMvpDelegate().onAttach(activity); | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - @Override public void onAttach(Context context) { | ||
| 136 | - super.onAttach(context); | ||
| 137 | - getMvpDelegate().onAttach(context); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - @Override public void onDetach() { | ||
| 141 | - super.onDetach(); | ||
| 142 | - getMvpDelegate().onDetach(); | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - @Override public void onSaveInstanceState(Bundle outState) { | ||
| 146 | - super.onSaveInstanceState(outState); | ||
| 147 | - getMvpDelegate().onSaveInstanceState(outState); | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | -} | ||
| 151 | \ No newline at end of file | 0 | \ No newline at end of file |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpFragment.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 18 | - | ||
| 19 | -import android.app.Activity; | ||
| 20 | -import android.content.Context; | ||
| 21 | -import android.os.Bundle; | ||
| 22 | -import android.view.View; | ||
| 23 | - | ||
| 24 | -import androidx.annotation.NonNull; | ||
| 25 | -import androidx.annotation.Nullable; | ||
| 26 | -import androidx.fragment.app.Fragment; | ||
| 27 | - | ||
| 28 | -import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegate; | ||
| 29 | -import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl; | ||
| 30 | -import com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback; | ||
| 31 | - | ||
| 32 | -/** | ||
| 33 | - * A Fragment that uses a {@link MvpPresenter} to implement a Model-View-Presenter architecture. | ||
| 34 | - * | ||
| 35 | - * @author Hannes Dorfmann | ||
| 36 | - * @since 1.0.0 | ||
| 37 | - */ | ||
| 38 | -public abstract class MvpFragment<V extends MvpView, P extends MvpPresenter<V>> extends Fragment | ||
| 39 | - implements MvpDelegateCallback<V, P>, MvpView { | ||
| 40 | - | ||
| 41 | - protected FragmentMvpDelegate<V, P> mvpDelegate; | ||
| 42 | - | ||
| 43 | - /** | ||
| 44 | - * The presenter for this view. Will be instantiated with {@link #createPresenter()} | ||
| 45 | - */ | ||
| 46 | - protected P presenter; | ||
| 47 | - | ||
| 48 | - /** | ||
| 49 | - * Creates a new presenter instance, if needed. Will reuse the previous presenter instance if | ||
| 50 | - * {@link #setRetainInstance(boolean)} is set to true. This method will be called from | ||
| 51 | - * {@link #onViewCreated(View, Bundle)} | ||
| 52 | - */ | ||
| 53 | - public abstract P createPresenter(); | ||
| 54 | - | ||
| 55 | - /** | ||
| 56 | - * Gets the mvp delegate. This is internally used for creating presenter, attaching and | ||
| 57 | - * detaching view from presenter. | ||
| 58 | - * | ||
| 59 | - * <p> | ||
| 60 | - * <b>Please note that only one instance of mvp delegate should be used per fragment instance</b>. | ||
| 61 | - * </p> | ||
| 62 | - * | ||
| 63 | - * <p> | ||
| 64 | - * Only override this method if you really know what you are doing. | ||
| 65 | - * </p> | ||
| 66 | - * | ||
| 67 | - * @return {@link FragmentMvpDelegateImpl} | ||
| 68 | - */ | ||
| 69 | - @NonNull | ||
| 70 | - protected FragmentMvpDelegate<V, P> getMvpDelegate() { | ||
| 71 | - if (mvpDelegate == null) { | ||
| 72 | - mvpDelegate = new FragmentMvpDelegateImpl<>(this, this, true, true); | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - return mvpDelegate; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - @NonNull @Override public P getPresenter() { | ||
| 79 | - return presenter; | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - @Override public void setPresenter(@NonNull P presenter) { | ||
| 83 | - this.presenter = presenter; | ||
| 84 | - } | ||
| 85 | - | ||
| 86 | - @NonNull @Override public V getMvpView() { | ||
| 87 | - return (V) this; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { | ||
| 91 | - super.onViewCreated(view, savedInstanceState); | ||
| 92 | - getMvpDelegate().onViewCreated(view, savedInstanceState); | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - @Override public void onDestroyView() { | ||
| 96 | - super.onDestroyView(); | ||
| 97 | - getMvpDelegate().onDestroyView(); | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - @Override public void onCreate(Bundle savedInstanceState) { | ||
| 101 | - super.onCreate(savedInstanceState); | ||
| 102 | - getMvpDelegate().onCreate(savedInstanceState); | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - @Override public void onDestroy() { | ||
| 106 | - super.onDestroy(); | ||
| 107 | - getMvpDelegate().onDestroy(); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - @Override public void onPause() { | ||
| 111 | - super.onPause(); | ||
| 112 | - getMvpDelegate().onPause(); | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | - @Override public void onResume() { | ||
| 116 | - super.onResume(); | ||
| 117 | - getMvpDelegate().onResume(); | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - @Override public void onStart() { | ||
| 121 | - super.onStart(); | ||
| 122 | - getMvpDelegate().onStart(); | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | - @Override public void onStop() { | ||
| 126 | - super.onStop(); | ||
| 127 | - getMvpDelegate().onStop(); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { | ||
| 131 | - super.onActivityCreated(savedInstanceState); | ||
| 132 | - getMvpDelegate().onActivityCreated(savedInstanceState); | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - @Deprecated @Override public void onAttach(Activity activity) { | ||
| 136 | - super.onAttach(activity); | ||
| 137 | - getMvpDelegate().onAttach(activity); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - @Override public void onAttach(Context context) { | ||
| 141 | - super.onAttach(context); | ||
| 142 | - getMvpDelegate().onAttach(context); | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - @Override public void onDetach() { | ||
| 146 | - super.onDetach(); | ||
| 147 | - getMvpDelegate().onDetach(); | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - @Override public void onSaveInstanceState(Bundle outState) { | ||
| 151 | - super.onSaveInstanceState(outState); | ||
| 152 | - getMvpDelegate().onSaveInstanceState(outState); | ||
| 153 | - } | ||
| 154 | -} | ||
| 155 | - |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpPresenter.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 18 | - | ||
| 19 | - | ||
| 20 | -import androidx.annotation.NonNull; | ||
| 21 | -import androidx.annotation.UiThread; | ||
| 22 | - | ||
| 23 | -/** | ||
| 24 | - * The base interface for each mvp presenter. | ||
| 25 | - * | ||
| 26 | - * <p> | ||
| 27 | - * Mosby assumes that all interaction (i.e. updating the View) between Presenter and View is | ||
| 28 | - * executed on Android's main UI thread. | ||
| 29 | - * </p> | ||
| 30 | - * | ||
| 31 | - * @author Hannes Dorfmann | ||
| 32 | - * @since 1.0.0 | ||
| 33 | - */ | ||
| 34 | -public interface MvpPresenter<V extends MvpView> { | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * Set or attach the view to this presenter | ||
| 38 | - */ | ||
| 39 | - @UiThread | ||
| 40 | - void attachView(@NonNull V view); | ||
| 41 | - | ||
| 42 | - /** | ||
| 43 | - * Will be called if the view has been destroyed. Typically this method will be invoked from | ||
| 44 | - * <code>Activity.detachView()</code> or <code>Fragment.onDestroyView()</code> | ||
| 45 | - * | ||
| 46 | - * @deprecated This method has been split into 2 methods: {@link #detachView()} and {@link #destroy()} | ||
| 47 | - */ | ||
| 48 | - @UiThread | ||
| 49 | - @Deprecated | ||
| 50 | - void detachView(boolean retainInstance); | ||
| 51 | - | ||
| 52 | - /** | ||
| 53 | - * Will be called if the view has been detached from the Presenter. | ||
| 54 | - * Usually this happens on screen orientation changes or view (like fragment) has been put on the backstack. | ||
| 55 | - */ | ||
| 56 | - @UiThread | ||
| 57 | - void detachView(); | ||
| 58 | - | ||
| 59 | - /** | ||
| 60 | - * Will be called if the presenter is no longer needed because the View has been destroyed permanently. | ||
| 61 | - * This is where you do clean up stuff. | ||
| 62 | - */ | ||
| 63 | - @UiThread | ||
| 64 | - void destroy(); | ||
| 65 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpView.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp; | ||
| 18 | - | ||
| 19 | -/** | ||
| 20 | - * The root view interface for every mvp view | ||
| 21 | - * | ||
| 22 | - * @author Hannes Dorfmann | ||
| 23 | - * @since 1.0.0 | ||
| 24 | - */ | ||
| 25 | -public interface MvpView { | ||
| 26 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ActivityMvpDelegate.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp.delegate; | ||
| 18 | - | ||
| 19 | -import android.app.Activity; | ||
| 20 | -import android.os.Bundle; | ||
| 21 | -import com.hannesdorfmann.mosby3.mvp.MvpPresenter; | ||
| 22 | -import com.hannesdorfmann.mosby3.mvp.MvpView; | ||
| 23 | - | ||
| 24 | -/** | ||
| 25 | - * A delegate for Activities to attach them to Mosby mvp. | ||
| 26 | - * | ||
| 27 | - * <p> | ||
| 28 | - * The following methods must be invoked from the corresponding Activities lifecycle methods: | ||
| 29 | - * <ul> | ||
| 30 | - * <li>{@link #onCreate(Bundle)}</li> | ||
| 31 | - * <li>{@link #onDestroy()}</li> | ||
| 32 | - * <li>{@link #onPause()} </li> | ||
| 33 | - * <li>{@link #onResume()} </li> | ||
| 34 | - * <li>{@link #onStart()} </li> | ||
| 35 | - * <li>{@link #onStop()} </li> | ||
| 36 | - * <li>{@link #onRestart()} </li> | ||
| 37 | - * <li>{@link #onContentChanged()} </li> | ||
| 38 | - * <li>{@link #onSaveInstanceState(Bundle)} </li> | ||
| 39 | - * <li>{@link #onPostCreate(Bundle)} </li> | ||
| 40 | - * <li></li> | ||
| 41 | - * </ul> | ||
| 42 | - * </p> | ||
| 43 | - * | ||
| 44 | - * @param <V> The type of {@link MvpView} | ||
| 45 | - * @param <P> The type of {@link MvpPresenter} | ||
| 46 | - * @author Hannes Dorfmann | ||
| 47 | - * @since 1.1.0 | ||
| 48 | - */ | ||
| 49 | -public interface ActivityMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> { | ||
| 50 | - | ||
| 51 | - /** | ||
| 52 | - * This method must be called from {@link Activity#onCreate(Bundle)}. | ||
| 53 | - * This method internally creates the presenter and attaches the view to it. | ||
| 54 | - */ | ||
| 55 | - void onCreate(Bundle bundle); | ||
| 56 | - | ||
| 57 | - /** | ||
| 58 | - * This method must be called from {@link Activity#onDestroy()}}. | ||
| 59 | - * This method internally detaches the view from presenter | ||
| 60 | - */ | ||
| 61 | - void onDestroy(); | ||
| 62 | - | ||
| 63 | - /** | ||
| 64 | - * This method must be called from {@link Activity#onPause()} | ||
| 65 | - */ | ||
| 66 | - void onPause(); | ||
| 67 | - | ||
| 68 | - /** | ||
| 69 | - * This method must be called from {@link Activity#onResume()} | ||
| 70 | - */ | ||
| 71 | - void onResume(); | ||
| 72 | - | ||
| 73 | - /** | ||
| 74 | - * This method must be called from {@link Activity#onStart()} | ||
| 75 | - */ | ||
| 76 | - void onStart(); | ||
| 77 | - | ||
| 78 | - /** | ||
| 79 | - * This method must be called from {@link Activity#onStop()} | ||
| 80 | - */ | ||
| 81 | - void onStop(); | ||
| 82 | - | ||
| 83 | - /** | ||
| 84 | - * This method must be called from {@link Activity#onRestart()} | ||
| 85 | - */ | ||
| 86 | - void onRestart(); | ||
| 87 | - | ||
| 88 | - /** | ||
| 89 | - * This method must be called from {@link Activity#onContentChanged()} | ||
| 90 | - */ | ||
| 91 | - void onContentChanged(); | ||
| 92 | - | ||
| 93 | - /** | ||
| 94 | - * This method must be called from {@link Activity#onSaveInstanceState(Bundle)} | ||
| 95 | - */ | ||
| 96 | - void onSaveInstanceState(Bundle outState); | ||
| 97 | - | ||
| 98 | - /** | ||
| 99 | - * This method must be called from {@link Activity#onPostCreate(Bundle)} | ||
| 100 | - */ | ||
| 101 | - void onPostCreate(Bundle savedInstanceState); | ||
| 102 | - | ||
| 103 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ActivityMvpDelegateImpl.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2015 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - */ | ||
| 16 | - | ||
| 17 | -package com.hannesdorfmann.mosby3.mvp.delegate; | ||
| 18 | - | ||
| 19 | -import android.app.Activity; | ||
| 20 | -import android.os.Bundle; | ||
| 21 | -import android.util.Log; | ||
| 22 | - | ||
| 23 | -import androidx.annotation.NonNull; | ||
| 24 | - | ||
| 25 | -import com.hannesdorfmann.mosby3.PresenterManager; | ||
| 26 | -import com.hannesdorfmann.mosby3.mvp.MvpPresenter; | ||
| 27 | -import com.hannesdorfmann.mosby3.mvp.MvpView; | ||
| 28 | -import java.util.UUID; | ||
| 29 | - | ||
| 30 | -/** | ||
| 31 | - * The concrete implementation of {@link} | ||
| 32 | - * | ||
| 33 | - * @param <V> The type of {@link MvpView} | ||
| 34 | - * @param <P> The type of {@link MvpPresenter} | ||
| 35 | - * @author Hannes Dorfmann | ||
| 36 | - * @see ActivityMvpDelegate | ||
| 37 | - * @since 1.1.0 | ||
| 38 | - */ | ||
| 39 | -public class ActivityMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>> | ||
| 40 | - implements ActivityMvpDelegate { | ||
| 41 | - | ||
| 42 | - protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.activity.mvp.id"; | ||
| 43 | - | ||
| 44 | - public static boolean DEBUG = false; | ||
| 45 | - private static final String DEBUG_TAG = "ActivityMvpDelegateImpl"; | ||
| 46 | - | ||
| 47 | - private MvpDelegateCallback<V, P> delegateCallback; | ||
| 48 | - protected boolean keepPresenterInstance; | ||
| 49 | - protected Activity activity; | ||
| 50 | - protected String mosbyViewId = null; | ||
| 51 | - | ||
| 52 | - /** | ||
| 53 | - * @param activity The Activity | ||
| 54 | - * @param delegateCallback The callback | ||
| 55 | - * @param keepPresenterInstance true, if the presenter instance should be kept across screen | ||
| 56 | - * orientation changes. Otherwise false. | ||
| 57 | - */ | ||
| 58 | - public ActivityMvpDelegateImpl(@NonNull Activity activity, | ||
| 59 | - @NonNull MvpDelegateCallback<V, P> delegateCallback, boolean keepPresenterInstance) { | ||
| 60 | - | ||
| 61 | - if (activity == null) { | ||
| 62 | - throw new NullPointerException("Activity is null!"); | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - if (delegateCallback == null) { | ||
| 66 | - throw new NullPointerException("MvpDelegateCallback is null!"); | ||
| 67 | - } | ||
| 68 | - this.delegateCallback = delegateCallback; | ||
| 69 | - this.activity = activity; | ||
| 70 | - this.keepPresenterInstance = keepPresenterInstance; | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - /** | ||
| 74 | - * Determines whether or not a Presenter Instance should be kept | ||
| 75 | - * | ||
| 76 | - * @param keepPresenterInstance true, if the delegate has enabled keep | ||
| 77 | - */ | ||
| 78 | - static boolean retainPresenterInstance(boolean keepPresenterInstance, Activity activity) { | ||
| 79 | - return keepPresenterInstance && (activity.isChangingConfigurations() | ||
| 80 | - || !activity.isFinishing()); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - /** | ||
| 84 | - * Generates the unique (mosby internal) view id and calls {@link | ||
| 85 | - * MvpDelegateCallback#createPresenter()} | ||
| 86 | - * to create a new presenter instance | ||
| 87 | - * | ||
| 88 | - * @return The new created presenter instance | ||
| 89 | - */ | ||
| 90 | - private P createViewIdAndCreatePresenter() { | ||
| 91 | - | ||
| 92 | - P presenter = delegateCallback.createPresenter(); | ||
| 93 | - if (presenter == null) { | ||
| 94 | - throw new NullPointerException( | ||
| 95 | - "Presenter returned from createPresenter() is null. Activity is " + activity); | ||
| 96 | - } | ||
| 97 | - if (keepPresenterInstance) { | ||
| 98 | - mosbyViewId = UUID.randomUUID().toString(); | ||
| 99 | - PresenterManager.putPresenter(activity, mosbyViewId, presenter); | ||
| 100 | - } | ||
| 101 | - return presenter; | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - @Override public void onCreate(Bundle bundle) { | ||
| 105 | - | ||
| 106 | - P presenter = null; | ||
| 107 | - | ||
| 108 | - if (bundle != null && keepPresenterInstance) { | ||
| 109 | - | ||
| 110 | - mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID); | ||
| 111 | - | ||
| 112 | - if (DEBUG) { | ||
| 113 | - Log.d(DEBUG_TAG, | ||
| 114 | - "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView()); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - if (mosbyViewId != null | ||
| 118 | - && (presenter = PresenterManager.getPresenter(activity, mosbyViewId)) != null) { | ||
| 119 | - // | ||
| 120 | - // Presenter restored from cache | ||
| 121 | - // | ||
| 122 | - if (DEBUG) { | ||
| 123 | - Log.d(DEBUG_TAG, | ||
| 124 | - "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView()); | ||
| 125 | - } | ||
| 126 | - } else { | ||
| 127 | - // | ||
| 128 | - // No presenter found in cache, most likely caused by process death | ||
| 129 | - // | ||
| 130 | - presenter = createViewIdAndCreatePresenter(); | ||
| 131 | - if (DEBUG) { | ||
| 132 | - Log.d(DEBUG_TAG, "No presenter found although view Id was here: " | ||
| 133 | - + mosbyViewId | ||
| 134 | - + ". Most likely this was caused by a process death. New Presenter created" | ||
| 135 | - + presenter | ||
| 136 | - + " for view " | ||
| 137 | - + getMvpView()); | ||
| 138 | - } | ||
| 139 | - } | ||
| 140 | - } else { | ||
| 141 | - // | ||
| 142 | - // Activity starting first time, so create a new presenter | ||
| 143 | - // | ||
| 144 | - presenter = createViewIdAndCreatePresenter(); | ||
| 145 | - if (DEBUG) { | ||
| 146 | - Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView()); | ||
| 147 | - } | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - if (presenter == null) { | ||
| 151 | - throw new IllegalStateException( | ||
| 152 | - "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues"); | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - delegateCallback.setPresenter(presenter); | ||
| 156 | - getPresenter().attachView(getMvpView()); | ||
| 157 | - | ||
| 158 | - if (DEBUG) { | ||
| 159 | - Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter); | ||
| 160 | - } | ||
| 161 | - } | ||
| 162 | - | ||
| 163 | - private P getPresenter() { | ||
| 164 | - P presenter = delegateCallback.getPresenter(); | ||
| 165 | - if (presenter == null) { | ||
| 166 | - throw new NullPointerException("Presenter returned from getPresenter() is null"); | ||
| 167 | - } | ||
| 168 | - return presenter; | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - private V getMvpView() { | ||
| 172 | - V view = delegateCallback.getMvpView(); | ||
| 173 | - if (view == null) { | ||
| 174 | - throw new NullPointerException("View returned from getMvpView() is null"); | ||
| 175 | - } | ||
| 176 | - return view; | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - @Override public void onDestroy() { | ||
| 180 | - boolean retainPresenterInstance = retainPresenterInstance(keepPresenterInstance, activity); | ||
| 181 | - getPresenter().detachView(); | ||
| 182 | - if (!retainPresenterInstance){ | ||
| 183 | - getPresenter().destroy(); | ||
| 184 | - } | ||
| 185 | - if (!retainPresenterInstance && mosbyViewId != null) { | ||
| 186 | - PresenterManager.remove(activity, mosbyViewId); | ||
| 187 | - } | ||
| 188 | - | ||
| 189 | - if (DEBUG) { | ||
| 190 | - if (retainPresenterInstance) { | ||
| 191 | - Log.d(DEBUG_TAG, "View" | ||
| 192 | - + getMvpView() | ||
| 193 | - + " destroyed temporarily. View detached from presenter " | ||
| 194 | - + getPresenter()); | ||
| 195 | - } else { | ||
| 196 | - Log.d(DEBUG_TAG, "View" | ||
| 197 | - + getMvpView() | ||
| 198 | - + " destroyed permanently. View detached permanently from presenter " | ||
| 199 | - + getPresenter()); | ||
| 200 | - } | ||
| 201 | - } | ||
| 202 | - } | ||
| 203 | - | ||
| 204 | - @Override public void onPause() { | ||
| 205 | - | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - @Override public void onResume() { | ||
| 209 | - | ||
| 210 | - } | ||
| 211 | - | ||
| 212 | - @Override public void onStart() { | ||
| 213 | - | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - @Override public void onStop() { | ||
| 217 | - | ||
| 218 | - } | ||
| 219 | - | ||
| 220 | - @Override public void onRestart() { | ||
| 221 | - | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - @Override public void onContentChanged() { | ||
| 225 | - | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - @Override public void onSaveInstanceState(Bundle outState) { | ||
| 229 | - if (keepPresenterInstance && outState != null) { | ||
| 230 | - outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId); | ||
| 231 | - if (DEBUG) { | ||
| 232 | - Log.d(DEBUG_TAG, | ||
| 233 | - "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId + " for view " + getMvpView()); | ||
| 234 | - } | ||
| 235 | - } | ||
| 236 | - } | ||
| 237 | - | ||
| 238 | - @Override public void onPostCreate(Bundle savedInstanceState) { | ||
| 239 | - } | ||
| 240 | -} |
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/BackstackAccessor.java deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2016 Hannes Dorfmann. | ||
| 3 | - * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | - * you may not use this file except in compliance with the License. | ||
| 6 | - * You may obtain a copy of the License at | ||
| 7 | - * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | - * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | - * See the License for the specific language governing permissions and | ||
| 14 | - * limitations under the License. | ||
| 15 | - * | ||
| 16 | - */ | ||
| 17 | - | ||
| 18 | -package com.hannesdorfmann.mosby3.mvp.delegate; | ||
| 19 | - | ||
| 20 | -import androidx.fragment.app.Fragment; | ||
| 21 | - | ||
| 22 | -import java.io.PrintWriter; | ||
| 23 | -import java.io.StringWriter; | ||
| 24 | - | ||
| 25 | -/** | ||
| 26 | - * With this utility class one can access the fragment backstack | ||
| 27 | - * | ||
| 28 | - * @author Hannes Dorfmann | ||
| 29 | - */ | ||
| 30 | -public class BackstackAccessor { | ||
| 31 | - | ||
| 32 | - private BackstackAccessor() { | ||
| 33 | - throw new IllegalStateException("Not instantiatable"); | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * Checks whether or not a given fragment is on the backstack of the fragment manager (could also | ||
| 38 | - * be on top of the backstack and hence visible) | ||
| 39 | - * | ||
| 40 | - * @param fragment The fragment you want to check if its on the back stack | ||
| 41 | - * @return true, if the given Fragment is on the back stack, otherwise false (not on the back | ||
| 42 | - * stack) | ||
| 43 | - */ | ||
| 44 | - //todo | ||
| 45 | -// public static boolean isFragmentOnBackStack(Fragment fragment) { | ||
| 46 | -// try { | ||
| 47 | -//// return fragment.isInBackStack(); | ||
| 48 | -// return true; | ||
| 49 | -// } catch (IllegalAccessError e) { | ||
| 50 | -// return isInBackStackAndroidX(fragment); | ||
| 51 | -// } | ||
| 52 | -// } | ||
| 53 | - | ||
| 54 | - /** | ||
| 55 | - * As of version 1.0 of AndroidX - fragment.isInBackStack() is package private which leads to | ||
| 56 | - * an IllegalAccessError being thrown when trying to use it. | ||
| 57 | - * This method is a temporary workaround until the issue is resolved in AndroidX. | ||
| 58 | - */ | ||
| 59 | - public static boolean isInBackStackAndroidX(final Fragment fragment) { | ||
| 60 | - final StringWriter writer = new StringWriter(); | ||
| 61 | - fragment.dump("", null, new PrintWriter(writer), null); | ||
| 62 | - final String dump = writer.toString(); | ||
| 63 | - return !dump.contains("mBackStackNesting=0"); | ||
| 64 | - } | ||
| 65 | -/* | ||
| 66 | - public static boolean isFragmentOnBackStack(Fragment fragment) { | ||
| 67 | - | ||
| 68 | - FragmentManager fragmentManager = fragment.getFragmentManager(); | ||
| 69 | - int backStackSize = fragmentManager.getBackStackEntryCount(); | ||
| 70 | - for (int i = 0; i < backStackSize; i++) { | ||
| 71 | - BackStackRecord stackEntry = (BackStackRecord) fragmentManager.getBackStackEntryAt(i); | ||
| 72 | - int opsCount = stackEntry.mOps == null ? 0 : stackEntry.mOps.size(); | ||
| 73 | - if (opsCount > 0) { | ||
| 74 | - BackStackRecord.Op op = stackEntry.mOps.get(opsCount-1); | ||
| 75 | - if (op.fragment == fragment) { | ||
| 76 | - return true; | ||
| 77 | - } | ||
| 78 | - } | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - return false; | ||
| 82 | - } | ||
| 83 | -*/ | ||
| 84 | - | ||
| 85 | -/* | ||
| 86 | - private static boolean findNext(@NonNull Fragment toFind, @Nullable BackStackRecord.Op next) { | ||
| 87 | - if (next == null) { | ||
| 88 | - return false; | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - if (toFind == next.fragment) { | ||
| 92 | - return true; | ||
| 93 | - } else { | ||
| 94 | - return findNext(toFind, next.next); | ||
| 95 | - } | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | - private static boolean findPrevious(@NonNull Fragment toFind, | ||
| 99 | - @Nullable BackStackRecord.Op previous) { | ||
| 100 | - if (previous == null) { | ||
| 101 | - return false; | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - if (toFind == previous.fragment) { | ||
| 105 | - return true; | ||
| 106 | - } else { | ||
| 107 | - return findPrevious(toFind, previous.prev); | ||
| 108 | - } | ||
| 109 | - } | ||
| 110 | - */ | ||
| 111 | -} |