[leanback] add player setting

pull/123/head
FongMi 3 years ago
parent 1dc9307806
commit 2f7c0e5782
  1. 5
      app/src/leanback/AndroidManifest.xml
  2. 6
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java
  3. 73
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java
  4. 97
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/UaDialog.java
  5. 104
      app/src/leanback/res/layout/activity_setting_player.xml
  6. 81
      app/src/leanback/res/layout/dialog_ua.xml
  7. 6
      app/src/main/java/com/fongmi/android/tv/impl/UaCallback.java
  8. 16
      app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java
  9. 11
      app/src/main/java/com/fongmi/android/tv/player/Players.java
  10. 24
      app/src/main/java/com/fongmi/android/tv/utils/Prefers.java
  11. 10
      app/src/main/res/values-zh-rCN/strings.xml
  12. 10
      app/src/main/res/values-zh-rTW/strings.xml
  13. 10
      app/src/main/res/values/strings.xml
  14. 9
      ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/IjkVideoView.java
  15. 16
      ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/Utils.java

@ -80,5 +80,10 @@
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
<activity
android:name=".ui.activity.SettingPlayerActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
</application>
</manifest>

@ -109,6 +109,7 @@ public class SettingActivity extends BaseActivity implements ConfigCallback, Sit
mBinding.vodHistory.setOnClickListener(this::onVodHistory);
mBinding.version.setOnLongClickListener(this::onVersionDev);
mBinding.liveHistory.setOnClickListener(this::onLiveHistory);
mBinding.player.setOnLongClickListener(this::onPlayerSetting);
mBinding.wallDefault.setOnClickListener(this::setWallDefault);
mBinding.wallRefresh.setOnClickListener(this::setWallRefresh);
mBinding.quality.setOnClickListener(this::setQuality);
@ -231,6 +232,11 @@ public class SettingActivity extends BaseActivity implements ConfigCallback, Sit
HistoryDialog.create(this).type(type = 1).show();
}
private boolean onPlayerSetting(View view) {
SettingPlayerActivity.start(this);
return true;
}
private void onVersion(View view) {
Updater.get().force().release().start();
}

@ -0,0 +1,73 @@
package com.fongmi.android.tv.ui.activity;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import androidx.viewbinding.ViewBinding;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.databinding.ActivitySettingPlayerBinding;
import com.fongmi.android.tv.impl.UaCallback;
import com.fongmi.android.tv.player.ExoUtil;
import com.fongmi.android.tv.ui.base.BaseActivity;
import com.fongmi.android.tv.ui.custom.dialog.UaDialog;
import com.fongmi.android.tv.utils.Prefers;
import com.fongmi.android.tv.utils.ResUtil;
public class SettingPlayerActivity extends BaseActivity implements UaCallback {
private ActivitySettingPlayerBinding mBinding;
private String[] http;
public static void start(Activity activity) {
activity.startActivity(new Intent(activity, SettingPlayerActivity.class));
}
private String getSwitch(boolean value) {
return getString(value ? R.string.setting_on : R.string.setting_off);
}
@Override
protected ViewBinding getBinding() {
return mBinding = ActivitySettingPlayerBinding.inflate(getLayoutInflater());
}
@Override
protected void initView() {
mBinding.uaText.setText(Prefers.getUa());
mBinding.tunnelText.setText(getSwitch(Prefers.isTunnel()));
mBinding.httpText.setText((http = ResUtil.getStringArray(R.array.select_player_http))[Prefers.getHttp()]);
mBinding.tunnel.setVisibility(Prefers.getPlayer() == 0 ? View.VISIBLE : View.GONE);
mBinding.http.setVisibility(Prefers.getPlayer() == 0 ? View.VISIBLE : View.GONE);
}
@Override
protected void initEvent() {
mBinding.ua.setOnClickListener(this::onUa);
mBinding.http.setOnClickListener(this::setHttp);
mBinding.tunnel.setOnClickListener(this::setTunnel);
}
private void onUa(View view) {
UaDialog.create(this).show();
}
private void setHttp(View view) {
int index = Prefers.getHttp();
Prefers.putHttp(index = index == http.length - 1 ? 0 : ++index);
mBinding.httpText.setText(http[index]);
ExoUtil.reset();
}
private void setTunnel(View view) {
Prefers.putTunnel(!Prefers.isTunnel());
mBinding.tunnelText.setText(getSwitch(Prefers.isTunnel()));
}
@Override
public void setUa(String ua) {
mBinding.uaText.setText(ua);
Prefers.putUa(ua);
}
}

