Commit e3d87fb50a8f22e7e0fa002b3373b8c6de48e363

Authored by 杨帅
1 parent 146a809a

1 封装视频库

Showing 72 changed files with 574 additions and 5011 deletions
.idea/gradle.xml
... ... @@ -3,11 +3,33 @@
3 3 <component name="GradleSettings">
4 4 <option name="linkedExternalProjectsSettings">
5 5 <GradleProjectSettings>
6   - <compositeConfiguration>
7   - <compositeBuild compositeDefinitionSource="SCRIPT" />
8   - </compositeConfiguration>
9 6 <option name="distributionType" value="DEFAULT_WRAPPED" />
10 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 33 <option name="resolveModulePerSourceSet" value="false" />
12 34 <option name="testRunner" value="PLATFORM" />
13 35 </GradleProjectSettings>
... ...
app/strike/build.gradle
... ... @@ -182,7 +182,7 @@ dependencies {
182 182 implementation project(path: ':module:shopcity')
183 183 // implementation project(path: ':module:shanghaishop')
184 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 186 // implementation project(path: ':core:util')
187 187 // implementation project(path: ':core:encipher')
188 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 23 import com.cnlive.cloud.user.auth.UserService;
24 24 import com.cnlive.core.libs.base.application.AppConfig;
25 25 import com.cnlive.core.libs.base.application.BaseApplication;
26   -import com.cnlive.strike.demo.exoplayer.demo.DownloadTracker;
27 26 import com.google.android.exoplayer2.BuildConfig;
28 27 import com.google.android.exoplayer2.DefaultRenderersFactory;
29 28 import com.google.android.exoplayer2.RenderersFactory;
... ... @@ -72,7 +71,6 @@ public class DemoApplication extends BaseApplication {
72 71 private File downloadDirectory;
73 72 private Cache downloadCache;
74 73 private DownloadManager downloadManager;
75   - private DownloadTracker downloadTracker;
76 74  
77 75 @Override
78 76 public void onCreate() {
... ... @@ -153,15 +151,7 @@ public class DemoApplication extends BaseApplication {
153 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 156 protected synchronized Cache getDownloadCache() {
167 157 if (downloadCache == null) {
... ... @@ -172,23 +162,6 @@ public class DemoApplication extends BaseApplication {
172 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 165 private void upgradeActionFile(
193 166 String fileName, DefaultDownloadIndex downloadIndex, boolean addNewDownloadsAsCompleted) {
194 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 39 import com.cnlive.moudle.pedometer.ui.activity.RunLineActivity;
40 40 import com.cnlive.strike.demo.activity.presenter.DemoActivityPresenter;
41 41 import com.cnlive.strike.demo.activity.view.DemoActivityView;
42   -import com.cnlive.strike.demo.exoplayer.demo.SampleChooserActivity;
43 42 import com.cnlive.strike.network.api.ApiService;
44 43 import com.cnlive.strike.network.api.ApiTimeService;
45 44 import com.cnlive.strike.network.api.TimeServiceBean;
... ... @@ -434,8 +433,6 @@ public class DemoMvpActivity extends BaseActivity&lt;DemoActivityView, DemoActivity
434 433 binding.btnExoHome.setOnClickListener(new View.OnClickListener() {
435 434 @Override
436 435 public void onClick(View v) {
437   - Intent intent=new Intent(me, SampleChooserActivity.class);
438   - startActivity(intent);
439 436 }
440 437 });
441 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 18 import com.google.android.exoplayer2.util.Util;
19 19 import com.google.android.exoplayer2.video.VideoListener;
20 20 import com.libs.video.video.exoplayer.component.DefaultErrorView;
  21 +import com.libs.video.video.exoplayer.component.DefaultYoukuPrepareView;
21 22 import com.libs.video.video.exoplayer.play.CNVideoView;
  23 +import com.libs.video.video.test.CNLiveVideoView;
22 24 import com.libs.video.video.test.VideoPlayer;
23 25 import com.libs.video.video.exoplayer.component.DefaultAdControlView;
24 26 import com.libs.video.video.exoplayer.controller.StandardVideoController;
... ... @@ -93,11 +95,13 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl
93 95 }
94 96 });
95 97 DefaultErrorView errorView=new DefaultErrorView(this);
96   - mController.addControlComponent(adControlView, errorView);
  98 + mController.addControlComponent(new DefaultYoukuPrepareView(me),errorView);
97 99 //直播
98 100 binding.playerView.setUrl("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8");
99 101 binding.playerView.setVideoController(mController);
  102 + binding.playerView.setScreenScaleType(CNVideoView.SCREEN_SCALE_16_9);
100 103 binding.playerView.start();
  104 +
101 105 //监听播放结束
102 106 // binding.playerView.addOnStateChangeListener(new CNVideoView.SimpleOnStateChangeListener() {
103 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 1 package com.libs.video.video.exoplayer.component;
2 2  
3 3 import android.content.Context;
  4 +import android.content.res.Configuration;
4 5 import android.util.AttributeSet;
5 6 import android.util.Log;
6 7 import android.view.LayoutInflater;
... ... @@ -17,6 +18,7 @@ import com.cnlive.core.libs.base.util.NetworkUtil;
17 18 import com.libs.video.video.exoplayer.PlayErrorException;
18 19 import com.libs.video.video.exoplayer.controller.ControlWrapper;
19 20 import com.libs.video.video.exoplayer.controller.IControlComponent;
  21 +import com.libs.video.video.exoplayer.controller.OrientationHelper;
20 22 import com.libs.video.video.exoplayer.play.AbstractPlayer;
21 23 import com.libs.video.video.exoplayer.play.CNVideoView;
22 24  
... ... @@ -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 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 39 @Override
40 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 65 * @param exception
66 66 */
67 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 9 */
10 10 public interface MediaPlayerControl {
11 11  
12   - int getMediaCount();
  12 +// int getMediaCount();
13 13  
14 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 16 import com.libs.video.video.exoplayer.PlayErrorException;
17 17 import com.libs.video.video.exoplayer.component.DefaultCompleteView;
18 18 import com.libs.video.video.exoplayer.component.DefaultErrorView;
  19 +import com.libs.video.video.exoplayer.component.DefaultYoukuPrepareView;
19 20 import com.libs.video.video.exoplayer.component.GestureView;
20 21 import com.libs.video.video.exoplayer.component.LiveControlView;
21 22 import com.libs.video.video.exoplayer.component.DefaultPrepareView;
... ... @@ -37,7 +38,7 @@ public class StandardVideoController extends GestureVideoController implements V
37 38  
38 39 protected ImageView mLockButton;//锁屏按钮
39 40  
40   - protected ProgressBar mLoadingProgress;
  41 +// protected ProgressBar mLoadingProgress;
41 42  
42 43 public StandardVideoController(@NonNull Context context) {
43 44 this(context, null);
... ... @@ -61,7 +62,7 @@ public class StandardVideoController extends GestureVideoController implements V
61 62 super.initView();
62 63 mLockButton = findViewById(R.id.lock);
63 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 171 //调用release方法会回到此状态
171 172 case CNVideoView.STATE_IDLE:
172 173 mLockButton.setSelected(false);
173   - mLoadingProgress.setVisibility(GONE);
  174 +// mLoadingProgress.setVisibility(GONE);
174 175 break;
175 176 case CNVideoView.STATE_PLAYING:
176 177 case CNVideoView.STATE_PAUSED:
177 178 case CNVideoView.STATE_PREPARED:
178 179 case CNVideoView.STATE_ERROR:
179 180 case CNVideoView.STATE_BUFFERED:
180   - mLoadingProgress.setVisibility(GONE);
  181 +// mLoadingProgress.setVisibility(GONE);
181 182 break;
182 183 case CNVideoView.STATE_PREPARING:
183 184 case CNVideoView.STATE_BUFFERING:
184   - mLoadingProgress.setVisibility(VISIBLE);
  185 +// mLoadingProgress.setVisibility(VISIBLE);
185 186 break;
186 187 case CNVideoView.STATE_PLAYBACK_COMPLETED:
187   - mLoadingProgress.setVisibility(GONE);
  188 +// mLoadingProgress.setVisibility(GONE);
188 189 mLockButton.setVisibility(GONE);
189 190 mLockButton.setSelected(false);
190 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 28 import com.libs.video.video.exoplayer.render.RenderViewFactory;
29 29  
30 30 import java.io.IOException;
  31 +import java.lang.annotation.Retention;
  32 +import java.lang.annotation.RetentionPolicy;
31 33 import java.util.ArrayList;
32 34 import java.util.List;
33 35 import java.util.Map;
34 36  
  37 +import androidx.annotation.IntDef;
35 38 import androidx.annotation.NonNull;
36 39 import androidx.annotation.Nullable;
37 40  
... ... @@ -125,8 +128,8 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; extends FrameLayout
125 128 */
126 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 134 public CNVideoView(@NonNull Context context) {
132 135 this(context, null);
... ... @@ -138,7 +141,7 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; extends FrameLayout
138 141  
139 142 public CNVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
140 143 super(context, attrs, defStyleAttr);
141   - dataSource = new ArrayList<>();
  144 +// dataSource = new ArrayList<>();
142 145 //读取全局配置
143 146 VideoViewConfig config = VideoViewManager.getConfig();
144 147 mEnableAudioFocus = config.mEnableAudioFocus;
... ... @@ -184,16 +187,16 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; 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 202 * 开始播放,注意:调用此方法后必须调用{@link #release()}释放播放器,否则会导致内存泄漏
... ... @@ -579,11 +582,11 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; extends FrameLayout
579 582 }
580 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 592 @Override
... ... @@ -655,19 +658,19 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; extends FrameLayout
655 658 * 设置视频地址
656 659 */
657 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&lt;P extends AbstractPlayer&gt; extends FrameLayout
960 963 * 设置视频比例
961 964 */
962 965 @Override
963   - public void setScreenScaleType(int screenScaleType) {
  966 + public void setScreenScaleType(@CNVideoView.screenScalType int screenScaleType) {
964 967 mCurrentScreenScaleType = screenScaleType;
965 968 if (mRenderView != null) {
966 969 mRenderView.setScaleType(screenScaleType);
... ... @@ -1144,4 +1147,11 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; 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 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 75 \ No newline at end of file
... ...
config.gradle
... ... @@ -80,10 +80,10 @@ ext {
80 80 // //权限
81 81 easypermissions : 'pub.devrel:easypermissions:1.0.0',
82 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 87 //UI框架库
88 88 qmui : 'com.qmuiteam:qmui:1.4.0',
89 89 qmui_arch : 'com.qmuiteam:arch:0.6.1',
... ... @@ -136,10 +136,10 @@ ext {
136 136 library.qmui,
137 137 library.qmui_arch,
138 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 143 //图片加载Glide
144 144 glide.api,
145 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 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   -}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/FragmentMvpDelegate.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.content.Context;
21   -import android.os.Bundle;
22   -import android.view.View;
23   -
24   -import androidx.annotation.Nullable;
25   -
26   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
27   -import com.hannesdorfmann.mosby3.mvp.MvpView;
28   -
29   -/**
30   - * A delegate for Fragments to attach them to mosby mvp.
31   - * <p>
32   - * The following methods must be invoked from the corresponding Fragments lifecycle methods:
33   - *
34   - * <ul>
35   - * <li>{@link #onCreate(Bundle)}</li>
36   - * <li>{@link #onDestroy()}</li>
37   - * <li>{@link #onPause()} </li>
38   - * <li>{@link #onResume()} </li>
39   - * <li>{@link #onStart()} </li>
40   - * <li>{@link #onStop()} </li>
41   - * <li>{@link #onViewCreated(View, Bundle)} </li>
42   - * <li>{@link #onActivityCreated(Bundle)} </li>
43   - * <li>{@link #onSaveInstanceState(Bundle)} </li>
44   - * <li>{@link #onAttach(Activity)} </li>
45   - * <li>{@link #onAttach(Context)} </li>
46   - * <li>{@link #onDetach()}</li>
47   - * <li></li>
48   - * </ul>
49   - * </p>
50   - *
51   - * @param <V> The type of {@link MvpView}
52   - * @param <P> The type of {@link MvpPresenter}
53   - * @author Hannes Dorfmann
54   - * @since 1.1.0
55   - */
56   -public interface FragmentMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> {
57   -
58   - /**
59   - * Must be called from {@link Fragment#onCreate(Bundle)}
60   - *
61   - * @param saved The bundle
62   - */
63   - void onCreate(Bundle saved);
64   -
65   - /**
66   - * Must be called from {@link Fragment#onDestroy()}
67   - */
68   - void onDestroy();
69   -
70   - /**
71   - * Must be called from {@link Fragment#onViewCreated(View, Bundle)}
72   - *
73   - * @param view The inflated view
74   - * @param savedInstanceState the bundle with the viewstate
75   - */
76   - void onViewCreated(View view, @Nullable Bundle savedInstanceState);
77   -
78   - /**
79   - * Must be called from {@link Fragment#onDestroyView()}
80   - */
81   - void onDestroyView();
82   -
83   - /**
84   - * Must be called from {@link Fragment#onPause()}
85   - */
86   - void onPause();
87   -
88   - /**
89   - * Must be called from {@link Fragment#onResume()}
90   - */
91   - void onResume();
92   -
93   - /**
94   - * Must be called from {@link Fragment#onStart()}
95   - */
96   - void onStart();
97   -
98   - /**
99   - * Must be called from {@link Fragment#onStop()}
100   - */
101   - void onStop();
102   -
103   - /**
104   - * Must be called from {@link Fragment#onActivityCreated(Bundle)}
105   - *
106   - * @param savedInstanceState The saved bundle
107   - */
108   - void onActivityCreated(Bundle savedInstanceState);
109   -
110   - /**
111   - * Must be called from {@link Fragment#onAttach(Activity)}
112   - *
113   - * @param activity The activity the fragment is attached to
114   - */
115   - @Deprecated
116   - void onAttach(Activity activity);
117   -
118   - /**
119   - * Must be called from {@link Fragment#onAttach(Context)}
120   - *
121   - * @param context The context the fragment is attached to
122   - */
123   - void onAttach(Context context);
124   -
125   - /**
126   - * Must be called from {@link Fragment#onDetach()}
127   - */
128   - void onDetach();
129   -
130   - /**
131   - * Must be called from {@link Fragment#onSaveInstanceState(Bundle)}
132   - */
133   - void onSaveInstanceState(Bundle outState);
134   -}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/FragmentMvpDelegateImpl.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.content.Context;
21   -import android.os.Bundle;
22   -import android.util.Log;
23   -import android.view.View;
24   -
25   -import androidx.annotation.NonNull;
26   -import androidx.annotation.Nullable;
27   -import androidx.fragment.app.Fragment;
28   -
29   -import com.hannesdorfmann.mosby3.PresenterManager;
30   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
31   -import com.hannesdorfmann.mosby3.mvp.MvpView;
32   -
33   -import java.util.UUID;
34   -
35   -/**
36   - * The default implementation of {@link FragmentMvpDelegate}
37   - * Presenter is available (has view that is attached) in {@link #onViewCreated(View, Bundle)} (after
38   - * super.onViewCreated() is called). View will be detached in {@link #onDestroyView()} from presenter,
39   - * and eventually presenter will be destroyed in {@link #onDestroy()}.
40   - *
41   - * @param <V> The type of {@link MvpView}
42   - * @param <P> The type of {@link MvpPresenter}
43   - * @author Hannes Dorfmann
44   - * @see FragmentMvpDelegate
45   - * @since 1.1.0
46   - */
47   -public class FragmentMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
48   - implements FragmentMvpDelegate<V, P> {
49   -
50   - protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.fragment.mvp.id";
51   -
52   - public static boolean DEBUG = false;
53   - private static final String DEBUG_TAG = "FragmentMvpVSDelegate";
54   -
55   - private MvpDelegateCallback<V, P> delegateCallback;
56   - protected Fragment fragment;
57   - protected final boolean keepPresenterInstanceDuringScreenOrientationChanges;
58   - protected final boolean keepPresenterOnBackstack;
59   - private boolean onViewCreatedCalled = false;
60   - protected String mosbyViewId;
61   -
62   - /**
63   - * @param fragment The Fragment
64   - * @param delegateCallback the DelegateCallback
65   - * @param keepPresenterDuringScreenOrientationChange true, if the presenter should be kept during
66   - * screen orientation
67   - * changes. Otherwise, false
68   - * @param keepPresenterOnBackstack true, if the presenter should be kept when the fragment is
69   - * destroyed because it is put on the backstack, Otherwise false
70   - */
71   - public FragmentMvpDelegateImpl(@NonNull Fragment fragment,
72   - @NonNull MvpDelegateCallback<V, P> delegateCallback,
73   - boolean keepPresenterDuringScreenOrientationChange, boolean keepPresenterOnBackstack) {
74   - if (delegateCallback == null) {
75   - throw new NullPointerException("MvpDelegateCallback is null!");
76   - }
77   -
78   - if (fragment == null) {
79   - throw new NullPointerException("Fragment is null!");
80   - }
81   -
82   - if (!keepPresenterDuringScreenOrientationChange && keepPresenterOnBackstack) {
83   - throw new IllegalArgumentException("It is not possible to keep the presenter on backstack, "
84   - + "but NOT keep presenter through screen orientation changes. Keep presenter on backstack also "
85   - + "requires keep presenter through screen orientation changes to be enabled");
86   - }
87   -
88   - this.fragment = fragment;
89   - this.delegateCallback = delegateCallback;
90   - this.keepPresenterInstanceDuringScreenOrientationChanges =
91   - keepPresenterDuringScreenOrientationChange;
92   - this.keepPresenterOnBackstack = keepPresenterOnBackstack;
93   - }
94   -
95   - /**
96   - * Generates the unique (mosby internal) view id and calls {@link
97   - * MvpDelegateCallback#createPresenter()}
98   - * to create a new presenter instance
99   - *
100   - * @return The new created presenter instance
101   - */
102   - private P createViewIdAndCreatePresenter() {
103   -
104   - P presenter = delegateCallback.createPresenter();
105   - if (presenter == null) {
106   - throw new NullPointerException(
107   - "Presenter returned from createPresenter() is null. Activity is " + getActivity());
108   - }
109   - if (keepPresenterInstanceDuringScreenOrientationChanges) {
110   - mosbyViewId = UUID.randomUUID().toString();
111   - PresenterManager.putPresenter(getActivity(), mosbyViewId, presenter);
112   - }
113   - return presenter;
114   - }
115   -
116   - @Override
117   - public void onViewCreated(View view, @Nullable Bundle bundle) {
118   -
119   - P presenter = getPresenter();
120   - presenter.attachView(getMvpView());
121   -
122   - if (DEBUG) {
123   - Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter);
124   - }
125   -
126   - onViewCreatedCalled = true;
127   - }
128   -
129   - @NonNull
130   - private Activity getActivity() {
131   - Activity activity = fragment.getActivity();
132   - if (activity == null) {
133   - throw new NullPointerException(
134   - "Activity returned by Fragment.getActivity() is null. Fragment is " + fragment);
135   - }
136   -
137   - return activity;
138   - }
139   -
140   - private P getPresenter() {
141   - P presenter = delegateCallback.getPresenter();
142   - if (presenter == null) {
143   - throw new NullPointerException("Presenter returned from getPresenter() is null");
144   - }
145   - return presenter;
146   - }
147   -
148   - private V getMvpView() {
149   - V view = delegateCallback.getMvpView();
150   - if (view == null) {
151   - throw new NullPointerException("View returned from getMvpView() is null");
152   - }
153   - return view;
154   - }
155   -
156   - static boolean retainPresenterInstance(Activity activity, Fragment fragment,
157   - boolean keepPresenterInstanceDuringScreenOrientationChanges,
158   - boolean keepPresenterOnBackstack) {
159   -
160   - if (activity.isChangingConfigurations()) {
161   - return keepPresenterInstanceDuringScreenOrientationChanges;
162   - }
163   -
164   - if (activity.isFinishing()) {
165   - return false;
166   - }
167   -//todo 修改androidx
168   - if (keepPresenterOnBackstack && BackstackAccessor.isInBackStackAndroidX(fragment)) {
169   - return true;
170   - }
171   -
172   - return !fragment.isRemoving();
173   - }
174   -
175   - @Override
176   - public void onDestroyView() {
177   -
178   - onViewCreatedCalled = false;
179   -
180   - getPresenter().detachView();
181   -
182   - if (DEBUG) {
183   - Log.d(DEBUG_TAG, "detached MvpView from Presenter. MvpView "
184   - + delegateCallback.getMvpView()
185   - + " Presenter: "
186   - + getPresenter());
187   - }
188   - }
189   -
190   - @Override
191   - public void onPause() {
192   -
193   - }
194   -
195   - @Override
196   - public void onResume() {
197   -
198   - }
199   -
200   - @Override
201   - public void onStart() {
202   -
203   - if (!onViewCreatedCalled) {
204   - throw new IllegalStateException("It seems that you are using "
205   - + delegateCallback.getClass().getCanonicalName()
206   - + " as headless (UI less) fragment (because onViewCreated() has not been called or maybe delegation misses that part). Having a Presenter without a View (UI) doesn't make sense. Simply use an usual fragment instead of an MvpFragment if you want to use a UI less Fragment");
207   - }
208   - }
209   -
210   - @Override
211   - public void onStop() {
212   -
213   - }
214   -
215   - @Override
216   - public void onActivityCreated(Bundle savedInstanceState) {
217   -
218   - }
219   -
220   - @Override
221   - public void onAttach(Activity activity) {
222   -
223   - }
224   -
225   - @Override
226   - public void onAttach(Context context) {
227   -
228   - }
229   -
230   - @Override
231   - public void onDetach() {
232   -
233   - }
234   -
235   - @Override
236   - public void onSaveInstanceState(Bundle outState) {
237   - if ((keepPresenterInstanceDuringScreenOrientationChanges || keepPresenterOnBackstack)
238   - && outState != null) {
239   - outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId);
240   -
241   - if (DEBUG) {
242   - Log.d(DEBUG_TAG, "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId);
243   - }
244   - }
245   - }
246   -
247   - @Override
248   - public void onCreate(Bundle bundle) {
249   -
250   - P presenter = null;
251   -
252   - if (bundle != null && keepPresenterInstanceDuringScreenOrientationChanges) {
253   -
254   - mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID);
255   -
256   - if (DEBUG) {
257   - Log.d(DEBUG_TAG,
258   - "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView());
259   - }
260   -
261   - if (mosbyViewId != null
262   - && (presenter = PresenterManager.getPresenter(getActivity(), mosbyViewId)) != null) {
263   - //
264   - // Presenter restored from cache
265   - //
266   - if (DEBUG) {
267   - Log.d(DEBUG_TAG,
268   - "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView());
269   - }
270   - } else {
271   - //
272   - // No presenter found in cache, most likely caused by process death
273   - //
274   - presenter = createViewIdAndCreatePresenter();
275   - if (DEBUG) {
276   - Log.d(DEBUG_TAG, "No presenter found although view Id was here: "
277   - + mosbyViewId
278   - + ". Most likely this was caused by a process death. New Presenter created"
279   - + presenter
280   - + " for view "
281   - + getMvpView());
282   - }
283   - }
284   - } else {
285   - //
286   - // Activity starting first time, so create a new presenter
287   - //
288   - presenter = createViewIdAndCreatePresenter();
289   - if (DEBUG) {
290   - Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView());
291   - }
292   - }
293   -
294   - if (presenter == null) {
295   - throw new IllegalStateException(
296   - "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
297   - }
298   -
299   - delegateCallback.setPresenter(presenter);
300   - }
301   -
302   - @Override
303   - public void onDestroy() {
304   -
305   - Activity activity = getActivity();
306   - boolean retainPresenterInstance = retainPresenterInstance(activity, fragment,
307   - keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack);
308   -
309   - P presenter = getPresenter();
310   - if (!retainPresenterInstance) {
311   - presenter.destroy();
312   - if (DEBUG) {
313   - Log.d(DEBUG_TAG, "Presenter destroyed. MvpView "
314   - + delegateCallback.getMvpView()
315   - + " Presenter: "
316   - + presenter);
317   - }
318   - }
319   -
320   - if (!retainPresenterInstance && mosbyViewId != null) {
321   - // mosbyViewId is null if keepPresenterInstanceDuringScreenOrientationChanges == false
322   - PresenterManager.remove(activity, mosbyViewId);
323   - }
324   - }
325   -}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/MvpDelegateCallback.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   -
20   -import androidx.annotation.NonNull;
21   -
22   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
23   -import com.hannesdorfmann.mosby3.mvp.MvpView;
24   -
25   -/**
26   - * The MvpDelegate callback that will be called from {@link
27   - * FragmentMvpDelegate} or {@link ViewGroupMvpDelegate}. This interface must be implemented by all
28   - * Fragment or android.view.View that you want to support Mosby mvp.
29   - *
30   - * @param <V> The type of {@link MvpView}
31   - * @param <P> The type of {@link MvpPresenter}
32   - * @author Hannes Dorfmann
33   - * @since 1.1.0
34   - */
35   -public interface MvpDelegateCallback<V extends MvpView, P extends MvpPresenter<V>> {
36   -
37   - /**
38   - * Creates the presenter instance
39   - *
40   - * @return the created presenter instance
41   - */
42   - @NonNull
43   - P createPresenter();
44   -
45   - /**
46   - * Gets the presenter. If null is returned, then a internally a new presenter instance gets
47   - * created by calling {@link #createPresenter()}
48   - *
49   - * @return the presenter instance. can be null.
50   - */
51   - P getPresenter();
52   -
53   - /**
54   - * Sets the presenter instance
55   - *
56   - * @param presenter The presenter instance
57   - */
58   - void setPresenter(P presenter);
59   -
60   - /**
61   - * Gets the MvpView for the presenter
62   - *
63   - * @return The view associated with the presenter
64   - */
65   - V getMvpView();
66   -}
67   -
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupDelegateCallback.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.content.Context;
20   -import android.os.Parcelable;
21   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
22   -import com.hannesdorfmann.mosby3.mvp.MvpView;
23   -
24   -/**
25   - * An enhanced version of {@link MvpDelegateCallback} that adds support for
26   - * android.view.View like FrameLayout etc.
27   - *
28   - * @author Hannes Dorfmann
29   - * @since 3.0
30   - */
31   -public interface ViewGroupDelegateCallback<V extends MvpView, P extends MvpPresenter<V>>
32   - extends MvpDelegateCallback<V, P> {
33   -
34   - /**
35   - * This method must call super.onSaveInstanceState() within any view
36   - */
37   - Parcelable superOnSaveInstanceState();
38   -
39   - /**
40   - * This method must call super.onRestoreInstanceState(state)
41   - *
42   - * @param state The parcelable containing the state
43   - */
44   - void superOnRestoreInstanceState(Parcelable state);
45   -
46   - /**
47   - * Get the context
48   - *
49   - * @return Get the context
50   - * @since 3.0
51   - */
52   - Context getContext();
53   -}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupMvpDelegate.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.os.Parcelable;
20   -import android.view.View;
21   -import android.widget.FrameLayout;
22   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
23   -import com.hannesdorfmann.mosby3.mvp.MvpView;
24   -
25   -/**
26   - * The mvp delegate used for everything that derives from {@link View} like {@link FrameLayout}
27   - * etc.
28   - *
29   - * <p>
30   - * The following methods must be called from the corresponding View lifecycle method:
31   - * <ul>
32   - * <li>{@link #onAttachedToWindow()}</li>
33   - * <li>{@link #onDetachedFromWindow()}</li>
34   - * </ul>
35   - * </p>
36   - *
37   - * @author Hannes Dorfmann
38   - * @since 1.1.0
39   - */
40   -public interface ViewGroupMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> {
41   -
42   - /**
43   - * Must be called from {@link View#onAttachedToWindow()}
44   - */
45   - void onAttachedToWindow();
46   -
47   - /**
48   - * Must be called from {@link View#onDetachedFromWindow()}
49   - */
50   - void onDetachedFromWindow();
51   -
52   - /**
53   - * Must be called from {@link View#onRestoreInstanceState(Parcelable)}
54   - *
55   - * @param state The parcelable state
56   - */
57   - void onRestoreInstanceState(Parcelable state);
58   -
59   - /**
60   - * Save the instatnce state
61   - *
62   - * @return The state with all the saved data
63   - */
64   - Parcelable onSaveInstanceState();
65   -}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupMvpDelegateImpl.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.mvp.delegate;
19   -
20   -import android.app.Activity;
21   -import android.app.Application;
22   -import android.content.Context;
23   -import android.os.Bundle;
24   -import android.os.Parcelable;
25   -import android.util.Log;
26   -import android.view.View;
27   -import android.widget.FrameLayout;
28   -
29   -import androidx.annotation.NonNull;
30   -
31   -import com.hannesdorfmann.mosby3.MosbySavedState;
32   -import com.hannesdorfmann.mosby3.PresenterManager;
33   -import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
34   -import com.hannesdorfmann.mosby3.mvp.MvpView;
35   -import java.util.UUID;
36   -
37   -/**
38   - * The mvp delegate used for everything that derives from {@link View} like {@link FrameLayout}
39   - * etc.
40   - *
41   - * <p>
42   - * The following methods must be called from the corresponding View lifecycle method:
43   - * <ul>
44   - * <li>{@link #onAttachedToWindow()}</li>
45   - * <li>{@link #onDetachedFromWindow()}</li>
46   - * </ul>
47   - * </p>
48   - *
49   - * @author Hannes Dorfmann
50   - * @since 1.1.0
51   - */
52   -public class ViewGroupMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
53   - implements ViewGroupMvpDelegate<V, P>, Application.ActivityLifecycleCallbacks {
54   -
55   - // TODO allow custom save state hook in
56   -
57   - public static boolean DEBUG = false;
58   - private static final String DEBUG_TAG = "ViewGroupMvpDelegateImp";
59   -
60   - private ViewGroupDelegateCallback<V, P> delegateCallback;
61   - private String mosbyViewId;
62   - private final boolean keepPresenterDuringScreenOrientationChange;
63   - private final Activity activity;
64   - private final boolean isInEditMode;
65   -
66   - private boolean checkedActivityFinishing = false;
67   - private boolean presenterDetached = false;
68   - private boolean presenterDestroyed = false;
69   -
70   - public ViewGroupMvpDelegateImpl(@NonNull View view,
71   - @NonNull ViewGroupDelegateCallback<V, P> delegateCallback,
72   - boolean keepPresenterDuringScreenOrientationChange) {
73   - if (view == null) {
74   - throw new NullPointerException("View is null!");
75   - }
76   -
77   - if (delegateCallback == null) {
78   - throw new NullPointerException("MvpDelegateCallback is null!");
79   - }
80   -
81   - this.delegateCallback = delegateCallback;
82   - this.keepPresenterDuringScreenOrientationChange = keepPresenterDuringScreenOrientationChange;
83   -
84   - isInEditMode = view.isInEditMode();
85   -
86   - if (!isInEditMode) {
87   - this.activity = PresenterManager.getActivity(delegateCallback.getContext());
88   - this.activity.getApplication().registerActivityLifecycleCallbacks(this);
89   - } else {
90   - this.activity = null;
91   - }
92   - }
93   -
94   - /**
95   - * Generates the unique (mosby internal) viewState id and calls {@link
96   - * MvpDelegateCallback#createPresenter()}
97   - * to create a new presenter instance
98   - *
99   - * @return The new created presenter instance
100   - */
101   - protected P createViewIdAndCreatePresenter() {
102   -
103   - P presenter = delegateCallback.createPresenter();
104   - if (presenter == null) {
105   - throw new NullPointerException("Presenter returned from createPresenter() is null.");
106   - }
107   - if (keepPresenterDuringScreenOrientationChange) {
108   - Context context = delegateCallback.getContext();
109   - mosbyViewId = UUID.randomUUID().toString();
110   - PresenterManager.putPresenter(PresenterManager.getActivity(context), mosbyViewId, presenter);
111   - }
112   - return presenter;
113   - }
114   -
115   - @NonNull private Context getContext() {
116   - Context c = delegateCallback.getContext();
117   - if (c == null) {
118   - throw new NullPointerException("Context returned from " + delegateCallback + " is null");
119   - }
120   - return c;
121   - }
122   -
123   - @Override public void onAttachedToWindow() {
124   - if (isInEditMode) return;
125   -
126   - P presenter = null;
127   - if (mosbyViewId == null) {
128   - // No presenter available,
129   - // Activity is starting for the first time (or keepPresenterInstance == false)
130   - presenter = createViewIdAndCreatePresenter();
131   - if (DEBUG) {
132   - Log.d(DEBUG_TAG, "new Presenter instance created: " + presenter);
133   - }
134   - } else {
135   - presenter = PresenterManager.getPresenter(activity, mosbyViewId);
136   - if (presenter == null) {
137   - // Process death,
138   - // hence no presenter with the given viewState id stored, although we have a viewState id
139   - presenter = createViewIdAndCreatePresenter();
140   - if (DEBUG) {
141   - Log.d(DEBUG_TAG,
142   - "No Presenter instance found in cache, although MosbyView ID present. This was caused by process death, therefore new Presenter instance created: "
143   - + presenter);
144   - }
145   - } else {
146   - if (DEBUG) {
147   - Log.d(DEBUG_TAG, "Presenter instance reused from internal cache: " + presenter);
148   - }
149   - }
150   - }
151   -
152   - // presenter is ready, so attach viewState
153   - V view = delegateCallback.getMvpView();
154   - if (view == null) {
155   - throw new NullPointerException(
156   - "MvpView returned from getMvpView() is null. Returned by " + delegateCallback);
157   - }
158   -
159   - if (presenter == null) {
160   - throw new IllegalStateException(
161   - "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
162   - }
163   -
164   - /*
165   - if (viewStateWillBeRestored) {
166   - delegateCallback.setRestoringViewState(true);
167   - }
168   - */
169   -
170   - delegateCallback.setPresenter(presenter);
171   - presenter.attachView(view);
172   -
173   - /*
174   - if (viewStateWillBeRestored) {
175   - delegateCallback.setRestoringViewState(false);
176   - }
177   - */
178   -
179   - if (DEBUG) {
180   - Log.d(DEBUG_TAG,
181   - "MvpView attached to Presenter. MvpView: " + view + " Presenter: " + presenter);
182   - }
183   - }
184   -
185   - /**
186   - * Must be called from {@link View#onSaveInstanceState()}
187   - */
188   - public Parcelable onSaveInstanceState() {
189   - if (isInEditMode) return null;
190   -
191   - Parcelable superState = delegateCallback.superOnSaveInstanceState();
192   -
193   - if (keepPresenterDuringScreenOrientationChange) {
194   - return new MosbySavedState(superState, mosbyViewId);
195   - } else {
196   - return superState;
197   - }
198   - }
199   -
200   - /**
201   - * Restore the data from SavedState
202   - *
203   - * @param state The state to read data from
204   - */
205   - private void restoreSavedState(MosbySavedState state) {
206   - mosbyViewId = state.getMosbyViewId();
207   - }
208   -
209   - /**
210   - * Must be called from {@link View#onRestoreInstanceState(Parcelable)}
211   - */
212   - public void onRestoreInstanceState(Parcelable state) {
213   - if (isInEditMode) return;
214   -
215   - if (!(state instanceof MosbySavedState)) {
216   - delegateCallback.superOnRestoreInstanceState(state);
217   - return;
218   - }
219   -
220   - MosbySavedState savedState = (MosbySavedState) state;
221   - restoreSavedState(savedState);
222   - delegateCallback.superOnRestoreInstanceState(savedState.getSuperState());
223   - }
224   -
225   - @Override public void onDetachedFromWindow() {
226   - if (isInEditMode) return;
227   -
228   - detachPresenterIfNotDoneYet();
229   -
230   - if (!checkedActivityFinishing) {
231   -
232   - boolean destroyPermanently = !ActivityMvpDelegateImpl.retainPresenterInstance(
233   - keepPresenterDuringScreenOrientationChange, activity);
234   -
235   - if (destroyPermanently) {
236   - destroyPresenterIfNotDoneYet();
237   - } else if (!activity.isChangingConfigurations()) {
238   - // View removed manually from screen
239   - destroyPresenterIfNotDoneYet();
240   - }
241   - } // else --> see onActivityDestroyed()
242   - }
243   -
244   - @Override public void onActivityDestroyed(Activity activity) {
245   -
246   - if (activity == this.activity) {
247   - // The hosting activity of this view has been destroyed, so time to destroy the presenter too?
248   -
249   - activity.getApplication().unregisterActivityLifecycleCallbacks(this);
250   - checkedActivityFinishing = true;
251   -
252   - boolean destroyedPermanently = !ActivityMvpDelegateImpl.retainPresenterInstance(
253   - keepPresenterDuringScreenOrientationChange, activity);
254   -
255   - if (destroyedPermanently) {
256   - // Whole activity will be destroyed
257   - detachPresenterIfNotDoneYet();
258   - destroyPresenterIfNotDoneYet();
259   - }
260   - }
261   -
262   - }
263   -
264   - @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
265   - }
266   -
267   - @Override public void onActivityStarted(Activity activity) {
268   - }
269   -
270   - @Override public void onActivityResumed(Activity activity) {
271   - }
272   -
273   - @Override public void onActivityPaused(Activity activity) {
274   - }
275   -
276   - @Override public void onActivityStopped(Activity activity) {
277   - }
278   -
279   - @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
280   - }
281   -
282   - private void destroyPresenterIfNotDoneYet() {
283   - if (!presenterDestroyed) {
284   - P presenter = delegateCallback.getPresenter();
285   - if (presenter != null) {
286   - presenter.destroy();
287   - }
288   - presenterDestroyed = true;
289   - activity.getApplication().unregisterActivityLifecycleCallbacks(this);
290   - if (DEBUG) {
291   - Log.d(DEBUG_TAG, "Presenter destroyed: " + presenter);
292   - }
293   -
294   - if (mosbyViewId != null) {
295   - // mosbyViewId == null if keepPresenterDuringScreenOrientationChange == false
296   - PresenterManager.remove(activity, mosbyViewId);
297   - }
298   - mosbyViewId = null;
299   - }
300   - }
301   -
302   - private void detachPresenterIfNotDoneYet() {
303   - if (!presenterDetached) {
304   - P presenter = delegateCallback.getPresenter();
305   - if (presenter != null) {
306   - presenter.detachView();
307   - }
308   - presenterDetached = true;
309   - if (DEBUG) {
310   - Log.d(DEBUG_TAG,
311   - "view " + delegateCallback.getMvpView() + " detached from Presenter " + presenter);
312   - }
313   - }
314   - }
315   -}