add media module
1
.idea/gradle.xml
generated
@@ -35,6 +35,7 @@
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-guide" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-main" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-map" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-media" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-search" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-service" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-share" />
|
||||
|
||||
@@ -156,7 +156,6 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.carcall
|
||||
implementation rootProject.ext.dependencies.guideshowprovider
|
||||
implementation rootProject.ext.dependencies.guideshow
|
||||
implementation rootProject.ext.dependencies.modulemedia
|
||||
|
||||
implementation rootProject.ext.dependencies.modulepush, {
|
||||
exclude group: 'com.mogo.module', module: 'module-common'
|
||||
@@ -180,6 +179,7 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.mogomoduleauth
|
||||
debugImplementation rootProject.ext.dependencies.gpssimulatordebug
|
||||
releaseImplementation rootProject.ext.dependencies.gpssimulatornoop
|
||||
implementation rootProject.ext.dependencies.modulemedia
|
||||
} else {
|
||||
launcherImplementation project(':main-extensions:mogo-module-main-launcher')
|
||||
independentImplementation project(':main-extensions:mogo-module-main-independent')
|
||||
@@ -189,6 +189,7 @@ dependencies {
|
||||
implementation project(':modules:mogo-module-back')
|
||||
implementation project(':modules:mogo-module-guide')
|
||||
implementation project(':modules:mogo-module-authorize')
|
||||
implementation project(':modules:mogo-module-media')
|
||||
debugImplementation project(':modules:mogo-module-gps-simulator-debug')
|
||||
releaseImplementation project(':modules:mogo-module-gps-simulator-noop')
|
||||
}
|
||||
|
||||
@@ -17,11 +17,6 @@
|
||||
tools:replace="android:value"
|
||||
android:name="com.amap.api.v2.apikey"
|
||||
android:value="40e2e7e773c7562b1f2b13699a93992c" />
|
||||
<provider
|
||||
android:name="com.mogo.module.navi.cp.AddressContentProvider"
|
||||
android:authorities="com.zhidao.auto.personal.provider"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.App"
|
||||
tools:replace="android:label">
|
||||
<provider
|
||||
<provide
|
||||
android:name="com.mogo.module.navi.cp.AddressContentProvider"
|
||||
android:authorities="com.zhidao.auto.personal.provider"
|
||||
android:enabled="true"
|
||||
|
||||
14
modules/mogo-module-media/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
68
modules/mogo-module-media/build.gradle
Normal file
@@ -0,0 +1,68 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode Integer.valueOf(VERSION_CODE)
|
||||
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [AROUTER_MODULE_NAME: project.getName()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
implementation rootProject.ext.dependencies.rxandroid
|
||||
implementation rootProject.ext.dependencies.guideshowprovider
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.androidxconstraintlayout
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
implementation rootProject.ext.dependencies.mogomap
|
||||
implementation rootProject.ext.dependencies.mogoutils
|
||||
implementation rootProject.ext.dependencies.mogocommons
|
||||
implementation rootProject.ext.dependencies.mogoserviceapi
|
||||
implementation rootProject.ext.dependencies.mogoservice
|
||||
implementation rootProject.ext.dependencies.moduleservice
|
||||
implementation rootProject.ext.dependencies.modulecommon
|
||||
implementation rootProject.ext.dependencies.mogomoduleauth
|
||||
} else {
|
||||
implementation project(":libraries:mogo-map")
|
||||
implementation project(":foudations:mogo-utils")
|
||||
implementation project(":foudations:mogo-commons")
|
||||
implementation project(':services:mogo-service-api')
|
||||
implementation project(':services:mogo-service')
|
||||
implementation project(':modules:mogo-module-common')
|
||||
implementation project(':modules:mogo-module-service')
|
||||
implementation project(':modules:mogo-module-authorize')
|
||||
}
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
0
modules/mogo-module-media/consumer-rules.pro
Normal file
3
modules/mogo-module-media/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.module
|
||||
POM_ARTIFACT_ID=module-media
|
||||
VERSION_CODE=1
|
||||
30
modules/mogo-module-media/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-dontwarn com.mogo.module.media.**
|
||||
-keep class com.mogo.module.media.listener.** { *; }
|
||||
-keep class com.mogo.module.media.model.** { *; }
|
||||
-keep class com.mogo.module.media.view.** { *; }
|
||||
-keep class com.mogo.module.media.widget.** { *; }
|
||||
-keep class com.mogo.module.media.api.** { *; }
|
||||
-keep class com.mogo.module.media.constants.** { *; }
|
||||
-keep class com.mogo.module.media.presenter.** { *; }
|
||||
-keep class com.mogo.module.media.receiver.** { *; }
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.module.media;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("com.mogo.module.media", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
22
modules/mogo-module-media/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.module.media">
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
|
||||
<uses-permission android:name="android.permission.TYPE_APPLICATION_OVERLAY" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application>
|
||||
<receiver android:name=".receiver.MediaSpeechReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.speech.adapter.send" />
|
||||
<action android:name="com.zhidao.speech.awake.notify" />
|
||||
<action android:name="com.zhidao.mediacenter.voiceltnews" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
BIN
modules/mogo-module-media/src/main/assets/images/img_0.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
modules/mogo-module-media/src/main/assets/images/img_1.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,95 @@
|
||||
package com.mogo.module.media;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.map.listener.IMogoMapListener;
|
||||
import com.mogo.map.location.IMogoLocationListener;
|
||||
import com.mogo.map.marker.IMogoMarkerClickListener;
|
||||
import com.mogo.map.navi.IMogoNaviListener;
|
||||
import com.mogo.service.module.IMogoModuleLifecycle;
|
||||
import com.mogo.service.module.IMogoModuleProvider;
|
||||
import com.mogo.service.module.ModuleType;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
@Route( path = MediaConstants.TAG )
|
||||
public class MediaCardViewProvider implements IMogoModuleProvider {
|
||||
|
||||
private static final String TAG = "MediaCardViewProvider";
|
||||
|
||||
private MediaWindow mMediaWindow;
|
||||
|
||||
|
||||
@Override
|
||||
public Fragment createFragment( Context context, Bundle data ) {
|
||||
// fragment = new MediaCardViewFragment();
|
||||
// fragment.setArguments( data );
|
||||
// Logger.i( TAG, "createFragment" );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init( Context context ) {
|
||||
ServiceMediaHandler.init( context );
|
||||
|
||||
mMediaWindow = new MediaWindow();
|
||||
mMediaWindow.initMedia(context);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
return MediaConstants.MODULE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createView( Context context ) {
|
||||
// don't
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return ModuleType.TYPE_CARD_FRAGMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMogoNaviListener getNaviListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IMogoModuleLifecycle getCardLifecycle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMogoMapListener getMapListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMogoLocationListener getLocationListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMogoMarkerClickListener getMarkerClickListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppPackage() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.mogo.module.media;
|
||||
|
||||
/**
|
||||
* 卡片类型 name
|
||||
*/
|
||||
public class MediaConstants {
|
||||
public static final String TAG = "/media/ui";
|
||||
public static final String MODULE_TYPE = "CARD_TYPE_SHARE_MUSIC";
|
||||
}
|
||||
@@ -0,0 +1,662 @@
|
||||
package com.mogo.module.media;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.mogo.map.marker.IMogoMarker;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
import com.mogo.module.common.entity.MarkerShowEntity;
|
||||
import com.mogo.module.media.constants.LeTingFieldConstants;
|
||||
import com.mogo.module.media.constants.QQMusicFieldConstants;
|
||||
import com.mogo.module.media.listener.NoDoubleClickListener;
|
||||
import com.mogo.module.media.model.LanRenInsertData;
|
||||
import com.mogo.module.media.model.LeTingNewsData;
|
||||
import com.mogo.module.media.model.MediaInfoData;
|
||||
import com.mogo.module.media.model.ShareLikeData;
|
||||
import com.mogo.module.media.presenter.MediaPresenter;
|
||||
import com.mogo.module.media.receiver.MediaSpeechReceiver;
|
||||
import com.mogo.module.media.utils.MusicControlBroadCast;
|
||||
import com.mogo.module.media.utils.StorageManager;
|
||||
import com.mogo.module.media.utils.Utils;
|
||||
import com.mogo.module.media.view.MediaView;
|
||||
import com.mogo.module.media.widget.AnimCircleImageView;
|
||||
import com.mogo.module.media.widget.NoScrollSeekBar;
|
||||
import com.mogo.module.media.widget.ScrollingTextView;
|
||||
import com.mogo.module.service.marker.MapMarkerManager;
|
||||
import com.mogo.utils.ActivityLifecycleManager;
|
||||
import com.mogo.utils.ThreadPoolService;
|
||||
import com.mogo.utils.UiThreadHandler;
|
||||
import com.mogo.utils.glide.GlideApp;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MediaWindow implements MediaView{
|
||||
|
||||
public static final String TAG = MediaWindow.class.getName();
|
||||
private Context mContext;
|
||||
private MediaPresenter mPresenter;
|
||||
|
||||
private MediaWindow.MediaStateReceiver mediaStateReceiver;
|
||||
private MediaWindow.MediaProcessReceiver mediaProcessReceiver;
|
||||
private MediaWindow.PlayingMusicReceiver playingMusicReceiver;
|
||||
private MediaWindow.MediaNewsPayInfo mediaNewsPayInfo;
|
||||
private MediaInfoData mMediaInfoData;
|
||||
|
||||
private View mWindowView;
|
||||
private AnimCircleImageView mCircleImg;
|
||||
private ScrollingTextView mScrollText;
|
||||
private ImageView mWindowPlayPause;
|
||||
private ImageView mWindowPlayNext;
|
||||
private LinearLayout mWindowMediaCenter;
|
||||
private TextView mWindowCurrTime;
|
||||
private TextView mWindowMaxTime;
|
||||
private NoScrollSeekBar mWindowProgress;
|
||||
|
||||
private boolean mHasAddWindow = false;
|
||||
private boolean mTwoChange = false;
|
||||
private boolean isFirstPlay = false;
|
||||
|
||||
private Runnable mRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MusicControlBroadCast.sendGetMusicPlayStateBroadcast();
|
||||
}
|
||||
};
|
||||
|
||||
public void initMedia(Context context){
|
||||
|
||||
mContext = context;
|
||||
mPresenter = new MediaPresenter(this);
|
||||
registerMediaReceiver();
|
||||
|
||||
MediaInfoData sMediaInfoData = MusicControlBroadCast.getHisMedia();
|
||||
mMediaInfoData = sMediaInfoData;
|
||||
|
||||
if (mMediaInfoData != null && !mHasAddWindow){
|
||||
addWindowView();
|
||||
}
|
||||
|
||||
//发送消息 如果在播放就会返回状态进行更新
|
||||
UiThreadHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MusicControlBroadCast.sendGetMusicPlayStateBroadcast();
|
||||
}
|
||||
},300);
|
||||
|
||||
isFirstPlay = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void addWindowView() {
|
||||
if (ServiceMediaHandler.getMogoWindowManager() == null){
|
||||
return ;
|
||||
}
|
||||
|
||||
if (!mHasAddWindow) {
|
||||
mHasAddWindow = true;
|
||||
mWindowView = LayoutInflater.from(mContext).inflate(R.layout.module_media_music_window_alert_layout, null);
|
||||
mWindowView.setVisibility(View.VISIBLE);
|
||||
mCircleImg = mWindowView.findViewById(R.id.window_circle_img);
|
||||
mScrollText = mWindowView.findViewById(R.id.window_scroll_txt);
|
||||
mWindowPlayPause = mWindowView.findViewById(R.id.window_play_pause);
|
||||
mWindowPlayNext = mWindowView.findViewById(R.id.window_music_next);
|
||||
mWindowMediaCenter = mWindowView.findViewById(R.id.window_media_center);
|
||||
mWindowCurrTime = mWindowView.findViewById(R.id.window_current_time);
|
||||
mWindowMaxTime = mWindowView.findViewById(R.id.window_max_time);
|
||||
mWindowProgress = mWindowView.findViewById(R.id.window_progress_bar);
|
||||
if (mWindowPlayPause != null){
|
||||
mWindowPlayPause.setImageResource(R.drawable.module_media_window_pop_pause);
|
||||
}
|
||||
int yPos = getContext().getResources().getDimensionPixelOffset(R.dimen.module_media_music_state_location);
|
||||
int xPos = getContext().getResources().getDimensionPixelOffset(R.dimen.module_media_music_state_location_x);
|
||||
ServiceMediaHandler.getMogoWindowManager().addView( mWindowView, xPos, yPos, false);
|
||||
updateWindowUI(true);
|
||||
mWindowMediaCenter.setOnClickListener(new NoDoubleClickListener() {
|
||||
@Override
|
||||
public void onClicks(View view) {
|
||||
if (mMediaInfoData != null) {
|
||||
MusicControlBroadCast.openMediaApp(mMediaInfoData.getType());
|
||||
} else {
|
||||
MusicControlBroadCast.openMediaApp(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mWindowPlayPause.setOnClickListener(new NoDoubleClickListener() {
|
||||
@Override
|
||||
public void onClicks(View view) {
|
||||
if (isFirstPlay){
|
||||
if (mMediaInfoData != null){
|
||||
MusicControlBroadCast.listeningSendData(mMediaInfoData);
|
||||
}
|
||||
}else{
|
||||
if (mMediaInfoData != null) {
|
||||
MusicControlBroadCast.commandPlayPause(mMediaInfoData.getType(),mMediaInfoData.getPlayState());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mWindowPlayNext.setOnClickListener(new NoDoubleClickListener() {
|
||||
@Override
|
||||
public void onClicks(View view) {
|
||||
if (mMediaInfoData != null) {
|
||||
MusicControlBroadCast.commandNext(mMediaInfoData.getType());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWindowUI(){
|
||||
updateWindowUI(false);
|
||||
}
|
||||
|
||||
private void updateWindowUI(boolean first) {
|
||||
if (mWindowView == null || mMediaInfoData == null){
|
||||
return;
|
||||
}
|
||||
if (mMediaInfoData != null) {
|
||||
if (mMediaInfoData.getType() == 1 || mMediaInfoData.getType() == 2 || mMediaInfoData.getType() == 3) {
|
||||
mWindowView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mWindowView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (mScrollText != null){
|
||||
mScrollText.setText(mMediaInfoData.getMediaName());
|
||||
}
|
||||
|
||||
if (first || mMediaInfoData.getPlayState() == 1 || mMediaInfoData.getPlayState() == 2) {
|
||||
if (mWindowMaxTime != null) mWindowMaxTime.setText(Utils.calculateTime((int) mMediaInfoData.getMaxTime()));
|
||||
if (mWindowCurrTime != null) mWindowCurrTime.setText(Utils.calculateTime((int) mMediaInfoData.getCurTime()));
|
||||
}
|
||||
|
||||
if (mCircleImg != null){
|
||||
com.bumptech.glide.request.RequestOptions options = new com.bumptech.glide.request.RequestOptions()
|
||||
.placeholder(R.drawable.module_media_share_default_icon);
|
||||
GlideApp.with(mContext).applyDefaultRequestOptions(options).load(mMediaInfoData.getMediaImg()).into(mCircleImg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showSharePush(boolean show) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNearShareMusicSuccess(List<MarkerShareMusic> list) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFriendShareMusicSuccess(List<MarkerShareMusic> list) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadShareLikeDataResultSuccess(ShareLikeData.ShareLikeDataResult likeDataResult, String mediaId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void likeShareSuccess() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shareSuccessResult(boolean success, MarkerShareMusic markerShareMusic) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
||||
private class PlayingMusicReceiver extends BroadcastReceiver{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
if (intent != null){
|
||||
String mediaStr = intent.getStringExtra("mediaData");
|
||||
if (!TextUtils.isEmpty(mediaStr)){
|
||||
MediaInfoData data = (MediaInfoData) GsonUtil.arrayFromJson(mediaStr, MediaInfoData.class);
|
||||
if (data != null){
|
||||
MusicControlBroadCast.listeningSendData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 音频播放状态改变广播监听
|
||||
*/
|
||||
private class MediaStateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
//用于请求点赞数
|
||||
boolean change = false;
|
||||
boolean cancleChoose = false;
|
||||
String ttMid = "";
|
||||
if (intent != null) {
|
||||
int type = intent.getIntExtra("type", -1);
|
||||
int playState = intent.getIntExtra(QQMusicFieldConstants.playState, 0);
|
||||
Logger.d("MediaStateReceiver", "===MediaStateReceiver==playState=="+playState+" type= "+type);
|
||||
if (playState == 1) {
|
||||
isFirstPlay = false;
|
||||
|
||||
if (mWindowPlayPause != null){
|
||||
mWindowPlayPause.setImageResource(R.drawable.module_media_window_pop_play);
|
||||
}
|
||||
|
||||
if (mCircleImg != null){
|
||||
mCircleImg.startAnim();
|
||||
}
|
||||
|
||||
/* if (ServiceMediaHandler.getGuideShowProviderManager().isPlayingVideo()){
|
||||
ServiceMediaHandler.getGuideShowProviderManager().closeGuideShowView();
|
||||
}*/
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (mWindowPlayPause != null){
|
||||
mWindowPlayPause.setImageResource(R.drawable.module_media_window_pop_pause);
|
||||
}
|
||||
|
||||
|
||||
if (mCircleImg != null) mCircleImg.stopAnim();
|
||||
|
||||
if (type == 1 || type == 2 || type ==3){
|
||||
UiThreadHandler.removeCallbacks(mRunnable);
|
||||
UiThreadHandler.postDelayed(mRunnable,3000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (playState == 1 || playState == 2){
|
||||
if (type == 1) {//qq音乐
|
||||
|
||||
int maxTime = intent.getIntExtra(QQMusicFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(QQMusicFieldConstants.curTime, 0);
|
||||
String mediaName = intent.getStringExtra(QQMusicFieldConstants.mediaName);
|
||||
String mediaUrl = intent.getStringExtra(QQMusicFieldConstants.mediaUrl);
|
||||
String mediaSinger = intent.getStringExtra(QQMusicFieldConstants.mediaSinger);
|
||||
String mediaImgUrl = intent.getStringExtra(QQMusicFieldConstants.mediaImgUrl);
|
||||
String mediaType = intent.getStringExtra(QQMusicFieldConstants.mediaType);
|
||||
String mediaMid = intent.getStringExtra(QQMusicFieldConstants.mediaMid);
|
||||
int mediaPLayMode = intent.getIntExtra(QQMusicFieldConstants.mediaPlayMode, -1);
|
||||
boolean isLocalMedia = intent.getBooleanExtra(QQMusicFieldConstants.isLocalMedia, false);
|
||||
|
||||
if (playState == 1 || playState == 2) {
|
||||
if (playState == 1){
|
||||
if (mMediaInfoData == null){
|
||||
change = true;
|
||||
ttMid = "";
|
||||
}else{
|
||||
ttMid = mMediaInfoData.getMediaId();
|
||||
}
|
||||
if (mMediaInfoData != null && mMediaInfoData.getMediaId() != null && !mMediaInfoData.getMediaId().equals(mediaMid)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mMediaInfoData == null) {
|
||||
mMediaInfoData = new MediaInfoData();
|
||||
}
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime * 1000);
|
||||
mMediaInfoData.setCurTime(curTime * 1000);
|
||||
mMediaInfoData.setMediaName(mediaName);
|
||||
mMediaInfoData.setMediaUrl(mediaUrl);
|
||||
mMediaInfoData.setMediaId(mediaMid);
|
||||
mMediaInfoData.setMediaImg(mediaImgUrl);
|
||||
mMediaInfoData.setMediaSinger(mediaSinger);
|
||||
mMediaInfoData.setMediaPlayMode(mediaPLayMode);
|
||||
mMediaInfoData.setLocalMedia(isLocalMedia);
|
||||
mMediaInfoData.setMediaType(mediaType);
|
||||
mMediaInfoData.setBookInfo("");
|
||||
|
||||
} else if (type == 2) {//懒人听书
|
||||
|
||||
int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
|
||||
|
||||
String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName);//章节数
|
||||
String bookInfoStr = intent.getStringExtra(LeTingFieldConstants.bookInfo);
|
||||
LanRenInsertData lanRenInsertData = GsonUtil.objectFromJson(bookInfoStr, LanRenInsertData.class);
|
||||
|
||||
String bookName = ""; // 书名 需要从bookinfo里面取
|
||||
String cover = ""; //封面 bookinfo中取
|
||||
String bookid = "";
|
||||
|
||||
try {
|
||||
if (lanRenInsertData != null){
|
||||
bookName = lanRenInsertData.getName(); // 书名 需要从bookinfo里面取
|
||||
cover = lanRenInsertData.getCover(); //封面 bookinfo中取
|
||||
bookid = lanRenInsertData.getBookId() + "";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
if (playState == 1 || playState == 2){
|
||||
if (playState == 1 || playState == 2){
|
||||
if (mMediaInfoData == null){
|
||||
change = true;
|
||||
ttMid = "";
|
||||
}else{
|
||||
ttMid = mMediaInfoData.getMediaId();
|
||||
}
|
||||
if (mMediaInfoData != null && mMediaInfoData.getMediaId() != null && !mMediaInfoData.getMediaId().equals(bookid)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mMediaInfoData == null) {
|
||||
mMediaInfoData = new MediaInfoData();
|
||||
}
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime);
|
||||
mMediaInfoData.setCurTime(curTime);
|
||||
if (!TextUtils.isEmpty(bookName)){
|
||||
mMediaInfoData.setMediaName(bookName); //bookName 或者mediaName
|
||||
}else if (!TextUtils.isEmpty(mediaName)){
|
||||
mMediaInfoData.setMediaName(mediaName); //bookName 或者mediaName
|
||||
}
|
||||
mMediaInfoData.setMediaSinger(mediaName); //章节数
|
||||
mMediaInfoData.setMediaImg(cover); //书籍封面
|
||||
mMediaInfoData.setMediaId(bookid);//书籍的bookid int
|
||||
mMediaInfoData.setBookInfo(bookInfoStr);
|
||||
mMediaInfoData.setMediaUrl("");
|
||||
mMediaInfoData.setLocalMedia(false);
|
||||
mMediaInfoData.setMediaType("");
|
||||
|
||||
} else if (type == 3) {//乐听头条
|
||||
int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
|
||||
String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName); //新闻title
|
||||
String artist = intent.getStringExtra(LeTingFieldConstants.artist); //新闻来源,赋值给singer mediaSinger
|
||||
String cover = intent.getStringExtra(LeTingFieldConstants.cover); //封面
|
||||
String bookInfo = intent.getStringExtra("news");//新闻实体
|
||||
String bookid = "";
|
||||
try {
|
||||
if (!TextUtils.isEmpty(bookInfo)){
|
||||
LeTingNewsData leTingNewsData = GsonUtil.objectFromJson(bookInfo, LeTingNewsData.class);
|
||||
if (leTingNewsData != null){
|
||||
mediaName = leTingNewsData.getTitle();
|
||||
artist = leTingNewsData.getSource();
|
||||
cover = leTingNewsData.getImage();
|
||||
bookid = leTingNewsData.getSid();
|
||||
}
|
||||
|
||||
if (mediaName == null) mediaName = "";
|
||||
if (artist == null) artist = "";
|
||||
if (cover == null) cover = "";
|
||||
if (bookid == null) bookid = "";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
if (playState == 1 || playState == 2){
|
||||
if (mMediaInfoData == null){
|
||||
change = true;
|
||||
ttMid = "";
|
||||
}else{
|
||||
ttMid = mMediaInfoData.getMediaId();
|
||||
}
|
||||
if (mMediaInfoData != null && mMediaInfoData.getMediaId() != null && !mMediaInfoData.getMediaId().equals(bookid)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime);
|
||||
mMediaInfoData.setCurTime(curTime);
|
||||
mMediaInfoData.setMediaName(mediaName); //新闻标题
|
||||
mMediaInfoData.setMediaSinger(artist); //新闻来源
|
||||
mMediaInfoData.setMediaImg(cover); //新闻封面
|
||||
|
||||
mMediaInfoData.setMediaId(bookid);//新闻的sid
|
||||
mMediaInfoData.setBookInfo(bookInfo);
|
||||
mMediaInfoData.setMediaUrl("");
|
||||
mMediaInfoData.setLocalMedia(false);
|
||||
mMediaInfoData.setMediaType("");
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
if (mMediaInfoData != null && (type == 1 || type == 2)){
|
||||
ThreadPoolService.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String tmData = GsonUtil.jsonFromObject(mMediaInfoData);
|
||||
StorageManager.setLastListenMediaMusic(tmData);
|
||||
Logger.d(TAG,"save"+tmData != null ? tmData:"");
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//播放另外一个时去掉选中状态
|
||||
if (!ttMid.equals(mMediaInfoData.getMediaId())){
|
||||
cancleChoose = true;
|
||||
}
|
||||
if (cancleChoose && mMediaInfoData != null && (playState == 1 || playState == 2)){
|
||||
if (ServiceMediaHandler.getMarkerManager() != null){
|
||||
List< IMogoMarker > mogoMarkersList = ServiceMediaHandler.getMarkerManager().getMarkers(MediaConstants.MODULE_TYPE);
|
||||
try {
|
||||
if ( mogoMarkersList != null && mogoMarkersList.size() > 0){
|
||||
for (IMogoMarker mogoMarker : mogoMarkersList){
|
||||
if (mogoMarker != null && !mogoMarker.isDestroyed()){
|
||||
if (mogoMarker.getObject() != null && mogoMarker.getObject() instanceof MarkerShowEntity){
|
||||
MarkerShowEntity markerShowEntity = (MarkerShowEntity) mogoMarker.getObject();
|
||||
if (markerShowEntity.getBindObj() != null && markerShowEntity.getBindObj() instanceof MarkerShareMusic){
|
||||
MarkerShareMusic markerShareMusic = (MarkerShareMusic) markerShowEntity.getBindObj();
|
||||
if (markerShowEntity.isChecked() && !markerShareMusic.getMediaId().equals(mMediaInfoData.getMediaId())){
|
||||
// MapMarkerManager.getInstance().closeMarkerSelect(mogoMarker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playState == 1 || playState == 2){
|
||||
if (mTwoChange){
|
||||
change = true;
|
||||
mTwoChange = false;
|
||||
}
|
||||
|
||||
|
||||
Logger.d(TAG,"onreceive state change = "+change+" mediaid= "+mMediaInfoData.getMediaId());
|
||||
// ifNeedRefreshMediaCard(change);
|
||||
}
|
||||
|
||||
//pop window 弹窗
|
||||
if (mMediaInfoData != null && !TextUtils.isEmpty(mMediaInfoData.getMediaName()) && !TextUtils.isEmpty(mMediaInfoData.getMediaSinger())){
|
||||
|
||||
if (!mHasAddWindow){
|
||||
addWindowView();
|
||||
}else{
|
||||
if (playState == 1 || playState == 2){
|
||||
updateWindowUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (playState == 1) {
|
||||
mPresenter.startedMusic(mMediaInfoData);
|
||||
} else {
|
||||
if (mMediaInfoData != null){
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
}
|
||||
mPresenter.stopMusic();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 音频进度改变广播接收者
|
||||
*/
|
||||
private class MediaProcessReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null) {
|
||||
int curTime = intent.getIntExtra("curTime", -1);
|
||||
Logger.d("MediaProcessReceiver", "===MediaProcessReceiver===="+curTime);
|
||||
UiThreadHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mMediaInfoData != null) {
|
||||
if (mWindowCurrTime != null) {
|
||||
mWindowCurrTime.setText(Utils.calculateTime(curTime));
|
||||
}
|
||||
try {
|
||||
int progress = (int) ((curTime * 1.0f * 100) / (mMediaInfoData.getMaxTime() * 1.0f));
|
||||
if (mWindowProgress != null) {
|
||||
mWindowProgress.setProgress(progress);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新闻是否付费
|
||||
* com.zhidao.mediacenter.ltnewsPayInfo
|
||||
*/
|
||||
private class MediaNewsPayInfo extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null) {
|
||||
boolean playinfo = intent.getBooleanExtra("payinfo", false);
|
||||
boolean appActive = ActivityLifecycleManager.getInstance().isAppActive();
|
||||
String category = MediaSpeechReceiver.mCategoryStr;
|
||||
MediaSpeechReceiver.mCategoryStr = "";
|
||||
Logger.d(TAG," MediaNewsPayInfo "+"news "+category == null?"":category+" "+appActive);
|
||||
if (playinfo){
|
||||
if (TextUtils.isEmpty(category)){
|
||||
//打开新闻
|
||||
//播放某一类型新闻
|
||||
if (appActive){
|
||||
MusicControlBroadCast.sendPlayTypeNews("推荐");
|
||||
}else{
|
||||
MusicControlBroadCast.sendPlayTypeNewsOpenApp("推荐");
|
||||
}
|
||||
}else{
|
||||
//播放某一类型新闻
|
||||
if (appActive){
|
||||
MusicControlBroadCast.sendPlayTypeNews(category);
|
||||
}else{
|
||||
MusicControlBroadCast.sendPlayTypeNewsOpenApp(category);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
MusicControlBroadCast.openMediaApp(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void registerMediaReceiver() {
|
||||
mediaStateReceiver = new MediaWindow.MediaStateReceiver();
|
||||
IntentFilter filterone = new IntentFilter();
|
||||
filterone.addAction("com.zhidao.action.MEDIA_LRTS");
|
||||
filterone.addAction("com.zhidao.action.MEDIA_LT_NEWS");
|
||||
filterone.addAction("com.qq.music.status.change");
|
||||
getContext().registerReceiver(mediaStateReceiver, filterone);
|
||||
|
||||
mediaProcessReceiver = new MediaWindow.MediaProcessReceiver();
|
||||
IntentFilter filtertwo = new IntentFilter();
|
||||
filtertwo.addAction("com.zhidao.action.MEDIA_PROGRESS");
|
||||
getContext().registerReceiver(mediaProcessReceiver, filtertwo);
|
||||
|
||||
playingMusicReceiver = new PlayingMusicReceiver();
|
||||
IntentFilter filterthree = new IntentFilter();
|
||||
filterthree.addAction("com.mogo.launcher.media.listening");
|
||||
getContext().registerReceiver(playingMusicReceiver, filterthree);
|
||||
|
||||
mediaNewsPayInfo = new MediaNewsPayInfo();
|
||||
IntentFilter filterFour = new IntentFilter();
|
||||
filterFour.addAction("com.zhidao.mediacenter.ltnewsPayInfo");
|
||||
getContext().registerReceiver(mediaNewsPayInfo, filterFour);
|
||||
|
||||
}
|
||||
|
||||
private void unRegisterMediaReceiver() {
|
||||
getContext().unregisterReceiver(mediaProcessReceiver);
|
||||
getContext().unregisterReceiver(mediaStateReceiver);
|
||||
getContext().unregisterReceiver(playingMusicReceiver);
|
||||
getContext().unregisterReceiver(mediaNewsPayInfo);
|
||||
}
|
||||
|
||||
private void destroy(){
|
||||
try {
|
||||
UiThreadHandler.removeCallbacks(mRunnable);
|
||||
mRunnable = null;
|
||||
unRegisterMediaReceiver();
|
||||
if (mCircleImg != null && mCircleImg.isRotationing()) {
|
||||
mCircleImg.stopAnim();
|
||||
}
|
||||
|
||||
if (ServiceMediaHandler.getMogoWindowManager() != null){
|
||||
ServiceMediaHandler.getMogoWindowManager().removeView(mWindowView);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.mogo.module.media;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.map.location.IMogoLocationClient;
|
||||
import com.mogo.map.marker.IMogoMarkerManager;
|
||||
import com.mogo.map.navi.IMogoNavi;
|
||||
import com.mogo.map.uicontroller.IMogoMapUIController;
|
||||
import com.mogo.module.authorize.authprovider.invoke.AuthorizeConstant;
|
||||
import com.mogo.module.authorize.authprovider.module.IMogoAuthorizeModuleManager;
|
||||
import com.mogo.module.guideshow.provider.GuideShowProviderConstant;
|
||||
import com.mogo.module.guideshow.provider.IGuideShowProvider;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.service.adas.IMogoADASController;
|
||||
import com.mogo.service.analytics.IMogoAnalytics;
|
||||
import com.mogo.service.cardmanager.IMogoCardManager;
|
||||
import com.mogo.service.datamanager.IMogoDataManager;
|
||||
import com.mogo.service.imageloader.IMogoImageloader;
|
||||
import com.mogo.service.impl.MogoServiceApis;
|
||||
import com.mogo.service.intent.IMogoIntentManager;
|
||||
import com.mogo.service.map.IMogoMapService;
|
||||
import com.mogo.service.module.IMogoActionManager;
|
||||
import com.mogo.service.module.IMogoMarkerService;
|
||||
import com.mogo.service.module.IMogoRegisterCenter;
|
||||
import com.mogo.service.network.IMogoNetwork;
|
||||
import com.mogo.service.statusmanager.IMogoStatusManager;
|
||||
import com.mogo.service.windowview.IMogoWindowManager;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 持有服务接口实例
|
||||
*/
|
||||
public class ServiceMediaHandler {
|
||||
|
||||
private static MogoServiceApis mApis;
|
||||
private static IMogoMapService mMapService;
|
||||
private static IMogoLocationClient mLocationClient;
|
||||
private static IMogoMarkerManager mMarkerManager;
|
||||
private static IMogoMapUIController mMapUIController;
|
||||
private static IMogoImageloader mImageloader;
|
||||
private static IMogoNetwork mMogoNetWorkService;
|
||||
private static IMogoWindowManager mMogoWindowManager;
|
||||
private static IMogoCardManager mMogoCardManager;
|
||||
private static IMogoAnalytics mMogoAnalytis;
|
||||
private static IMogoRegisterCenter mMogoRegisterCenter;
|
||||
private static IMogoIntentManager mMogoVoiceManager;
|
||||
private static IMogoStatusManager mIMogoStatusManager;
|
||||
private static IMogoNavi mMogoNavi;
|
||||
private static IMogoDataManager mMogoDataManager;
|
||||
private static IMogoActionManager mMogoActionManager;
|
||||
private static IMogoADASController mMogoADASController;
|
||||
private static IMogoAuthorizeModuleManager mMogoAuthorizeModuleManager;
|
||||
private static IGuideShowProvider mGuideShowProviderManager;
|
||||
private static IMogoMarkerService sMarkerService;
|
||||
|
||||
public static void init(Context context) {
|
||||
mApis = (MogoServiceApis) ARouter.getInstance().build(MogoServicePaths.PATH_SERVICE_APIS).navigation(context);
|
||||
mMapService = mApis.getMapServiceApi();
|
||||
mImageloader = mApis.getImageLoaderApi();
|
||||
mLocationClient = mMapService.getLocationClient(context);
|
||||
mMarkerManager = mMapService.getMarkerManager(context);
|
||||
mMapUIController = mMapService.getMapUIController();//zoomTo
|
||||
mMogoNetWorkService = mApis.getNetworkApi();
|
||||
mMogoWindowManager = mApis.getWindowManagerApi();
|
||||
mMogoCardManager = mApis.getCardManagerApi();
|
||||
mMogoAnalytis = mApis.getAnalyticsApi();
|
||||
mMogoRegisterCenter = mApis.getRegisterCenterApi();
|
||||
mMogoVoiceManager = mApis.getIntentManagerApi();
|
||||
mIMogoStatusManager = mApis.getStatusManagerApi();
|
||||
mMogoNavi = mMapService.getNavi( context );
|
||||
mMogoDataManager = mApis.getDataManagerApi();
|
||||
mMogoActionManager = mApis.getActionManagerApi();
|
||||
mMogoADASController = mApis.getAdasControllerApi();
|
||||
mMogoAuthorizeModuleManager = (IMogoAuthorizeModuleManager) ARouter.getInstance().build(AuthorizeConstant.PROVIDER_MODULE).navigation(context);
|
||||
mGuideShowProviderManager = (IGuideShowProvider) ARouter.getInstance().build(GuideShowProviderConstant.GUIDE_SHOW_PROVIDER).navigation(context);
|
||||
sMarkerService = mApis.getMarkerService();
|
||||
}
|
||||
|
||||
public static IMogoADASController getMogoADASController(){
|
||||
isApisNull(mMogoADASController);
|
||||
return mMogoADASController;
|
||||
}
|
||||
|
||||
public static IMogoMapService getMapService() {
|
||||
isApisNull(mMapService);
|
||||
return mMapService;
|
||||
}
|
||||
|
||||
public static IMogoLocationClient getLocationClient() {
|
||||
isApisNull(mLocationClient);
|
||||
return mLocationClient;
|
||||
}
|
||||
|
||||
public static IMogoMarkerManager getMarkerManager() {
|
||||
isApisNull(mMarkerManager);
|
||||
return mMarkerManager;
|
||||
}
|
||||
|
||||
public static IMogoMapUIController getMapUIController() {
|
||||
isApisNull(mMapUIController);
|
||||
return mMapUIController;
|
||||
}
|
||||
|
||||
public static IMogoImageloader getImageloader() {
|
||||
isApisNull(mImageloader);
|
||||
return mImageloader;
|
||||
}
|
||||
|
||||
public static IMogoNetwork getMogoNetWorkService(){
|
||||
isApisNull(mMogoNetWorkService);
|
||||
return mMogoNetWorkService;
|
||||
}
|
||||
|
||||
public static IMogoWindowManager getMogoWindowManager() {
|
||||
isApisNull(mMogoWindowManager);
|
||||
return mMogoWindowManager;
|
||||
}
|
||||
|
||||
public static IMogoCardManager getMogoCardManager() {
|
||||
isApisNull(mMogoCardManager);
|
||||
return mMogoCardManager;
|
||||
}
|
||||
|
||||
public static IMogoAnalytics getMogoAnalytis() {
|
||||
isApisNull(mMogoAnalytis);
|
||||
return mMogoAnalytis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1 2 3 dev qa release
|
||||
* @return
|
||||
*/
|
||||
public static int getCurrentEvent(){
|
||||
return DebugConfig.getNetMode();
|
||||
}
|
||||
|
||||
public static IMogoRegisterCenter getMogoRegisterCenter(){
|
||||
isApisNull(mMogoRegisterCenter);
|
||||
return mMogoRegisterCenter;
|
||||
}
|
||||
|
||||
public static IMogoIntentManager getMogoVoiceManager(){
|
||||
isApisNull(mMogoVoiceManager);
|
||||
return mMogoVoiceManager;
|
||||
}
|
||||
|
||||
public static IMogoStatusManager getIMogoStatusManager(){
|
||||
isApisNull(mIMogoStatusManager);
|
||||
return mIMogoStatusManager;
|
||||
}
|
||||
|
||||
public static IMogoNavi getMogoNavi(){
|
||||
isApisNull(mMogoNavi);
|
||||
return mMogoNavi;}
|
||||
|
||||
public static IMogoDataManager getMogoDataManager(){
|
||||
isApisNull(mMogoDataManager);
|
||||
return mMogoDataManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个注册的第一个参数是模块名称,目的是只给当前显示的卡片分发事件
|
||||
* @return
|
||||
*/
|
||||
public static IMogoActionManager getMogoctionManager(){
|
||||
isApisNull(mMogoActionManager);
|
||||
return mMogoActionManager;
|
||||
}
|
||||
|
||||
public static IMogoAuthorizeModuleManager getMogoAuthorizeModuleManager(){
|
||||
isApisNull(mMogoAuthorizeModuleManager);
|
||||
return mMogoAuthorizeModuleManager;
|
||||
}
|
||||
|
||||
public static IGuideShowProvider getGuideShowProviderManager(){
|
||||
isApisNull(mGuideShowProviderManager);
|
||||
return mGuideShowProviderManager;
|
||||
}
|
||||
|
||||
public static boolean isObjStaticNull(Object object){
|
||||
if (mApis == null || object == null){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IMogoMarkerService getMarkerService() {
|
||||
isApisNull(sMarkerService);
|
||||
return sMarkerService;
|
||||
}
|
||||
|
||||
public static void isApisNull( Object object){
|
||||
if (isObjStaticNull(object)){
|
||||
init(AbsMogoApplication.getApp());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.mogo.module.media.api;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
import com.mogo.module.common.entity.MarkerResponse;
|
||||
import com.mogo.module.media.model.ShareLikeData;
|
||||
import com.mogo.module.media.model.ShareMediaMarkerInfoData;
|
||||
import com.mogo.module.media.model.ShareSuccessResult;
|
||||
import com.mogo.module.media.model.ShowShareData;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import okhttp3.RequestBody;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.FieldMap;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Header;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.QueryMap;
|
||||
import retrofit2.http.Url;
|
||||
|
||||
public interface MediaDztService {
|
||||
|
||||
/**
|
||||
* 查询音频分享信息
|
||||
*/
|
||||
@GET("/sunflower/os/music/car/v1/selectByPrimaryKey")
|
||||
Observable<ShareLikeData> selectByPrimaryKey(@QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 分享音乐
|
||||
*/
|
||||
@Headers({"Content-type:application/json;charset=UTF-8"})
|
||||
@POST
|
||||
Observable<ShareSuccessResult> shareMusic(@Url String url, @Body RequestBody body);
|
||||
|
||||
/**
|
||||
* 好友分享的歌
|
||||
*/
|
||||
@GET("/sunflower/os/music/car/v1/getFriendsMusic")
|
||||
Observable<ShareMediaMarkerInfoData> getFriendShareMusic(@QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 是否需要触发分享
|
||||
*/
|
||||
@GET("/sunflower/os/music/car/v1/checkShare")
|
||||
Observable<ShowShareData> getShouldPushShare(@QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 开始音乐
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("/yycp-launcherSnapshot/mediaShare/mediaStart")
|
||||
Observable<BaseData> startedMusic(@FieldMap Map<String, Object> params );
|
||||
|
||||
/**
|
||||
* 停止音乐
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("/yycp-launcherSnapshot/mediaShare/mediaPause")
|
||||
Observable<BaseData> stopMusic(@FieldMap Map<String, Object> params );
|
||||
|
||||
/**
|
||||
* 点赞分享
|
||||
*/
|
||||
@Headers({"Content-type:application/json;charset=UTF-8"})
|
||||
@POST
|
||||
Observable<BaseData> likeShare(@Url String url, @Body RequestBody body);
|
||||
|
||||
/**
|
||||
* 获取附近分享的歌,传入一个type,单独拉取模块的markerdata
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("/yycp-launcherSnapshot/launcherSnapshot/querySnapshotSync")
|
||||
Observable<MarkerResponse> getNearShareMusic(@FieldMap Map<String, Object> params );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface BaseUrlConstants {
|
||||
String DEV_BASE_URL = "http://dzt-dev.zhidaohulian.com";
|
||||
String QA_BASE_URL = "http://dzt-test.zhidaohulian.com";
|
||||
String SHOW_BASE_URL = "http://dzt-show.zhidaohulian.com";
|
||||
String RELEASE_BASE_URL = "http://dzt.zhidaohulian.com";
|
||||
|
||||
|
||||
String SHARE_MUSIC_URL = "/sunflower/os/music/car/v1/osMusiceShare";
|
||||
String SHARE_MUSIC_LIKE_URL = "/sunflower/os/music/car/v1/likedShareMusic";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
int ONE_KB = 1024;
|
||||
int ONE_MB = ONE_KB * 1024;
|
||||
|
||||
int SIZE_DEFAULT = 2048;
|
||||
int SIZE_LIMIT = 2048;
|
||||
|
||||
String IMAGE_COMPRESS_PATH = "image/compress/";
|
||||
|
||||
//storage
|
||||
String SHOW_SHARE_PUSH_TIME = "show_share_push_time";
|
||||
//his music
|
||||
String LAST_TIME_LISTEN_MEDIA_MUSIC = "last_time_listen_media_music";
|
||||
String MEDIA_UNIQUE_NAME = "media_unique_name";
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface EventConstants {
|
||||
String EVENT_QQ_OPEN_SHARE_DIALOG_SHOW = "card_QQMusic_pop";//打开分享弹窗 type 1、click,2、小智语音
|
||||
String EVENT_QQ_SHARE_DIALOG_OK = "card_QQMusic_affirm";//弹窗内选择“确认”
|
||||
String EVENT_QQ_SHARE_DIALOG_CANCLE = "card_QQMusic_close";//弹窗内选择“取消”
|
||||
String EVENT_QQ_MUSIC_START = "QQMusicBegin";// 音乐开始 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_QQ_MUSIC_PAUSE = "QQMusicSuspend";// 音乐暂停 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_QQ_LAST_PLAY = "QQMusicTheLast";//qq音乐上一章 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_QQ_Next_PLAY = "QQMusicNext";//qq音乐下一章 type 1、click,2、小智语音,3、卡片
|
||||
|
||||
String EVENT_BOOK_OPEN_SHARE_DIALOG_SHOW = "card_Book_pop";//打开分享弹窗 type 1、click,2、小智语音
|
||||
String EVENT_BOOK_SHARE_DIALOG_OK = "card_Book_affirm";//弹窗内选择“确认”
|
||||
String EVENT_BOOK_SHARE_DIALOG_CANCLE = "card_Book_close";//弹窗内选择“取消”
|
||||
String EVENT_BOOK_MUSIC_START = "BookBegin";// 书开始 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_BOOK_MUSIC_PAUSE = "BookSuspend";// 书暂停 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_BOOK_LAST_PLAY = "BookTheLast";//懒人听书上一章 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_BOOK_Next_PLAY = "BookNext";//懒人听书下一章 type 1、click,2、小智语音,3、卡片
|
||||
|
||||
String EVENT_NEWS_OPEN_SHARE_DIALOG_SHOW = "card_News_pop";//打开分享弹窗 type 1、click,2、小智语音
|
||||
String EVENT_NEWS_SHARE_DIALOG_OK = "card_News_affirm";//弹窗内选择“确认”
|
||||
String EVENT_NEWS_SHARE_DIALOG_CANCLE = "card_News_close";//弹窗内选择“取消”
|
||||
String EVENT_NEWS_MUSIC_START = "NewsBegin";// 新闻开始 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_NEWS_MUSIC_PAUSE = "NewsSuspend";// 新闻暂停 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_NEWS_LAST_PLAY = "NewsTheLast";//新闻上一章 type 1、click,2、小智语音,3、卡片
|
||||
String EVENT_NEWS_Next_PLAY = "NewsNext";//新闻下一章 type 1、click,2、小智语音,3、卡片
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface LeTingFieldConstants {
|
||||
String curTime = "curTime";//当前播放时长
|
||||
String maxTime = "maxTime";//书籍总时长
|
||||
String type = "type";//2 为书籍听书,3 为新闻 1 qq音乐
|
||||
String mediaName = "mediaName";//新书标题,新闻标题
|
||||
String artist = "artist";//新书来源,新闻来源
|
||||
String cover = "cover";//作者封面,封面
|
||||
String bookName = "bookName";//书籍名
|
||||
String playState = "playState";//1 播放 2 缓冲 0 暂停/停止 -1 播放错误
|
||||
String bookInfo = "bookInfo";//书本实例
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface QQMusicFieldConstants {
|
||||
String curTime = "curTime";//当前播放时长
|
||||
String maxTime = "maxTime";//书籍总时长
|
||||
String type = "type";//2 为书籍听书,3 为新闻,1 为qq音乐
|
||||
String mediaName = "mediaName";//歌曲名
|
||||
String playState = "playState";//1 播放 2 缓冲 0 暂停/停止 -1 播放错误
|
||||
String mediaUrl = "mediaUrl";//音乐url
|
||||
String mediaSinger = "mediaSinger";//歌手名
|
||||
String mediaImgUrl = "mediaImgUrl";//封面
|
||||
String mediaType = "mediaType";//歌曲类别
|
||||
String mediaMid = "mediaMid";//song mid
|
||||
String isLocalMedia = "isLocalMedia";//是否是本地歌曲
|
||||
String mediaPlayMode = "mediaPlayMode";//播放模式
|
||||
String mediaAlbumName = "mediaAlbumName";//专辑名
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.mogo.module.media.constants;
|
||||
|
||||
public interface VoiceConstants {
|
||||
String SHARE_QQ_MUSIC = "确认分享该歌曲,你可对我说确认或取消";
|
||||
String SHARE_LANREN_MUSIC = "确认分享本书,你可对我说确认或取消";
|
||||
String SHARE_LETINGNES_MUSIC = "确认分享新闻,你可对我说确认或取消";
|
||||
String COMMAND_SHARE_MUSIC_PUSH_MESSAGE ="可把歌曲,书籍,新闻分享给附近的车友,语音回复分享即可分享";
|
||||
String[] COMMAND_SHARE_MUSIC_PUSH_MESSAGE_OK = {"分享"};
|
||||
String[] COMMAND_SHARE_MUSIC_PUSH_MESSAGE_CANCEL = { "不分享"};
|
||||
|
||||
String[] COMMAND_NO_WAKEUP_MUSIC_SHARE = {"分享歌曲","分享音乐","分享这首歌","帮我分享一下这个歌","把这首歌分享一下"};
|
||||
String COMMAND_NO_WAKEUP_SHARE_MUSIC_CMD = "media_card_music_no_wake_share";
|
||||
|
||||
String[] COMMAND_NO_WAKEUP_BOOK_SHARE = {"分享书","分享这本书","帮我分享一下这本书","把这本书分享一下"};
|
||||
String COMMAND_NO_WAKEUP_SHARE_BOOK_CMD = "media_card_book_no_wake_share";
|
||||
|
||||
String[] COMMAND_NO_WAKEUP_NEWS_SHARE = {"分享新闻","分享这条新闻","把这条新闻分享一下","帮我分享一下这条新闻"};
|
||||
String COMMAND_NO_WAKEUP_SHARE_NEWS_CMD = "media_card_news_no_wake_share";
|
||||
|
||||
String[] COMMAND_NO_WAKEUP_BOOK_MUSIC_SHARE = {"分享"};
|
||||
String COMMAND_NO_WAKEUP_SHARE_BOOK_MUSIC_CMD = "media_card_book_music_no_wake_share";
|
||||
|
||||
String[] COMMAND_SHARE_MUSIC_OK = {"确认", "是","分享"};
|
||||
String[] COMMAND_NO_SHARE_MUSIC_CANCEL = {"取消", "不分享"};
|
||||
|
||||
String[] COMMAND_OPEN_MUSIC = {"**打开**音乐**","打开音乐","帮我打开一下音乐好不好","打开一下音乐好不好","帮我打开音乐","打开音乐谢谢"};
|
||||
String COMMAND_OPEN_MUSIC_CMD = "media_card_open_music";
|
||||
|
||||
String[] COMMAND_CLOSE_MUSIC = {"**关闭**音乐**","关闭音乐","退出音乐","帮我关闭一下音乐好不好","关闭一下音乐好不好","帮我关闭音乐","关闭那个音乐","关闭音乐谢谢"};
|
||||
String COMMAND_CLOSE_MUSIC_CMD = "media_card_close_music";
|
||||
|
||||
String[] COMMAND_NEAR_MUSIC = {"附近的歌","附近的人听的歌","附近的人听的音乐","周围的人听的歌","周围的人听的音乐"};
|
||||
String COMMAND_NEAR_MUSIC_CMD = "media_card_near_music";
|
||||
|
||||
String[] COMMAND_FRIEND_MUSIC = {"好友听的歌","好友听的音乐","播放好友的歌","放好友的歌","听好友的歌","播放好友的音乐","放好友的音乐","听好友的音乐"};
|
||||
String COMMAND_FRIEND_MUSIC_CMD = "media_card_friend_music";
|
||||
|
||||
String[] COMMAND_QUERY_MUSIC_NAME = {"这歌是什么","这歌叫啥","这首歌叫什么名字","歌名是什么","这首歌的名字","这首音乐叫什么","这个歌是啥"};
|
||||
String COMMAND_QUERY_MUSIC_NAME_CMD = "media_card_query_music_name";
|
||||
|
||||
String[] COMMAND_QUERY_MUSIC_SINGER = {"这首歌是谁唱的","这歌谁唱的","这首歌的歌手","这首歌的歌手是谁","查一下这首歌的歌手"};
|
||||
String COMMAND_QUERY_MUSIC_SINGERME_CMD = "media_card_query_music_singer";
|
||||
|
||||
String[] COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE = {"关闭","取消","关闭分享","取消分享","关闭弹窗","取消弹窗","不分享"};
|
||||
String COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE_COMMAND = "share_dialog_timeout_close_command";
|
||||
|
||||
String[] COMMAND_SHARE_DIALOG_TIMEOUT_OK = {"确认","确定","分享","确认分享","确定分享"};
|
||||
String COMMAND_SHARE_DIALOG_TIMEOUT_OK_COMMAND = "share_dialog_timeout_confirm_command";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.mogo.module.media.dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.mogo.utils.TipToast;
|
||||
|
||||
|
||||
public abstract class BaseDialogFragment extends DialogFragment {
|
||||
protected Bundle mBundle;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mBundle = savedInstanceState == null ? getArguments() : savedInstanceState;
|
||||
if (mBundle == null) {
|
||||
mBundle = new Bundle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if (mBundle != null) {
|
||||
outState.putAll(mBundle);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
public void openActivity(Class<? extends Activity> cls) {
|
||||
openActivity(cls, null);
|
||||
}
|
||||
|
||||
public void openActivity(Class<? extends Activity> cls, Bundle bundle) {
|
||||
Intent intent = new Intent();
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
intent.setClass(getActivity(), cls);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public void openActivity(String url, Bundle bundle) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public void openActivityForResult(Class<? extends Activity> cls, Bundle bundle, int requestCode) {
|
||||
Intent intent = new Intent();
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
intent.setClass(getActivity(), cls);
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
public void backForResult(int resultCode, Bundle bundle) {
|
||||
Intent intent = new Intent();
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
getActivity().setResult(resultCode, intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
public void backToActivity(Class<? extends Activity> cls, Bundle bundle) {
|
||||
Intent intent = new Intent();
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
intent.setClass(getActivity(), cls);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return super.getContext();
|
||||
}
|
||||
|
||||
public boolean isVisibleToUser() {
|
||||
return isResumed();
|
||||
}
|
||||
|
||||
|
||||
public void showToast(CharSequence toast) {
|
||||
TipToast.shortTip(toast.toString());
|
||||
}
|
||||
public void showInputMethod(View view) {
|
||||
if (getContext() == null) return;
|
||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) {
|
||||
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
|
||||
public void hideInputMethod(View view) {
|
||||
if (getContext() == null) return;
|
||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) {
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.mogo.module.media.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.mogo.module.media.R;
|
||||
|
||||
public class CustomDialog extends Dialog {
|
||||
TextView txtOk;
|
||||
TextView txtCancel;
|
||||
TextView txtTitle;
|
||||
TextView txtContent;
|
||||
TextView txtSubContent;
|
||||
|
||||
private int mContentSize = 0;
|
||||
private int mContentColor = 0;
|
||||
private int mBtnSize = 0;
|
||||
|
||||
private int mSubContentSize = 0;
|
||||
private int mContentLeftPadding = 0;
|
||||
|
||||
private View.OnClickListener onOkListener, onCancelListener;
|
||||
|
||||
private String title, subContent, okText, cancelText;
|
||||
private CharSequence content;
|
||||
private boolean isAutoDismissDialog = true;
|
||||
|
||||
private int contentGravity = Gravity.CENTER;
|
||||
private int subContentGravity = Gravity.LEFT;
|
||||
|
||||
private boolean isContentClickSpanEnable = false;
|
||||
|
||||
public CustomDialog(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.module_media_dialog_cutom_layout);
|
||||
|
||||
initView();
|
||||
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
txtTitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
txtTitle.setText(title);
|
||||
txtTitle.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (mContentSize > 0){
|
||||
txtContent.setTextSize(TypedValue.COMPLEX_UNIT_PX,mContentSize);
|
||||
}
|
||||
|
||||
if (mSubContentSize > 0){
|
||||
txtSubContent.setTextSize(TypedValue.COMPLEX_UNIT_PX,mSubContentSize);
|
||||
}
|
||||
|
||||
if (mContentColor > 0){
|
||||
txtContent.setTextColor(mContentColor);
|
||||
}
|
||||
|
||||
if (mContentLeftPadding > 0){
|
||||
txtContent.setPadding(mContentLeftPadding,0,mContentLeftPadding,0);
|
||||
}
|
||||
|
||||
if ( content instanceof String) {
|
||||
content = ( (String) content ).replace( "\\n", "\n" );
|
||||
}
|
||||
|
||||
txtContent.setText(content);
|
||||
if (TextUtils.isEmpty(subContent)) {
|
||||
txtSubContent.setVisibility(View.GONE);
|
||||
} else {
|
||||
txtSubContent.setVisibility(View.VISIBLE);
|
||||
txtSubContent.setText(subContent);
|
||||
}
|
||||
|
||||
txtSubContent.setGravity(subContentGravity);
|
||||
|
||||
if (mBtnSize > 0){
|
||||
txtOk.setTextSize(TypedValue.COMPLEX_UNIT_PX,mBtnSize);
|
||||
txtCancel.setTextSize(TypedValue.COMPLEX_UNIT_PX,mBtnSize);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(okText)) {
|
||||
txtOk.setVisibility(View.VISIBLE);
|
||||
txtOk.setText(okText);
|
||||
} else {
|
||||
txtOk.setVisibility(View.GONE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(cancelText)) {
|
||||
txtCancel.setVisibility(View.VISIBLE);
|
||||
txtCancel.setText(cancelText);
|
||||
} else {
|
||||
txtCancel.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
txtOk.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (isAutoDismissDialog) {
|
||||
dismiss();
|
||||
}
|
||||
if (onOkListener != null) {
|
||||
onOkListener.onClick(v);
|
||||
}
|
||||
}
|
||||
});
|
||||
txtCancel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (isAutoDismissDialog) {
|
||||
dismiss();
|
||||
}
|
||||
if (onCancelListener != null) {
|
||||
onCancelListener.onClick(v);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
txtContent.setGravity( contentGravity );
|
||||
|
||||
if ( isContentClickSpanEnable ) {
|
||||
txtContent.setMovementMethod( LinkMovementMethod.getInstance() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
txtOk = findViewById(R.id.txt_ok);
|
||||
txtCancel = findViewById(R.id.txt_cancel);
|
||||
txtTitle = findViewById(R.id.txt_title);
|
||||
txtContent = findViewById(R.id.txt_content);
|
||||
txtSubContent = findViewById(R.id.txt_sub_content);
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setContent(CharSequence content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public void setSubContent(String subContent) {
|
||||
this.subContent = subContent;
|
||||
}
|
||||
|
||||
public void setContentGravity(int gravity) {
|
||||
contentGravity = gravity;
|
||||
}
|
||||
|
||||
public void hiddenBtnCancel() {
|
||||
txtCancel.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setOnOkClickListener(String okText, View.OnClickListener onOkClickListener) {
|
||||
this.okText = okText;
|
||||
this.onOkListener = onOkClickListener;
|
||||
}
|
||||
|
||||
public void setOnOkClickListener(View.OnClickListener onOkClickListener) {
|
||||
setOnOkClickListener("确定", onOkClickListener);
|
||||
}
|
||||
|
||||
public void setOnCancelListener(String cancelText, View.OnClickListener onCancelListener) {
|
||||
this.cancelText = cancelText;
|
||||
this.onCancelListener = onCancelListener;
|
||||
}
|
||||
|
||||
public void setOnCancelListener(View.OnClickListener onCancelListener) {
|
||||
setOnCancelListener("取消", onCancelListener);
|
||||
}
|
||||
|
||||
public void setAutoDismissDialog(boolean autoDismissDialog) {
|
||||
isAutoDismissDialog = autoDismissDialog;
|
||||
}
|
||||
|
||||
public void setBtnTextSize(int size){
|
||||
mBtnSize = size;
|
||||
}
|
||||
|
||||
public void setContentTextSize(int size){
|
||||
mContentSize = size;
|
||||
}
|
||||
|
||||
public void setSubContentTextSize(int size){
|
||||
mSubContentSize = size;
|
||||
}
|
||||
|
||||
public void setContentColor(int color){
|
||||
mContentColor = color;
|
||||
}
|
||||
|
||||
public int getContentGravity() {
|
||||
return contentGravity;
|
||||
}
|
||||
|
||||
public int getSubContentGravity() {
|
||||
return subContentGravity;
|
||||
}
|
||||
|
||||
public void setSubContentGravity(int subContentGravity) {
|
||||
this.subContentGravity = subContentGravity;
|
||||
}
|
||||
|
||||
public void setContentClickSpanEnable(boolean contentClickSpanEnable ) {
|
||||
isContentClickSpanEnable = contentClickSpanEnable;
|
||||
}
|
||||
|
||||
public int getContentLeftPadding() {
|
||||
return mContentLeftPadding;
|
||||
}
|
||||
|
||||
public void setContentLeftPadding(int mContentLeftPadding) {
|
||||
this.mContentLeftPadding = mContentLeftPadding;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,445 @@
|
||||
package com.mogo.module.media.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.commons.network.ParamsProvider;
|
||||
import com.mogo.commons.network.ParamsUtil;
|
||||
import com.mogo.commons.network.SubscribeImpl;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
|
||||
import com.mogo.map.location.MogoLocation;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
import com.mogo.module.media.MediaConstants;
|
||||
import com.mogo.module.media.R;
|
||||
import com.mogo.module.media.ServiceMediaHandler;
|
||||
import com.mogo.module.media.api.MediaDztService;
|
||||
import com.mogo.module.media.constants.BaseUrlConstants;
|
||||
import com.mogo.module.media.constants.EventConstants;
|
||||
import com.mogo.module.media.constants.VoiceConstants;
|
||||
import com.mogo.module.media.listener.MogoVoiceCmdCallBackImp;
|
||||
import com.mogo.module.media.model.MediaInfoData;
|
||||
import com.mogo.module.media.model.ShareSuccessResult;
|
||||
import com.mogo.module.media.utils.BaseUrlManager;
|
||||
import com.mogo.module.media.utils.MediaAnalyticsUtils;
|
||||
import com.mogo.module.media.utils.ToastHelper;
|
||||
import com.mogo.module.media.widget.RoundedImageView;
|
||||
import com.mogo.utils.TipToast;
|
||||
import com.mogo.utils.glide.GlideApp;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.RequestOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* media 分享dialog
|
||||
*/
|
||||
public class MediaShareDialogFragment extends BaseDialogFragment {
|
||||
|
||||
private Disposable mDisposable;
|
||||
private Context context;
|
||||
private Callback callback;
|
||||
private RoundedImageView mMediaImg;
|
||||
private TextView mMediaName;
|
||||
private TextView mMediaSinger;
|
||||
private TextView mOk;
|
||||
private TextView mCancel;
|
||||
private TextView mDialogContent;
|
||||
private MediaInfoData mMediaInfoData;
|
||||
private VoiceCallBack voiceCallBack = new VoiceCallBack();
|
||||
private boolean shareSuccess = false;
|
||||
private MarkerShareMusic markerShareMusic;
|
||||
private boolean navi = false;
|
||||
private ShareOkReceiver mShareOkReceiver;
|
||||
|
||||
public interface Callback {
|
||||
void onShareDialogShow();
|
||||
|
||||
void onShareDialogDismiss(boolean success,MarkerShareMusic markerShareMusic);
|
||||
}
|
||||
|
||||
public static final String TAG = "MediaShareDialogFragment";
|
||||
|
||||
public static MediaShareDialogFragment newInstance(MediaInfoData data,boolean navi) {
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable("data", data);
|
||||
args.putBoolean("navi",navi);
|
||||
MediaShareDialogFragment fragment = new MediaShareDialogFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
this.context = context;
|
||||
if (getParentFragment() instanceof Callback) {
|
||||
callback = ((Callback) getParentFragment());
|
||||
} else if (context instanceof Callback) {
|
||||
callback = ((Callback) context);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
final Dialog dialog = getDialog();
|
||||
if (dialog != null) {
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
if (dialog.getWindow() != null) {
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));
|
||||
}
|
||||
}
|
||||
|
||||
return inflater.inflate(R.layout.module_media_share_fragment_view, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (callback != null) {
|
||||
callback.onShareDialogShow();
|
||||
}
|
||||
try {
|
||||
mMediaInfoData = (MediaInfoData) getArguments().getSerializable("data");
|
||||
navi = getArguments().getBoolean("navi");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
initViews();
|
||||
registerMediaReceiver();
|
||||
registerCloseNoWakeUp();
|
||||
}
|
||||
|
||||
private class VoiceCallBack implements IMogoVoiceCmdCallBack {
|
||||
@Override
|
||||
public void onCmdSelected(String cmd) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction(String speakText) {
|
||||
//确认
|
||||
shareMusic(mMediaInfoData,false);
|
||||
Logger.d("MediaShareDialogFragment","qa onCmdAction"+speakText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel(String speakText) {
|
||||
//取消
|
||||
dissMisDialog(false);
|
||||
Logger.d("MediaShareDialogFragment","qa onCmdCancel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd(String speakText) {
|
||||
Logger.d("MediaShareDialogFragment","qa onSpeakEnd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut(String speakText) {
|
||||
if (!navi) registerCloseNoWakeUp();
|
||||
Logger.d("MediaShareDialogFragment","qa onSpeakSelectTimeOut");
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMediaReceiver() {
|
||||
mShareOkReceiver = new ShareOkReceiver();
|
||||
IntentFilter filterone = new IntentFilter();
|
||||
filterone.addAction("com.zhidao.speech.awake.notify");
|
||||
getContext().registerReceiver(mShareOkReceiver, filterone);
|
||||
}
|
||||
|
||||
private void unRegisterMediaReceiver() {
|
||||
try {
|
||||
getContext().unregisterReceiver(mShareOkReceiver);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private class ShareOkReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
if (intent != null){
|
||||
String cmdStr = intent.getStringExtra("command");
|
||||
if(cmdStr.equals("com.zhidao.multiMedia.share.comfirm")){
|
||||
shareMusic(mMediaInfoData,false);
|
||||
}else if (cmdStr.equals("com.zhidao.multiMedia.share.cancel")){
|
||||
dissMisDialog(false);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCloseNoWakeUp() {
|
||||
AIAssist.getInstance(getActivity()).registerUnWakeupCommand(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE_COMMAND
|
||||
, VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE
|
||||
,new MogoVoiceCmdCallBackImp(){
|
||||
@Override
|
||||
public void onCmdSelected(String cmd) {
|
||||
super.onCmdSelected(cmd);
|
||||
if (cmd.equals(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE_COMMAND)){
|
||||
dismissAllowingStateLoss();
|
||||
}
|
||||
Logger.d("MediaShareDialogFragment","registerUnWakeupCommand onCmdSelected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd(String speakText) {
|
||||
super.onSpeakEnd(speakText);
|
||||
Logger.d("MediaShareDialogFragment","registerUnWakeupCommand onSpeakEnd"+speakText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut(String speakText) {
|
||||
super.onSpeakSelectTimeOut(speakText);
|
||||
Logger.d("MediaShareDialogFragment","registerUnWakeupCommand onSpeakSelectTimeOut");
|
||||
}
|
||||
});
|
||||
|
||||
AIAssist.getInstance(getActivity()).registerUnWakeupCommand(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_OK_COMMAND
|
||||
, VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_OK
|
||||
,new MogoVoiceCmdCallBackImp(){
|
||||
@Override
|
||||
public void onCmdSelected(String cmd) {
|
||||
super.onCmdSelected(cmd);
|
||||
if (cmd.equals(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_OK_COMMAND)){
|
||||
shareMusic(mMediaInfoData,false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd(String speakText) {
|
||||
super.onSpeakEnd(speakText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut(String speakText) {
|
||||
super.onSpeakSelectTimeOut(speakText);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
mMediaImg = getView().findViewById(R.id.media_img);
|
||||
mMediaName = getView().findViewById(R.id.media_name);
|
||||
mMediaSinger = getView().findViewById(R.id.media_singer);
|
||||
mOk = getView().findViewById(R.id.txt_ok);
|
||||
mCancel = getView().findViewById(R.id.txt_cancle);
|
||||
mDialogContent = getView().findViewById(R.id.media_dialog_content);
|
||||
mCancel.setOnClickListener(view -> {
|
||||
dissMisDialog(true);
|
||||
});
|
||||
|
||||
mOk.setOnClickListener(view -> {
|
||||
shareMusic(mMediaInfoData,true);
|
||||
});
|
||||
|
||||
if (mMediaInfoData != null) {
|
||||
if (mMediaInfoData.getMediaImg() != null) {
|
||||
com.bumptech.glide.request.RequestOptions options = new com.bumptech.glide.request.RequestOptions()
|
||||
.placeholder(R.drawable.module_media_share_default_rect_icon);
|
||||
GlideApp.with(getActivity()).applyDefaultRequestOptions(options).load(mMediaInfoData.getMediaImg()).into(mMediaImg);
|
||||
}
|
||||
|
||||
if (mMediaInfoData.getMediaName() != null) {
|
||||
mMediaName.setText(mMediaInfoData.getMediaName());
|
||||
}
|
||||
|
||||
if (mMediaInfoData.getMediaSinger() != null) {
|
||||
mMediaSinger.setText(mMediaInfoData.getMediaSinger());
|
||||
}
|
||||
|
||||
if (mMediaInfoData.getType() == 1) {
|
||||
mDialogContent.setText(context.getResources().getString(R.string.module_media_share_qq_music));
|
||||
} else if (mMediaInfoData.getType() == 2){
|
||||
mDialogContent.setText(context.getResources().getString(R.string.module_media_share_lan_ren));
|
||||
} else if (mMediaInfoData.getType() == 3){
|
||||
mDialogContent.setText(context.getResources().getString(R.string.module_media_share_le_ting_news));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dissMisDialog(boolean click) {
|
||||
dismissAllowingStateLoss();
|
||||
try {
|
||||
if (mMediaInfoData != null){
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
hashMap.put("type",click ?1:2);
|
||||
String trackId = "";
|
||||
if (mMediaInfoData.getType() == 1){
|
||||
trackId = EventConstants.EVENT_QQ_SHARE_DIALOG_CANCLE;
|
||||
}else if (mMediaInfoData.getType() == 2){
|
||||
trackId = EventConstants.EVENT_BOOK_SHARE_DIALOG_CANCLE;
|
||||
}else if (mMediaInfoData.getType() == 3){
|
||||
trackId = EventConstants.EVENT_NEWS_SHARE_DIALOG_CANCLE;
|
||||
}
|
||||
MediaAnalyticsUtils.track(trackId ,hashMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
try {
|
||||
|
||||
unRegisterMediaReceiver();
|
||||
|
||||
AIAssist.getInstance(getActivity()).unregisterUnWakeupCommand(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_CLOSE_COMMAND);
|
||||
AIAssist.getInstance(getActivity()).unregisterUnWakeupCommand(VoiceConstants.COMMAND_SHARE_DIALOG_TIMEOUT_OK_COMMAND);
|
||||
|
||||
if (mDisposable != null && !mDisposable.isDisposed()) {
|
||||
mDisposable.dispose();
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onShareDialogDismiss(shareSuccess,markerShareMusic);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void shareMusic(MediaInfoData mCurrentMusic,boolean click) {
|
||||
if (mCurrentMusic == null) return;
|
||||
markerShareMusic = new MarkerShareMusic();
|
||||
try {
|
||||
if (mMediaInfoData != null){
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
hashMap.put("type",click ? 1:2);
|
||||
String trackId = "";
|
||||
if (mMediaInfoData.getType() == 1){
|
||||
trackId = EventConstants.EVENT_QQ_SHARE_DIALOG_OK;
|
||||
}else if (mMediaInfoData.getType() == 2){
|
||||
trackId = EventConstants.EVENT_BOOK_SHARE_DIALOG_OK;
|
||||
}else if (mMediaInfoData.getType() == 3){
|
||||
trackId = EventConstants.EVENT_NEWS_SHARE_DIALOG_OK;
|
||||
}
|
||||
MediaAnalyticsUtils.track(trackId ,hashMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
final Map<String, Object> businessParams = new HashMap<>();
|
||||
final MogoLocation location = ServiceMediaHandler.getLocationClient().getLastKnowLocation();
|
||||
if (location != null) {
|
||||
businessParams.put("address", location.getAddress());
|
||||
}
|
||||
|
||||
businessParams.put("bookInfo", mCurrentMusic.getBookInfo());
|
||||
businessParams.put("mediaDuration", mCurrentMusic.getMaxTime() + "");
|
||||
businessParams.put("mediaId", mCurrentMusic.getMediaId());
|
||||
businessParams.put("mediaImg", mCurrentMusic.getMediaImg());
|
||||
businessParams.put("mediaName", mCurrentMusic.getMediaName());
|
||||
businessParams.put("mediaSinger", mCurrentMusic.getMediaSinger());
|
||||
businessParams.put("mediaType", mCurrentMusic.getMediaType());
|
||||
businessParams.put("mediaUrl", mCurrentMusic.getMediaUrl());
|
||||
businessParams.put("shareType", mCurrentMusic.getType());
|
||||
|
||||
ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
if (location != null) {
|
||||
builder.append("lat", location.getLatitude());
|
||||
builder.append("lng", location.getLongitude());
|
||||
}else{
|
||||
TipToast.shortTip("分享失败,定位出错请重试!");
|
||||
shareSuccess = false;
|
||||
dismissAllowingStateLoss();
|
||||
return;
|
||||
}
|
||||
final Map<String, Object> params = builder
|
||||
.append(businessParams)
|
||||
.build();
|
||||
Observable<ShareSuccessResult> observable = ServiceMediaHandler.getMogoNetWorkService().create(MediaDztService.class, BaseUrlManager.getDztBaseUrl())
|
||||
.shareMusic(ParamsUtil.toQueryUrl(BaseUrlManager.getDztBaseUrl() + BaseUrlConstants.SHARE_MUSIC_URL, params, businessParams), ParamsUtil.convert(businessParams));
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<ShareSuccessResult>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
mDisposable = d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ShareSuccessResult resultData) {
|
||||
try {
|
||||
ToastHelper.showShortSuccess(getContext(), getContext().getResources().getString(R.string.module_media_share_success));
|
||||
if (!navi) AIAssist.getInstance(getActivity()).speakTTSVoice(getContext().getResources().getString(R.string.module_media_share_success),null);
|
||||
shareSuccess = true;
|
||||
if (resultData != null && resultData.result != null){
|
||||
markerShareMusic = resultData.result;
|
||||
markerShareMusic.setType(MediaConstants.MODULE_TYPE);
|
||||
}
|
||||
dismissAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
try {
|
||||
ToastHelper.showShortError(getContext(), getContext().getResources().getString(R.string.module_media_share_fail));
|
||||
TipToast.shortTip("分享失败");
|
||||
if (!navi)AIAssist.getInstance(getActivity()).speakTTSVoice(getContext().getResources().getString(R.string.module_media_share_fail),null);
|
||||
dismissAllowingStateLoss();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
try {
|
||||
ToastHelper.showShortError(getContext(), getContext().getResources().getString(R.string.module_media_share_fail));
|
||||
TipToast.shortTip(!TextUtils.isEmpty(message)?message:"分享失败");
|
||||
if (!navi)AIAssist.getInstance(getActivity()).speakTTSVoice(!TextUtils.isEmpty(message)?message:"分享失败",null);
|
||||
dismissAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.module.media.listener;
|
||||
|
||||
import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
|
||||
|
||||
public abstract class MogoVoiceCmdCallBackImp implements IMogoVoiceCmdCallBack {
|
||||
@Override
|
||||
public void onCmdSelected(String cmd) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction(String speakText) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel(String speakText) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd(String speakText) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut(String speakText) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.module.media.listener;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public abstract class NoDoubleClickListener implements View.OnClickListener {
|
||||
|
||||
public static final int MIN_CLICK_DELAY_TIME = 700;
|
||||
|
||||
private long lastClickTime = 0;
|
||||
|
||||
@Override
|
||||
|
||||
public void onClick(View v) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastClickTime) > MIN_CLICK_DELAY_TIME) {
|
||||
lastClickTime = currentTime;
|
||||
onClicks(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onClicks(View view);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LanRenInsertData implements Serializable {
|
||||
|
||||
/**
|
||||
* announcer : 动之以情
|
||||
* auth : 耗子扛大刀
|
||||
* bookId : 28862
|
||||
* cover : http://bookpic.lrts.me/b8d33429fa0840578207c1685e8fa22a_180x254.jpg
|
||||
* desc : 传说中的兵之王者,神秘莫测的杀手之王,带着仇恨与疑惑进入都市寻找仇敌!
|
||||
* isCollect : false
|
||||
* name : 特种军医在都市
|
||||
* sections : 447
|
||||
* typeName : 都市传说
|
||||
*/
|
||||
|
||||
private String announcer;
|
||||
private String auth;
|
||||
private int bookId;
|
||||
private String cover;
|
||||
private String desc;
|
||||
private boolean isCollect;
|
||||
private String name;
|
||||
private int sections;
|
||||
private String typeName;
|
||||
|
||||
public String getAnnouncer() {
|
||||
return announcer;
|
||||
}
|
||||
|
||||
public void setAnnouncer(String announcer) {
|
||||
this.announcer = announcer;
|
||||
}
|
||||
|
||||
public String getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setAuth(String auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public int getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(int bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public String getCover() {
|
||||
return cover;
|
||||
}
|
||||
|
||||
public void setCover(String cover) {
|
||||
this.cover = cover;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean isIsCollect() {
|
||||
return isCollect;
|
||||
}
|
||||
|
||||
public void setIsCollect(boolean isCollect) {
|
||||
this.isCollect = isCollect;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getSections() {
|
||||
return sections;
|
||||
}
|
||||
|
||||
public void setSections(int sections) {
|
||||
this.sections = sections;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LeTingNewsData implements Serializable {
|
||||
|
||||
/**
|
||||
* catalog_id : channel_recommend
|
||||
* catalog_name : 推荐
|
||||
* title : 内蒙古:妈妈去武汉打“怪兽”
|
||||
* hms : 02:20
|
||||
* image : https://image.leting.io/a066db4d5c615605e79c3235d9f54669.jpg
|
||||
* sid : Pfzgptk29ZG86N0JStE5l-1srtNmDnAwBBLMCm-2l7QvQAP7vq0G_Jlm6YM8z9kHb97sJVd5mJ_2zW5EWtahbQ==
|
||||
* source : 北京您早
|
||||
* source_icon : https://image.leting.io/a77d7b23030e49007c148a563c386dbe.jpg
|
||||
* pub_time : 0
|
||||
* updated_at : 0
|
||||
* duration : 140
|
||||
* hot : 0
|
||||
*/
|
||||
|
||||
private String catalog_id;
|
||||
private String catalog_name;
|
||||
private String title;
|
||||
private String hms;
|
||||
private String image;
|
||||
private String sid;
|
||||
private String source;
|
||||
private String source_icon;
|
||||
private int pub_time;
|
||||
private int updated_at;
|
||||
private int duration;
|
||||
private int hot;
|
||||
|
||||
public String getCatalog_id() {
|
||||
return catalog_id;
|
||||
}
|
||||
|
||||
public void setCatalog_id(String catalog_id) {
|
||||
this.catalog_id = catalog_id;
|
||||
}
|
||||
|
||||
public String getCatalog_name() {
|
||||
return catalog_name;
|
||||
}
|
||||
|
||||
public void setCatalog_name(String catalog_name) {
|
||||
this.catalog_name = catalog_name;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getHms() {
|
||||
return hms;
|
||||
}
|
||||
|
||||
public void setHms(String hms) {
|
||||
this.hms = hms;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public void setSid(String sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSource_icon() {
|
||||
return source_icon;
|
||||
}
|
||||
|
||||
public void setSource_icon(String source_icon) {
|
||||
this.source_icon = source_icon;
|
||||
}
|
||||
|
||||
public int getPub_time() {
|
||||
return pub_time;
|
||||
}
|
||||
|
||||
public void setPub_time(int pub_time) {
|
||||
this.pub_time = pub_time;
|
||||
}
|
||||
|
||||
public int getUpdated_at() {
|
||||
return updated_at;
|
||||
}
|
||||
|
||||
public void setUpdated_at(int updated_at) {
|
||||
this.updated_at = updated_at;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public int getHot() {
|
||||
return hot;
|
||||
}
|
||||
|
||||
public void setHot(int hot) {
|
||||
this.hot = hot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MediaInfoData implements Serializable {
|
||||
|
||||
//QQ音乐,懒人听书,乐听头条 2 为书籍听书,3 为新闻,1 为qq音乐
|
||||
private int type;
|
||||
|
||||
private String mediaId;//qq音乐id,书的bookId
|
||||
//qq音乐url 懒人听书为“”
|
||||
private String mediaUrl;
|
||||
|
||||
//歌曲名 ,当前播放书名,新闻标题内容
|
||||
private String mediaName;
|
||||
|
||||
//演唱歌手,当前章节,新闻来源
|
||||
private String mediaSinger;
|
||||
|
||||
//歌曲封面,书籍封面,新闻预览图
|
||||
private String mediaImg;
|
||||
|
||||
//音乐类别,类似经典 ,流行只有qq特有
|
||||
private String mediaType;
|
||||
|
||||
private int maxTime;//音频总时长
|
||||
|
||||
private String bookInfo;//懒人听书json串
|
||||
|
||||
//当前播放时长,可以不加,播放进度单独独立出来
|
||||
private int curTime;
|
||||
|
||||
//是否是本地音频,只有qq音乐
|
||||
private boolean isLocalMedia;//本地
|
||||
|
||||
//播放模式,顺序,单曲循环,随机
|
||||
private int mediaPlayMode;
|
||||
|
||||
//1 播放 2 缓冲 0 暂停/停止 -1 播放错误
|
||||
private int playState;
|
||||
|
||||
public String getMediaId() {
|
||||
return mediaId;
|
||||
}
|
||||
|
||||
public void setMediaId(String mediaId) {
|
||||
this.mediaId = mediaId;
|
||||
}
|
||||
|
||||
public String getMediaUrl() {
|
||||
return mediaUrl;
|
||||
}
|
||||
|
||||
public void setMediaUrl(String mediaUrl) {
|
||||
this.mediaUrl = mediaUrl;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getPlayState() {
|
||||
return playState;
|
||||
}
|
||||
|
||||
public void setPlayState(int playState) {
|
||||
this.playState = playState;
|
||||
}
|
||||
|
||||
public String getMediaName() {
|
||||
return mediaName;
|
||||
}
|
||||
|
||||
public void setMediaName(String mediaName) {
|
||||
this.mediaName = mediaName;
|
||||
}
|
||||
|
||||
public String getMediaSinger() {
|
||||
return mediaSinger;
|
||||
}
|
||||
|
||||
public void setMediaSinger(String mediaSinger) {
|
||||
this.mediaSinger = mediaSinger;
|
||||
}
|
||||
|
||||
public String getMediaImg() {
|
||||
return mediaImg;
|
||||
}
|
||||
|
||||
public void setMediaImg(String mediaImg) {
|
||||
this.mediaImg = mediaImg;
|
||||
}
|
||||
|
||||
public int getMaxTime() {
|
||||
return maxTime;
|
||||
}
|
||||
|
||||
public void setMaxTime(int maxTime) {
|
||||
this.maxTime = maxTime;
|
||||
}
|
||||
|
||||
public int getCurTime() {
|
||||
return curTime;
|
||||
}
|
||||
|
||||
public void setCurTime(int curTime) {
|
||||
this.curTime = curTime;
|
||||
}
|
||||
|
||||
public String getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public void setMediaType(String mediaType) {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
public boolean isLocalMedia() {
|
||||
return isLocalMedia;
|
||||
}
|
||||
|
||||
public void setLocalMedia(boolean localMedia) {
|
||||
isLocalMedia = localMedia;
|
||||
}
|
||||
|
||||
public int getMediaPlayMode() {
|
||||
return mediaPlayMode;
|
||||
}
|
||||
|
||||
public void setMediaPlayMode(int mediaPlayMode) {
|
||||
this.mediaPlayMode = mediaPlayMode;
|
||||
}
|
||||
|
||||
public String getBookInfo() {
|
||||
return bookInfo;
|
||||
}
|
||||
|
||||
public void setBookInfo(String bookInfo) {
|
||||
this.bookInfo = bookInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MediaInfoDataEvent implements Serializable {
|
||||
public MediaInfoData data;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MediaProcessEvent implements Serializable {
|
||||
public int process;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NearShareRequestParameter {
|
||||
|
||||
/**
|
||||
* location : {"lat":31,"lon":116}
|
||||
* radius : 1000
|
||||
* dataType : ["CARD_TYPE_CARS_CHATTING","CARD_TYPE_ROAD_CODITION"]
|
||||
* limit : 100
|
||||
*/
|
||||
|
||||
private LocationBean location;
|
||||
private int radius;
|
||||
private int limit;
|
||||
private List<String> dataType;
|
||||
|
||||
public LocationBean getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(LocationBean location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public void setRadius(int radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public void setLimit(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public List<String> getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public void setDataType(List<String> dataType) {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
public static class LocationBean {
|
||||
/**
|
||||
* lat : 31.0
|
||||
* lon : 116.0
|
||||
*/
|
||||
|
||||
private double lat;
|
||||
private double lon;
|
||||
|
||||
public double getLat() {
|
||||
return lat;
|
||||
}
|
||||
|
||||
public void setLat(double lat) {
|
||||
this.lat = lat;
|
||||
}
|
||||
|
||||
public double getLon() {
|
||||
return lon;
|
||||
}
|
||||
|
||||
public void setLon(double lon) {
|
||||
this.lon = lon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class QQMediaListData implements Serializable {
|
||||
//唯一区分歌曲
|
||||
private String mediaUrl;
|
||||
|
||||
//歌曲名 ,当前播放书名,新闻标题内容
|
||||
private String mediaName;
|
||||
|
||||
//演唱歌手,当前章节,新闻来源
|
||||
private String mediaSinger;
|
||||
|
||||
private String mediaImgUrl;
|
||||
|
||||
private String mediaMid;
|
||||
|
||||
public String getMediaMid() {
|
||||
return mediaMid;
|
||||
}
|
||||
|
||||
public void setMediaMid(String mediaMid) {
|
||||
this.mediaMid = mediaMid;
|
||||
}
|
||||
|
||||
public String getMediaUrl() {
|
||||
return mediaUrl;
|
||||
}
|
||||
|
||||
public void setMediaUrl(String mediaUrl) {
|
||||
this.mediaUrl = mediaUrl;
|
||||
}
|
||||
|
||||
public String getMediaName() {
|
||||
return mediaName;
|
||||
}
|
||||
|
||||
public void setMediaName(String mediaName) {
|
||||
this.mediaName = mediaName;
|
||||
}
|
||||
|
||||
public String getMediaSinger() {
|
||||
return mediaSinger;
|
||||
}
|
||||
|
||||
public void setMediaSinger(String mediaSinger) {
|
||||
this.mediaSinger = mediaSinger;
|
||||
}
|
||||
|
||||
public String getMediaImgUrl() {
|
||||
return mediaImgUrl;
|
||||
}
|
||||
|
||||
public void setMediaImgUrl(String mediaImgUrl) {
|
||||
this.mediaImgUrl = mediaImgUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
|
||||
public class ShareLikeData extends BaseData {
|
||||
|
||||
public ShareLikeDataResult result;
|
||||
|
||||
public static class ShareLikeDataResult{
|
||||
|
||||
public boolean checkLiked;
|
||||
public int likedCount;
|
||||
public String mediaId;
|
||||
public String mediaUrl;
|
||||
public int type; //1真是数据 2虚拟数据
|
||||
public long userId;
|
||||
public String userImg;
|
||||
public String userName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ShareMediaJsonData implements Serializable {
|
||||
public String type;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
MarkerShareMusic 结构说明:
|
||||
* bookInfo : 懒人听书实体json串
|
||||
* id : 100
|
||||
* likeNumber : 99
|
||||
* location : {"address":"北京市朝阳区三里屯街道108号","angle":"36.5","lat":"39.989368","lon":"116.480888"}
|
||||
* mediaId : 音乐id
|
||||
* mediaImg : 歌曲封面img url
|
||||
* mediaName : 歌曲名
|
||||
* mediaSinger : 歌手名
|
||||
* mediaUrl : 歌曲url
|
||||
* shareContentText : 分享的文字
|
||||
* shareType : 1
|
||||
* type : 卡片类型
|
||||
* userInfo : {"age":"00后","gender":"男|女|无(也可以0|1|2根据实际库存返回即可)","sn":"018209312809312","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","userId":1,"userName":"用户昵称"}
|
||||
*/
|
||||
public class ShareMediaMarkerInfoData extends BaseData {
|
||||
|
||||
public ShareMediaMarkerInfoDataResult result;
|
||||
|
||||
public ShareMediaMarkerInfoDataResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(ShareMediaMarkerInfoDataResult result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public static class ShareMediaMarkerInfoDataResult{
|
||||
public ArrayList<MarkerShareMusic> shareMusic;
|
||||
|
||||
public ArrayList<MarkerShareMusic> getShareMusic() {
|
||||
return shareMusic;
|
||||
}
|
||||
|
||||
public void setShareMusic(ArrayList<MarkerShareMusic> shareMusic) {
|
||||
this.shareMusic = shareMusic;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
|
||||
public class ShareSuccessResult extends BaseData {
|
||||
public MarkerShareMusic result;
|
||||
|
||||
public MarkerShareMusic getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(MarkerShareMusic result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.module.media.model;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
|
||||
public class ShowShareData extends BaseData {
|
||||
public ShowShareResult result;
|
||||
|
||||
public ShowShareResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(ShowShareResult result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public static class ShowShareResult{
|
||||
public boolean check;
|
||||
|
||||
public boolean isCheck() {
|
||||
return check;
|
||||
}
|
||||
|
||||
public void setCheck(boolean check) {
|
||||
this.check = check;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.mogo.module.media.model.url;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class UrlData implements Serializable {
|
||||
private String dztUrl;
|
||||
private String apiUrl;
|
||||
|
||||
public UrlData(String dztUrl, String apiUrl) {
|
||||
this.dztUrl = dztUrl;
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
|
||||
public String getDztUrl() {
|
||||
return dztUrl;
|
||||
}
|
||||
|
||||
public void setDztUrl(String dztUrl) {
|
||||
this.dztUrl = dztUrl;
|
||||
}
|
||||
|
||||
public String getApiUrl() {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
public void setApiUrl(String apiUrl) {
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
package com.mogo.module.media.presenter;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.mogo.commons.data.BaseData;
|
||||
import com.mogo.commons.mvp.Presenter;
|
||||
import com.mogo.commons.network.ParamsProvider;
|
||||
import com.mogo.commons.network.ParamsUtil;
|
||||
import com.mogo.commons.network.SubscribeImpl;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.map.location.MogoLocation;
|
||||
import com.mogo.module.common.entity.MarkerResponse;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
import com.mogo.module.media.MediaConstants;
|
||||
import com.mogo.module.media.R;
|
||||
import com.mogo.module.media.ServiceMediaHandler;
|
||||
import com.mogo.module.media.api.MediaDztService;
|
||||
import com.mogo.module.media.constants.BaseUrlConstants;
|
||||
import com.mogo.module.media.constants.EventConstants;
|
||||
import com.mogo.module.media.model.MediaInfoData;
|
||||
import com.mogo.module.media.model.NearShareRequestParameter;
|
||||
import com.mogo.module.media.model.ShareLikeData;
|
||||
import com.mogo.module.media.model.ShareMediaMarkerInfoData;
|
||||
import com.mogo.module.media.model.ShareSuccessResult;
|
||||
import com.mogo.module.media.model.ShowShareData;
|
||||
import com.mogo.module.media.utils.BaseUrlManager;
|
||||
import com.mogo.module.media.utils.MediaAnalyticsUtils;
|
||||
import com.mogo.module.media.utils.StorageManager;
|
||||
import com.mogo.module.media.utils.ToastHelper;
|
||||
import com.mogo.module.media.view.MediaView;
|
||||
import com.mogo.utils.TipToast;
|
||||
import com.mogo.utils.network.RequestOptions;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class MediaPresenter extends Presenter<MediaView> {
|
||||
|
||||
private static final String TAG = "MediaPresenter";
|
||||
private ArrayList<Disposable> mDisPosables;
|
||||
|
||||
public MediaPresenter(MediaView view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NonNull LifecycleOwner owner) {
|
||||
super.onCreate(owner);
|
||||
}
|
||||
|
||||
public void getFriendMusic() {
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
final MogoLocation location = ServiceMediaHandler.getLocationClient().getLastKnowLocation();
|
||||
if (location != null) {
|
||||
builder.append("address", location.getAddress());
|
||||
builder.append("lat", location.getLatitude());
|
||||
builder.append("lng", location.getLongitude());
|
||||
}
|
||||
|
||||
Map<String, Object> parameters = builder.build();
|
||||
Observable<ShareMediaMarkerInfoData> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getFriendShareMusic(parameters);
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<ShareMediaMarkerInfoData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ShareMediaMarkerInfoData resultData) {
|
||||
if (resultData != null && resultData.getResult() != null
|
||||
&& resultData.getResult().getShareMusic() != null
|
||||
&& resultData.getResult().getShareMusic().size() > 0){
|
||||
mView.loadFriendShareMusicSuccess(resultData.getResult().getShareMusic());
|
||||
}else{
|
||||
TipToast.shortTip("您的好友未分享过歌曲");
|
||||
AIAssist.getInstance(mView.getContext()).speakTTSVoice("您的好友未分享过歌曲",null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
TipToast.shortTip("获取好友的歌失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
TipToast.shortTip("获取好友的歌失败");
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始音乐播放的接口
|
||||
* @param mCurrentMusic
|
||||
*/
|
||||
public void startedMusic(MediaInfoData mCurrentMusic) {
|
||||
if (mCurrentMusic == null)return;
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
hashMap.put("mediaType", mCurrentMusic.getType());
|
||||
hashMap.put("shareData", mCurrentMusic);
|
||||
builder.append("data", GsonUtil.jsonFromObject(hashMap));
|
||||
Map<String, Object> parameters = builder.build();
|
||||
Observable<BaseData> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).startedMusic(parameters);
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<BaseData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(BaseData resultData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 请求附近的
|
||||
*/
|
||||
public void getNearShareMusic() {
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
NearShareRequestParameter nearData = new NearShareRequestParameter();
|
||||
NearShareRequestParameter.LocationBean locationBean = new NearShareRequestParameter.LocationBean();
|
||||
final MogoLocation location = ServiceMediaHandler.getLocationClient().getLastKnowLocation();
|
||||
if ( location != null ) {
|
||||
locationBean.setLat(locationBean.getLat());
|
||||
locationBean.setLon(locationBean.getLon());
|
||||
}
|
||||
nearData.setLocation(locationBean);
|
||||
nearData.setLimit(10);
|
||||
nearData.setRadius(2000);
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add(MediaConstants.MODULE_TYPE);
|
||||
nearData.setDataType(list);
|
||||
builder.append("data", GsonUtil.jsonFromObject(nearData));
|
||||
Map<String, Object> parameters = builder.build();
|
||||
Observable<MarkerResponse> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getNearShareMusic(parameters);
|
||||
Disposable disposable = observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
new Consumer<MarkerResponse>() {
|
||||
@Override
|
||||
public void accept(MarkerResponse markerResponse) throws Exception {
|
||||
if (markerResponse != null && markerResponse.getCode() == 0
|
||||
&& markerResponse.getResult() != null
|
||||
&& markerResponse.getResult().getShareMusic() != null
|
||||
&& markerResponse.getResult().getShareMusic().size() > 0){
|
||||
mView.loadNearShareMusicSuccess(markerResponse.getResult().getShareMusic());
|
||||
}else{
|
||||
AIAssist.getInstance(mView.getContext()).speakTTSVoice("当前暂无分享的歌曲",null);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
TipToast.shortTip("获取附近的歌失败");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
addDispose(disposable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音乐播放的接口
|
||||
*/
|
||||
public void stopMusic() {
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
Map<String, Object> parameters = builder.build();
|
||||
Observable<BaseData> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).stopMusic(parameters);
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<BaseData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(BaseData resultData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public void getShouldShare() {
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
Map<String, Object> parameters = builder.build();
|
||||
Observable<ShowShareData> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getShouldPushShare(parameters);
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<ShowShareData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ShowShareData resultData) {
|
||||
//存储请求了触发分享的接口,每次accon一次
|
||||
StorageManager.setShowPushShareTime(System.currentTimeMillis()+"");
|
||||
if (resultData != null && resultData.result != null){
|
||||
mView.showSharePush(resultData.result.check);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public void selectByPrimaryKey(int id,String mediaId){
|
||||
final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
builder.append("id",id);
|
||||
Map<String, Object> parameters = builder.build();
|
||||
|
||||
Observable<ShareLikeData> observable = ServiceMediaHandler.getMogoNetWorkService().
|
||||
create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).selectByPrimaryKey(parameters);
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<ShareLikeData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ShareLikeData resultData) {
|
||||
//存储请求了触发分享的接口,每次accon一次
|
||||
if (resultData == null){
|
||||
return;
|
||||
}
|
||||
if (resultData.result == null){
|
||||
return;
|
||||
}
|
||||
mView.loadShareLikeDataResultSuccess(resultData.result,mediaId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
TipToast.shortTip("加载点赞信息失败,请重试");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
TipToast.shortTip("加载点赞信息失败,请重试");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public void likeShare(ShareLikeData.ShareLikeDataResult likeDataResult){
|
||||
|
||||
final Map<String, Object> businessParams = new HashMap<>();
|
||||
final MogoLocation location = ServiceMediaHandler.getLocationClient().getLastKnowLocation();
|
||||
|
||||
businessParams.put("musicId", likeDataResult.mediaId);
|
||||
businessParams.put("musicUrl", likeDataResult.mediaUrl);
|
||||
businessParams.put("userId", likeDataResult.userId);
|
||||
businessParams.put("userType", likeDataResult.type);
|
||||
|
||||
ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
if (location != null) {
|
||||
builder.append("lat", location.getLatitude());
|
||||
builder.append("lng", location.getLongitude());
|
||||
}
|
||||
final Map<String, Object> params = builder
|
||||
.append(businessParams)
|
||||
.build();
|
||||
|
||||
|
||||
Observable<BaseData> observable = ServiceMediaHandler.getMogoNetWorkService().create(MediaDztService.class, BaseUrlManager.getDztBaseUrl())
|
||||
.likeShare(ParamsUtil.toQueryUrl(BaseUrlManager.getDztBaseUrl() + BaseUrlConstants.SHARE_MUSIC_LIKE_URL, params, businessParams), ParamsUtil.convert(businessParams));
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<BaseData>(RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(BaseData resultData) {
|
||||
mView.likeShareSuccess();
|
||||
TipToast.shortTip("点赞成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
TipToast.shortTip("点赞失败,请重试");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
TipToast.shortTip(message != null ?message:"点赞失败,请重试");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void addDispose(Disposable subscription){
|
||||
if (subscription != null){
|
||||
if (mDisPosables == null) mDisPosables = new ArrayList<>();
|
||||
mDisPosables.add(subscription);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPackageName(MediaInfoData mMediaInfoData){
|
||||
if (mMediaInfoData == null) return "";
|
||||
if (mMediaInfoData.getType() == 1){
|
||||
return "com.pvetec.musics";
|
||||
}else if (mMediaInfoData.getType() == 2){
|
||||
return "com.zhidao.lrts";
|
||||
}else if (mMediaInfoData.getType() == 3){
|
||||
return "com.zhidao.ltnews";
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getAppName(MediaInfoData mMediaInfoData){
|
||||
if (mMediaInfoData == null) return "";
|
||||
if (mMediaInfoData.getType() == 1){
|
||||
return "QQ音乐";
|
||||
}else if (mMediaInfoData.getType() == 2){
|
||||
return "懒人听书";
|
||||
}else if (mMediaInfoData.getType() == 3){
|
||||
return "乐听头条";
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void shareMusic(MediaInfoData mCurrentMusic,boolean click) {
|
||||
if (mCurrentMusic == null) return;
|
||||
try {
|
||||
if (mCurrentMusic != null){
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
hashMap.put("type",click ? 1:2);
|
||||
String trackId = "";
|
||||
if (mCurrentMusic.getType() == 1){
|
||||
trackId = EventConstants.EVENT_QQ_SHARE_DIALOG_OK;
|
||||
}else if (mCurrentMusic.getType() == 2){
|
||||
trackId = EventConstants.EVENT_BOOK_SHARE_DIALOG_OK;
|
||||
}else if (mCurrentMusic.getType() == 3){
|
||||
trackId = EventConstants.EVENT_NEWS_SHARE_DIALOG_OK;
|
||||
}
|
||||
MediaAnalyticsUtils.track(trackId ,hashMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
final Map<String, Object> businessParams = new HashMap<>();
|
||||
final MogoLocation location = ServiceMediaHandler.getLocationClient().getLastKnowLocation();
|
||||
if (location != null) {
|
||||
businessParams.put("address", location.getAddress());
|
||||
}
|
||||
|
||||
businessParams.put("bookInfo", mCurrentMusic.getBookInfo());
|
||||
businessParams.put("mediaDuration", mCurrentMusic.getMaxTime() + "");
|
||||
businessParams.put("mediaId", mCurrentMusic.getMediaId());
|
||||
businessParams.put("mediaImg", mCurrentMusic.getMediaImg());
|
||||
businessParams.put("mediaName", mCurrentMusic.getMediaName());
|
||||
businessParams.put("mediaSinger", mCurrentMusic.getMediaSinger());
|
||||
businessParams.put("mediaType", mCurrentMusic.getMediaType());
|
||||
businessParams.put("mediaUrl", mCurrentMusic.getMediaUrl());
|
||||
businessParams.put("shareType", mCurrentMusic.getType());
|
||||
|
||||
ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
|
||||
if (location != null) {
|
||||
builder.append("lat", location.getLatitude());
|
||||
builder.append("lng", location.getLongitude());
|
||||
}else{
|
||||
TipToast.shortTip("分享失败,定位出错请重试!");
|
||||
return;
|
||||
}
|
||||
final Map<String, Object> params = builder
|
||||
.append(businessParams)
|
||||
.build();
|
||||
Observable<ShareSuccessResult> observable = ServiceMediaHandler.getMogoNetWorkService().create(MediaDztService.class, BaseUrlManager.getDztBaseUrl())
|
||||
.shareMusic(ParamsUtil.toQueryUrl(BaseUrlManager.getDztBaseUrl() + BaseUrlConstants.SHARE_MUSIC_URL, params, businessParams), ParamsUtil.convert(businessParams));
|
||||
observable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SubscribeImpl<ShareSuccessResult>(com.mogo.utils.network.RequestOptions.create(getContext())) {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
super.onSubscribe(d);
|
||||
addDispose(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ShareSuccessResult resultData) {
|
||||
try {
|
||||
ToastHelper.showShortSuccess(getContext(), getContext().getResources().getString(R.string.module_media_share_success));
|
||||
AIAssist.getInstance(getContext()).speakTTSVoice(getContext().getResources().getString(R.string.module_media_share_success),null);
|
||||
if (resultData != null && resultData.result != null){
|
||||
MarkerShareMusic markerShareMusic = resultData.result;
|
||||
markerShareMusic.setType(MediaConstants.MODULE_TYPE);
|
||||
mView.shareSuccessResult(true,markerShareMusic);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
super.onError(e);
|
||||
try {
|
||||
ToastHelper.showShortError(getContext(), getContext().getResources().getString(R.string.module_media_share_fail));
|
||||
TipToast.shortTip("分享失败");
|
||||
AIAssist.getInstance(getContext()).speakTTSVoice(getContext().getResources().getString(R.string.module_media_share_fail),null);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, int code) {
|
||||
super.onError(message, code);
|
||||
try {
|
||||
ToastHelper.showShortError(getContext(), getContext().getResources().getString(R.string.module_media_share_fail));
|
||||
TipToast.shortTip(!TextUtils.isEmpty(message)?message:"分享失败");
|
||||
AIAssist.getInstance(getContext()).speakTTSVoice(!TextUtils.isEmpty(message)?message:"分享失败",null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NonNull LifecycleOwner owner) {
|
||||
super.onDestroy(owner);
|
||||
if (mDisPosables != null && !mDisPosables.isEmpty()) {
|
||||
for (Disposable subscription : mDisPosables) {
|
||||
if (subscription == null || subscription.isDisposed()) {
|
||||
continue;
|
||||
}
|
||||
subscription.dispose();
|
||||
}
|
||||
mDisPosables.clear();
|
||||
mDisPosables = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.mogo.module.media.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.mogo.module.media.model.MediaProcessEvent;
|
||||
|
||||
public class MediaProcessReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
{
|
||||
if (intent != null) {
|
||||
int curTime = intent.getIntExtra("curTime", -1);
|
||||
MediaProcessEvent event = new MediaProcessEvent();
|
||||
event.process = curTime;
|
||||
// EventBus.getDefault().post(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.mogo.module.media.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.mogo.module.media.MediaCardViewFragment;
|
||||
import com.mogo.module.media.utils.MusicControlBroadCast;
|
||||
import com.mogo.utils.ActivityLifecycleManager;
|
||||
import com.mogo.utils.UiThreadHandler;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
/**
|
||||
* 我要听{歌手/歌名}:
|
||||
* 语音通知桌面广播: com.speech.adapter.send 参数:music_model
|
||||
* 桌面通过该action转发给QQ音乐:com.txznet.adapter.send 参数 :music_model
|
||||
*
|
||||
* 播放音乐:
|
||||
* 语音通知桌面广播:com.zhidao.speech.awake.notify 参数:command == com.ileja.music.playapp
|
||||
*
|
||||
* 懒人听书:我要听书、听书 com.zhidao.speech.awake.notify 参数:command:com.zhidao.book.play
|
||||
* 乐听头条:播放新闻、我要听新闻、我要听{类型}新闻、听新闻action:com.zhidao.mediacenter.voiceltnews 参数:category
|
||||
*/
|
||||
public class MediaSpeechReceiver extends BroadcastReceiver {
|
||||
public static String mCategoryStr = "";
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
{
|
||||
if (intent != null) {
|
||||
String cmdAction = intent.getAction();
|
||||
boolean appActive = ActivityLifecycleManager.getInstance().isAppActive();
|
||||
appActive = MediaCardViewFragment.isMediaResume;
|
||||
Logger.d("MediaSpeechReceiver"," "+cmdAction+" "+appActive);
|
||||
if (cmdAction.equals("com.speech.adapter.send")){
|
||||
//我要听{歌手/歌名}
|
||||
Logger.d("MediaSpeechReceiver"," "+"type qq ");
|
||||
String musicModel = intent.getStringExtra("music_model");
|
||||
if (appActive){
|
||||
MusicControlBroadCast.playSomeBodyMusic(musicModel);
|
||||
MusicControlBroadCast.mediaCenterBroadcast();
|
||||
}else {
|
||||
MusicControlBroadCast.playSomeBodyMusic(musicModel);
|
||||
UiThreadHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MusicControlBroadCast.qqOpenQQMusic();
|
||||
}
|
||||
},300);
|
||||
}
|
||||
}else if (cmdAction.equals("com.zhidao.speech.awake.notify")){
|
||||
//播放音乐
|
||||
String musicCmd = intent.getStringExtra("command");
|
||||
Logger.d("MediaSpeechReceiver"," "+"qq book"+musicCmd==null?"":musicCmd);
|
||||
if (musicCmd.equals("com.ileja.music.playapp")){
|
||||
//QQ音乐
|
||||
if (appActive){
|
||||
MusicControlBroadCast.qqPlayQQMusic();
|
||||
MusicControlBroadCast.mediaCenterBroadcast();
|
||||
}else{
|
||||
MusicControlBroadCast.qqOpenQQMusic();
|
||||
}
|
||||
}else if (musicCmd.equals("com.zhidao.book.play")){
|
||||
//懒人听书
|
||||
if (appActive){
|
||||
MusicControlBroadCast.controlLanRenPlayBack();
|
||||
MusicControlBroadCast.mediaCenterBroadcast();
|
||||
}else{
|
||||
MusicControlBroadCast.openMediaApp(2);
|
||||
}
|
||||
}
|
||||
}else if (cmdAction.equals("com.zhidao.mediacenter.voiceltnews")){
|
||||
//新闻
|
||||
try {
|
||||
String category = intent.getStringExtra("category");
|
||||
Logger.d("MediaSpeechReceiver"," "+"news "+category==null?"":category);
|
||||
mCategoryStr = category;
|
||||
MusicControlBroadCast.getNewsPayInfoState();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.mogo.module.media.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.mogo.module.media.constants.LeTingFieldConstants;
|
||||
import com.mogo.module.media.constants.QQMusicFieldConstants;
|
||||
import com.mogo.module.media.model.LanRenInsertData;
|
||||
import com.mogo.module.media.model.MediaInfoData;
|
||||
import com.mogo.module.media.model.MediaInfoDataEvent;
|
||||
import com.mogo.module.media.utils.StorageManager;
|
||||
import com.mogo.module.media.utils.Utils;
|
||||
import com.mogo.utils.DateTimeUtils;
|
||||
import com.mogo.utils.ThreadPoolService;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
|
||||
public class MediaStateReceiver extends BroadcastReceiver {
|
||||
//action:com.zhidao.action.MEDIA_LRTS
|
||||
//action:com.zhidao.action.MEDIA_LT_NEWS
|
||||
//action:com.qq.music.status.change
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
{
|
||||
MediaInfoData mMediaInfoData = new MediaInfoData();
|
||||
if (intent != null) {
|
||||
int type = intent.getIntExtra("type", -1);
|
||||
int playState = intent.getIntExtra(QQMusicFieldConstants.playState, 0);
|
||||
|
||||
if (type == 1) {//qq音乐
|
||||
|
||||
int maxTime = intent.getIntExtra(QQMusicFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(QQMusicFieldConstants.curTime, 0);
|
||||
String mediaName = intent.getStringExtra(QQMusicFieldConstants.mediaName);
|
||||
String mediaUrl = intent.getStringExtra(QQMusicFieldConstants.mediaUrl);
|
||||
String mediaSinger = intent.getStringExtra(QQMusicFieldConstants.mediaSinger);
|
||||
String mediaImgUrl = intent.getStringExtra(QQMusicFieldConstants.mediaImgUrl);
|
||||
String mediaType = intent.getStringExtra(QQMusicFieldConstants.mediaType);
|
||||
String mediaMid = intent.getStringExtra(QQMusicFieldConstants.mediaMid);
|
||||
int mediaPLayMode = intent.getIntExtra(QQMusicFieldConstants.mediaPlayMode, -1);
|
||||
boolean isLocalMedia = intent.getBooleanExtra(QQMusicFieldConstants.isLocalMedia, false);
|
||||
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime * 1000);
|
||||
mMediaInfoData.setCurTime(curTime * 1000);
|
||||
mMediaInfoData.setMediaName(mediaName);
|
||||
mMediaInfoData.setMediaUrl(mediaUrl);
|
||||
mMediaInfoData.setMediaId(mediaMid);
|
||||
mMediaInfoData.setMediaImg(mediaImgUrl);
|
||||
mMediaInfoData.setMediaSinger(mediaSinger);
|
||||
mMediaInfoData.setMediaPlayMode(mediaPLayMode);
|
||||
mMediaInfoData.setLocalMedia(isLocalMedia);
|
||||
mMediaInfoData.setMediaType(mediaType);
|
||||
|
||||
} else if (type == 2) {//懒人听书
|
||||
int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
|
||||
|
||||
String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName);//章节数
|
||||
String bookInfoStr = intent.getStringExtra(LeTingFieldConstants.bookInfo);
|
||||
LanRenInsertData lanRenInsertData = GsonUtil.objectFromJson(bookInfoStr, LanRenInsertData.class);
|
||||
|
||||
String bookName = ""; // 书名 需要从bookinfo里面取
|
||||
String cover = ""; //封面 bookinfo中取
|
||||
String bookid = "";
|
||||
|
||||
try {
|
||||
if (lanRenInsertData != null) {
|
||||
bookName = lanRenInsertData.getName(); // 书名 需要从bookinfo里面取
|
||||
cover = lanRenInsertData.getCover(); //封面 bookinfo中取
|
||||
bookid = lanRenInsertData.getBookId() + "";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime);
|
||||
mMediaInfoData.setCurTime(curTime);
|
||||
mMediaInfoData.setMediaName(bookName); //bookName 或者mediaName
|
||||
mMediaInfoData.setMediaSinger(mediaName); //章节数
|
||||
mMediaInfoData.setMediaImg(cover); //书籍封面
|
||||
mMediaInfoData.setMediaId(bookid);//书籍的bookid int
|
||||
mMediaInfoData.setBookInfo(bookInfoStr);
|
||||
mMediaInfoData.setMediaUrl("");
|
||||
mMediaInfoData.setLocalMedia(false);
|
||||
mMediaInfoData.setMediaType("");
|
||||
|
||||
} else if (type == 3) {//乐听头条
|
||||
int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
|
||||
int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
|
||||
String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName); //新闻title
|
||||
String artist = intent.getStringExtra(LeTingFieldConstants.artist); //新闻来源,赋值给singer mediaSinger
|
||||
String cover = intent.getStringExtra(LeTingFieldConstants.cover); //封面
|
||||
|
||||
mMediaInfoData.setType(type);
|
||||
mMediaInfoData.setPlayState(playState);
|
||||
mMediaInfoData.setMaxTime(maxTime);
|
||||
mMediaInfoData.setCurTime(curTime);
|
||||
mMediaInfoData.setMediaName(mediaName); //新闻标题
|
||||
mMediaInfoData.setMediaSinger(artist); //新闻来源
|
||||
mMediaInfoData.setMediaImg(cover); //新闻封面
|
||||
|
||||
mMediaInfoData.setMediaId("");//书籍的bookid int
|
||||
mMediaInfoData.setBookInfo("");
|
||||
mMediaInfoData.setMediaUrl("");
|
||||
mMediaInfoData.setLocalMedia(true);
|
||||
mMediaInfoData.setMediaType("");
|
||||
}
|
||||
|
||||
MediaInfoDataEvent event = new MediaInfoDataEvent();
|
||||
event.data = mMediaInfoData;
|
||||
// EventBus.getDefault().post(event);
|
||||
|
||||
/* try {
|
||||
if (mMediaInfoData != null) {
|
||||
ThreadPoolService.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
StorageManager.setLastListenMediaMusic(GsonUtil.jsonFromObject(mMediaInfoData));
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import com.mogo.module.media.ServiceMediaHandler;
|
||||
import com.mogo.module.media.constants.BaseUrlConstants;
|
||||
import com.mogo.module.media.model.url.UrlData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BaseUrlManager {
|
||||
|
||||
private static final List<UrlData> urlEntityList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
urlEntityList.add( getDevEntity() );
|
||||
urlEntityList.add( getQaEntity() );
|
||||
urlEntityList.add( getReleaseEntity() );
|
||||
urlEntityList.add( getShowEntity() );
|
||||
}
|
||||
|
||||
private static UrlData getShowEntity() {
|
||||
return new UrlData(BaseUrlConstants.SHOW_BASE_URL,BaseUrlConstants.SHOW_BASE_URL);
|
||||
}
|
||||
|
||||
private static UrlData getQaEntity() {
|
||||
return new UrlData(BaseUrlConstants.QA_BASE_URL,BaseUrlConstants.QA_BASE_URL);
|
||||
}
|
||||
|
||||
private static UrlData getDevEntity() {
|
||||
return new UrlData(BaseUrlConstants.DEV_BASE_URL,BaseUrlConstants.DEV_BASE_URL);
|
||||
}
|
||||
|
||||
private static UrlData getReleaseEntity() {
|
||||
return new UrlData(BaseUrlConstants.RELEASE_BASE_URL,BaseUrlConstants.RELEASE_BASE_URL);
|
||||
}
|
||||
|
||||
public static String getDztBaseUrl(){
|
||||
return urlEntityList.get(ServiceMediaHandler.getCurrentEvent() - 1).getDztUrl();
|
||||
}
|
||||
|
||||
public static String getApiBaseUrl(){
|
||||
return urlEntityList.get(ServiceMediaHandler.getCurrentEvent() - 1).getApiUrl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,982 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.opengl.GLES10;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import com.mogo.module.media.constants.Constants;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
public class BitmapHelper {
|
||||
private static final String TAG = "BitmapHelper";
|
||||
|
||||
/**
|
||||
* 根据原图添加圆角
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap createRoundCornerImage(Bitmap source, float corner) {
|
||||
final Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
Bitmap target = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(target);
|
||||
RectF rect = new RectF(0, 0, source.getWidth(), source.getHeight());
|
||||
canvas.drawRoundRect(rect, corner, corner, paint);
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||
canvas.drawBitmap(source, 0, 0, paint);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static byte[] bitmapToBytes(Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
|
||||
result = bos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently(bos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use quality compression to compress bitmap's size to be smaller than a max size, and convert it to bytes thereafter.
|
||||
* Note that this method will not report compressing ratio related data.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param maxSize unit in kb
|
||||
* @return bytes after compressing bitmap to a size smaller than a specific max size.
|
||||
*/
|
||||
public static byte[] bitmapToBytes(Bitmap bitmap, int maxSize) {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int maxSizeOfBytes = maxSize * Constants.ONE_KB;
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
int fullSize = 0;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
|
||||
if (quality == 100) {
|
||||
fullSize = bos.size();
|
||||
}
|
||||
Logger.i(TAG, "quality<---->size, " + quality + "<---->" + bos.size() / 1024);
|
||||
}
|
||||
while (bos.size() > maxSizeOfBytes && (quality -= (fullSize > Constants.ONE_MB) ? 10 : 5) >= 0);
|
||||
|
||||
result = bos.toByteArray();
|
||||
|
||||
final long end = System.currentTimeMillis();
|
||||
Logger.i(TAG,
|
||||
"bitmap to bytes costs " + (end - start) + "ms, \n" +
|
||||
"bitmap full size is " + (fullSize / 1024) + "kb, \n" +
|
||||
"bitmap final size is " + (bos.size() / 1024) + "kb, \n" +
|
||||
"bitmap quality is " + quality);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently(bos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use quality compression to compress bitmap to be smaller than a specific max size.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param maxSize a specific max size which's unit is kb.
|
||||
* @return a compressed bitmap smaller than the max size.
|
||||
*/
|
||||
public static void compressBitmap(Bitmap bitmap, int maxSize, final BitmapHelper.OnCompressListener listener) {
|
||||
if (bitmap == null || bitmap.isRecycled() || listener == null) {
|
||||
return;
|
||||
}
|
||||
listener.onBeforeCompress();
|
||||
ByteArrayOutputStream bos = null;
|
||||
Bitmap target = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
int step = 5;
|
||||
int fullSize = 0;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
|
||||
if (quality == 100) {
|
||||
fullSize = bos.size();
|
||||
}
|
||||
if (quality <= 10) {
|
||||
step = 2;
|
||||
}
|
||||
}
|
||||
while (bos.size() / 1024 > maxSize && (quality -= (fullSize > Constants.ONE_MB) ? 10 : step) > 0);
|
||||
|
||||
byte[] result = bos.toByteArray();
|
||||
//target = bytesToBitmap(result);
|
||||
listener.onCompressSuccess(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// target = null;
|
||||
listener.onCompressFailed("压缩失败");
|
||||
|
||||
} finally {
|
||||
IOUtils.closeSilently(bos);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap compressBitmap(Bitmap bitmap, int maxSize) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
Bitmap target = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
|
||||
}
|
||||
while (bos.size() / 1024 > maxSize && (quality -= 5) >= 0);
|
||||
|
||||
byte[] result = bos.toByteArray();
|
||||
target = bytesToBitmap(result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
target = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently(bos);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static byte[] compress(File bitmapFile, int maxSize) {
|
||||
if (bitmapFile == null || !bitmapFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getAbsolutePath());
|
||||
int degree = readPictureDegree( bitmapFile.getAbsolutePath() );
|
||||
if ( degree != 0 ) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.reset();
|
||||
matrix.setRotate( degree );
|
||||
bitmap = Bitmap.createBitmap(bitmap,0,0, bitmap.getWidth(), bitmap.getHeight(),matrix, true);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] target = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
|
||||
}
|
||||
while (bos.size() / 1024 > maxSize && (quality -= 5) >= 0);
|
||||
|
||||
target = bos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
target = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently(bos);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an immutable bitmap from the specified byte array.
|
||||
*
|
||||
* @param b byte array of compressed image data
|
||||
* @return an immutable bitmap or null in case of exception.
|
||||
*/
|
||||
public static Bitmap bytesToBitmap(byte[] b) {
|
||||
if (b != null && b.length != 0) {
|
||||
return BitmapFactory.decodeByteArray(b, 0, b.length);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an immutable bitmap from the specified byte array.
|
||||
*
|
||||
* @param b byte array of compressed image data
|
||||
* @param options Options that control downsampling and whether the
|
||||
* image should be completely decoded, or just is size returned.
|
||||
* @return an immutable bitmap or null in case of exception.
|
||||
*/
|
||||
public static Bitmap bytesToBitmap(byte[] b, BitmapFactory.Options options) {
|
||||
if (b.length != 0) {
|
||||
return BitmapFactory.decodeByteArray(b, 0, b.length, options);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get max supported image size which will differ from different devices.
|
||||
*
|
||||
* @return max size related to the device.
|
||||
*/
|
||||
public static int getMaxSupportedImageSize() {
|
||||
int textureLimit = getMaxTextureSize();
|
||||
if (textureLimit == 0) {
|
||||
return Constants.SIZE_DEFAULT;
|
||||
} else {
|
||||
return Math.min(textureLimit, Constants.SIZE_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getMaxTextureSize2() {
|
||||
// The OpenGL texture size is the maximum size that can be drawn in an ImageView
|
||||
int[] maxSize = new int[1];
|
||||
GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
|
||||
return maxSize[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* duplicated from
|
||||
*/
|
||||
public static int computeSampleSize(InputStream is, boolean close) {
|
||||
// Just decode image size into options
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
||||
try {
|
||||
BitmapFactory.decodeStream(is, null, options);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (close) IOUtils.closeSilently(is);
|
||||
}
|
||||
|
||||
int srcWidth = options.outWidth;
|
||||
int srcHeight = options.outHeight;
|
||||
|
||||
srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
|
||||
srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;
|
||||
|
||||
int longSide = Math.max(srcWidth, srcHeight);
|
||||
int shortSide = Math.min(srcWidth, srcHeight);
|
||||
|
||||
float scale = ((float) shortSide / longSide);
|
||||
if (scale <= 1 && scale > 0.5625) {
|
||||
if (longSide < 1664) {
|
||||
return 1;
|
||||
} else if (longSide < 4990) {
|
||||
return 2;
|
||||
} else if (longSide > 4990 && longSide < 10240) {
|
||||
return 4;
|
||||
} else {
|
||||
return longSide / 1280 == 0 ? 1 : longSide / 1280;
|
||||
}
|
||||
} else if (scale <= 0.5625 && scale > 0.5) {
|
||||
return longSide / 1280 == 0 ? 1 : longSide / 1280;
|
||||
} else {
|
||||
return (int) Math.ceil(longSide / (1280.0 / scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode a bitmap's input stream to find a proper inSampleSize according to device's max supported size.
|
||||
*
|
||||
* @param is bitmap's data source
|
||||
* @param close whether to close input stream after work is done.
|
||||
* @return a proper inSampleSize
|
||||
*/
|
||||
public static int findProperInSampleSize(InputStream is, boolean close) {
|
||||
// Just decode image size into options
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
||||
try {
|
||||
BitmapFactory.decodeStream(is, null, options);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (close) IOUtils.closeSilently(is);
|
||||
}
|
||||
|
||||
int maxSize = getMaxSupportedImageSize();
|
||||
int sampleSize = 1;
|
||||
|
||||
while (options.outHeight / sampleSize > maxSize || options.outWidth / sampleSize > maxSize) {
|
||||
sampleSize = sampleSize << 1;
|
||||
}
|
||||
|
||||
Logger.i(TAG, "sample size is " + sampleSize);
|
||||
return sampleSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a picture's degree from a file.
|
||||
*
|
||||
* @param file data source of a picture
|
||||
* @return degrees range from 0 to 360
|
||||
*/
|
||||
public static int readPictureDegree(File file) {
|
||||
return readPictureDegree(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a picture's degree from a file, we use {@link ExifInterface} instead of {@link android.media.ExifInterface}
|
||||
* to avoid some unexpected bugs.
|
||||
*
|
||||
* @param filePath file's absolute path which we can read data source of a picture from.
|
||||
* @return degrees range from 0 to 360
|
||||
*/
|
||||
public static int readPictureDegree(String filePath) {
|
||||
int degree = 0;
|
||||
|
||||
try {
|
||||
ExifInterface exifInterface = new ExifInterface(filePath);
|
||||
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
degree = 90;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
degree = 180;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
degree = 270;
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Logger.i(TAG, "ExifInterface, degree is " + degree);
|
||||
|
||||
return degree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate an bitmap to a specific angle.
|
||||
*
|
||||
* @param angle target angle
|
||||
* @param bitmap data source
|
||||
* @return Returns an immutable bitmap from subset of the source bitmap,
|
||||
* transformed by the optional matrix. The new bitmap may be the
|
||||
* same object as source, or a copy may have been made. It is
|
||||
* initialized with the same density as the original bitmap.
|
||||
* <p>
|
||||
* If the source bitmap is immutable and the requested subset is the
|
||||
* same as the source bitmap itself, then the source bitmap is
|
||||
* returned and no new bitmap is created.
|
||||
*/
|
||||
public static Bitmap rotateBitmap(int angle, Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
int width = bitmap.getWidth();
|
||||
int height = bitmap.getHeight();
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.preRotate(angle);
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get picture's absolute path according to its uri.
|
||||
*
|
||||
* @param context context
|
||||
* @param uri picture's uri
|
||||
* @return absolute path of uri.
|
||||
*/
|
||||
public static String getRealPathFromUri(Context context, Uri uri) {
|
||||
int sdkVersion = Build.VERSION.SDK_INT;
|
||||
if (sdkVersion >= 19) {
|
||||
return getRealPathFromUriAboveApi19(context, uri);
|
||||
} else {
|
||||
return getRealPathFromUriBelowAPI19(context, uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default {@link BitmapFactory.Options} .
|
||||
* Note this options use rgb_565 and a proper inSampleSize in order to save memory.
|
||||
*
|
||||
* @param is data source of picture
|
||||
* @param close whether to close data source
|
||||
* @return options containing rgb_565 config and a proper inSampleSize.
|
||||
*/
|
||||
public static BitmapFactory.Options newDefaultOptions(InputStream is, boolean close) {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
options.inSampleSize = BitmapHelper.findProperInSampleSize(is, close);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save picture to local file.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param file local file to store picture.
|
||||
*/
|
||||
public static void savePicture(Bitmap bitmap, File file) {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
if (bitmap == null || file == null) {
|
||||
Logger.i(TAG, "保存失败, bitmap or file is null.");
|
||||
return;
|
||||
}
|
||||
if (file.getParentFile() != null && !file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
try {
|
||||
final FileOutputStream fos = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
|
||||
if (file.exists()) {
|
||||
Logger.i(TAG, "保存成功");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Logger.i(TAG, "saving picture costs " + (System.currentTimeMillis() - start) + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配api19以下(不包括api19),根据uri获取图片的绝对路径
|
||||
*
|
||||
* @param context 上下文对象
|
||||
* @param uri 图片的Uri
|
||||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||||
*/
|
||||
private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
|
||||
return getDataColumn(context, uri, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配api19及以上,根据uri获取图片的绝对路径
|
||||
*
|
||||
* @param context 上下文对象
|
||||
* @param uri 图片的Uri
|
||||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
|
||||
String filePath = null;
|
||||
|
||||
try {
|
||||
// 如果是document类型的 uri, 则通过document id来进行处理
|
||||
if (DocumentsContract.isDocumentUri(context, uri)) {
|
||||
String documentId = DocumentsContract.getDocumentId(uri);
|
||||
if (isMediaDocument(uri)) {
|
||||
// 使用':'分割
|
||||
String id = documentId.split(":")[1];
|
||||
String selection = MediaStore.Images.Media._ID + "=?";
|
||||
String[] selectionArgs = {id};
|
||||
filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
|
||||
} else if (isDownloadsDocument(uri)) {
|
||||
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
|
||||
filePath = getDataColumn(context, contentUri, null, null);
|
||||
}
|
||||
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
filePath = getDataColumn(context, uri, null, null);
|
||||
} else if ("file".equals(uri.getScheme())) {
|
||||
filePath = uri.getPath();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库表中的 _data 列,即返回Uri对应的文件路径
|
||||
*/
|
||||
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
|
||||
String path = null;
|
||||
String[] projection = new String[]{MediaStore.Images.Media.DATA};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
|
||||
path = cursor.getString(columnIndex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
cursor = null;
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
cursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri the Uri to check
|
||||
* @return Whether the Uri authority is MediaProvider
|
||||
*/
|
||||
private static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri the Uri to check
|
||||
* @return Whether the Uri authority is DownloadsProvider
|
||||
*/
|
||||
private static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
public static int getMaxTextureSize() {
|
||||
try {
|
||||
// Safe minimum default size
|
||||
final int IMAGE_MAX_BITMAP_DIMENSION = Constants.SIZE_DEFAULT;
|
||||
|
||||
// Get EGL Display
|
||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// Initialise
|
||||
int[] version = new int[2];
|
||||
egl.eglInitialize(display, version);
|
||||
|
||||
// Query total number of configurations
|
||||
int[] totalConfigurations = new int[1];
|
||||
egl.eglGetConfigs(display, null, 0, totalConfigurations);
|
||||
|
||||
// Query actual list configurations
|
||||
EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
|
||||
egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);
|
||||
|
||||
int[] textureSize = new int[1];
|
||||
int maximumTextureSize = 0;
|
||||
|
||||
// Iterate through all the configurations to located the maximum texture size
|
||||
for (int i = 0; i < totalConfigurations[0]; i++) {
|
||||
// Only need to check for width since opengl textures are always squared
|
||||
egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);
|
||||
|
||||
// Keep trackCustomEvent of the maximum texture size
|
||||
if (maximumTextureSize < textureSize[0])
|
||||
maximumTextureSize = textureSize[0];
|
||||
}
|
||||
|
||||
// Release
|
||||
egl.eglTerminate(display);
|
||||
|
||||
// Return largest texture size found, or default
|
||||
return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如需二次计算,请用 {@link #dip2pxF}
|
||||
*/
|
||||
private static int dip2px(Context context, float dp) {
|
||||
return (int) (convertUnitToPixel(context, TypedValue.COMPLEX_UNIT_DIP, dp) + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* dip2px的返回float版
|
||||
*
|
||||
* @see #dip2px
|
||||
*/
|
||||
private static float dip2pxF(Context context, float dp) {
|
||||
return convertUnitToPixel(context, TypedValue.COMPLEX_UNIT_DIP, dp);
|
||||
}
|
||||
|
||||
private static float px2dip(Context context, float px) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return px / scale;
|
||||
}
|
||||
|
||||
private static int px(Context context, float dp) {
|
||||
return (int) (dip2px(context, dp) + 0.5f);
|
||||
}
|
||||
|
||||
private static float convertUnitToPixel(Context context, int unit, float in) {
|
||||
return TypedValue.applyDimension(unit, in, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
private static int getScreenWidth(Context context) {
|
||||
if (context == null) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
|
||||
private static int getScreenHeight(Context context) {
|
||||
if (context == null) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
public static String bitmapToBase64(Bitmap bitmap) {
|
||||
String result = null;
|
||||
try {
|
||||
if (bitmap != null) {
|
||||
result = Base64.encodeToString(bitmapToBytes(bitmap), Base64.DEFAULT);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String bitmapArrayToBase64(byte[] data) {
|
||||
String result = null;
|
||||
try {
|
||||
if (data != null) {
|
||||
result = Base64.encodeToString(data, Base64.DEFAULT);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Bitmap base64ToBitmap(String base64Data) {
|
||||
byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);
|
||||
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在系统返回的intent中获取图片信息,并转化为uri
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public static Uri convertUri(Context context, Intent data) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return null;
|
||||
}
|
||||
Uri localUri = data.getData();
|
||||
String scheme = localUri.getScheme();
|
||||
String imagePath = "";
|
||||
if ("content".equals(scheme)) {
|
||||
String[] filePathColumns = {MediaStore.Images.Media.DATA};
|
||||
Cursor c = context.getContentResolver().query(localUri, filePathColumns, null, null, null);
|
||||
if (c != null) {
|
||||
try {
|
||||
c.moveToFirst();
|
||||
int columnIndex = c.getColumnIndex(filePathColumns[0]);
|
||||
imagePath = c.getString(columnIndex);
|
||||
c.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
c.close();
|
||||
imagePath = "";
|
||||
}
|
||||
}
|
||||
} else if ("file".equals(scheme)) {//小米4选择云相册中的图片是根据此方法获得路径
|
||||
imagePath = localUri.getPath();
|
||||
}
|
||||
if (TextUtils.isEmpty(imagePath)) {
|
||||
return localUri;
|
||||
}
|
||||
Uri uri = Uri.fromFile(new File(imagePath));
|
||||
return uri != null ? uri : localUri;
|
||||
}
|
||||
|
||||
public static Bitmap colorToBitmap(Context context,int colorResId) {// drawable 转换成bitmap
|
||||
Bitmap.Config config = Bitmap.Config.ARGB_8888;// 取drawable的颜色格式
|
||||
Bitmap bitmap = Bitmap.createBitmap(1, 1, config);// 建立对应bitmap
|
||||
bitmap.eraseColor(context.getResources().getColor(colorResId));
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static String getAlphaHexValue(float alpha) {
|
||||
String color = Integer.toHexString((int) alpha * 255);
|
||||
return TextUtils.isEmpty(color) ? color : color.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 抓取本地视频缩略图(操作可能耗时,尽量异步进行)
|
||||
*
|
||||
* @param filePath
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap getVideoThumbnail(String filePath) {
|
||||
Bitmap b = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
retriever.setDataSource(filePath);
|
||||
b = retriever.getFrameAtTime();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
} finally {
|
||||
try {
|
||||
retriever.release();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static BitmapFactory.Options getBitmapOptions(String path) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(path, options);
|
||||
return options;
|
||||
}
|
||||
|
||||
public static int calculateInSampleSize(BitmapFactory.Options options, int targetWidth, int targetHeight) {
|
||||
int height = options.outHeight;
|
||||
int width = options.outWidth;
|
||||
int size = 1;
|
||||
if (height > targetHeight || width > targetWidth) {
|
||||
int scaleHeight = Math.round((float) height / (float) targetHeight);
|
||||
int scaleWidth = Math.round((float) width / (float) targetWidth);
|
||||
size = scaleHeight > scaleWidth ? scaleHeight : scaleWidth;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public static Bitmap decodeScaleImage(String path, int targetWidth, int targetHeight) {
|
||||
BitmapFactory.Options options = getBitmapOptions(path);
|
||||
options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
|
||||
options.inJustDecodeBounds = false;
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
|
||||
int degree = readPictureDegree(path);
|
||||
Bitmap rotateBitmap;
|
||||
if (bitmap != null && degree != 0) {
|
||||
rotateBitmap = rotateBitmap(degree, bitmap);
|
||||
bitmap.recycle();
|
||||
return rotateBitmap;
|
||||
} else {
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap getImage(String fileName) {
|
||||
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = new FileInputStream(fileName);
|
||||
FileDescriptor fd = stream.getFD();
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = 1;
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFileDescriptor(fd, null, options);
|
||||
if (options.mCancel || options.outWidth == -1
|
||||
|| options.outHeight == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1.换算合适的图片缩放值,以减少对JVM太多的内存请求。
|
||||
options.inSampleSize = calculateInSampleSize(options, options.outWidth,
|
||||
options.outHeight);
|
||||
options.inJustDecodeBounds = false;
|
||||
|
||||
options.inDither = false;
|
||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
|
||||
// 2. inPurgeable 设定为 true,可以让java系统, 在内存不足时先行回收部分的内存
|
||||
options.inPurgeable = true;
|
||||
// 与inPurgeable 一起使用
|
||||
options.inInputShareable = true;
|
||||
|
||||
try {
|
||||
// 4. inNativeAlloc 属性设置为true,可以不把使用的内存算到VM里
|
||||
BitmapFactory.Options.class.getField("inNativeAlloc")
|
||||
.setBoolean(options, true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 5. 使用decodeStream 解码,则利用NDK层中,利用nativeDecodeAsset()
|
||||
// 进行解码,不用CreateBitmap
|
||||
return BitmapFactory.decodeStream(stream, null, options);
|
||||
|
||||
} catch (IOException ex) {
|
||||
Logger.e(TAG, "", ex);
|
||||
} catch (OutOfMemoryError oom) {
|
||||
Logger.e(TAG, "Unable to decode file " + fileName
|
||||
+ ". OutOfMemoryError.", oom);
|
||||
} finally {
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap convertViewToBitmap(View view) {
|
||||
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
|
||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
|
||||
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
c.drawColor(Color.WHITE);
|
||||
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
|
||||
view.draw(c);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static boolean checkBitmapIsLegal(Bitmap bitmap) {
|
||||
return bitmap != null && bitmap.getByteCount() > 0 && bitmap.getWidth() > 0 && bitmap.getHeight() > 0;
|
||||
}
|
||||
|
||||
public static File saveToTempFile(Context context,byte[] bytes) {
|
||||
if (bytes == null || bytes.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String compressPath = FileUtils.getCachePath(context);
|
||||
String md5 = Md5Utils.hexdigest(bytes);
|
||||
File tempFile = new File(compressPath, md5 + ".temp");
|
||||
|
||||
if (!tempFile.exists()) {
|
||||
tempFile.getParentFile().mkdirs();
|
||||
} else if (tempFile.length() > 0) {
|
||||
return tempFile;
|
||||
}
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
fileOutputStream = new FileOutputStream(tempFile);
|
||||
fileOutputStream.write(bytes);
|
||||
fileOutputStream.flush();
|
||||
fileOutputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert px to its equivalent sp
|
||||
* <p>
|
||||
* 将px转换为sp
|
||||
*/
|
||||
private static int px2sp(Context context, float pxValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (pxValue / fontScale + 0.5f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* convert sp to its equivalent px
|
||||
* <p>
|
||||
* 将sp转换为px
|
||||
*/
|
||||
public static int sp2px(Context context, float spValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (spValue * fontScale + 0.5f);
|
||||
}
|
||||
|
||||
public interface OnCompressListener {
|
||||
|
||||
void onCompressSuccess( byte[] data );
|
||||
|
||||
void onCompressFailed( String msg );
|
||||
|
||||
void onBeforeCompress();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.renderscript.Allocation;
|
||||
import android.renderscript.Element;
|
||||
import android.renderscript.RenderScript;
|
||||
import android.renderscript.ScriptIntrinsicBlur;
|
||||
|
||||
public class BlurImageUtils {
|
||||
public static Bitmap rsBlur(Context context, Bitmap source, int radius){
|
||||
|
||||
Bitmap inputBmp = source;
|
||||
RenderScript renderScript = RenderScript.create(context);
|
||||
|
||||
// Allocate memory for Renderscript to work with
|
||||
final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
|
||||
final Allocation output = Allocation.createTyped(renderScript,input.getType());
|
||||
// Load up an instance of the specific script that we want to use.
|
||||
ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
|
||||
scriptIntrinsicBlur.setInput(input);
|
||||
// Set the blur radius
|
||||
scriptIntrinsicBlur.setRadius(radius);
|
||||
// Start the ScriptIntrinisicBlur
|
||||
scriptIntrinsicBlur.forEach(output);
|
||||
// Copy the output to the blurred bitmap
|
||||
output.copyTo(inputBmp);
|
||||
renderScript.destroy();
|
||||
|
||||
return inputBmp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Created by jay on 11/7/15.
|
||||
*/
|
||||
public class FastBlurUtil {
|
||||
/**
|
||||
* 根据imagepath获取bitmap
|
||||
*/
|
||||
/**
|
||||
* 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如:
|
||||
* A.网络路径: url="http://blog.foreverlove.us/girl2.png" ;
|
||||
* B.本地路径:url="file://mnt/sdcard/photo/image.png";
|
||||
* C.支持的图片格式 ,png, jpg,bmp,gif等等
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static int IO_BUFFER_SIZE = 2 * 1024;
|
||||
|
||||
public static Bitmap GetUrlBitmap(String url, int scaleRatio) {
|
||||
|
||||
int blurRadius = 8;//通常设置为8就行。
|
||||
if (scaleRatio <= 0) {
|
||||
scaleRatio = 10;
|
||||
}
|
||||
|
||||
|
||||
Bitmap originBitmap = null;
|
||||
InputStream in = null;
|
||||
BufferedOutputStream out = null;
|
||||
try {
|
||||
in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);
|
||||
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
|
||||
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
|
||||
copy(in, out);
|
||||
out.flush();
|
||||
byte[] data = dataStream.toByteArray();
|
||||
originBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originBitmap,
|
||||
originBitmap.getWidth() / scaleRatio,
|
||||
originBitmap.getHeight() / scaleRatio,
|
||||
false);
|
||||
Bitmap blurBitmap = doBlur(scaledBitmap, blurRadius, true);
|
||||
return blurBitmap;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
byte[] b = new byte[IO_BUFFER_SIZE];
|
||||
int read;
|
||||
while ((read = in.read(b)) != -1) {
|
||||
out.write(b, 0, read);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 把本地图片毛玻璃化
|
||||
public static Bitmap toBlur(Bitmap originBitmap, int scaleRatio) {
|
||||
// int scaleRatio = 10;
|
||||
// 增大scaleRatio缩放比,使用一样更小的bitmap去虚化可以到更好的得模糊效果,而且有利于占用内存的减小;
|
||||
int blurRadius = 6;//通常设置为8就行。
|
||||
//增大blurRadius,可以得到更高程度的虚化,不过会导致CPU更加intensive
|
||||
|
||||
/* 其中前三个参数很明显,其中宽高我们可以选择为原图尺寸的1/10;
|
||||
第四个filter是指缩放的效果,filter为true则会得到一个边缘平滑的bitmap,
|
||||
反之,则会得到边缘锯齿、pixelrelated的bitmap。
|
||||
这里我们要对缩放的图片进行虚化,所以无所谓边缘效果,filter=false。*/
|
||||
if (scaleRatio <= 0) {
|
||||
scaleRatio = 10;
|
||||
}
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originBitmap,
|
||||
originBitmap.getWidth() / scaleRatio,
|
||||
originBitmap.getHeight() / scaleRatio,
|
||||
false);
|
||||
Bitmap blurBitmap = doBlur(scaledBitmap, blurRadius, true);
|
||||
return blurBitmap;
|
||||
}
|
||||
|
||||
public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {
|
||||
|
||||
// Stack Blur v1.0 from
|
||||
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
|
||||
//
|
||||
// Java Author: Mario Klingemann <mario at quasimondo.com>
|
||||
// http://incubator.quasimondo.com
|
||||
// created Feburary 29, 2004
|
||||
// Android port : Yahel Bouaziz <yahel at kayenko.com>
|
||||
// http://www.kayenko.com
|
||||
// ported april 5th, 2012
|
||||
|
||||
// This is a compromise between Gaussian Blur and Box blur
|
||||
// It creates much better looking blurs than Box Blur, but is
|
||||
// 7x faster than my Gaussian Blur implementation.
|
||||
//
|
||||
// I called it Stack Blur because this describes best how this
|
||||
// filter works internally: it creates a kind of moving stack
|
||||
// of colors whilst scanning through the image. Thereby it
|
||||
// just has to add one new block of color to the right side
|
||||
// of the stack and remove the leftmost color. The remaining
|
||||
// colors on the topmost layer of the stack are either added on
|
||||
// or reduced by one, depending on if they are on the right or
|
||||
// on the left side of the stack.
|
||||
//
|
||||
// If you are using this algorithm in your code please add
|
||||
// the following line:
|
||||
//
|
||||
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
|
||||
|
||||
Bitmap bitmap;
|
||||
if (canReuseInBitmap) {
|
||||
bitmap = sentBitmap;
|
||||
} else {
|
||||
bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
|
||||
}
|
||||
|
||||
if (radius < 1) {
|
||||
return (null);
|
||||
}
|
||||
|
||||
int w = bitmap.getWidth();
|
||||
int h = bitmap.getHeight();
|
||||
|
||||
int[] pix = new int[w * h];
|
||||
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
|
||||
|
||||
int wm = w - 1;
|
||||
int hm = h - 1;
|
||||
int wh = w * h;
|
||||
int div = radius + radius + 1;
|
||||
|
||||
int r[] = new int[wh];
|
||||
int g[] = new int[wh];
|
||||
int b[] = new int[wh];
|
||||
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
|
||||
int vmin[] = new int[Math.max(w, h)];
|
||||
|
||||
int divsum = (div + 1) >> 1;
|
||||
divsum *= divsum;
|
||||
int dv[] = new int[256 * divsum];
|
||||
for (i = 0; i < 256 * divsum; i++) {
|
||||
dv[i] = (i / divsum);
|
||||
}
|
||||
|
||||
yw = yi = 0;
|
||||
|
||||
int[][] stack = new int[div][3];
|
||||
int stackpointer;
|
||||
int stackstart;
|
||||
int[] sir;
|
||||
int rbs;
|
||||
int r1 = radius + 1;
|
||||
int routsum, goutsum, boutsum;
|
||||
int rinsum, ginsum, binsum;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
p = pix[yi + Math.min(wm, Math.max(i, 0))];
|
||||
sir = stack[i + radius];
|
||||
sir[0] = (p & 0xff0000) >> 16;
|
||||
sir[1] = (p & 0x00ff00) >> 8;
|
||||
sir[2] = (p & 0x0000ff);
|
||||
rbs = r1 - Math.abs(i);
|
||||
rsum += sir[0] * rbs;
|
||||
gsum += sir[1] * rbs;
|
||||
bsum += sir[2] * rbs;
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
}
|
||||
}
|
||||
stackpointer = radius;
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
|
||||
r[yi] = dv[rsum];
|
||||
g[yi] = dv[gsum];
|
||||
b[yi] = dv[bsum];
|
||||
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = stack[stackstart % div];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
|
||||
if (y == 0) {
|
||||
vmin[x] = Math.min(x + radius + 1, wm);
|
||||
}
|
||||
p = pix[yw + vmin[x]];
|
||||
|
||||
sir[0] = (p & 0xff0000) >> 16;
|
||||
sir[1] = (p & 0x00ff00) >> 8;
|
||||
sir[2] = (p & 0x0000ff);
|
||||
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = stack[(stackpointer) % div];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
|
||||
yi++;
|
||||
}
|
||||
yw += w;
|
||||
}
|
||||
for (x = 0; x < w; x++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
yp = -radius * w;
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
yi = Math.max(0, yp) + x;
|
||||
|
||||
sir = stack[i + radius];
|
||||
|
||||
sir[0] = r[yi];
|
||||
sir[1] = g[yi];
|
||||
sir[2] = b[yi];
|
||||
|
||||
rbs = r1 - Math.abs(i);
|
||||
|
||||
rsum += r[yi] * rbs;
|
||||
gsum += g[yi] * rbs;
|
||||
bsum += b[yi] * rbs;
|
||||
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
}
|
||||
|
||||
if (i < hm) {
|
||||
yp += w;
|
||||
}
|
||||
}
|
||||
yi = x;
|
||||
stackpointer = radius;
|
||||
for (y = 0; y < h; y++) {
|
||||
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
|
||||
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
|
||||
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = stack[stackstart % div];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
|
||||
if (x == 0) {
|
||||
vmin[y] = Math.min(y + r1, hm) * w;
|
||||
}
|
||||
p = x + vmin[y];
|
||||
|
||||
sir[0] = r[p];
|
||||
sir[1] = g[p];
|
||||
sir[2] = b[p];
|
||||
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = stack[stackpointer];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
|
||||
yi += w;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
|
||||
|
||||
return (bitmap);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.mogo.module.media.constants.Constants;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FileUtils {
|
||||
private static final String[] IMAGE_SUPPORT_EXTS = {"png", "jpg", "jpeg", "bmp"};
|
||||
private static final String[] VIDEO_SUPPORT_EXTS = {"mp4"};
|
||||
|
||||
public static String fileToBase64(File file) {
|
||||
String base64 = null;
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
byte[] bytes = new byte[in.available()];
|
||||
int length = in.read(bytes);
|
||||
base64 = Base64.encodeToString(bytes, 0, length, Base64.DEFAULT);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently(in);
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建一个用于拍照图片输出路径的Uri (FileProvider)
|
||||
*/
|
||||
public static Uri getUriForFile(Context context, File file) {
|
||||
return FileProvider.getUriForFile(context, getFileProviderName(context), file);
|
||||
}
|
||||
|
||||
public static String getFileProviderName(Context context) {
|
||||
return context.getPackageName() + ".fileprovider";
|
||||
}
|
||||
|
||||
/**
|
||||
* 把Uri 解析出文件绝对路径
|
||||
*/
|
||||
public static String parseOwnUri(Context context, Uri uri) {
|
||||
if (uri == null || uri.getPath() == null) return null;
|
||||
String path;
|
||||
if (TextUtils.equals(uri.getAuthority(), getFileProviderName(context))) {
|
||||
path = new File(uri.getPath()).getAbsolutePath();
|
||||
} else {
|
||||
path = uri.getPath();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static void copy(final String from, final String to, final FileCopyListener listener) {
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
File file = null;
|
||||
try {
|
||||
file = new File(from);
|
||||
} catch (Exception e) {
|
||||
if (listener != null) {
|
||||
listener.onFail(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!file.isFile()) {
|
||||
if (listener != null) {
|
||||
listener.onFail(new Exception(String.format("%s is not a file", from)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!file.exists()) {
|
||||
if (listener != null) {
|
||||
listener.onFail(new FileNotFoundException(String.format("%s is not exists.", from)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
long fileSize = file.length();
|
||||
long process = 0;
|
||||
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
|
||||
byte[] buff = new byte[1024];
|
||||
int rc = 0;
|
||||
|
||||
File toFile = new File(to);
|
||||
if (!toFile.getParentFile().exists()) {
|
||||
toFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(toFile);
|
||||
|
||||
while ((rc = fis.read(buff, 0, 1024)) > 0) {
|
||||
process += rc;
|
||||
fos.write(buff, 0, rc);
|
||||
if (listener != null) {
|
||||
listener.onProcess(((int) (((float) process) * 100 / fileSize)));
|
||||
}
|
||||
}
|
||||
|
||||
fos.flush();
|
||||
fos.close();
|
||||
fis.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
if (listener != null) {
|
||||
listener.onFail(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onFinish(to);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void copy(final InputStream is, final String to, final FileCopyListener listener) {
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
long fileSize = is.available();
|
||||
long process = 0;
|
||||
|
||||
byte[] buff = new byte[1024];
|
||||
int rc = 0;
|
||||
|
||||
File toFile = new File(to);
|
||||
if (!toFile.getParentFile().exists()) {
|
||||
toFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(toFile);
|
||||
|
||||
while ((rc = is.read(buff, 0, 1024)) > 0) {
|
||||
process += rc;
|
||||
fos.write(buff, 0, rc);
|
||||
if (listener != null) {
|
||||
listener.onProcess(((int) (((float) process) * 100 / fileSize)));
|
||||
}
|
||||
}
|
||||
|
||||
fos.flush();
|
||||
fos.close();
|
||||
is.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
if (listener != null) {
|
||||
listener.onFail(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onFinish(to);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public interface FileCopyListener {
|
||||
void onStart();
|
||||
|
||||
void onFail(Exception e);
|
||||
|
||||
void onProcess(@IntRange(from = 0, to = 100) int process);
|
||||
|
||||
void onFinish(String toPath);
|
||||
}
|
||||
|
||||
public static void createPath(String file) {
|
||||
File f = new File(file);
|
||||
if (f.exists()) {
|
||||
return;
|
||||
}
|
||||
if (!f.getParentFile().exists()) {
|
||||
f.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] read(String file) {
|
||||
|
||||
File f = new File(file);
|
||||
if (!f.exists() || f.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
byte[] buffer = new byte[((int) f.length())];
|
||||
fis.read(buffer);
|
||||
IOUtils.closeSilently(fis);
|
||||
return buffer;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toBase64(byte[] buffer) {
|
||||
if (buffer == null || buffer.length == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Base64.encodeToString(buffer, Base64.DEFAULT);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取不带扩展名的文件名
|
||||
*
|
||||
* @param filePath
|
||||
* @return
|
||||
*/
|
||||
public static String getFileNameNoEx(String filePath) {
|
||||
try {
|
||||
if ((filePath != null) && (filePath.length() > 0)) {
|
||||
int index = filePath.lastIndexOf("/") + 1;
|
||||
int dot = filePath.lastIndexOf(".");
|
||||
if ((dot > -1) && (dot < (filePath.length()))) {
|
||||
if (index != -1 && index < filePath.length()) {
|
||||
return filePath.substring(index, dot);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filePath;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public static boolean isVideo(String path) {
|
||||
String extName = FileUtils.getExtensionName(path);
|
||||
if (TextUtils.isEmpty(extName)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.asList(VIDEO_SUPPORT_EXTS).contains(extName.toLowerCase());
|
||||
}
|
||||
|
||||
public static boolean isImage(String filePath) {
|
||||
String extName = FileUtils.getExtensionName(filePath);
|
||||
if (TextUtils.isEmpty(extName)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.asList(IMAGE_SUPPORT_EXTS).contains(extName.toLowerCase());
|
||||
}
|
||||
|
||||
public static boolean isExist(String path) {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File file = new File(path);
|
||||
return file.exists() && file.isFile() && getFileSize(path) != 0;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isExist(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return file.exists();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean deleteFile(String path) {
|
||||
try {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
return false;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
return file.delete();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static long getFileSize(String path) {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return new File(path).length();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Uri getFileProviderUri(Context context, File file) {
|
||||
Uri data;
|
||||
// 判断版本大于等于7.0
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
data = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
|
||||
} else {
|
||||
data = Uri.fromFile(file);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void saveBitmapToCache(Bitmap bitmap, String path, OnBitmapToLocalListener onBitmapToLocalListener) {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
fileOutputStream = new FileOutputStream(path);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
|
||||
fileOutputStream.close();
|
||||
if (onBitmapToLocalListener != null) {
|
||||
onBitmapToLocalListener.saveSuccess(path);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (onBitmapToLocalListener != null) {
|
||||
onBitmapToLocalListener.saveFailed();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getDiskCacheDir(Context context, String uniqueName) {
|
||||
String cachePath;
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment
|
||||
.getExternalStorageState()) && context.getExternalCacheDir() != null) {
|
||||
cachePath = context.getExternalCacheDir().getPath();
|
||||
} else {
|
||||
cachePath = context.getCacheDir().getPath();
|
||||
}
|
||||
return new File(cachePath + File.separator + uniqueName);
|
||||
}
|
||||
|
||||
public static String getCachePath(Context context) {
|
||||
File targetFile = getDiskCacheDir(context, Constants.IMAGE_COMPRESS_PATH);
|
||||
if (!targetFile.exists()) {
|
||||
targetFile.mkdirs();
|
||||
}
|
||||
return targetFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static String formatFileSize(long size) {
|
||||
DecimalFormat formatter = new DecimalFormat("####.00");
|
||||
if (size < 1024) {
|
||||
return size + "B";
|
||||
} else if (size < 1024 * 1024L) {
|
||||
float kbSize = size / 1024f;
|
||||
return formatter.format(kbSize) + "KB";
|
||||
} else if (size < 1024 * 1024 * 1024L) {
|
||||
float mbSize = size / 1024f / 1024f;
|
||||
return formatter.format(mbSize) + "MB";
|
||||
} else if (size < 1024 * 1024 * 1024 * 1024L) {
|
||||
float gbSize = size / 1024f / 1024f / 1024f;
|
||||
return formatter.format(gbSize) + "GB";
|
||||
} else {
|
||||
return "0KB";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileWithEx(String filePath) {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
return "";
|
||||
}
|
||||
int index = filePath.lastIndexOf("/");
|
||||
try {
|
||||
return filePath.substring(index + 1, filePath.length());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void writeToFile(String content, String logPath) {
|
||||
|
||||
if (TextUtils.isEmpty(logPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = logPath + "/location.txt";//log日志名,使用时间命名,保证不重复
|
||||
//如果父路径不存在
|
||||
File file = new File(logPath);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();//创建父路径
|
||||
}
|
||||
|
||||
FileOutputStream fos;//FileOutputStream会自动调用底层的close()方法,不用关闭
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
fos = new FileOutputStream(fileName, true);//这里的第二个参数代表追加还是覆盖,true为追加,flase为覆盖
|
||||
bw = new BufferedWriter(new OutputStreamWriter(fos));
|
||||
bw.write(content + "\n");
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (bw != null) {
|
||||
bw.close();//关闭缓冲流
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*
|
||||
* @param filePath
|
||||
* @return
|
||||
*/
|
||||
public static String getExtensionName(String filePath) {
|
||||
if ((filePath != null) && (filePath.length() > 0)) {
|
||||
int dot = filePath.lastIndexOf('.');
|
||||
if ((dot > -1) && (dot < (filePath.length() - 1))) {
|
||||
return filePath.substring(dot + 1);
|
||||
}
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class IOUtils {
|
||||
|
||||
public static byte[] inputToBytes(InputStream is) {
|
||||
if(is == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try{
|
||||
bos = new ByteArrayOutputStream();
|
||||
byte[] buff = new byte[100];
|
||||
int rc = 0;
|
||||
while ((rc = is.read(buff, 0, 100)) > 0) {
|
||||
bos.write(buff, 0, rc);
|
||||
}
|
||||
|
||||
result = bos.toByteArray();
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
}finally {
|
||||
closeSilently(bos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void closeSilently(@Nullable Closeable c) {
|
||||
if (c == null) return;
|
||||
try {
|
||||
c.close();
|
||||
c = null;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class Md5Utils {
|
||||
|
||||
private static final char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
public static String hexdigest(String string) {
|
||||
String s = null;
|
||||
|
||||
try {
|
||||
s = hexdigest(string.getBytes());
|
||||
} catch (Exception var3) {
|
||||
var3.printStackTrace();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static String hexdigest(byte[] bytes) {
|
||||
String s = null;
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(bytes);
|
||||
byte[] tmp = md.digest();
|
||||
char[] str = new char[32];
|
||||
int k = 0;
|
||||
|
||||
for(int i = 0; i < 16; ++i) {
|
||||
byte byte0 = tmp[i];
|
||||
str[k++] = hexDigits[byte0 >>> 4 & 15];
|
||||
str[k++] = hexDigits[byte0 & 15];
|
||||
}
|
||||
|
||||
s = new String(str);
|
||||
} catch (Exception var8) {
|
||||
var8.printStackTrace();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import com.mogo.module.media.ServiceMediaHandler;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MediaAnalyticsUtils {
|
||||
/**
|
||||
* 统一管理打点
|
||||
*/
|
||||
public static void track(String id, HashMap<String ,Object> map){
|
||||
Logger.d("MediaAnalyticsUtils","addLogger "+id);
|
||||
ServiceMediaHandler.getMogoAnalytis().track(id,map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,513 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
import com.mogo.module.media.ServiceMediaHandler;
|
||||
import com.mogo.module.media.model.LanRenInsertData;
|
||||
import com.mogo.module.media.model.MediaInfoData;
|
||||
import com.mogo.module.media.model.QQMediaListData;
|
||||
import com.mogo.utils.UiThreadHandler;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MusicControlBroadCast {
|
||||
|
||||
public static final String TAG = "MusicControlBroadCast";
|
||||
public static boolean OPEN = false;
|
||||
/**
|
||||
*
|
||||
* @param actionValue
|
||||
*/
|
||||
public static void sendQQMusicControl(String actionValue) {
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
Intent intent = new Intent("com.txznet.adapter.send");
|
||||
intent.putExtra("action", actionValue);
|
||||
intent.putExtra("source", "com.mogo.launcher");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d(TAG,"sendQQMusicControl "+actionValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开qq音乐
|
||||
*/
|
||||
public static void qqOpenQQMusic() {
|
||||
sendQQMusicControl("music_open");
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭qq音乐
|
||||
*/
|
||||
public static void qqCloseQQMusic() {
|
||||
sendQQMusicControl("music_exit");
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放音乐
|
||||
*/
|
||||
public static void qqPlayPauseQQMusic() {
|
||||
sendQQMusicControl("music_play_or_pause");
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐
|
||||
*/
|
||||
|
||||
public static void qqPlayQQMusic() {
|
||||
sendQQMusicControl("music_play");
|
||||
}
|
||||
/**
|
||||
* 暂停音乐
|
||||
*/
|
||||
public static void qqPauseQQMusic() {
|
||||
sendQQMusicControl("music_pause");
|
||||
}
|
||||
|
||||
/**
|
||||
* 上一首音乐
|
||||
*/
|
||||
public static void qqPreQQMusic() {
|
||||
sendQQMusicControl("music_prev");
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一首音乐
|
||||
*/
|
||||
public static void qqNextQQMusic() {
|
||||
sendQQMusicControl("music_next");
|
||||
}
|
||||
|
||||
/**
|
||||
* "music_sequential";//顺序播放
|
||||
* "music_random";//随机播放
|
||||
* "music_loopone";//单曲循环
|
||||
* "music_loopall";//列表循环
|
||||
* 修改qq 音乐播放模式
|
||||
*/
|
||||
public static void qqChangePlayModeQQMusic(String playMode) {
|
||||
sendQQMusicControl(playMode);
|
||||
}
|
||||
|
||||
//乐听新闻 actionValue 101 102
|
||||
public static void sendLeTingControl(int actionValue) {
|
||||
Intent intent = new Intent("com.zhidao.ltnews.sendplayaudio");
|
||||
intent.putExtra("controlstate", actionValue);
|
||||
intent.putExtra("source", "com.mogo.launcher");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d(TAG,"sendLeTingControl "+actionValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭乐听头条
|
||||
*/
|
||||
public static void newsCloseLeTing() {
|
||||
sendLeTingControl(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放乐听头条
|
||||
*/
|
||||
public static void newsPlayPauseLeTing() {
|
||||
sendLeTingControl(101);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐乐听头条
|
||||
*/
|
||||
public static void newsPlayLeTing() {
|
||||
sendLeTingControl(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停音乐乐听头条
|
||||
*/
|
||||
public static void newsPauseLeTing() {
|
||||
sendLeTingControl(101);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上一首音乐乐听头条
|
||||
*/
|
||||
public static void newsPreLeTing() {
|
||||
sendLeTingControl(103);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一首音乐乐听头条
|
||||
*/
|
||||
public static void newsNextLeTing() {
|
||||
sendLeTingControl(102);
|
||||
}
|
||||
|
||||
|
||||
//懒人听书
|
||||
public static void sendLanRenControl(int actionValue) {
|
||||
Intent intent = new Intent("com.zhidao.lrts.sendplayaudio");
|
||||
intent.putExtra("controlstate", actionValue);
|
||||
intent.putExtra("source", "com.mogo.launcher");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d(TAG,"sendLanRenControl "+actionValue);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭懒人听书
|
||||
*/
|
||||
public static void newsCloseLanRen() {
|
||||
sendLanRenControl(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放懒人听书
|
||||
*/
|
||||
public static void newsPlayPauseLanRen() {
|
||||
sendLanRenControl(101);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐懒人听书
|
||||
*/
|
||||
public static void newsPlayLanRen() {
|
||||
sendLanRenControl(101);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停音乐懒人听书
|
||||
*/
|
||||
public static void newsPauseLanRen() {
|
||||
sendLanRenControl(101);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上一首音乐懒人听书
|
||||
*/
|
||||
public static void newsPreLanRen() {
|
||||
sendLanRenControl(103);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一首音乐懒人听书
|
||||
*/
|
||||
public static void newsNextLanRen() {
|
||||
sendLanRenControl(102);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qq 音乐添加进播放列表
|
||||
*/
|
||||
public static void addQQMusicPlayList(ArrayList<QQMediaListData> list) {
|
||||
Intent intent = new Intent("com.txznet.adapter.send");
|
||||
intent.putExtra("musicAddList", GsonUtil.jsonFromObject(list));
|
||||
intent.putExtra("action","share_list");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d(TAG,"addQQMusicPlayList ");
|
||||
}
|
||||
|
||||
/**
|
||||
* qq 音乐添加进播放列表
|
||||
*/
|
||||
public static void addQQMusicShareListPlayList(ArrayList<MarkerShareMusic> shareList) {
|
||||
ArrayList<QQMediaListData> list = new ArrayList<>();
|
||||
for (MarkerShareMusic shareMusic:shareList){
|
||||
if (shareMusic == null || shareMusic.getShareType() != 1)continue;
|
||||
QQMediaListData data = new QQMediaListData();
|
||||
data.setMediaImgUrl(shareMusic.getMediaImg() != null ? shareMusic.getMediaImg():"");
|
||||
data.setMediaMid(shareMusic.getMediaId() != null ? shareMusic.getMediaId():"");
|
||||
data.setMediaSinger(shareMusic.getMediaSinger() != null ? shareMusic.getMediaSinger():"");
|
||||
data.setMediaName(shareMusic.getMediaName() != null ? shareMusic.getMediaName():"");
|
||||
data.setMediaUrl(shareMusic.getMediaUrl() != null ? shareMusic.getMediaUrl() :"");
|
||||
list.add(data);
|
||||
}
|
||||
String jsonaddList = "";
|
||||
try {
|
||||
jsonaddList = GsonUtil.jsonFromObject(list);
|
||||
Intent intent = new Intent("com.txznet.adapter.send");
|
||||
intent.putExtra("musicAddList", jsonaddList);
|
||||
intent.putExtra("action","share_list");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d(TAG,"addQQMusicShareListPlayList "+(list != null ?list.size():"null")+" "+jsonaddList);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 懒人听书进播放列表
|
||||
*/
|
||||
public static void controlLanRenPlay(LanRenInsertData data) {
|
||||
// Intent intent = new Intent("com.zhidao.lrts.sendplayaudio");
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.lrts");
|
||||
intent.putExtra("bookinfo", GsonUtil.jsonFromObject(data));
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 懒人听书添加列表
|
||||
* @param jsonStr
|
||||
*/
|
||||
public static void controlLanRenPlay(String jsonStr){
|
||||
Logger.d(TAG,"controlLanRenPlay "+jsonStr);
|
||||
if (TextUtils.isEmpty(jsonStr))return;
|
||||
//Intent intent = new Intent("com.zhidao.lrts.sendplayaudio");
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.lrts");
|
||||
intent.putExtra("bookinfo", jsonStr);
|
||||
intent.putExtra("acceptType", 1000);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 懒人听书后台播放
|
||||
* @param
|
||||
*/
|
||||
public static void controlLanRenPlayBack(){
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.lrts");
|
||||
intent.putExtra("acceptType", 1001);
|
||||
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放新闻,不需要打开app
|
||||
* @param
|
||||
*/
|
||||
public static void sendPlayNews(String jsonStr){
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
Logger.d(TAG,"sendPlayNews "+jsonStr);
|
||||
if (TextUtils.isEmpty(jsonStr))return;
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.ltnews");
|
||||
intent.putExtra("news", jsonStr);
|
||||
intent.putExtra("insertType", 1000);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取付费情况
|
||||
*/
|
||||
public static void getNewsPayInfoState(){
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.ltnews");
|
||||
intent.putExtra("insertType", 1002);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放类型新闻,不需要打开app
|
||||
* @param
|
||||
*/
|
||||
public static void sendPlayTypeNews(String category){
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
Logger.d(TAG,"sendPlayNews "+category);
|
||||
if (TextUtils.isEmpty(category))return;
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.ltnews");
|
||||
intent.putExtra("category", category.replace("新闻",""));
|
||||
intent.putExtra("insertType", 1001);
|
||||
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放类型新闻,需要打开app
|
||||
* @param
|
||||
*/
|
||||
public static void sendPlayTypeNewsOpenApp(String type){
|
||||
if (TextUtils.isEmpty(type))return;
|
||||
Logger.d(TAG,"sendPlayNews2 "+type);
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("android.intent.action.VIEW");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setData(Uri.parse("letingschema://playNews?category="+type.replace("新闻","")));
|
||||
AbsMogoApplication.getApp().startActivity(intent);
|
||||
}
|
||||
|
||||
//2 为书籍听书,3 为新闻,1 为qq音乐
|
||||
public static void clickMarkerSendData(MarkerShareMusic markerShareMusic){
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (markerShareMusic != null){
|
||||
if (markerShareMusic.getShareType() == 1){
|
||||
ArrayList<QQMediaListData> list = new ArrayList<>();
|
||||
QQMediaListData data = new QQMediaListData();
|
||||
data.setMediaUrl(markerShareMusic.getMediaUrl());
|
||||
data.setMediaName(markerShareMusic.getMediaName());
|
||||
data.setMediaSinger(markerShareMusic.getMediaSinger());
|
||||
data.setMediaMid(markerShareMusic.getMediaId());
|
||||
data.setMediaImgUrl(markerShareMusic.getMediaImg());
|
||||
list.add(data);
|
||||
addQQMusicPlayList(list);
|
||||
}else if (markerShareMusic.getShareType() == 2){
|
||||
String bookJson = markerShareMusic.getBookInfo();
|
||||
controlLanRenPlay(bookJson);
|
||||
}else if (markerShareMusic.getShareType() == 3){
|
||||
String bookJson = markerShareMusic.getBookInfo();
|
||||
sendPlayNews(bookJson);
|
||||
}
|
||||
|
||||
UiThreadHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sendGetMusicPlayStateBroadcast();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//2 为书籍听书,3 为新闻,1 为qq音乐
|
||||
public static void listeningSendData(MediaInfoData markerShareMusic){
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (markerShareMusic != null){
|
||||
if (markerShareMusic.getType() == 1){
|
||||
ArrayList<QQMediaListData> list = new ArrayList<>();
|
||||
QQMediaListData data = new QQMediaListData();
|
||||
data.setMediaUrl(markerShareMusic.getMediaUrl());
|
||||
data.setMediaName(markerShareMusic.getMediaName());
|
||||
data.setMediaSinger(markerShareMusic.getMediaSinger());
|
||||
data.setMediaMid(markerShareMusic.getMediaId());
|
||||
data.setMediaImgUrl(markerShareMusic.getMediaImg());
|
||||
list.add(data);
|
||||
addQQMusicPlayList(list);
|
||||
}else if (markerShareMusic.getType() == 2){
|
||||
String bookJson = markerShareMusic.getBookInfo();
|
||||
controlLanRenPlay(bookJson);
|
||||
}else if (markerShareMusic.getType() == 3){
|
||||
String newsJson = markerShareMusic.getBookInfo();
|
||||
sendPlayNews(newsJson);
|
||||
}
|
||||
|
||||
UiThreadHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sendGetMusicPlayStateBroadcast();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
public static void commandPre(int type) {
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (type == 1) {
|
||||
qqPreQQMusic();
|
||||
} else if (type == 2) {
|
||||
newsPreLanRen();
|
||||
} else if (type == 3) {
|
||||
newsPreLeTing();
|
||||
}
|
||||
}
|
||||
|
||||
public static void commandNext(int type) {
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (type == 1) {
|
||||
qqNextQQMusic();
|
||||
} else if (type == 2) {
|
||||
newsNextLanRen();
|
||||
} else if (type == 3) {
|
||||
newsNextLeTing();
|
||||
}
|
||||
}
|
||||
|
||||
public static void commandPlayPause(int type,int play) {
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (type == 1) {
|
||||
if (play == 1){
|
||||
qqPauseQQMusic();
|
||||
}else{
|
||||
qqPlayQQMusic();
|
||||
}
|
||||
} else if (type == 2) {
|
||||
newsPlayPauseLanRen();
|
||||
} else if (type == 3) {
|
||||
newsPlayPauseLeTing();
|
||||
}
|
||||
}
|
||||
|
||||
public static void openMediaApp(int type) {
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
if (type == 1) {
|
||||
SkipToAppUtils.SkipToQQMusic();
|
||||
} else if (type == 2) {
|
||||
SkipToAppUtils.SkipToLrListen();
|
||||
} else if (type == 3) {
|
||||
SkipToAppUtils.SkipToLtNews();
|
||||
}
|
||||
}
|
||||
|
||||
public static void qqMusicSearch(){
|
||||
Intent intent = new Intent("com.txznet.adapter.send");
|
||||
intent.putExtra("music_model","{\"field\":1,\"text\":\"我要听周杰伦的歌\",\"title\":\"\",\"keywords\":[],\"artist\":[\"周杰伦\"],\"album\":\"\"}");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public static void sendGetMusicPlayStateBroadcast(){
|
||||
if (OPEN && ServiceMediaHandler.getMogoNavi().isNaviing())return;
|
||||
Intent intent = new Intent("com.zhidao.mediacenter.getaudioinfo");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
Logger.d("MusicControlBroadCast===","sendGetMusicPlayStateBroadcast");
|
||||
}
|
||||
|
||||
public static MediaInfoData getHisMedia() {
|
||||
String lastMediaInfo = StorageManager.getLastListenMediaMusic();
|
||||
if (!TextUtils.isEmpty(lastMediaInfo)){
|
||||
MediaInfoData sMediaInfoData = GsonUtil.objectFromJson(lastMediaInfo, MediaInfoData.class);
|
||||
if (sMediaInfoData != null){
|
||||
sMediaInfoData.setPlayState(0);
|
||||
return sMediaInfoData;
|
||||
}
|
||||
}
|
||||
|
||||
// return null;
|
||||
MediaInfoData mediaInfoData = new MediaInfoData();
|
||||
mediaInfoData.setMediaId("001jiOrk2g389Y");
|
||||
mediaInfoData.setBookInfo("");
|
||||
mediaInfoData.setType(1);
|
||||
mediaInfoData.setMediaName("恭喜发财 (广场舞)");
|
||||
mediaInfoData.setMediaSinger("刘德华");
|
||||
mediaInfoData.setMediaType("物流派");
|
||||
mediaInfoData.setPlayState(0);
|
||||
mediaInfoData.setLocalMedia(false);
|
||||
mediaInfoData.setCurTime(0);
|
||||
mediaInfoData.setMaxTime(410*1000);
|
||||
mediaInfoData.setMediaUrl("http://isure.stream.qqmusic.qq.com/C200000s2wCd3pzdnA.m4a?guid=2000001271&vkey=8CE1A876F5079A6E4E9BCB8306252EF152F3D4F237B3BF4C1450B50BA7E065D3D55A0735FD2E957B129E83FF7D7D5D398479D53FE2171DF0&uin=&fromtag=50");
|
||||
mediaInfoData.setMediaImg("http://music.qq.com/musicbox/img/uccpic_error.jpg");
|
||||
return mediaInfoData;//刘德华的恭喜发财
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制QQ音乐播放某人的歌
|
||||
*/
|
||||
public static void playSomeBodyMusic(String musicModel){
|
||||
Intent intent = new Intent("com.txznet.adapter.send");
|
||||
intent.putExtra("music_model", musicModel);
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public static void mediaCenterBroadcast(){
|
||||
Intent intent = new Intent("com.mogo.launcher.media.card.center");
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送是否可以分享
|
||||
* @param canshare 是否可以分享 true 可以分享 false 不可分享
|
||||
* @param auth 是否授权 1:已授权 0:未授权 isShare 1:有可分享数据, 0:无可分享数据
|
||||
* @param notType 不能分享的类型 1 2 3
|
||||
* @param notWhy 不能分享的原因 1 没有可以分享的音频 2 媒体卡片不再C位 3 未授权
|
||||
*/
|
||||
public static void ifCanShare(boolean canshare,boolean auth,int notType,String notWhy){
|
||||
Logger.d(TAG,"ifCanShare "+canshare);
|
||||
Intent intent = new Intent("com.mogo.launcher.media.canshare");
|
||||
intent.putExtra("isShare", canshare?"1":"0");
|
||||
intent.putExtra("authResult", auth?"1":"0");
|
||||
if (!canshare){
|
||||
intent.putExtra("notType", notType);
|
||||
intent.putExtra("notWhy", notWhy);
|
||||
}
|
||||
|
||||
AbsMogoApplication.getApp().sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
public interface OnBitmapToLocalListener {
|
||||
void saveSuccess(String path);
|
||||
void saveFailed();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
public interface OnCompressListener {
|
||||
void onCompressSuccess(byte[] data);
|
||||
|
||||
void onCompressFailed(String msg);
|
||||
|
||||
void onBeforeCompress();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
|
||||
public class SkipToAppUtils {
|
||||
/**
|
||||
* 跳转到懒人听书
|
||||
*/
|
||||
public static void SkipToLrListen() {
|
||||
if (Utils.isActivityExits("com.zhidao.lrts",
|
||||
"com.zhidao.lrts.main.MainActivity")){
|
||||
try {
|
||||
Intent intent = new Intent();
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ComponentName comp = new ComponentName("com.zhidao.lrts",
|
||||
"com.zhidao.lrts.main.MainActivity");
|
||||
intent.setComponent(comp);
|
||||
AbsMogoApplication.getApp().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到乐听新闻
|
||||
*/
|
||||
public static void SkipToLtNews() {
|
||||
if (Utils.isActivityExits("com.zhidao.ltnews",
|
||||
"com.zhidao.ltnews.main.MainActivity")){
|
||||
try {
|
||||
Intent intent = new Intent();
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ComponentName comp = new ComponentName("com.zhidao.ltnews",
|
||||
"com.zhidao.ltnews.main.MainActivity");
|
||||
intent.setComponent(comp);
|
||||
AbsMogoApplication.getApp().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到QQ音乐
|
||||
*/
|
||||
public static void SkipToQQMusic() {
|
||||
if (Utils.isActivityExits("com.pvetec.musics",
|
||||
"com.pvetec.musics.activity.MainActivity")){
|
||||
try {
|
||||
Intent intent = new Intent();
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ComponentName comp = new ComponentName("com.pvetec.musics",
|
||||
"com.pvetec.musics.activity.MainActivity");
|
||||
intent.setComponent(comp);
|
||||
AbsMogoApplication.getApp().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.module.media.constants.Constants;
|
||||
import com.mogo.utils.storage.SharedPrefsMgr;
|
||||
import com.mogo.utils.storage.lrucache.DiskCacheManager;
|
||||
|
||||
public class StorageManager {
|
||||
|
||||
public static void setShowPushShareTime(String time){
|
||||
SharedPrefsMgr.getInstance( AbsMogoApplication.getApp() ).putString(Constants.SHOW_SHARE_PUSH_TIME,time);
|
||||
}
|
||||
|
||||
public static String getShowPushShareTime(){
|
||||
return SharedPrefsMgr.getInstance( AbsMogoApplication.getApp() ).getString( Constants.SHOW_SHARE_PUSH_TIME);
|
||||
}
|
||||
|
||||
public static String getLastListenMediaMusic(){
|
||||
return new DiskCacheManager(AbsMogoApplication.getApp(), Constants.MEDIA_UNIQUE_NAME).getString(Constants.LAST_TIME_LISTEN_MEDIA_MUSIC);
|
||||
}
|
||||
|
||||
public static void setLastListenMediaMusic(String json){
|
||||
new DiskCacheManager(AbsMogoApplication.getApp(), Constants.MEDIA_UNIQUE_NAME).put(Constants.LAST_TIME_LISTEN_MEDIA_MUSIC, json);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mogo.utils.DateTimeUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by congtaowang on 2018/10/19.
|
||||
*/
|
||||
public class TimeUtils {
|
||||
|
||||
public static String parseYMD(long timestamp ) {
|
||||
return parse( DateTimeUtils.yyyyMMdd, timestamp );
|
||||
}
|
||||
|
||||
public static String parse(String pattern, long timestamp ) {
|
||||
if ( TextUtils.isEmpty( pattern ) ) {
|
||||
pattern = DateTimeUtils.yyyyMMdd;
|
||||
}
|
||||
try {
|
||||
return new SimpleDateFormat( pattern ).format( new Date( timestamp ) );
|
||||
} catch ( Exception e ) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//两个时间戳是否是同一天
|
||||
public static boolean isSameData(String currentTime, String lastTime) {
|
||||
if (TextUtils.isEmpty(currentTime)) currentTime = "0";
|
||||
if (TextUtils.isEmpty(lastTime)) lastTime = "0";
|
||||
try {
|
||||
Calendar nowCal = Calendar.getInstance();
|
||||
Calendar dataCal = Calendar.getInstance();
|
||||
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Long nowLong = new Long(currentTime);
|
||||
Long dataLong = new Long(lastTime);
|
||||
String data1 = df1.format(nowLong);
|
||||
String data2 = df2.format(dataLong);
|
||||
java.util.Date now = df1.parse(data1);
|
||||
java.util.Date date = df2.parse(data2);
|
||||
nowCal.setTime(now);
|
||||
dataCal.setTime(date);
|
||||
return isSameDay(nowCal, dataCal);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
|
||||
if(cal1 != null && cal2 != null) {
|
||||
return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
|
||||
&& cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
|
||||
&& cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.module.media.R;
|
||||
import com.mogo.utils.WindowUtils;
|
||||
|
||||
public class ToastHelper {
|
||||
private static View toastView;
|
||||
private static ImageView imageView;
|
||||
private static TextView textView;
|
||||
private static Toast toast;
|
||||
|
||||
private ToastHelper() {
|
||||
}
|
||||
|
||||
private static void createToast(Context context) {
|
||||
toastView = LayoutInflater.from(context).inflate(R.layout.module_media_share_toast_view, (ViewGroup) null);
|
||||
FrameLayout frameLayout = toastView.findViewById(R.id.module_media_toast_inner);
|
||||
FrameLayout.LayoutParams vlp = new FrameLayout.LayoutParams(WindowUtils.getScreenWidth(context), WindowUtils.getScreenHeight(context));
|
||||
frameLayout.setLayoutParams(vlp);
|
||||
frameLayout.setPadding(0,0,0,WindowUtils.getStatusBarHeight(context));
|
||||
imageView = (ImageView) toastView.findViewById(R.id.imgViewIcon);
|
||||
textView = (TextView) toastView.findViewById(R.id.txtViewContent);
|
||||
toast = new Toast(context);
|
||||
toast.setView(toastView);
|
||||
toast.setGravity(1, 0, 0);
|
||||
}
|
||||
|
||||
public static void showShortSuccess(Context context, String msg) {
|
||||
context = context.getApplicationContext();
|
||||
if (toast == null) {
|
||||
createToast(context);
|
||||
}
|
||||
|
||||
imageView.setImageResource(R.drawable.module_media_share_success);
|
||||
textView.setText(msg);
|
||||
toast.setDuration(Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
public static void showShortError(Context context, String msg) {
|
||||
context = context.getApplicationContext();
|
||||
if (toast == null) {
|
||||
createToast(context);
|
||||
}
|
||||
|
||||
imageView.setImageResource(R.drawable.module_media_share_fail);
|
||||
textView.setText(msg);
|
||||
toast.setDuration(Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
public static void cancel() {
|
||||
if (toast != null) {
|
||||
if (AbsMogoApplication.getApp() != null) {
|
||||
new Handler(AbsMogoApplication.getApp().getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (toast != null)
|
||||
toast.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Toast customToast(Context context,
|
||||
@LayoutRes int layout,
|
||||
@IdRes int msgTextViewId,
|
||||
int duration,
|
||||
CharSequence message) {
|
||||
Toast toast = new Toast(context);
|
||||
final View view = LayoutInflater.from(context).inflate(layout, null);
|
||||
TextView msgView = view.findViewById(msgTextViewId);
|
||||
if (msgView != null) {
|
||||
msgView.setText(message);
|
||||
}
|
||||
toast.setView(view);
|
||||
toast.setDuration(duration);
|
||||
toast.setGravity(Gravity.CENTER, 0, 0);
|
||||
return toast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
package com.mogo.module.media.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.module.media.R;
|
||||
import com.mogo.module.media.constants.Constants;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* 验证手机格式
|
||||
*/
|
||||
public static boolean isMobilePhone( String mobiles ) {
|
||||
String telRegex = "[1]\\d{10}";
|
||||
if ( TextUtils.isEmpty( mobiles ) ) return false;
|
||||
else return mobiles.matches( telRegex );
|
||||
}
|
||||
|
||||
public static boolean isVerifyCodeRight( String code ) {
|
||||
if ( !TextUtils.isEmpty( code ) && code.trim().length() == 4 ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 格式化用于拨打的电话号码
|
||||
public static String formatPhoneNumber(String phoneNumber ) {
|
||||
String StrTmp = "tel:" + phoneNumber.replace( "-", "" ).replace( " ", "" );
|
||||
StrTmp = StrTmp.replace( "转", "p" );
|
||||
return StrTmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前点击点是否在视图中
|
||||
*/
|
||||
public static boolean isInsideView(MotionEvent event, View view ) {
|
||||
if ( view != null && event != null ) {
|
||||
float eventX = event.getRawX();
|
||||
float eventY = event.getRawY();
|
||||
|
||||
int[] contentArray = new int[2];
|
||||
|
||||
Rect contentRect = new Rect();
|
||||
view.getLocationOnScreen( contentArray );
|
||||
view.getDrawingRect( contentRect );
|
||||
contentRect.offsetTo( contentArray[0], contentArray[1] );
|
||||
|
||||
return contentRect.contains( ( int ) eventX, ( int ) eventY );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getChannel(Context appContext ) {
|
||||
String channel = "";
|
||||
try {
|
||||
final ApplicationInfo appInfo = appContext.getPackageManager().getApplicationInfo( appContext.getPackageName(), PackageManager.GET_META_DATA );
|
||||
Bundle configBundle = appInfo.metaData;
|
||||
if ( null != configBundle ) {
|
||||
channel = configBundle.getString( "com.elegant.analytics.AnalyticsConfig.Channel", "" );
|
||||
}
|
||||
} catch ( final PackageManager.NameNotFoundException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
public static File getDiskCacheDir(Context context, String uniqueName ) {
|
||||
String cachePath;
|
||||
if ( Environment.MEDIA_MOUNTED.equals( Environment
|
||||
.getExternalStorageState() ) && context.getExternalCacheDir() != null ) {
|
||||
cachePath = context.getExternalCacheDir().getPath();
|
||||
} else {
|
||||
cachePath = context.getCacheDir().getPath();
|
||||
}
|
||||
return new File( cachePath + File.separator + uniqueName );
|
||||
}
|
||||
|
||||
public static File saveBitmap(Bitmap source, String targetPath ) {
|
||||
File file = new File( targetPath, System.currentTimeMillis() + ".jpg" );
|
||||
if ( !file.getParentFile().exists() ) {
|
||||
file.mkdirs();
|
||||
}
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream( file );
|
||||
source.compress( Bitmap.CompressFormat.JPEG, 100, fos );
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch ( Exception e ) {
|
||||
return null;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public static void showKeyBoard( Context context ) {
|
||||
try {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService( Context.INPUT_METHOD_SERVICE );
|
||||
if ( imm != null ) {
|
||||
imm.toggleSoftInput( 0, InputMethodManager.HIDE_NOT_ALWAYS );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void hiddenKeyBoard(Context context, EditText editText ) {
|
||||
try {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService( Context.INPUT_METHOD_SERVICE );
|
||||
if ( imm != null ) {
|
||||
imm.hideSoftInputFromWindow( editText.getWindowToken(), 0 );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断微信是否已安装
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWeichatAvailable( Context context ) {
|
||||
final PackageManager packageManager = context.getPackageManager();// 获取packagemanager
|
||||
List<PackageInfo> pinfo = packageManager.getInstalledPackages( 0 );// 获取所有已安装程序的包信息
|
||||
if ( pinfo != null ) {
|
||||
for ( int i = 0; i < pinfo.size(); i++ ) {
|
||||
String pn = pinfo.get( i ).packageName;
|
||||
if ( pn.equals( "com.tencent.mm" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断qq是否已安装
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean isQQAvailable( Context context ) {
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> pinfo = packageManager.getInstalledPackages( 0 );
|
||||
if ( pinfo != null ) {
|
||||
for ( int i = 0; i < pinfo.size(); i++ ) {
|
||||
String pn = pinfo.get( i ).packageName;
|
||||
if ( pn.equals( "com.tencent.mobileqq" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getVersionName(Context context, String packageName ) {
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packInfo = packageManager.getPackageInfo( packageName, 0 );
|
||||
return packInfo.versionName;
|
||||
} catch ( Exception e ) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static int getVersionCode(Context context, String packageName ) {
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packInfo = packageManager.getPackageInfo( packageName, 0 );
|
||||
return packInfo.versionCode;
|
||||
} catch ( Exception e ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isActivityExits(String packageName,String classStr){
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(packageName, classStr);
|
||||
ResolveInfo resolveInfo = AbsMogoApplication.getApp().getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
if(resolveInfo != null) {
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//计算播放时间
|
||||
public static String calculateTime(int duration) {
|
||||
try {
|
||||
String time = "";
|
||||
long minute = duration / 60000;
|
||||
long seconds = duration % 60000;
|
||||
long second = Math.round((float) seconds / 1000);
|
||||
if (minute < 10) {
|
||||
time += "0";
|
||||
}
|
||||
time += minute + ":";
|
||||
if (second < 10) {
|
||||
time += "0";
|
||||
}
|
||||
time += second;
|
||||
return time;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "0:00";
|
||||
}
|
||||
|
||||
public static Integer[] getIconArray(){
|
||||
Integer[] iconArr = {
|
||||
R.drawable.module_media_music_animal_icon1
|
||||
,R.drawable.module_media_music_animal_icon2
|
||||
,R.drawable.module_media_music_animal_icon3
|
||||
,R.drawable.module_media_music_animal_icon5
|
||||
,R.drawable.module_media_music_animal_icon4
|
||||
,R.drawable.module_media_music_animal_icon6
|
||||
,R.drawable.module_media_music_animal_icon7
|
||||
,R.drawable.module_media_music_animal_icon8
|
||||
,R.drawable.module_media_music_animal_icon9
|
||||
,R.drawable.module_media_music_animal_icon10
|
||||
,R.drawable.module_media_music_animal_icon11
|
||||
,R.drawable.module_media_music_animal_icon12
|
||||
,R.drawable.module_media_music_animal_icon13
|
||||
,R.drawable.module_media_music_animal_icon14
|
||||
,R.drawable.module_media_music_animal_icon15
|
||||
,R.drawable.module_media_music_animal_icon16
|
||||
,R.drawable.module_media_music_animal_icon17
|
||||
,R.drawable.module_media_music_animal_icon18
|
||||
,R.drawable.module_media_music_animal_icon19
|
||||
,R.drawable.module_media_music_animal_icon20
|
||||
,R.drawable.module_media_music_animal_icon21
|
||||
,R.drawable.module_media_music_animal_icon22
|
||||
,R.drawable.module_media_music_animal_icon23
|
||||
,R.drawable.module_media_music_animal_icon24
|
||||
,R.drawable.module_media_music_animal_icon25
|
||||
,R.drawable.module_media_music_animal_icon26
|
||||
,R.drawable.module_media_music_animal_icon27
|
||||
,R.drawable.module_media_music_animal_icon28
|
||||
,R.drawable.module_media_music_animal_icon29
|
||||
,R.drawable.module_media_music_animal_icon30
|
||||
,R.drawable.module_media_music_animal_icon31
|
||||
,R.drawable.module_media_music_animal_icon32
|
||||
,R.drawable.module_media_music_animal_icon33
|
||||
,R.drawable.module_media_music_animal_icon34
|
||||
,R.drawable.module_media_music_animal_icon35
|
||||
,R.drawable.module_media_music_animal_icon36
|
||||
,R.drawable.module_media_music_animal_icon37
|
||||
,R.drawable.module_media_music_animal_icon38
|
||||
,R.drawable.module_media_music_animal_icon39
|
||||
,R.drawable.module_media_music_animal_icon40
|
||||
,R.drawable.module_media_music_animal_icon41
|
||||
,R.drawable.module_media_music_animal_icon42
|
||||
,R.drawable.module_media_music_animal_icon43
|
||||
,R.drawable.module_media_music_animal_icon44
|
||||
,R.drawable.module_media_music_animal_icon45
|
||||
,R.drawable.module_media_music_animal_icon46
|
||||
,R.drawable.module_media_music_animal_icon47
|
||||
,R.drawable.module_media_music_animal_icon48
|
||||
,R.drawable.module_media_music_animal_icon49
|
||||
,R.drawable.module_media_music_animal_icon50
|
||||
,R.drawable.module_media_music_animal_icon51
|
||||
,R.drawable.module_media_music_animal_icon52
|
||||
,R.drawable.module_media_music_animal_icon53
|
||||
,R.drawable.module_media_music_animal_icon54
|
||||
,R.drawable.module_media_music_animal_icon55
|
||||
,R.drawable.module_media_music_animal_icon56
|
||||
,R.drawable.module_media_music_animal_icon57
|
||||
,R.drawable.module_media_music_animal_icon58
|
||||
,R.drawable.module_media_music_animal_icon59
|
||||
,R.drawable.module_media_music_animal_icon60
|
||||
,R.drawable.module_media_music_animal_icon61
|
||||
,R.drawable.module_media_music_animal_icon62
|
||||
,R.drawable.module_media_music_animal_icon63
|
||||
,R.drawable.module_media_music_animal_icon64
|
||||
,R.drawable.module_media_music_animal_icon65
|
||||
,R.drawable.module_media_music_animal_icon66
|
||||
,R.drawable.module_media_music_animal_icon67
|
||||
,R.drawable.module_media_music_animal_icon68
|
||||
,R.drawable.module_media_music_animal_icon69
|
||||
,R.drawable.module_media_music_animal_icon70
|
||||
,R.drawable.module_media_music_animal_icon71
|
||||
,R.drawable.module_media_music_animal_icon72
|
||||
,R.drawable.module_media_music_animal_icon73
|
||||
,R.drawable.module_media_music_animal_icon74
|
||||
,R.drawable.module_media_music_animal_icon75
|
||||
};
|
||||
return iconArr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.mogo.module.media.view;
|
||||
|
||||
import com.mogo.commons.mvp.IView;
|
||||
import com.mogo.module.common.entity.MarkerShareMusic;
|
||||
import com.mogo.module.media.model.ShareLikeData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MediaView extends IView {
|
||||
void showSharePush(boolean show);
|
||||
|
||||
void loadNearShareMusicSuccess(List<MarkerShareMusic> list);
|
||||
|
||||
void loadFriendShareMusicSuccess(List<MarkerShareMusic> list);
|
||||
|
||||
void loadShareLikeDataResultSuccess(ShareLikeData.ShareLikeDataResult likeDataResult, String mediaId);
|
||||
|
||||
void likeShareSuccess();
|
||||
|
||||
void shareSuccessResult(boolean success, MarkerShareMusic markerShareMusic);
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PaintFlagsDrawFilter;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.NinePatchDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.mogo.module.common.utils.CarSeries;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class AnimCircleImageView extends ImageView {
|
||||
Drawable mDrawbleSrc;
|
||||
Context context;
|
||||
Bitmap mBitmapOut;
|
||||
Bitmap output;
|
||||
int defaultWidth;
|
||||
int defaultHeight;
|
||||
int diameter;
|
||||
int radius;
|
||||
|
||||
int currentDegree;
|
||||
int savedDegree;
|
||||
boolean isRotateEnable;
|
||||
boolean isRotating;
|
||||
private int delayMilliseconds = 450;
|
||||
private int mRotateAngleStep = 3;
|
||||
|
||||
public AnimCircleImageView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AnimCircleImageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AnimCircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.context = context;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mDrawbleSrc = getDrawable();
|
||||
isRotateEnable = false;
|
||||
isRotating = false;
|
||||
delayMilliseconds = CarSeries.getSeries() == CarSeries.CAR_SERIES_F80X ? 10 : 450;
|
||||
mRotateAngleStep = CarSeries.getSeries() == CarSeries.CAR_SERIES_F80X ? 1 : 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBitmap(Bitmap bm) {
|
||||
super.setImageBitmap(bm);
|
||||
mDrawbleSrc = getDrawable();
|
||||
output = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageDrawable(Drawable drawable) {
|
||||
super.setImageDrawable(drawable);
|
||||
mDrawbleSrc = getDrawable();
|
||||
output = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageResource(int resId) {
|
||||
super.setImageResource(resId);
|
||||
mDrawbleSrc = getDrawable();
|
||||
output = null;
|
||||
}
|
||||
|
||||
public void startAnim() {
|
||||
if (isRotating == true) return;
|
||||
isRotateEnable = true;
|
||||
isRotating = true;
|
||||
currentDegree = savedDegree;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void stopAnim() {
|
||||
isRotating = false;
|
||||
isRotateEnable = false;
|
||||
savedDegree = currentDegree;
|
||||
}
|
||||
|
||||
public boolean isRotationing(){
|
||||
return isRotating;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
|
||||
try {
|
||||
if (mDrawbleSrc == null)
|
||||
return;
|
||||
|
||||
if (getWidth() == 0 || getHeight() == 0)
|
||||
return;
|
||||
|
||||
if (mDrawbleSrc.getClass() == NinePatchDrawable.class)
|
||||
return;
|
||||
|
||||
if (output == null) {
|
||||
defaultHeight = getHeight();
|
||||
defaultWidth = getWidth();
|
||||
diameter = (defaultHeight > defaultWidth ? defaultWidth : defaultHeight);
|
||||
radius = diameter / 2;
|
||||
mBitmapOut = getCuttedPicture(mDrawbleSrc);
|
||||
|
||||
Paint paint = new Paint();
|
||||
Rect rect = new Rect(0, 0, mBitmapOut.getWidth(),
|
||||
mBitmapOut.getHeight());
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
paint.setFilterBitmap(true);
|
||||
paint.setDither(true);
|
||||
|
||||
output = Bitmap.createBitmap(mBitmapOut.getWidth(),
|
||||
mBitmapOut.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas mTempCanvas = new Canvas(output);
|
||||
mTempCanvas.drawARGB(0, 0, 0, 0);
|
||||
mTempCanvas.drawCircle(mBitmapOut.getWidth() / 2,
|
||||
mBitmapOut.getHeight() / 2, mBitmapOut.getWidth() / 2,
|
||||
paint);
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||
mTempCanvas.drawBitmap(mBitmapOut, rect, rect, paint);
|
||||
|
||||
}
|
||||
|
||||
if (isRotateEnable) {
|
||||
currentDegree = (currentDegree + mRotateAngleStep) % 360;
|
||||
canvas.save();
|
||||
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
|
||||
canvas.rotate(currentDegree, defaultWidth / 2, defaultHeight / 2);
|
||||
canvas.drawBitmap(output, defaultWidth / 2 - radius, defaultHeight / 2 - radius, null);
|
||||
canvas.restore();
|
||||
if (isRotateEnable) {
|
||||
postInvalidateDelayed(delayMilliseconds);
|
||||
}
|
||||
} else {
|
||||
canvas.save();
|
||||
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
|
||||
canvas.rotate(currentDegree, defaultWidth / 2, defaultHeight / 2);
|
||||
canvas.drawBitmap(output, defaultWidth / 2 - radius, defaultHeight / 2 - radius, null);
|
||||
canvas.restore();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Bitmap getCuttedPicture(Drawable DrawbleSrc) {
|
||||
Bitmap mBitmapOrigin = ((BitmapDrawable) DrawbleSrc).getBitmap();
|
||||
int mWidth = mBitmapOrigin.getWidth();
|
||||
int mHeight = mBitmapOrigin.getHeight();
|
||||
|
||||
|
||||
float scale = Math.min((float) mWidth / (float) defaultWidth, (float) mHeight / (float) defaultHeight);
|
||||
Bitmap mBitmapScaled = Bitmap.createScaledBitmap(mBitmapOrigin, (int) (mWidth / scale), (int) (mHeight / scale), false);
|
||||
int x;
|
||||
int y;
|
||||
|
||||
x = mBitmapScaled.getWidth() / 2 - radius;
|
||||
y = mBitmapScaled.getHeight() / 2 - radius;
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
Bitmap mBitmapCropped = Bitmap.createBitmap(mBitmapScaled, x, y, diameter, diameter);
|
||||
return mBitmapCropped;
|
||||
}
|
||||
|
||||
public int getDelayMilliseconds() {
|
||||
return delayMilliseconds;
|
||||
}
|
||||
|
||||
public void setDelayMilliseconds(int delayMilliseconds) {
|
||||
this.delayMilliseconds = delayMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import com.mogo.utils.ThreadPoolService;
|
||||
|
||||
public class AnimalJSurfaceView extends SurfaceView implements Runnable, SurfaceHolder.Callback {
|
||||
|
||||
private SurfaceHolder mHolder;
|
||||
|
||||
/**
|
||||
* 动画是否执行中
|
||||
*/
|
||||
private boolean bRunning = false;
|
||||
/**
|
||||
* 当前执行的第几帧
|
||||
*/
|
||||
private int mCurrentPos;
|
||||
/**
|
||||
* 动画集合
|
||||
*/
|
||||
private int[] mFrames;
|
||||
|
||||
public AnimalJSurfaceView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public AnimalJSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public AnimalJSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mHolder = getHolder();
|
||||
mHolder.addCallback(this);
|
||||
setZOrderOnTop(true);
|
||||
mHolder.setFormat(PixelFormat.TRANSLUCENT);
|
||||
}
|
||||
|
||||
public void setFrames(int[] frames) {
|
||||
mFrames = frames;
|
||||
}
|
||||
|
||||
public void startAnim() {
|
||||
if (bRunning) {
|
||||
return;
|
||||
}
|
||||
ThreadPoolService.execute(this);
|
||||
bRunning = true;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
bRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (bRunning) {
|
||||
drawBitmap();
|
||||
mCurrentPos++;
|
||||
try {
|
||||
Thread.sleep(400);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void drawBitmap() {
|
||||
//获取画布并锁定
|
||||
Canvas mCanvas = mHolder.lockCanvas();
|
||||
if (mCanvas == null) {
|
||||
return;
|
||||
}else{
|
||||
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
|
||||
}
|
||||
//绘制透明色
|
||||
mCanvas.drawColor(Color.parseColor("#00000000"));
|
||||
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), mFrames[mCurrentPos % mFrames.length]);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setAlpha(70);
|
||||
Rect mSrcRect = new Rect(0,
|
||||
0,
|
||||
mBitmap.getWidth(),
|
||||
mBitmap.getHeight()); // 图片绘制
|
||||
Rect mDestRect = new Rect(0,
|
||||
0,
|
||||
getWidth(),
|
||||
getHeight());// 图片绘制位置
|
||||
|
||||
mCanvas.drawBitmap(mBitmap, mSrcRect, mDestRect, paint);
|
||||
//解锁画布,并展示bitmap到surface
|
||||
mHolder.unlockCanvasAndPost(mCanvas);
|
||||
mBitmap.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Xfermode;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class CircleImageView extends ImageView {
|
||||
|
||||
private Paint mPaint;
|
||||
|
||||
private Xfermode mXfermode;
|
||||
|
||||
private boolean onceLoad = false;
|
||||
|
||||
private int mWidth;
|
||||
|
||||
private int mHeight;
|
||||
|
||||
private Bitmap mBitmap;
|
||||
|
||||
public CircleImageView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CircleImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (changed && !onceLoad) {
|
||||
mPaint = new Paint();
|
||||
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
|
||||
mPaint.setFilterBitmap(true);
|
||||
mPaint.setXfermode(mXfermode);
|
||||
mPaint.setAntiAlias(true);
|
||||
mWidth = getWidth();
|
||||
mHeight = getHeight();
|
||||
if(mWidth <= 0 || mHeight <= 0){
|
||||
return;
|
||||
}
|
||||
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(mBitmap);
|
||||
RectF oval = new RectF(0, 0, mWidth, mHeight);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawOval(oval, paint);
|
||||
onceLoad = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas) {
|
||||
|
||||
Drawable image = getDrawable();
|
||||
if(image==null || mWidth<=0 || mHeight<=0){
|
||||
return;
|
||||
}
|
||||
int level = canvas.saveLayer(0, 0, mWidth, mHeight, null, Canvas.ALL_SAVE_FLAG);
|
||||
image.setBounds(0, 0, mWidth, mHeight);
|
||||
image.draw(canvas);
|
||||
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
|
||||
canvas.restoreToCount(level);
|
||||
//super.onDraw(canvas);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
import com.mogo.module.media.R;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class CircleImageView2 extends ImageView {
|
||||
|
||||
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
|
||||
|
||||
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
|
||||
private static final int COLORDRAWABLE_DIMENSION = 2;
|
||||
|
||||
private static final int DEFAULT_BORDER_WIDTH = 0;
|
||||
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
|
||||
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
|
||||
private static final boolean DEFAULT_BORDER_OVERLAY = false;
|
||||
|
||||
private final RectF mDrawableRect = new RectF();
|
||||
private final RectF mBorderRect = new RectF();
|
||||
|
||||
private final Matrix mShaderMatrix = new Matrix();
|
||||
private final Paint mBitmapPaint = new Paint();
|
||||
private final Paint mBorderPaint = new Paint();
|
||||
private final Paint mFillPaint = new Paint();
|
||||
|
||||
private int mBorderColor = DEFAULT_BORDER_COLOR;
|
||||
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
|
||||
private int mFillColor = DEFAULT_FILL_COLOR;
|
||||
|
||||
private Bitmap mBitmap;
|
||||
private BitmapShader mBitmapShader;
|
||||
private int mBitmapWidth;
|
||||
private int mBitmapHeight;
|
||||
|
||||
private float mDrawableRadius;
|
||||
private float mBorderRadius;
|
||||
|
||||
private ColorFilter mColorFilter;
|
||||
|
||||
private boolean mReady;
|
||||
private boolean mSetupPending;
|
||||
private boolean mBorderOverlay;
|
||||
|
||||
public CircleImageView2(Context context) {
|
||||
super(context);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public CircleImageView2(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CircleImageView2(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MediaCircleImageView2, defStyle, 0);
|
||||
|
||||
mBorderWidth = a.getDimensionPixelSize(R.styleable.MediaCircleImageView2_civ_border_width, DEFAULT_BORDER_WIDTH);
|
||||
mBorderColor = a.getColor(R.styleable.MediaCircleImageView2_civ_border_color, DEFAULT_BORDER_COLOR);
|
||||
mBorderOverlay = a.getBoolean(R.styleable.MediaCircleImageView2_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
|
||||
mFillColor = a.getColor(R.styleable.MediaCircleImageView2_civ_fill_color, DEFAULT_FILL_COLOR);
|
||||
|
||||
a.recycle();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
super.setScaleType(SCALE_TYPE);
|
||||
mReady = true;
|
||||
|
||||
if (mSetupPending) {
|
||||
setup();
|
||||
mSetupPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScaleType getScaleType() {
|
||||
return SCALE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScaleType(ScaleType scaleType) {
|
||||
if (scaleType != SCALE_TYPE) {
|
||||
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdjustViewBounds(boolean adjustViewBounds) {
|
||||
if (adjustViewBounds) {
|
||||
throw new IllegalArgumentException("adjustViewBounds not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mBitmap == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFillColor != Color.TRANSPARENT) {
|
||||
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
|
||||
}
|
||||
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
|
||||
if (mBorderWidth != 0) {
|
||||
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
setup();
|
||||
}
|
||||
|
||||
public int getBorderColor() {
|
||||
return mBorderColor;
|
||||
}
|
||||
|
||||
public void setBorderColor(@ColorInt int borderColor) {
|
||||
if (borderColor == mBorderColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBorderColor = borderColor;
|
||||
mBorderPaint.setColor(mBorderColor);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setBorderColorResource(@ColorRes int borderColorRes) {
|
||||
setBorderColor(getContext().getResources().getColor(borderColorRes));
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return mFillColor;
|
||||
}
|
||||
|
||||
public void setFillColor(@ColorInt int fillColor) {
|
||||
if (fillColor == mFillColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFillColor = fillColor;
|
||||
mFillPaint.setColor(fillColor);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setFillColorResource(@ColorRes int fillColorRes) {
|
||||
setFillColor(getContext().getResources().getColor(fillColorRes));
|
||||
}
|
||||
|
||||
public int getBorderWidth() {
|
||||
return mBorderWidth;
|
||||
}
|
||||
|
||||
public void setBorderWidth(int borderWidth) {
|
||||
if (borderWidth == mBorderWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBorderWidth = borderWidth;
|
||||
setup();
|
||||
}
|
||||
|
||||
public boolean isBorderOverlay() {
|
||||
return mBorderOverlay;
|
||||
}
|
||||
|
||||
public void setBorderOverlay(boolean borderOverlay) {
|
||||
if (borderOverlay == mBorderOverlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBorderOverlay = borderOverlay;
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBitmap(Bitmap bm) {
|
||||
super.setImageBitmap(bm);
|
||||
mBitmap = bm;
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageDrawable(Drawable drawable) {
|
||||
super.setImageDrawable(drawable);
|
||||
mBitmap = getBitmapFromDrawable(drawable);
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageResource(@DrawableRes int resId) {
|
||||
super.setImageResource(resId);
|
||||
mBitmap = getBitmapFromDrawable(getDrawable());
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageURI(Uri uri) {
|
||||
super.setImageURI(uri);
|
||||
mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
if (cf == mColorFilter) {
|
||||
return;
|
||||
}
|
||||
|
||||
mColorFilter = cf;
|
||||
mBitmapPaint.setColorFilter(mColorFilter);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromDrawable(Drawable drawable) {
|
||||
if (drawable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
|
||||
try {
|
||||
Bitmap bitmap;
|
||||
|
||||
if (drawable instanceof ColorDrawable) {
|
||||
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
|
||||
} else {
|
||||
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
|
||||
}
|
||||
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
return bitmap;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
if (!mReady) {
|
||||
mSetupPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (getWidth() == 0 && getHeight() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBitmap == null) {
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
|
||||
mBitmapPaint.setAntiAlias(true);
|
||||
mBitmapPaint.setShader(mBitmapShader);
|
||||
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
mBorderPaint.setAntiAlias(true);
|
||||
mBorderPaint.setColor(mBorderColor);
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
|
||||
mFillPaint.setStyle(Paint.Style.FILL);
|
||||
mFillPaint.setAntiAlias(true);
|
||||
mFillPaint.setColor(mFillColor);
|
||||
|
||||
mBitmapHeight = mBitmap.getHeight();
|
||||
mBitmapWidth = mBitmap.getWidth();
|
||||
|
||||
mBorderRect.set(0, 0, getWidth(), getHeight());
|
||||
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
|
||||
|
||||
mDrawableRect.set(mBorderRect);
|
||||
if (!mBorderOverlay) {
|
||||
mDrawableRect.inset(mBorderWidth, mBorderWidth);
|
||||
}
|
||||
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
|
||||
|
||||
updateShaderMatrix();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void updateShaderMatrix() {
|
||||
float scale;
|
||||
float dx = 0;
|
||||
float dy = 0;
|
||||
|
||||
mShaderMatrix.set(null);
|
||||
|
||||
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
|
||||
scale = mDrawableRect.height() / (float) mBitmapHeight;
|
||||
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
|
||||
} else {
|
||||
scale = mDrawableRect.width() / (float) mBitmapWidth;
|
||||
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
|
||||
}
|
||||
|
||||
mShaderMatrix.setScale(scale, scale);
|
||||
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
|
||||
|
||||
mBitmapShader.setLocalMatrix(mShaderMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.module.media.widget;
|
||||
import androidx.annotation.IntDef;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
Corner.TOP_LEFT, Corner.TOP_RIGHT,
|
||||
Corner.BOTTOM_LEFT, Corner.BOTTOM_RIGHT
|
||||
})
|
||||
public @interface Corner {
|
||||
int TOP_LEFT = 0;
|
||||
int TOP_RIGHT = 1;
|
||||
int BOTTOM_RIGHT = 2;
|
||||
int BOTTOM_LEFT = 3;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class NoScrollSeekBar extends SeekBar {
|
||||
|
||||
public NoScrollSeekBar(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public NoScrollSeekBar(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public NoScrollSeekBar(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
/**
|
||||
* onTouchEvent 是在 SeekBar 继承的抽象类 AbsSeekBar 里
|
||||
* 你可以看下他们的继承关系
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
//原来是要将TouchEvent传递下去的,我们不让它传递下去就行了
|
||||
//return super.onTouchEvent(event);
|
||||
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,618 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public class RoundedDrawable extends Drawable {
|
||||
|
||||
public static final String TAG = "RoundedDrawable";
|
||||
public static final int DEFAULT_BORDER_COLOR = Color.BLACK;
|
||||
|
||||
private final RectF mBounds = new RectF();
|
||||
private final RectF mDrawableRect = new RectF();
|
||||
private final RectF mBitmapRect = new RectF();
|
||||
private final Bitmap mBitmap;
|
||||
private final Paint mBitmapPaint;
|
||||
private final int mBitmapWidth;
|
||||
private final int mBitmapHeight;
|
||||
private final RectF mBorderRect = new RectF();
|
||||
private final Paint mBorderPaint;
|
||||
private final Matrix mShaderMatrix = new Matrix();
|
||||
private final RectF mSquareCornersRect = new RectF();
|
||||
|
||||
private Shader.TileMode mTileModeX = Shader.TileMode.CLAMP;
|
||||
private Shader.TileMode mTileModeY = Shader.TileMode.CLAMP;
|
||||
private boolean mRebuildShader = true;
|
||||
|
||||
private float mCornerRadius = 0f;
|
||||
// [ topLeft, topRight, bottomLeft, bottomRight ]
|
||||
private final boolean[] mCornersRounded = new boolean[] { true, true, true, true };
|
||||
|
||||
private boolean mOval = false;
|
||||
private float mBorderWidth = 0;
|
||||
private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
|
||||
private ScaleType mScaleType = ScaleType.FIT_CENTER;
|
||||
|
||||
public RoundedDrawable(Bitmap bitmap) {
|
||||
mBitmap = bitmap;
|
||||
|
||||
mBitmapWidth = bitmap.getWidth();
|
||||
mBitmapHeight = bitmap.getHeight();
|
||||
mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);
|
||||
|
||||
mBitmapPaint = new Paint();
|
||||
mBitmapPaint.setStyle(Paint.Style.FILL);
|
||||
mBitmapPaint.setAntiAlias(true);
|
||||
|
||||
mBorderPaint = new Paint();
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
mBorderPaint.setAntiAlias(true);
|
||||
mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
}
|
||||
|
||||
public static RoundedDrawable fromBitmap(Bitmap bitmap) {
|
||||
if (bitmap != null) {
|
||||
return new RoundedDrawable(bitmap);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable fromDrawable(Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
if (drawable instanceof RoundedDrawable) {
|
||||
// just return if it's already a RoundedDrawable
|
||||
return drawable;
|
||||
} else if (drawable instanceof LayerDrawable) {
|
||||
LayerDrawable ld = (LayerDrawable) drawable;
|
||||
int num = ld.getNumberOfLayers();
|
||||
|
||||
// loop through layers to and change to RoundedDrawables if possible
|
||||
for (int i = 0; i < num; i++) {
|
||||
Drawable d = ld.getDrawable(i);
|
||||
ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d));
|
||||
}
|
||||
return ld;
|
||||
}
|
||||
|
||||
// try to get a bitmap from the drawable and
|
||||
Bitmap bm = drawableToBitmap(drawable);
|
||||
if (bm != null) {
|
||||
return new RoundedDrawable(bm);
|
||||
}
|
||||
}
|
||||
return drawable;
|
||||
}
|
||||
|
||||
public static Bitmap drawableToBitmap(Drawable drawable) {
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
|
||||
Bitmap bitmap;
|
||||
int width = Math.max(drawable.getIntrinsicWidth(), 2);
|
||||
int height = Math.max(drawable.getIntrinsicHeight(), 2);
|
||||
try {
|
||||
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Log.w(TAG, "Failed to create bitmap from drawable!");
|
||||
bitmap = null;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public Bitmap getSourceBitmap() {
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStateful() {
|
||||
return mBorderColor.isStateful();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onStateChange(int[] state) {
|
||||
int newColor = mBorderColor.getColorForState(state, 0);
|
||||
if (mBorderPaint.getColor() != newColor) {
|
||||
mBorderPaint.setColor(newColor);
|
||||
return true;
|
||||
} else {
|
||||
return super.onStateChange(state);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateShaderMatrix() {
|
||||
float scale;
|
||||
float dx;
|
||||
float dy;
|
||||
|
||||
switch (mScaleType) {
|
||||
case CENTER:
|
||||
mBorderRect.set(mBounds);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
|
||||
mShaderMatrix.reset();
|
||||
mShaderMatrix.setTranslate((int) ((mBorderRect.width() - mBitmapWidth) * 0.5f + 0.5f),
|
||||
(int) ((mBorderRect.height() - mBitmapHeight) * 0.5f + 0.5f));
|
||||
break;
|
||||
|
||||
case CENTER_CROP:
|
||||
mBorderRect.set(mBounds);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
|
||||
mShaderMatrix.reset();
|
||||
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
|
||||
if (mBitmapWidth * mBorderRect.height() > mBorderRect.width() * mBitmapHeight) {
|
||||
scale = mBorderRect.height() / (float) mBitmapHeight;
|
||||
dx = (mBorderRect.width() - mBitmapWidth * scale) * 0.5f;
|
||||
} else {
|
||||
scale = mBorderRect.width() / (float) mBitmapWidth;
|
||||
dy = (mBorderRect.height() - mBitmapHeight * scale) * 0.5f;
|
||||
}
|
||||
|
||||
mShaderMatrix.setScale(scale, scale);
|
||||
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth / 2,
|
||||
(int) (dy + 0.5f) + mBorderWidth / 2);
|
||||
break;
|
||||
|
||||
case CENTER_INSIDE:
|
||||
mShaderMatrix.reset();
|
||||
|
||||
if (mBitmapWidth <= mBounds.width() && mBitmapHeight <= mBounds.height()) {
|
||||
scale = 1.0f;
|
||||
} else {
|
||||
scale = Math.min(mBounds.width() / (float) mBitmapWidth,
|
||||
mBounds.height() / (float) mBitmapHeight);
|
||||
}
|
||||
|
||||
dx = (int) ((mBounds.width() - mBitmapWidth * scale) * 0.5f + 0.5f);
|
||||
dy = (int) ((mBounds.height() - mBitmapHeight * scale) * 0.5f + 0.5f);
|
||||
|
||||
mShaderMatrix.setScale(scale, scale);
|
||||
mShaderMatrix.postTranslate(dx, dy);
|
||||
|
||||
mBorderRect.set(mBitmapRect);
|
||||
mShaderMatrix.mapRect(mBorderRect);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
|
||||
break;
|
||||
|
||||
default:
|
||||
case FIT_CENTER:
|
||||
mBorderRect.set(mBitmapRect);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.CENTER);
|
||||
mShaderMatrix.mapRect(mBorderRect);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
|
||||
break;
|
||||
|
||||
case FIT_END:
|
||||
mBorderRect.set(mBitmapRect);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.END);
|
||||
mShaderMatrix.mapRect(mBorderRect);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
|
||||
break;
|
||||
|
||||
case FIT_START:
|
||||
mBorderRect.set(mBitmapRect);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.START);
|
||||
mShaderMatrix.mapRect(mBorderRect);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
|
||||
break;
|
||||
|
||||
case FIT_XY:
|
||||
mBorderRect.set(mBounds);
|
||||
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
|
||||
mShaderMatrix.reset();
|
||||
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
|
||||
break;
|
||||
}
|
||||
|
||||
mDrawableRect.set(mBorderRect);
|
||||
mRebuildShader = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(@NonNull Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
|
||||
mBounds.set(bounds);
|
||||
|
||||
updateShaderMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (mRebuildShader) {
|
||||
BitmapShader bitmapShader = new BitmapShader(mBitmap, mTileModeX, mTileModeY);
|
||||
if (mTileModeX == Shader.TileMode.CLAMP && mTileModeY == Shader.TileMode.CLAMP) {
|
||||
bitmapShader.setLocalMatrix(mShaderMatrix);
|
||||
}
|
||||
mBitmapPaint.setShader(bitmapShader);
|
||||
mRebuildShader = false;
|
||||
}
|
||||
|
||||
if (mOval) {
|
||||
if (mBorderWidth > 0) {
|
||||
canvas.drawOval(mDrawableRect, mBitmapPaint);
|
||||
canvas.drawOval(mBorderRect, mBorderPaint);
|
||||
} else {
|
||||
canvas.drawOval(mDrawableRect, mBitmapPaint);
|
||||
}
|
||||
} else {
|
||||
if (any(mCornersRounded)) {
|
||||
float radius = mCornerRadius;
|
||||
if (mBorderWidth > 0) {
|
||||
canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint);
|
||||
canvas.drawRoundRect(mBorderRect, radius, radius, mBorderPaint);
|
||||
redrawBitmapForSquareCorners(canvas);
|
||||
redrawBorderForSquareCorners(canvas);
|
||||
} else {
|
||||
canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint);
|
||||
redrawBitmapForSquareCorners(canvas);
|
||||
}
|
||||
} else {
|
||||
canvas.drawRect(mDrawableRect, mBitmapPaint);
|
||||
if (mBorderWidth > 0) {
|
||||
canvas.drawRect(mBorderRect, mBorderPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void redrawBitmapForSquareCorners(Canvas canvas) {
|
||||
if (all(mCornersRounded)) {
|
||||
// no square corners
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCornerRadius == 0) {
|
||||
return; // no round corners
|
||||
}
|
||||
|
||||
float left = mDrawableRect.left;
|
||||
float top = mDrawableRect.top;
|
||||
float right = left + mDrawableRect.width();
|
||||
float bottom = top + mDrawableRect.height();
|
||||
float radius = mCornerRadius;
|
||||
|
||||
if (!mCornersRounded[Corner.TOP_LEFT]) {
|
||||
mSquareCornersRect.set(left, top, left + radius, top + radius);
|
||||
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.TOP_RIGHT]) {
|
||||
mSquareCornersRect.set(right - radius, top, right, radius);
|
||||
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.BOTTOM_RIGHT]) {
|
||||
mSquareCornersRect.set(right - radius, bottom - radius, right, bottom);
|
||||
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.BOTTOM_LEFT]) {
|
||||
mSquareCornersRect.set(left, bottom - radius, left + radius, bottom);
|
||||
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void redrawBorderForSquareCorners(Canvas canvas) {
|
||||
if (all(mCornersRounded)) {
|
||||
// no square corners
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCornerRadius == 0) {
|
||||
return; // no round corners
|
||||
}
|
||||
|
||||
float left = mDrawableRect.left;
|
||||
float top = mDrawableRect.top;
|
||||
float right = left + mDrawableRect.width();
|
||||
float bottom = top + mDrawableRect.height();
|
||||
float radius = mCornerRadius;
|
||||
float offset = mBorderWidth / 2;
|
||||
|
||||
if (!mCornersRounded[Corner.TOP_LEFT]) {
|
||||
canvas.drawLine(left - offset, top, left + radius, top, mBorderPaint);
|
||||
canvas.drawLine(left, top - offset, left, top + radius, mBorderPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.TOP_RIGHT]) {
|
||||
canvas.drawLine(right - radius - offset, top, right, top, mBorderPaint);
|
||||
canvas.drawLine(right, top - offset, right, top + radius, mBorderPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.BOTTOM_RIGHT]) {
|
||||
canvas.drawLine(right - radius - offset, bottom, right + offset, bottom, mBorderPaint);
|
||||
canvas.drawLine(right, bottom - radius, right, bottom, mBorderPaint);
|
||||
}
|
||||
|
||||
if (!mCornersRounded[Corner.BOTTOM_LEFT]) {
|
||||
canvas.drawLine(left - offset, bottom, left + radius, bottom, mBorderPaint);
|
||||
canvas.drawLine(left, bottom - radius, left, bottom, mBorderPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlpha() {
|
||||
return mBitmapPaint.getAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mBitmapPaint.setAlpha(alpha);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorFilter getColorFilter() {
|
||||
return mBitmapPaint.getColorFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mBitmapPaint.setColorFilter(cf);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDither(boolean dither) {
|
||||
mBitmapPaint.setDither(dither);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilterBitmap(boolean filter) {
|
||||
mBitmapPaint.setFilterBitmap(filter);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mBitmapWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mBitmapHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the corner radius.
|
||||
*/
|
||||
public float getCornerRadius() {
|
||||
return mCornerRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param corner the specific corner to get radius of.
|
||||
* @return the corner radius of the specified corner.
|
||||
*/
|
||||
public float getCornerRadius(@Corner int corner) {
|
||||
return mCornersRounded[corner] ? mCornerRadius : 0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all corners to the specified radius.
|
||||
*
|
||||
* @param radius the radius.
|
||||
* @return the {@link RoundedDrawable} for chaining.
|
||||
*/
|
||||
public RoundedDrawable setCornerRadius(float radius) {
|
||||
setCornerRadius(radius, radius, radius, radius);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the corner radius of one specific corner.
|
||||
*
|
||||
* @param corner the corner.
|
||||
* @param radius the radius.
|
||||
* @return the {@link RoundedDrawable} for chaining.
|
||||
*/
|
||||
public RoundedDrawable setCornerRadius(@Corner int corner, float radius) {
|
||||
if (radius != 0 && mCornerRadius != 0 && mCornerRadius != radius) {
|
||||
throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
|
||||
}
|
||||
|
||||
if (radius == 0) {
|
||||
if (only(corner, mCornersRounded)) {
|
||||
mCornerRadius = 0;
|
||||
}
|
||||
mCornersRounded[corner] = false;
|
||||
} else {
|
||||
if (mCornerRadius == 0) {
|
||||
mCornerRadius = radius;
|
||||
}
|
||||
mCornersRounded[corner] = true;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the corner radii of all the corners.
|
||||
*
|
||||
* @param topLeft top left corner radius.
|
||||
* @param topRight top right corner radius
|
||||
* @param bottomRight bototm right corner radius.
|
||||
* @param bottomLeft bottom left corner radius.
|
||||
* @return the {@link RoundedDrawable} for chaining.
|
||||
*/
|
||||
public RoundedDrawable setCornerRadius(float topLeft, float topRight, float bottomRight,
|
||||
float bottomLeft) {
|
||||
Set<Float> radiusSet = new HashSet<>(4);
|
||||
radiusSet.add(topLeft);
|
||||
radiusSet.add(topRight);
|
||||
radiusSet.add(bottomRight);
|
||||
radiusSet.add(bottomLeft);
|
||||
|
||||
radiusSet.remove(0f);
|
||||
|
||||
if (radiusSet.size() > 1) {
|
||||
throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
|
||||
}
|
||||
|
||||
if (!radiusSet.isEmpty()) {
|
||||
float radius = radiusSet.iterator().next();
|
||||
if (Float.isInfinite(radius) || Float.isNaN(radius) || radius < 0) {
|
||||
throw new IllegalArgumentException("Invalid radius value: " + radius);
|
||||
}
|
||||
mCornerRadius = radius;
|
||||
} else {
|
||||
mCornerRadius = 0f;
|
||||
}
|
||||
|
||||
mCornersRounded[Corner.TOP_LEFT] = topLeft > 0;
|
||||
mCornersRounded[Corner.TOP_RIGHT] = topRight > 0;
|
||||
mCornersRounded[Corner.BOTTOM_RIGHT] = bottomRight > 0;
|
||||
mCornersRounded[Corner.BOTTOM_LEFT] = bottomLeft > 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getBorderWidth() {
|
||||
return mBorderWidth;
|
||||
}
|
||||
|
||||
public RoundedDrawable setBorderWidth(float width) {
|
||||
mBorderWidth = width;
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getBorderColor() {
|
||||
return mBorderColor.getDefaultColor();
|
||||
}
|
||||
|
||||
public RoundedDrawable setBorderColor(@ColorInt int color) {
|
||||
return setBorderColor(ColorStateList.valueOf(color));
|
||||
}
|
||||
|
||||
public ColorStateList getBorderColors() {
|
||||
return mBorderColor;
|
||||
}
|
||||
|
||||
public RoundedDrawable setBorderColor(ColorStateList colors) {
|
||||
mBorderColor = colors != null ? colors : ColorStateList.valueOf(0);
|
||||
mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isOval() {
|
||||
return mOval;
|
||||
}
|
||||
|
||||
public RoundedDrawable setOval(boolean oval) {
|
||||
mOval = oval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScaleType getScaleType() {
|
||||
return mScaleType;
|
||||
}
|
||||
|
||||
public RoundedDrawable setScaleType(ScaleType scaleType) {
|
||||
if (scaleType == null) {
|
||||
scaleType = ScaleType.FIT_CENTER;
|
||||
}
|
||||
if (mScaleType != scaleType) {
|
||||
mScaleType = scaleType;
|
||||
updateShaderMatrix();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Shader.TileMode getTileModeX() {
|
||||
return mTileModeX;
|
||||
}
|
||||
|
||||
public RoundedDrawable setTileModeX(Shader.TileMode tileModeX) {
|
||||
if (mTileModeX != tileModeX) {
|
||||
mTileModeX = tileModeX;
|
||||
mRebuildShader = true;
|
||||
invalidateSelf();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Shader.TileMode getTileModeY() {
|
||||
return mTileModeY;
|
||||
}
|
||||
|
||||
public RoundedDrawable setTileModeY(Shader.TileMode tileModeY) {
|
||||
if (mTileModeY != tileModeY) {
|
||||
mTileModeY = tileModeY;
|
||||
mRebuildShader = true;
|
||||
invalidateSelf();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static boolean only(int index, boolean[] booleans) {
|
||||
for (int i = 0, len = booleans.length; i < len; i++) {
|
||||
if (booleans[i] != (i == index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean any(boolean[] booleans) {
|
||||
for (boolean b : booleans) {
|
||||
if (b) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean all(boolean[] booleans) {
|
||||
for (boolean b : booleans) {
|
||||
if (b) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Bitmap toBitmap() {
|
||||
return drawableToBitmap(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.net.Uri;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
import com.mogo.module.media.R;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class RoundedImageView extends ImageView {
|
||||
|
||||
// Constants for tile mode attributes
|
||||
private static final int TILE_MODE_UNDEFINED = -2;
|
||||
private static final int TILE_MODE_CLAMP = 0;
|
||||
private static final int TILE_MODE_REPEAT = 1;
|
||||
private static final int TILE_MODE_MIRROR = 2;
|
||||
|
||||
public static final String TAG = "RoundedImageView";
|
||||
public static final float DEFAULT_RADIUS = 0f;
|
||||
public static final float DEFAULT_BORDER_WIDTH = 0f;
|
||||
public static final Shader.TileMode DEFAULT_TILE_MODE = Shader.TileMode.CLAMP;
|
||||
private static final ImageView.ScaleType[] SCALE_TYPES = {
|
||||
ImageView.ScaleType.MATRIX,
|
||||
ImageView.ScaleType.FIT_XY,
|
||||
ImageView.ScaleType.FIT_START,
|
||||
ImageView.ScaleType.FIT_CENTER,
|
||||
ImageView.ScaleType.FIT_END,
|
||||
ImageView.ScaleType.CENTER,
|
||||
ImageView.ScaleType.CENTER_CROP,
|
||||
ImageView.ScaleType.CENTER_INSIDE
|
||||
};
|
||||
|
||||
private final float[] mCornerRadii =
|
||||
new float[] { DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS };
|
||||
|
||||
private Drawable mBackgroundDrawable;
|
||||
private ColorStateList mBorderColor =
|
||||
ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
|
||||
private float mBorderWidth = DEFAULT_BORDER_WIDTH;
|
||||
private ColorFilter mColorFilter = null;
|
||||
private boolean mColorMod = false;
|
||||
private Drawable mDrawable;
|
||||
private boolean mHasColorFilter = false;
|
||||
private boolean mIsOval = false;
|
||||
private boolean mMutateBackground = false;
|
||||
private int mResource;
|
||||
private int mBackgroundResource;
|
||||
private ImageView.ScaleType mScaleType;
|
||||
private Shader.TileMode mTileModeX = DEFAULT_TILE_MODE;
|
||||
private Shader.TileMode mTileModeY = DEFAULT_TILE_MODE;
|
||||
|
||||
public RoundedImageView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public RoundedImageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MediaRoundedImageView, defStyle, 0);
|
||||
|
||||
int index = a.getInt(R.styleable.MediaRoundedImageView_android_scaleType, -1);
|
||||
if (index >= 0) {
|
||||
setScaleType(SCALE_TYPES[index]);
|
||||
} else {
|
||||
// default scaletype to FIT_CENTER
|
||||
setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
}
|
||||
|
||||
float cornerRadiusOverride =
|
||||
a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_corner_radius, -1);
|
||||
|
||||
mCornerRadii[Corner.TOP_LEFT] =
|
||||
a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_corner_radius_top_left, -1);
|
||||
mCornerRadii[Corner.TOP_RIGHT] =
|
||||
a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_corner_radius_top_right, -1);
|
||||
mCornerRadii[Corner.BOTTOM_RIGHT] =
|
||||
a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_corner_radius_bottom_right, -1);
|
||||
mCornerRadii[Corner.BOTTOM_LEFT] =
|
||||
a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_corner_radius_bottom_left, -1);
|
||||
|
||||
boolean any = false;
|
||||
for (int i = 0, len = mCornerRadii.length; i < len; i++) {
|
||||
if (mCornerRadii[i] < 0) {
|
||||
mCornerRadii[i] = 0f;
|
||||
} else {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!any) {
|
||||
if (cornerRadiusOverride < 0) {
|
||||
cornerRadiusOverride = DEFAULT_RADIUS;
|
||||
}
|
||||
for (int i = 0, len = mCornerRadii.length; i < len; i++) {
|
||||
mCornerRadii[i] = cornerRadiusOverride;
|
||||
}
|
||||
}
|
||||
|
||||
mBorderWidth = a.getDimensionPixelSize(R.styleable.MediaRoundedImageView_riv_border_width, -1);
|
||||
if (mBorderWidth < 0) {
|
||||
mBorderWidth = DEFAULT_BORDER_WIDTH;
|
||||
}
|
||||
|
||||
mBorderColor = a.getColorStateList(R.styleable.MediaRoundedImageView_riv_border_color);
|
||||
if (mBorderColor == null) {
|
||||
mBorderColor = ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
|
||||
}
|
||||
|
||||
mMutateBackground = a.getBoolean(R.styleable.MediaRoundedImageView_riv_mutate_background, false);
|
||||
mIsOval = a.getBoolean(R.styleable.MediaRoundedImageView_riv_oval, false);
|
||||
|
||||
final int tileMode = a.getInt(R.styleable.MediaRoundedImageView_riv_tile_mode, TILE_MODE_UNDEFINED);
|
||||
if (tileMode != TILE_MODE_UNDEFINED) {
|
||||
setTileModeX(parseTileMode(tileMode));
|
||||
setTileModeY(parseTileMode(tileMode));
|
||||
}
|
||||
|
||||
final int tileModeX =
|
||||
a.getInt(R.styleable.MediaRoundedImageView_riv_tile_mode_x, TILE_MODE_UNDEFINED);
|
||||
if (tileModeX != TILE_MODE_UNDEFINED) {
|
||||
setTileModeX(parseTileMode(tileModeX));
|
||||
}
|
||||
|
||||
final int tileModeY =
|
||||
a.getInt(R.styleable.MediaRoundedImageView_riv_tile_mode_y, TILE_MODE_UNDEFINED);
|
||||
if (tileModeY != TILE_MODE_UNDEFINED) {
|
||||
setTileModeY(parseTileMode(tileModeY));
|
||||
}
|
||||
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(true);
|
||||
|
||||
if (mMutateBackground) {
|
||||
//noinspection deprecation
|
||||
super.setBackgroundDrawable(mBackgroundDrawable);
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
private static Shader.TileMode parseTileMode(int tileMode) {
|
||||
switch (tileMode) {
|
||||
case TILE_MODE_CLAMP:
|
||||
return Shader.TileMode.CLAMP;
|
||||
case TILE_MODE_REPEAT:
|
||||
return Shader.TileMode.REPEAT;
|
||||
case TILE_MODE_MIRROR:
|
||||
return Shader.TileMode.MIRROR;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageView.ScaleType getScaleType() {
|
||||
return mScaleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScaleType(ImageView.ScaleType scaleType) {
|
||||
assert scaleType != null;
|
||||
|
||||
if (mScaleType != scaleType) {
|
||||
mScaleType = scaleType;
|
||||
|
||||
switch (scaleType) {
|
||||
case CENTER:
|
||||
case CENTER_CROP:
|
||||
case CENTER_INSIDE:
|
||||
case FIT_CENTER:
|
||||
case FIT_START:
|
||||
case FIT_END:
|
||||
case FIT_XY:
|
||||
super.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
break;
|
||||
default:
|
||||
super.setScaleType(scaleType);
|
||||
break;
|
||||
}
|
||||
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageDrawable(Drawable drawable) {
|
||||
mResource = 0;
|
||||
mDrawable = RoundedDrawable.fromDrawable(drawable);
|
||||
updateDrawableAttrs();
|
||||
super.setImageDrawable(mDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBitmap(Bitmap bm) {
|
||||
mResource = 0;
|
||||
mDrawable = RoundedDrawable.fromBitmap(bm);
|
||||
updateDrawableAttrs();
|
||||
super.setImageDrawable(mDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageResource(@DrawableRes int resId) {
|
||||
if (mResource != resId) {
|
||||
mResource = resId;
|
||||
mDrawable = resolveResource();
|
||||
updateDrawableAttrs();
|
||||
super.setImageDrawable(mDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageURI(Uri uri) {
|
||||
super.setImageURI(uri);
|
||||
setImageDrawable(getDrawable());
|
||||
}
|
||||
|
||||
private Drawable resolveResource() {
|
||||
Resources rsrc = getResources();
|
||||
if (rsrc == null) { return null; }
|
||||
|
||||
Drawable d = null;
|
||||
|
||||
if (mResource != 0) {
|
||||
try {
|
||||
d = rsrc.getDrawable(mResource);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Unable to find resource: " + mResource, e);
|
||||
// Don't try again.
|
||||
mResource = 0;
|
||||
}
|
||||
}
|
||||
return RoundedDrawable.fromDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Drawable background) {
|
||||
setBackgroundDrawable(background);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundResource(@DrawableRes int resId) {
|
||||
if (mBackgroundResource != resId) {
|
||||
mBackgroundResource = resId;
|
||||
mBackgroundDrawable = resolveBackgroundResource();
|
||||
setBackgroundDrawable(mBackgroundDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int color) {
|
||||
mBackgroundDrawable = new ColorDrawable(color);
|
||||
setBackgroundDrawable(mBackgroundDrawable);
|
||||
}
|
||||
|
||||
private Drawable resolveBackgroundResource() {
|
||||
Resources rsrc = getResources();
|
||||
if (rsrc == null) { return null; }
|
||||
|
||||
Drawable d = null;
|
||||
|
||||
if (mBackgroundResource != 0) {
|
||||
try {
|
||||
d = rsrc.getDrawable(mBackgroundResource);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Unable to find resource: " + mBackgroundResource, e);
|
||||
// Don't try again.
|
||||
mBackgroundResource = 0;
|
||||
}
|
||||
}
|
||||
return RoundedDrawable.fromDrawable(d);
|
||||
}
|
||||
|
||||
private void updateDrawableAttrs() {
|
||||
updateAttrs(mDrawable, mScaleType);
|
||||
}
|
||||
|
||||
private void updateBackgroundDrawableAttrs(boolean convert) {
|
||||
if (mMutateBackground) {
|
||||
if (convert) {
|
||||
mBackgroundDrawable = RoundedDrawable.fromDrawable(mBackgroundDrawable);
|
||||
}
|
||||
updateAttrs(mBackgroundDrawable, ImageView.ScaleType.FIT_XY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
if (mColorFilter != cf) {
|
||||
mColorFilter = cf;
|
||||
mHasColorFilter = true;
|
||||
mColorMod = true;
|
||||
applyColorMod();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyColorMod() {
|
||||
// Only mutate and apply when modifications have occurred. This should
|
||||
// not reset the mColorMod flag, since these filters need to be
|
||||
// re-applied if the Drawable is changed.
|
||||
if (mDrawable != null && mColorMod) {
|
||||
mDrawable = mDrawable.mutate();
|
||||
if (mHasColorFilter) {
|
||||
mDrawable.setColorFilter(mColorFilter);
|
||||
}
|
||||
// TODO: support, eventually...
|
||||
//mDrawable.setXfermode(mXfermode);
|
||||
//mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAttrs(Drawable drawable, ImageView.ScaleType scaleType) {
|
||||
if (drawable == null) { return; }
|
||||
|
||||
if (drawable instanceof RoundedDrawable) {
|
||||
((RoundedDrawable) drawable)
|
||||
.setScaleType(scaleType)
|
||||
.setBorderWidth(mBorderWidth)
|
||||
.setBorderColor(mBorderColor)
|
||||
.setOval(mIsOval)
|
||||
.setTileModeX(mTileModeX)
|
||||
.setTileModeY(mTileModeY);
|
||||
|
||||
if (mCornerRadii != null) {
|
||||
((RoundedDrawable) drawable).setCornerRadius(
|
||||
mCornerRadii[Corner.TOP_LEFT],
|
||||
mCornerRadii[Corner.TOP_RIGHT],
|
||||
mCornerRadii[Corner.BOTTOM_RIGHT],
|
||||
mCornerRadii[Corner.BOTTOM_LEFT]);
|
||||
}
|
||||
|
||||
applyColorMod();
|
||||
} else if (drawable instanceof LayerDrawable) {
|
||||
// loop through layers to and set drawable attrs
|
||||
LayerDrawable ld = ((LayerDrawable) drawable);
|
||||
for (int i = 0, layers = ld.getNumberOfLayers(); i < layers; i++) {
|
||||
updateAttrs(ld.getDrawable(i), scaleType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setBackgroundDrawable(Drawable background) {
|
||||
mBackgroundDrawable = background;
|
||||
updateBackgroundDrawableAttrs(true);
|
||||
//noinspection deprecation
|
||||
super.setBackgroundDrawable(mBackgroundDrawable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the largest corner radius.
|
||||
*/
|
||||
public float getCornerRadius() {
|
||||
return getMaxCornerRadius();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the largest corner radius.
|
||||
*/
|
||||
public float getMaxCornerRadius() {
|
||||
float maxRadius = 0;
|
||||
for (float r : mCornerRadii) {
|
||||
maxRadius = Math.max(r, maxRadius);
|
||||
}
|
||||
return maxRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the corner radius of a specified corner.
|
||||
*
|
||||
* @param corner the corner.
|
||||
* @return the radius.
|
||||
*/
|
||||
public float getCornerRadius(@Corner int corner) {
|
||||
return mCornerRadii[corner];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the corner radii from a dimension resource id.
|
||||
*
|
||||
* @param resId dimension resource id of radii.
|
||||
*/
|
||||
public void setCornerRadiusDimen(@DimenRes int resId) {
|
||||
float radius = getResources().getDimension(resId);
|
||||
setCornerRadius(radius, radius, radius, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the corner radius of a specific corner from a dimension resource id.
|
||||
*
|
||||
* @param corner the corner to set.
|
||||
* @param resId the dimension resource id of the corner radius.
|
||||
*/
|
||||
public void setCornerRadiusDimen(@Corner int corner, @DimenRes int resId) {
|
||||
setCornerRadius(corner, getResources().getDimensionPixelSize(resId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the corner radii of all corners in px.
|
||||
*
|
||||
* @param radius the radius to set.
|
||||
*/
|
||||
public void setCornerRadius(float radius) {
|
||||
setCornerRadius(radius, radius, radius, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the corner radius of a specific corner in px.
|
||||
*
|
||||
* @param corner the corner to set.
|
||||
* @param radius the corner radius to set in px.
|
||||
*/
|
||||
public void setCornerRadius(@Corner int corner, float radius) {
|
||||
if (mCornerRadii[corner] == radius) {
|
||||
return;
|
||||
}
|
||||
mCornerRadii[corner] = radius;
|
||||
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the corner radii of each corner individually. Currently only one unique nonzero value is
|
||||
* supported.
|
||||
*
|
||||
* @param topLeft radius of the top left corner in px.
|
||||
* @param topRight radius of the top right corner in px.
|
||||
* @param bottomRight radius of the bottom right corner in px.
|
||||
* @param bottomLeft radius of the bottom left corner in px.
|
||||
*/
|
||||
public void setCornerRadius(float topLeft, float topRight, float bottomLeft, float bottomRight) {
|
||||
if (mCornerRadii[Corner.TOP_LEFT] == topLeft
|
||||
&& mCornerRadii[Corner.TOP_RIGHT] == topRight
|
||||
&& mCornerRadii[Corner.BOTTOM_RIGHT] == bottomRight
|
||||
&& mCornerRadii[Corner.BOTTOM_LEFT] == bottomLeft) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCornerRadii[Corner.TOP_LEFT] = topLeft;
|
||||
mCornerRadii[Corner.TOP_RIGHT] = topRight;
|
||||
mCornerRadii[Corner.BOTTOM_LEFT] = bottomLeft;
|
||||
mCornerRadii[Corner.BOTTOM_RIGHT] = bottomRight;
|
||||
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getBorderWidth() {
|
||||
return mBorderWidth;
|
||||
}
|
||||
|
||||
public void setBorderWidth(@DimenRes int resId) {
|
||||
setBorderWidth(getResources().getDimension(resId));
|
||||
}
|
||||
|
||||
public void setBorderWidth(float width) {
|
||||
if (mBorderWidth == width) { return; }
|
||||
|
||||
mBorderWidth = width;
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
public int getBorderColor() {
|
||||
return mBorderColor.getDefaultColor();
|
||||
}
|
||||
|
||||
public void setBorderColor(@ColorInt int color) {
|
||||
setBorderColor(ColorStateList.valueOf(color));
|
||||
}
|
||||
|
||||
public ColorStateList getBorderColors() {
|
||||
return mBorderColor;
|
||||
}
|
||||
|
||||
public void setBorderColor(ColorStateList colors) {
|
||||
if (mBorderColor.equals(colors)) { return; }
|
||||
|
||||
mBorderColor =
|
||||
(colors != null) ? colors : ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
if (mBorderWidth > 0) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this view should be oval and always set corner radii to half the height or
|
||||
* width.
|
||||
*
|
||||
* @return if this {@link RoundedImageView} is set to oval.
|
||||
*/
|
||||
public boolean isOval() {
|
||||
return mIsOval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the drawable should ignore the corner radii set and always round the source to
|
||||
* exactly half the height or width.
|
||||
*
|
||||
* @param oval if this {@link RoundedImageView} should be oval.
|
||||
*/
|
||||
public void setOval(boolean oval) {
|
||||
mIsOval = oval;
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public Shader.TileMode getTileModeX() {
|
||||
return mTileModeX;
|
||||
}
|
||||
|
||||
public void setTileModeX(Shader.TileMode tileModeX) {
|
||||
if (this.mTileModeX == tileModeX) { return; }
|
||||
|
||||
this.mTileModeX = tileModeX;
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public Shader.TileMode getTileModeY() {
|
||||
return mTileModeY;
|
||||
}
|
||||
|
||||
public void setTileModeY(Shader.TileMode tileModeY) {
|
||||
if (this.mTileModeY == tileModeY) { return; }
|
||||
|
||||
this.mTileModeY = tileModeY;
|
||||
updateDrawableAttrs();
|
||||
updateBackgroundDrawableAttrs(false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code true}, we will also round the background drawable according to the settings on this
|
||||
* ImageView.
|
||||
*
|
||||
* @return whether the background is mutated.
|
||||
*/
|
||||
public boolean mutatesBackground() {
|
||||
return mMutateBackground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the {@link RoundedImageView} should round the background drawable according to
|
||||
* the settings in addition to the source drawable.
|
||||
*
|
||||
* @param mutate true if this view should mutate the background drawable.
|
||||
*/
|
||||
public void mutateBackground(boolean mutate) {
|
||||
if (mMutateBackground == mutate) { return; }
|
||||
|
||||
mMutateBackground = mutate;
|
||||
updateBackgroundDrawableAttrs(true);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.mogo.module.media.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
||||
public class ScrollingTextView extends AppCompatTextView {
|
||||
public ScrollingTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public ScrollingTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ScrollingTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||
if (focused)
|
||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean focused) {
|
||||
if (focused)
|
||||
super.onWindowFocusChanged(focused);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
public static final int DEFAULT_FRAME_DURATION_MILLISECOND = 50;
|
||||
|
||||
private HandlerThread handlerThread;
|
||||
private SurfaceViewHandler handler;
|
||||
protected int frameDuration = DEFAULT_FRAME_DURATION_MILLISECOND;
|
||||
private Canvas canvas;
|
||||
private boolean isAlive;
|
||||
public boolean pause = false;
|
||||
|
||||
public BaseSurfaceView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BaseSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public BaseSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
protected int getFrameDuration() {
|
||||
return frameDuration;
|
||||
}
|
||||
|
||||
protected void setFrameDuration(int frameDuration) {
|
||||
this.frameDuration = frameDuration;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
getHolder().addCallback(this);
|
||||
setBackgroundTransparent();
|
||||
}
|
||||
|
||||
private void setBackgroundTransparent() {
|
||||
setZOrderOnTop(false);
|
||||
setZOrderMediaOverlay(true);
|
||||
getHolder().setFormat(PixelFormat.TRANSLUCENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
isAlive = true;
|
||||
startDrawThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
stopDrawThread();
|
||||
isAlive = false;
|
||||
}
|
||||
|
||||
public void stopDrawThread() {
|
||||
handlerThread.quit();
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
handler = null;
|
||||
}
|
||||
|
||||
public void startDrawThread() {
|
||||
handlerThread = new HandlerThread("SurfaceViewThread");
|
||||
handlerThread.start();
|
||||
handler = new SurfaceViewHandler(handlerThread.getLooper());
|
||||
handler.post(new DrawRunnable());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int originWidth = getMeasuredWidth();
|
||||
int originHeight = getMeasuredHeight();
|
||||
int width = widthMode == MeasureSpec.AT_MOST ? getDefaultWidth() : originWidth;
|
||||
int height = heightMode == MeasureSpec.AT_MOST ? getDefaultHeight() : originHeight;
|
||||
setMeasuredDimension(width, height);
|
||||
Log.v("ttaylor", "BaseSurfaceView.onMeasure()" + " default Width=" + getDefaultWidth() + " default height=" + getDefaultHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* the width is used when wrap_content is set to layout_width
|
||||
* the child knows how big it should be
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract int getDefaultWidth();
|
||||
|
||||
/**
|
||||
* the height is used when wrap_content is set to layout_height
|
||||
* the child knows how big it should be
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract int getDefaultHeight();
|
||||
|
||||
|
||||
private class SurfaceViewHandler extends Handler {
|
||||
|
||||
public SurfaceViewHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class DrawRunnable implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isAlive) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
canvas = getHolder().lockCanvas();
|
||||
onFrameDraw(canvas);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
getHolder().unlockCanvasAndPost(canvas);
|
||||
onFrameDrawFinish();
|
||||
}
|
||||
|
||||
// TODO: 2019-05-08 stop the drawing thread
|
||||
if (handler != null && !pause){
|
||||
handler.postDelayed(this, frameDuration);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void setPause(boolean pause){
|
||||
this.pause = pause;
|
||||
}
|
||||
|
||||
public boolean getPause(){
|
||||
return this.pause;
|
||||
}
|
||||
|
||||
public void reStartDrawRunnable(){
|
||||
if (handler != null){
|
||||
handler.post(new DrawRunnable());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* it is will be invoked after one frame is drawn
|
||||
*/
|
||||
protected abstract void onFrameDrawFinish();
|
||||
|
||||
/**
|
||||
* draw one frame to the surface by canvas
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
protected abstract void onFrameDraw(Canvas canvas);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.TextureView;
|
||||
|
||||
public abstract class BaseTextureView extends TextureView implements TextureView.SurfaceTextureListener {
|
||||
public static final int DEFAULT_FRAME_DURATION_MILLISECOND = 50;
|
||||
|
||||
private HandlerThread handlerThread;
|
||||
private SurfaceViewHandler handler;
|
||||
protected int frameDuration = DEFAULT_FRAME_DURATION_MILLISECOND;
|
||||
private Canvas canvas;
|
||||
private boolean isAlive;
|
||||
public boolean pause = false;
|
||||
|
||||
public BaseTextureView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BaseTextureView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public BaseTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
protected int getFrameDuration() {
|
||||
return frameDuration;
|
||||
}
|
||||
|
||||
protected void setFrameDuration(int frameDuration) {
|
||||
this.frameDuration = frameDuration;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
setOpaque(false);//设置背景透明,记住这里是[是否不透明]
|
||||
setSurfaceTextureListener(this);//设置监听
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
//当TextureView初始化时调用
|
||||
isAlive = true;
|
||||
startDrawThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
||||
//当TextureView的大小改变时调用
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
//当TextureView被销毁时调用
|
||||
stopDrawThread();
|
||||
isAlive = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
//当TextureView更新时调用,也就是当我们调用unlockCanvasAndPost方法时
|
||||
}
|
||||
|
||||
public void stopDrawThread() {
|
||||
handlerThread.quit();
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
handler = null;
|
||||
}
|
||||
|
||||
public void startDrawThread() {
|
||||
handlerThread = new HandlerThread("SurfaceViewThread");
|
||||
handlerThread.start();
|
||||
handler = new SurfaceViewHandler(handlerThread.getLooper());
|
||||
handler.post(new DrawRunnable());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int originWidth = getMeasuredWidth();
|
||||
int originHeight = getMeasuredHeight();
|
||||
int width = widthMode == MeasureSpec.AT_MOST ? getDefaultWidth() : originWidth;
|
||||
int height = heightMode == MeasureSpec.AT_MOST ? getDefaultHeight() : originHeight;
|
||||
setMeasuredDimension(width, height);
|
||||
Log.v("ttaylor", "BaseSurfaceView.onMeasure()" + " default Width=" + getDefaultWidth() + " default height=" + getDefaultHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* the width is used when wrap_content is set to layout_width
|
||||
* the child knows how big it should be
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract int getDefaultWidth();
|
||||
|
||||
/**
|
||||
* the height is used when wrap_content is set to layout_height
|
||||
* the child knows how big it should be
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract int getDefaultHeight();
|
||||
|
||||
|
||||
private class SurfaceViewHandler extends Handler {
|
||||
|
||||
public SurfaceViewHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class DrawRunnable implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isAlive) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
canvas = lockCanvas();
|
||||
onFrameDraw(canvas);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
unlockCanvasAndPost(canvas);
|
||||
onFrameDrawFinish();
|
||||
}
|
||||
|
||||
if (handler != null && !pause){
|
||||
handler.postDelayed(this, frameDuration);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void setPause(boolean pause){
|
||||
this.pause = pause;
|
||||
}
|
||||
|
||||
public boolean getPause(){
|
||||
return this.pause;
|
||||
}
|
||||
|
||||
public void reStartDrawRunnable(){
|
||||
pause = false;
|
||||
if (handler != null){
|
||||
handler.post(new DrawRunnable());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* it is will be invoked after one frame is drawn
|
||||
*/
|
||||
protected abstract void onFrameDrawFinish();
|
||||
|
||||
/**
|
||||
* draw one frame to the surface by canvas
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
protected abstract void onFrameDraw(Canvas canvas);
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* a SurfaceView which draws bitmaps one after another like frame animation
|
||||
*/
|
||||
public class FrameSurfaceView extends BaseSurfaceView {
|
||||
public static final int INVALID_INDEX = Integer.MAX_VALUE;
|
||||
private int bufferSize = 3;
|
||||
public static final String DECODE_THREAD_NAME = "DecodingThread";
|
||||
public static final int INFINITE = -1;
|
||||
//-1 means repeat infinitely
|
||||
private int repeatTimes;
|
||||
private int repeatedCount;
|
||||
|
||||
/**
|
||||
* the resources of frame animation
|
||||
*/
|
||||
private List<Integer> bitmapIds = new ArrayList<>();
|
||||
/**
|
||||
* the index of bitmap resource which is decoding
|
||||
*/
|
||||
private int bitmapIdIndex;
|
||||
/**
|
||||
* the index of frame which is drawing
|
||||
*/
|
||||
private int frameIndex = INVALID_INDEX;
|
||||
/**
|
||||
* decoded bitmaps stores in this queue
|
||||
* consumer is drawing thread, producer is decoding thread.
|
||||
*/
|
||||
private LinkedBlockingQueue decodedBitmaps = new LinkedBlockingQueue(bufferSize);
|
||||
/**
|
||||
* bitmaps already drawn by canvas stores in this queue
|
||||
* consumer is decoding thread, producer is drawing thread.
|
||||
*/
|
||||
private LinkedBlockingQueue drawnBitmaps = new LinkedBlockingQueue(bufferSize);
|
||||
/**
|
||||
* the thread for decoding bitmaps
|
||||
*/
|
||||
private HandlerThread decodeThread;
|
||||
/**
|
||||
* the Runnable describes how to decode one bitmap
|
||||
*/
|
||||
private DecodeRunnable decodeRunnable;
|
||||
/**
|
||||
* this handler helps to decode bitmap one after another
|
||||
*/
|
||||
private Handler handler;
|
||||
private BitmapFactory.Options options;
|
||||
private Paint paint = new Paint();
|
||||
private Rect srcRect;
|
||||
private Rect dstRect = new Rect();
|
||||
private int defaultWidth;
|
||||
private int defaultHeight;
|
||||
|
||||
public FrameSurfaceView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FrameSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public FrameSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void setRepeatTimes(int repeatTimes) {
|
||||
this.repeatTimes = repeatTimes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
options = new BitmapFactory.Options();
|
||||
options.inMutable = true;
|
||||
decodeThread = new HandlerThread(DECODE_THREAD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
dstRect.set(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultWidth() {
|
||||
return defaultWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultHeight() {
|
||||
return defaultHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameDrawFinish() {
|
||||
}
|
||||
|
||||
/**
|
||||
* set the duration of frame animation
|
||||
*
|
||||
* @param duration time in milliseconds
|
||||
*/
|
||||
public void setDuration(int duration) {
|
||||
int frameDuration = duration / bitmapIds.size();
|
||||
setFrameDuration(frameDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the materials of frame animation which is an array of bitmap resource id
|
||||
*
|
||||
* @param bitmapIds an array of bitmap resource id
|
||||
*/
|
||||
public void setBitmapIds(List<Integer> bitmapIds) {
|
||||
if (bitmapIds == null || bitmapIds.size() == 0) {
|
||||
return;
|
||||
}
|
||||
this.bitmapIds = bitmapIds;
|
||||
//by default, take the first bitmap's dimension into consideration
|
||||
getBitmapDimension(bitmapIds.get(bitmapIdIndex));
|
||||
preloadFrames();
|
||||
decodeRunnable = new DecodeRunnable(bitmapIdIndex, bitmapIds, options);
|
||||
}
|
||||
|
||||
private void getBitmapDimension(int bitmapId) {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeResource(this.getResources(), bitmapId, options);
|
||||
defaultWidth = options.outWidth;
|
||||
defaultHeight = options.outHeight;
|
||||
srcRect = new Rect(0, 0, defaultWidth, defaultHeight);
|
||||
//we have to re-measure to make defaultWidth in use in onMeasure()
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* load the first several frames of animation before it is started
|
||||
*/
|
||||
private void preloadFrames() {
|
||||
putDecodedBitmap(bitmapIds.get(bitmapIdIndex++), options, new LinkedBitmap());
|
||||
putDecodedBitmap(bitmapIds.get(bitmapIdIndex++), options, new LinkedBitmap());
|
||||
}
|
||||
|
||||
/**
|
||||
* recycle the bitmap used by frame animation.
|
||||
* Usually it should be invoked when the ui of frame animation is no longer visible
|
||||
*/
|
||||
public void destroy() {
|
||||
if (drawnBitmaps != null) {
|
||||
drawnBitmaps.clear();
|
||||
}
|
||||
if (decodeThread != null) {
|
||||
decodeThread.quit();
|
||||
decodeThread = null;
|
||||
}
|
||||
if (handler != null) {
|
||||
handler = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameDraw(Canvas canvas) {
|
||||
clearCanvas(canvas);
|
||||
if (!isStart()) {
|
||||
return;
|
||||
}
|
||||
if (!isFinish()) {
|
||||
drawOneFrame(canvas);
|
||||
} else {
|
||||
onFrameAnimationEnd();
|
||||
if (repeatTimes != 0 && repeatTimes == INFINITE) {
|
||||
start();
|
||||
} else if (repeatedCount < repeatTimes) {
|
||||
start();
|
||||
repeatedCount++;
|
||||
} else {
|
||||
repeatedCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draw a single frame which is a bitmap
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawOneFrame(Canvas canvas) {
|
||||
try {
|
||||
LinkedBitmap linkedBitmap = getDecodedBitmap();
|
||||
if (linkedBitmap != null) {
|
||||
canvas.drawBitmap(linkedBitmap.bitmap, srcRect, dstRect, paint);
|
||||
}
|
||||
putDrawnBitmap(linkedBitmap);
|
||||
frameIndex++;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* invoked when frame animation is done
|
||||
*/
|
||||
private void onFrameAnimationEnd() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the index of frame, preparing for the next frame animation
|
||||
*/
|
||||
private void reset() {
|
||||
frameIndex = INVALID_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether frame animation is finished
|
||||
*
|
||||
* @return true: animation is finished, false: animation is doing
|
||||
*/
|
||||
private boolean isFinish() {
|
||||
return frameIndex >= bitmapIds.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether frame animation is started
|
||||
*
|
||||
* @return true: animation is started, false: animation is not started
|
||||
*/
|
||||
private boolean isStart() {
|
||||
return frameIndex != INVALID_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* start frame animation from the first frame
|
||||
*/
|
||||
public void start() {
|
||||
frameIndex = 0;
|
||||
if (decodeThread == null) {
|
||||
decodeThread = new HandlerThread(DECODE_THREAD_NAME);
|
||||
}
|
||||
if (!decodeThread.isAlive()) {
|
||||
decodeThread.start();
|
||||
}
|
||||
if (handler == null) {
|
||||
handler = new Handler(decodeThread.getLooper());
|
||||
}
|
||||
if (decodeRunnable != null) {
|
||||
decodeRunnable.setIndex(0);
|
||||
}
|
||||
handler.post(decodeRunnable);
|
||||
}
|
||||
|
||||
public void pause(){
|
||||
setPause(true);
|
||||
}
|
||||
|
||||
public void start(boolean restart){
|
||||
if (restart){
|
||||
if (frameIndex == INVALID_INDEX ){
|
||||
start();
|
||||
}else{
|
||||
if (getPause()){
|
||||
setPause(false);
|
||||
reStartDrawRunnable();
|
||||
}else{
|
||||
start();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear out the drawing on canvas,preparing for the next frame
|
||||
* * @param canvas
|
||||
*/
|
||||
private void clearCanvas(Canvas canvas) {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
canvas.drawPaint(paint);
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
|
||||
}
|
||||
|
||||
/**
|
||||
* decode bitmap by BitmapFactory.decodeStream(), it is about twice faster than BitmapFactory.decodeResource()
|
||||
*
|
||||
* @param resId the bitmap resource
|
||||
* @param options
|
||||
* @return
|
||||
*/
|
||||
private Bitmap decodeBitmap(int resId, BitmapFactory.Options options) {
|
||||
options.inScaled = false;
|
||||
InputStream inputStream = getResources().openRawResource(resId);
|
||||
return BitmapFactory.decodeStream(inputStream, null, options);
|
||||
}
|
||||
|
||||
private void putDecodedBitmapByReuse(int resId, BitmapFactory.Options options) {
|
||||
LinkedBitmap linkedBitmap = getDrawnBitmap();
|
||||
if (linkedBitmap == null) {
|
||||
linkedBitmap = new LinkedBitmap();
|
||||
}
|
||||
options.inBitmap = linkedBitmap.bitmap;
|
||||
putDecodedBitmap(resId, options, linkedBitmap);
|
||||
}
|
||||
|
||||
private void putDecodedBitmap(int resId, BitmapFactory.Options options, LinkedBitmap linkedBitmap) {
|
||||
Bitmap bitmap = decodeBitmap(resId, options);
|
||||
linkedBitmap.bitmap = bitmap;
|
||||
try {
|
||||
decodedBitmaps.put(linkedBitmap);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void putDrawnBitmap(LinkedBitmap bitmap) {
|
||||
if (bitmap == null)return;
|
||||
drawnBitmaps.offer(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* get bitmap which already drawn by canvas
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private LinkedBitmap getDrawnBitmap() {
|
||||
LinkedBitmap bitmap = null;
|
||||
try {
|
||||
bitmap = drawnBitmaps.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* get decoded bitmap in the decoded bitmap queue
|
||||
* it might block due to new bitmap is not ready
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private LinkedBitmap getDecodedBitmap() {
|
||||
LinkedBitmap bitmap = null;
|
||||
try {
|
||||
bitmap = decodedBitmaps.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private class DecodeRunnable implements Runnable {
|
||||
|
||||
private int index;
|
||||
private List<Integer> bitmapIds;
|
||||
private BitmapFactory.Options options;
|
||||
|
||||
public DecodeRunnable(int index, List<Integer> bitmapIds, BitmapFactory.Options options) {
|
||||
this.index = index;
|
||||
this.bitmapIds = bitmapIds;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
putDecodedBitmapByReuse(bitmapIds.get(index), options);
|
||||
index++;
|
||||
if (index < bitmapIds.size()) {
|
||||
handler.post(this);
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* a SurfaceView which draws bitmaps one after another like frame animation
|
||||
*/
|
||||
public class FrameTextureView extends BaseTextureView {
|
||||
public static final int INVALID_INDEX = Integer.MAX_VALUE;
|
||||
private int bufferSize = 3;
|
||||
public static final String DECODE_THREAD_NAME = "DecodingThread";
|
||||
public static final int INFINITE = -1;
|
||||
//-1 means repeat infinitely
|
||||
private int repeatTimes;
|
||||
private int repeatedCount;
|
||||
|
||||
/**
|
||||
* the resources of frame animation
|
||||
*/
|
||||
private List<Integer> bitmapIds = new ArrayList<>();
|
||||
/**
|
||||
* the index of bitmap resource which is decoding
|
||||
*/
|
||||
private int bitmapIdIndex;
|
||||
/**
|
||||
* the index of frame which is drawing
|
||||
*/
|
||||
private int frameIndex = INVALID_INDEX;
|
||||
/**
|
||||
* decoded bitmaps stores in this queue
|
||||
* consumer is drawing thread, producer is decoding thread.
|
||||
*/
|
||||
private LinkedBlockingQueue decodedBitmaps = new LinkedBlockingQueue(bufferSize);
|
||||
/**
|
||||
* bitmaps already drawn by canvas stores in this queue
|
||||
* consumer is decoding thread, producer is drawing thread.
|
||||
*/
|
||||
private LinkedBlockingQueue drawnBitmaps = new LinkedBlockingQueue(bufferSize);
|
||||
/**
|
||||
* the thread for decoding bitmaps
|
||||
*/
|
||||
private HandlerThread decodeThread;
|
||||
/**
|
||||
* the Runnable describes how to decode one bitmap
|
||||
*/
|
||||
private DecodeRunnable decodeRunnable;
|
||||
/**
|
||||
* this handler helps to decode bitmap one after another
|
||||
*/
|
||||
private Handler handler;
|
||||
private BitmapFactory.Options options;
|
||||
private Paint paint = new Paint();
|
||||
private Rect srcRect;
|
||||
private Rect dstRect = new Rect();
|
||||
private int defaultWidth;
|
||||
private int defaultHeight;
|
||||
|
||||
public FrameTextureView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FrameTextureView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public FrameTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void setRepeatTimes(int repeatTimes) {
|
||||
this.repeatTimes = repeatTimes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
options = new BitmapFactory.Options();
|
||||
options.inMutable = true;
|
||||
decodeThread = new HandlerThread(DECODE_THREAD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
dstRect.set(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultWidth() {
|
||||
return defaultWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultHeight() {
|
||||
return defaultHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameDrawFinish() {
|
||||
}
|
||||
|
||||
/**
|
||||
* set the duration of frame animation
|
||||
*
|
||||
* @param duration time in milliseconds
|
||||
*/
|
||||
public void setDuration(int duration) {
|
||||
int frameDuration = duration / bitmapIds.size();
|
||||
setFrameDuration(frameDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the materials of frame animation which is an array of bitmap resource id
|
||||
*
|
||||
* @param bitmapIds an array of bitmap resource id
|
||||
*/
|
||||
public void setBitmapIds(List<Integer> bitmapIds) {
|
||||
if (bitmapIds == null || bitmapIds.size() == 0) {
|
||||
return;
|
||||
}
|
||||
this.bitmapIds = bitmapIds;
|
||||
//by default, take the first bitmap's dimension into consideration
|
||||
getBitmapDimension(bitmapIds.get(bitmapIdIndex));
|
||||
preloadFrames();
|
||||
decodeRunnable = new DecodeRunnable(bitmapIdIndex, bitmapIds, options);
|
||||
}
|
||||
|
||||
private void getBitmapDimension(int bitmapId) {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeResource(this.getResources(), bitmapId, options);
|
||||
defaultWidth = options.outWidth;
|
||||
defaultHeight = options.outHeight;
|
||||
srcRect = new Rect(0, 0, defaultWidth, defaultHeight);
|
||||
//we have to re-measure to make defaultWidth in use in onMeasure()
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* load the first several frames of animation before it is started
|
||||
*/
|
||||
private void preloadFrames() {
|
||||
putDecodedBitmap(bitmapIds.get(bitmapIdIndex++), options, new LinkedBitmap());
|
||||
putDecodedBitmap(bitmapIds.get(bitmapIdIndex++), options, new LinkedBitmap());
|
||||
}
|
||||
|
||||
/**
|
||||
* recycle the bitmap used by frame animation.
|
||||
* Usually it should be invoked when the ui of frame animation is no longer visible
|
||||
*/
|
||||
public void destroy() {
|
||||
if (drawnBitmaps != null) {
|
||||
drawnBitmaps.clear();
|
||||
}
|
||||
if (decodeThread != null) {
|
||||
decodeThread.quit();
|
||||
decodeThread = null;
|
||||
}
|
||||
if (handler != null) {
|
||||
handler = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameDraw(Canvas canvas) {
|
||||
clearCanvas(canvas);
|
||||
if (!isStart()) {
|
||||
return;
|
||||
}
|
||||
if (!isFinish()) {
|
||||
drawOneFrame(canvas);
|
||||
} else {
|
||||
onFrameAnimationEnd();
|
||||
if (repeatTimes != 0 && repeatTimes == INFINITE) {
|
||||
start();
|
||||
} else if (repeatedCount < repeatTimes) {
|
||||
start();
|
||||
repeatedCount++;
|
||||
} else {
|
||||
repeatedCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draw a single frame which is a bitmap
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawOneFrame(Canvas canvas) {
|
||||
LinkedBitmap linkedBitmap = getDecodedBitmap();
|
||||
if (linkedBitmap != null) {
|
||||
canvas.drawBitmap(linkedBitmap.bitmap, srcRect, dstRect, paint);
|
||||
}
|
||||
putDrawnBitmap(linkedBitmap);
|
||||
frameIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
* invoked when frame animation is done
|
||||
*/
|
||||
private void onFrameAnimationEnd() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the index of frame, preparing for the next frame animation
|
||||
*/
|
||||
private void reset() {
|
||||
frameIndex = INVALID_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether frame animation is finished
|
||||
*
|
||||
* @return true: animation is finished, false: animation is doing
|
||||
*/
|
||||
private boolean isFinish() {
|
||||
return frameIndex >= bitmapIds.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether frame animation is started
|
||||
*
|
||||
* @return true: animation is started, false: animation is not started
|
||||
*/
|
||||
private boolean isStart() {
|
||||
return frameIndex != INVALID_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* start frame animation from the first frame
|
||||
*/
|
||||
public void start() {
|
||||
pause = false;
|
||||
frameIndex = 0;
|
||||
if (decodeThread == null) {
|
||||
decodeThread = new HandlerThread(DECODE_THREAD_NAME);
|
||||
}
|
||||
if (!decodeThread.isAlive()) {
|
||||
decodeThread.start();
|
||||
}
|
||||
if (handler == null) {
|
||||
handler = new Handler(decodeThread.getLooper());
|
||||
}
|
||||
if (decodeRunnable != null) {
|
||||
decodeRunnable.setIndex(0);
|
||||
}
|
||||
handler.post(decodeRunnable);
|
||||
}
|
||||
|
||||
public void pause(){
|
||||
setPause(true);
|
||||
}
|
||||
|
||||
public void start(boolean restart){
|
||||
if (restart){
|
||||
if (!isStart() || !getPause()){
|
||||
start();
|
||||
}else{
|
||||
reStartDrawRunnable();
|
||||
}
|
||||
}else{
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear out the drawing on canvas,preparing for the next frame
|
||||
* * @param canvas
|
||||
*/
|
||||
private void clearCanvas(Canvas canvas) {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
canvas.drawPaint(paint);
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
|
||||
}
|
||||
|
||||
/**
|
||||
* decode bitmap by BitmapFactory.decodeStream(), it is about twice faster than BitmapFactory.decodeResource()
|
||||
*
|
||||
* @param resId the bitmap resource
|
||||
* @param options
|
||||
* @return
|
||||
*/
|
||||
private Bitmap decodeBitmap(int resId, BitmapFactory.Options options) {
|
||||
options.inScaled = false;
|
||||
InputStream inputStream = getResources().openRawResource(resId);
|
||||
return BitmapFactory.decodeStream(inputStream, null, options);
|
||||
}
|
||||
|
||||
private void putDecodedBitmapByReuse(int resId, BitmapFactory.Options options) {
|
||||
LinkedBitmap linkedBitmap = getDrawnBitmap();
|
||||
if (linkedBitmap == null) {
|
||||
linkedBitmap = new LinkedBitmap();
|
||||
}
|
||||
options.inBitmap = linkedBitmap.bitmap;
|
||||
putDecodedBitmap(resId, options, linkedBitmap);
|
||||
}
|
||||
|
||||
private void putDecodedBitmap(int resId, BitmapFactory.Options options, LinkedBitmap linkedBitmap) {
|
||||
Bitmap bitmap = decodeBitmap(resId, options);
|
||||
linkedBitmap.bitmap = bitmap;
|
||||
try {
|
||||
decodedBitmaps.put(linkedBitmap);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void putDrawnBitmap(LinkedBitmap bitmap) {
|
||||
drawnBitmaps.offer(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* get bitmap which already drawn by canvas
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private LinkedBitmap getDrawnBitmap() {
|
||||
LinkedBitmap bitmap = null;
|
||||
try {
|
||||
bitmap = drawnBitmaps.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* get decoded bitmap in the decoded bitmap queue
|
||||
* it might block due to new bitmap is not ready
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private LinkedBitmap getDecodedBitmap() {
|
||||
LinkedBitmap bitmap = null;
|
||||
try {
|
||||
bitmap = decodedBitmaps.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private class DecodeRunnable implements Runnable {
|
||||
|
||||
private int index;
|
||||
private List<Integer> bitmapIds;
|
||||
private BitmapFactory.Options options;
|
||||
|
||||
public DecodeRunnable(int index, List<Integer> bitmapIds, BitmapFactory.Options options) {
|
||||
this.index = index;
|
||||
this.bitmapIds = bitmapIds;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
putDecodedBitmapByReuse(bitmapIds.get(index), options);
|
||||
index++;
|
||||
if (index < bitmapIds.size()) {
|
||||
handler.post(this);
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class LinkedBitmap {
|
||||
public Bitmap bitmap;
|
||||
public LinkedBitmap next;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class LinkedBlockingQueue {
|
||||
/**
|
||||
* Current number of elements
|
||||
*/
|
||||
private final AtomicInteger count = new AtomicInteger();
|
||||
/**
|
||||
* Lock held by take, poll, etc
|
||||
*/
|
||||
private final ReentrantLock takeLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Wait queue for waiting takes
|
||||
*/
|
||||
private final Condition notEmpty = takeLock.newCondition();
|
||||
|
||||
/**
|
||||
* Lock held by put, offer, etc
|
||||
*/
|
||||
private final ReentrantLock putLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Wait queue for waiting puts
|
||||
*/
|
||||
private final Condition notFull = putLock.newCondition();
|
||||
/**
|
||||
* The capacity bound, or Integer.MAX_VALUE if none
|
||||
*/
|
||||
private final int capacity;
|
||||
/**
|
||||
* the first element in the queue
|
||||
*/
|
||||
private LinkedBitmap head;
|
||||
/**
|
||||
* the last element int the queue
|
||||
*/
|
||||
private LinkedBitmap tail;
|
||||
|
||||
|
||||
public LinkedBlockingQueue(int capacity) {
|
||||
if (capacity <= 0) throw new IllegalArgumentException();
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public void put(LinkedBitmap bitmap) throws InterruptedException {
|
||||
if (bitmap == null) throw new NullPointerException();
|
||||
// Note: convention in all put/take/etc is to preset local var
|
||||
// holding count negative to indicate failure unless set.
|
||||
int c = -1;
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
final AtomicInteger count = this.count;
|
||||
putLock.lockInterruptibly();
|
||||
try {
|
||||
/*
|
||||
* Note that count is used in wait guard even though it is
|
||||
* not protected by lock. This works because count can
|
||||
* only decrease at this point (all other puts are shut
|
||||
* out by lock), and we (or some other waiting put) are
|
||||
* signalled if it ever changes from capacity. Similarly
|
||||
* for all other uses of count in other wait guards.
|
||||
*/
|
||||
while (count.get() == capacity) {
|
||||
notFull.await();
|
||||
}
|
||||
enqueue(bitmap);
|
||||
c = count.getAndIncrement();
|
||||
if (c + 1 < capacity)
|
||||
notFull.signal();
|
||||
} finally {
|
||||
putLock.unlock();
|
||||
}
|
||||
if (c == 0)
|
||||
signalNotEmpty();
|
||||
}
|
||||
|
||||
public boolean offer(LinkedBitmap bitmap) {
|
||||
if (bitmap == null) throw new NullPointerException();
|
||||
final AtomicInteger count = this.count;
|
||||
if (count.get() == capacity)
|
||||
return false;
|
||||
int c = -1;
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
putLock.lock();
|
||||
try {
|
||||
if (count.get() < capacity) {
|
||||
enqueue(bitmap);
|
||||
c = count.getAndIncrement();
|
||||
if (c + 1 < capacity)
|
||||
notFull.signal();
|
||||
}
|
||||
} finally {
|
||||
putLock.unlock();
|
||||
}
|
||||
if (c == 0)
|
||||
signalNotEmpty();
|
||||
return c >= 0;
|
||||
}
|
||||
|
||||
public LinkedBitmap take() throws InterruptedException {
|
||||
LinkedBitmap x;
|
||||
int c = -1;
|
||||
final AtomicInteger count = this.count;
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lockInterruptibly();
|
||||
try {
|
||||
while (count.get() == 0) {
|
||||
notEmpty.await();
|
||||
}
|
||||
x = dequeue();
|
||||
c = count.getAndDecrement();
|
||||
if (c > 1)
|
||||
notEmpty.signal();
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
if (c == capacity)
|
||||
signalNotFull();
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* insert element into the end of queue
|
||||
*
|
||||
* @param bitmap
|
||||
*/
|
||||
private void enqueue(LinkedBitmap bitmap) {
|
||||
if (head == null) {
|
||||
head = bitmap;
|
||||
tail = bitmap;
|
||||
bitmap.next = null;
|
||||
} else {
|
||||
tail.next = bitmap;
|
||||
bitmap.next = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get and remove the first element of the queue
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private LinkedBitmap dequeue() {
|
||||
LinkedBitmap p = head;
|
||||
if (p == null) {
|
||||
return null;
|
||||
} else {
|
||||
head = head.next;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals a waiting take. Called only from put/offer (which do not
|
||||
* otherwise ordinarily lock takeLock.)
|
||||
*/
|
||||
private void signalNotEmpty() {
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lock();
|
||||
try {
|
||||
notEmpty.signal();
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals a waiting put. Called only from take/poll.
|
||||
*/
|
||||
private void signalNotFull() {
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
putLock.lock();
|
||||
try {
|
||||
notFull.signal();
|
||||
} finally {
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recycle the bitmaps one by one
|
||||
*/
|
||||
public void clear() {
|
||||
LinkedBitmap p = head;
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
while (p != null) {
|
||||
if (p.bitmap != null) {
|
||||
p.bitmap.recycle();
|
||||
}
|
||||
p.bitmap = null;
|
||||
p = p.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
public class MethodUtil {
|
||||
|
||||
/**
|
||||
* calculate the time consumed by runnable invocation, print log in millisecond
|
||||
*
|
||||
* @param runnable
|
||||
*/
|
||||
public static long time(Runnable runnable) {
|
||||
long start = SystemClock.elapsedRealtime();
|
||||
runnable.run();
|
||||
long end = SystemClock.elapsedRealtime();
|
||||
long span = end - start;
|
||||
Log.v("ttaylor", "MethodUtil.time()" + " time span = " + span + " ms");
|
||||
return span;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mogo.module.media.widget.surfaceview;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
public class NumberUtil {
|
||||
|
||||
private static long total;
|
||||
private static int times;
|
||||
|
||||
private static String tag;
|
||||
|
||||
/**
|
||||
* calculate the average of a series long number and print it
|
||||
* @param tag
|
||||
* @param l
|
||||
*/
|
||||
public static void average(String tag, Long l) {
|
||||
if (!TextUtils.isEmpty(tag) && !tag.equals(NumberUtil.tag)) {
|
||||
reset();
|
||||
NumberUtil.tag = tag;
|
||||
}
|
||||
times++;
|
||||
total += l;
|
||||
Log.v("ttaylor", "Average.average() " + NumberUtil.tag + " average = " + (total / times));
|
||||
}
|
||||
|
||||
private static void reset() {
|
||||
total = 0;
|
||||
times = 0;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 520 B |
|
After Width: | Height: | Size: 879 B |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 454 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 703 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 885 B |
|
After Width: | Height: | Size: 3.0 KiB |