@ -0,0 +1,97 @@
package com.fongmi.android.tv.ui.custom.dialog;
import android.content.DialogInterface;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.databinding.DialogUaBinding;
import com.fongmi.android.tv.event.ServerEvent;
import com.fongmi.android.tv.impl.UaCallback;
import com.fongmi.android.tv.server.Server;
import com.fongmi.android.tv.utils.Prefers;
import com.fongmi.android.tv.utils.QRCode;
import com.fongmi.android.tv.utils.ResUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class UaDialog implements DialogInterface.OnDismissListener {
private final DialogUaBinding binding;
private final UaCallback callback;
private final AlertDialog dialog;
public static UaDialog create(FragmentActivity activity) {
return new UaDialog(activity);
}
public UaDialog(FragmentActivity activity) {
this.callback = (UaCallback) activity;
this.binding = DialogUaBinding.inflate(LayoutInflater.from(activity));
this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create();
}
public void show() {
initDialog();
initView();
initEvent();
}
private void initDialog() {
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.width = (int) (ResUtil.getScreenWidth() * 0.55f);
dialog.getWindow().setAttributes(params);
dialog.getWindow().setDimAmount(0);
dialog.setOnDismissListener(this);
dialog.show();
}
private void initView() {
String ua = Prefers.getUa();
String address = Server.get().getAddress();
binding.text.setText(ua);
binding.code.setImageBitmap(QRCode.getBitmap(address, 200, 0));
binding.text.setSelection(TextUtils.isEmpty(ua) ? 0 : ua.length());
binding.info.setText(ResUtil.getString(R.string.push_info, address).replace(",", "\n"));
}
private void initEvent() {
EventBus.getDefault().register(this);
binding.positive.setOnClickListener(this::onPositive);
binding.negative.setOnClickListener(this::onNegative);
binding.text.setOnEditorActionListener((textView, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) binding.positive.performClick();
return true;
});
}
private void onPositive(View view) {
callback.setUa(binding.text.getText().toString().trim());
dialog.dismiss();
}
private void onNegative(View view) {
dialog.dismiss();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onServerEvent(ServerEvent event) {
if (event.getType() != ServerEvent.Type.API) return;
binding.text.setText(event.getText());
binding.positive.performClick();
}
@Override
public void onDismiss(DialogInterface dialogInterface) {
EventBus.getDefault().unregister(this);
}
}

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:keepScreenOn="true"
tools:ignore="NestedWeights">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp">
<LinearLayout
android:id="@+id/ua"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_item"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="0.3"
android:text="@string/setting_player_ua"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/uaText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:ellipsize="middle"
android:gravity="end"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="18sp"
tools:text="okhttp/4.11.0" />
</LinearLayout>
<LinearLayout
android:id="@+id/http"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/selector_item"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/setting_player_http"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/httpText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
tools:text="OkHttp" />
</LinearLayout>
<LinearLayout
android:id="@+id/tunnel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/selector_item"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/setting_player_tunnel"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/tunnelText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
tools:text="關" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp">
<ImageView
android:id="@+id/code"
android:layout_width="180dp"
android:layout_height="180dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_toEndOf="@+id/code"
android:focusable="true"
android:lineSpacingExtra="4dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textColor="@color/grey_700"
android:textSize="18sp"
tools:text="@string/push_info" />
<EditText
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom"
android:layout_alignStart="@+id/info"
android:layout_marginBottom="10dp"
android:hint="@string/setting_player_ua"
android:imeOptions="actionDone"
android:importantForAutofill="no"
android:inputType="text"
android:nextFocusDown="@id/positive"
android:singleLine="true"
android:textSize="18sp" />
<LinearLayout
android:id="@+id/bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/info"
android:layout_alignBottom="@+id/code"
android:orientation="horizontal">
<TextView
android:id="@+id/positive"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:background="@drawable/selector_text"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:singleLine="true"
android:text="@string/dialog_positive"
android:textColor="@color/white"
android:textSize="14sp" />
<TextView
android:id="@+id/negative"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_text"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:singleLine="true"
android:text="@string/dialog_negative"
android:textColor="@color/white"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

@ -0,0 +1,6 @@
package com.fongmi.android.tv.impl;
public interface UaCallback {
void setUa(String ua);
}

@ -12,6 +12,7 @@ import androidx.media3.database.DatabaseProvider;
import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.datasource.DefaultHttpDataSource;
import androidx.media3.datasource.HttpDataSource;
import androidx.media3.datasource.cache.Cache;
import androidx.media3.datasource.cache.CacheDataSource;
@ -39,7 +40,6 @@ import com.fongmi.android.tv.bean.Rule;
import com.fongmi.android.tv.bean.Sub;
import com.fongmi.android.tv.utils.FileUtil;
import com.fongmi.android.tv.utils.Prefers;
import com.fongmi.android.tv.utils.Sniffer;
import com.github.catvod.net.OkHttp;
import com.google.common.net.HttpHeaders;
@ -64,7 +64,7 @@ public class ExoUtil {
public static TrackSelector buildTrackSelector() {
DefaultTrackSelector trackSelector = new DefaultTrackSelector(App.get());
trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("zh"));
trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("zh").setTunnelingEnabled(Prefers.isTunnel()));
return trackSelector;
}
@ -122,12 +122,11 @@ public class ExoUtil {
}
private static synchronized HttpDataSource.Factory getHttpDataSourceFactory() {
if (httpDataSourceFactory == null) httpDataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) OkHttp.client());
if (httpDataSourceFactory == null) httpDataSourceFactory = Prefers.getHttp() == 0 ? new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true) : new OkHttpDataSource.Factory((Call.Factory) OkHttp.client());
return httpDataSourceFactory;
}
private static synchronized DataSource.Factory getDataSourceFactory(Map<String, String> headers) {
if (!headers.containsKey(HttpHeaders.USER_AGENT)) headers.put(HttpHeaders.USER_AGENT, Sniffer.CHROME);
if (dataSourceFactory == null) dataSourceFactory = buildReadOnlyCacheDataSource(new DefaultDataSource.Factory(App.get(), getHttpDataSourceFactory()), getCache());
httpDataSourceFactory.setDefaultRequestProperties(headers);
return dataSourceFactory;
@ -146,4 +145,13 @@ public class ExoUtil {
if (cache == null) cache = new SimpleCache(FileUtil.getCacheDir("player"), new NoOpCacheEvictor(), getDatabase());
return cache;
}
public static void reset() {
if (cache != null) cache.release();
httpDataSourceFactory = null;
dataSourceFactory = null;
extractorsFactory = null;
database = null;
cache = null;
}
}

@ -24,6 +24,7 @@ import com.fongmi.android.tv.utils.Prefers;
import com.fongmi.android.tv.utils.ResUtil;
import com.github.catvod.crawler.SpiderDebug;
import com.google.common.collect.ImmutableList;
import com.google.common.net.HttpHeaders;
import java.util.Formatter;
import java.util.List;
@ -327,8 +328,14 @@ public class Players implements Player.Listener, IMediaPlayer.Listener, Analytic
if (parseJob != null) parseJob.stop();
}
private Map<String, String> checkHeaders(Map<String, String> headers) {
if (Prefers.getUa().isEmpty() || headers.containsKey(HttpHeaders.USER_AGENT) || headers.containsKey(HttpHeaders.USER_AGENT.toLowerCase())) return headers;
headers.put(HttpHeaders.USER_AGENT, Prefers.getUa());
return headers;
}
private void setMediaSource(Result result) {
SpiderDebug.log(errorCode + "," + result.getRealUrl() + "," + result.getHeaders());
SpiderDebug.log(errorCode + "," + result.getRealUrl() + "," + checkHeaders(result.getHeaders()));
if (isIjk()) ijkPlayer.setMediaSource(result.getRealUrl(), result.getHeaders());
if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(result, errorCode));
if (isExo()) exoPlayer.prepare();
@ -336,7 +343,7 @@ public class Players implements Player.Listener, IMediaPlayer.Listener, Analytic
}
private void setMediaSource(Map<String, String> headers, String url) {
SpiderDebug.log(errorCode + "," + url + "," + headers);
SpiderDebug.log(errorCode + "," + url + "," + checkHeaders(headers));
if (isIjk()) ijkPlayer.setMediaSource(url, headers);
if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(headers, url, errorCode));
if (isExo()) exoPlayer.prepare();

@ -203,6 +203,30 @@ public class Prefers {
put("update", update);
}
public static String getUa() {
return getString("ua", Sniffer.CHROME);
}
public static void putUa(String ua) {
put("ua", ua);
}
public static boolean isTunnel() {
return getBoolean("exo_tunnel");
}
public static void putTunnel(boolean tunnel) {
put("exo_tunnel", tunnel);
}
public static int getHttp() {
return getInt("exo_http", 1);
}
public static void putHttp(int http) {
put("exo_http", http);
}
public static float getThumbnail() {
return 0.3f * getQuality() + 0.4f;
}

@ -61,6 +61,9 @@
<string name="setting_live">直播</string>
<string name="setting_wall">壁纸</string>
<string name="setting_player">播放器</string>
<string name="setting_player_ua">User Agent</string>
<string name="setting_player_tunnel">Tunnel Mode</string>
<string name="setting_player_http">Http Source</string>
<string name="setting_decode">解码方式</string>
<string name="setting_render">渲染方式</string>
<string name="setting_scale">缩放比例</string>
@ -70,6 +73,8 @@
<string name="setting_cache">缓存</string>
<string name="setting_version">版本</string>
<string name="setting_storage">权限</string>
<string name="setting_off"></string>
<string name="setting_on"></string>
<!-- Search -->
<string name="search_keyword">关键字…</string>
@ -120,6 +125,11 @@
<item>IJK</item>
</string-array>
<string-array name="select_player_http">
<item>预设</item>
<item>OkHttp</item>
</string-array>
<string-array name="select_quality">
<item></item>
<item></item>

@ -61,6 +61,9 @@
<string name="setting_live">直播</string>
<string name="setting_wall">壁紙</string>
<string name="setting_player">播放器</string>
<string name="setting_player_ua">User Agent</string>
<string name="setting_player_tunnel">Tunnel Mode</string>
<string name="setting_player_http">Http Source</string>
<string name="setting_decode">解碼方式</string>
<string name="setting_render">渲染方式</string>
<string name="setting_scale">縮放比例</string>
@ -70,6 +73,8 @@
<string name="setting_cache">暫存</string>
<string name="setting_version">版本</string>
<string name="setting_storage">權限</string>
<string name="setting_off"></string>
<string name="setting_on"></string>
<!-- Search -->
<string name="search_keyword">關鍵字…</string>
@ -120,6 +125,11 @@
<item>IJK</item>
</string-array>
<string-array name="select_player_http">
<item>預設</item>
<item>OkHttp</item>
</string-array>
<string-array name="select_quality">
<item></item>
<item></item>

@ -61,6 +61,9 @@
<string name="setting_live">Live</string>
<string name="setting_wall">Wallpaper</string>
<string name="setting_player">Player</string>
<string name="setting_player_ua">User Agent</string>
<string name="setting_player_tunnel">Tunnel Mode</string>
<string name="setting_player_http">Http Source</string>
<string name="setting_decode">Decode</string>
<string name="setting_render">Render</string>
<string name="setting_scale">Scale</string>
@ -70,6 +73,8 @@
<string name="setting_cache">Cache</string>
<string name="setting_version">Version</string>
<string name="setting_storage">Permission</string>
<string name="setting_off">OFF</string>
<string name="setting_on">ON</string>
<!-- Search -->
<string name="search_keyword">Keywords…</string>
@ -120,6 +125,11 @@
<item>IJK</item>
</string-array>
<string-array name="select_player_http">
<item>Default</item>
<item>OkHttp</item>
</string-array>
<string-array name="select_render">
<item>Surface</item>
<item>Texture</item>

@ -14,6 +14,7 @@ import android.widget.MediaController;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -187,9 +188,11 @@ public class IjkVideoView extends FrameLayout implements MediaController.MediaPl
}
private void fixUserAgent(Map<String, String> headers) {
if (!headers.containsKey(Utils.USER_AGENT)) headers.put(Utils.USER_AGENT, Utils.CHROME);
mPlayer.setOption(format, "user_agent", headers.get(Utils.USER_AGENT));
headers.remove(Utils.USER_AGENT);
for (String key : Arrays.asList(Utils.USER_AGENT, Utils.USER_AGENT.toLowerCase())) {
if (!headers.containsKey(key)) continue;
mPlayer.setOption(format, "user_agent", headers.get(key));
headers.remove(key);
}
}
private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {

@ -1,29 +1,13 @@
package tv.danmaku.ijk.media.player.ui;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.DisplayMetrics;
public class Utils {
public static final String USER_AGENT = "User-Agent";
public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36";
public static float dp2px(Context context, float dpValue) {
return Math.round((dpValue * context.getResources().getDisplayMetrics().densityDpi) / DisplayMetrics.DENSITY_DEFAULT);
}
public static String getUserAgent(Context context) {
String versionName;
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
versionName = info.versionName;
} catch (PackageManager.NameNotFoundException e) {
versionName = "?";
}
return context.getPackageName() + "/" + versionName + " (Linux;Android " + Build.VERSION.RELEASE + ") " + "IjkPlayerLib/0.8.9";
}
}

Loading…
Cancel
Save