add media module

This commit is contained in:
wangcongtao
2020-06-03 15:57:06 +08:00
parent b62e66e9c9
commit 82e0a15f2e
243 changed files with 13684 additions and 11 deletions

1
.idea/gradle.xml generated
View File

@@ -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" />

View File

@@ -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')
}

View File

@@ -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" />

View File

@@ -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
View 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

View 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()

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.module
POM_ARTIFACT_ID=module-media
VERSION_CODE=1

View 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.** { *; }

View File

@@ -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());
}
}

View 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>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

View File

@@ -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 "";
}
}

View File

@@ -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";
}

View File

@@ -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();
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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 );
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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、click2、小智语音
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、click2、小智语音3、卡片
String EVENT_QQ_MUSIC_PAUSE = "QQMusicSuspend";// 音乐暂停 type 1、click2、小智语音3、卡片
String EVENT_QQ_LAST_PLAY = "QQMusicTheLast";//qq音乐上一章 type 1、click2、小智语音3、卡片
String EVENT_QQ_Next_PLAY = "QQMusicNext";//qq音乐下一章 type 1、click2、小智语音3、卡片
String EVENT_BOOK_OPEN_SHARE_DIALOG_SHOW = "card_Book_pop";//打开分享弹窗 type 1、click2、小智语音
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、click2、小智语音3、卡片
String EVENT_BOOK_MUSIC_PAUSE = "BookSuspend";// 书暂停 type 1、click2、小智语音3、卡片
String EVENT_BOOK_LAST_PLAY = "BookTheLast";//懒人听书上一章 type 1、click2、小智语音3、卡片
String EVENT_BOOK_Next_PLAY = "BookNext";//懒人听书下一章 type 1、click2、小智语音3、卡片
String EVENT_NEWS_OPEN_SHARE_DIALOG_SHOW = "card_News_pop";//打开分享弹窗 type 1、click2、小智语音
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、click2、小智语音3、卡片
String EVENT_NEWS_MUSIC_PAUSE = "NewsSuspend";// 新闻暂停 type 1、click2、小智语音3、卡片
String EVENT_NEWS_LAST_PLAY = "NewsTheLast";//新闻上一章 type 1、click2、小智语音3、卡片
String EVENT_NEWS_Next_PLAY = "NewsNext";//新闻下一章 type 1、click2、小智语音3、卡片
}

View File

@@ -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";//书本实例
}

View File

@@ -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";//专辑名
}

View File

@@ -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";
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}
);
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,7 @@
package com.mogo.module.media.model;
import java.io.Serializable;
public class MediaInfoDataEvent implements Serializable {
public MediaInfoData data;
}

View File

@@ -0,0 +1,7 @@
package com.mogo.module.media.model;
import java.io.Serializable;
public class MediaProcessEvent implements Serializable {
public int process;
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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":"男也可以012根据实际库存返回即可","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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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 参数commandcom.zhidao.book.play
* 乐听头条:播放新闻、我要听新闻、我要听{类型}新闻、听新闻actioncom.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();
}
}
}
}
}
}

View File

@@ -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 {
//actioncom.zhidao.action.MEDIA_LRTS
//actioncom.zhidao.action.MEDIA_LT_NEWS
//actioncom.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();
}*/
}
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,6 @@
package com.mogo.module.media.utils;
public interface OnBitmapToLocalListener {
void saveSuccess(String path);
void saveFailed();
}

View File

@@ -0,0 +1,9 @@
package com.mogo.module.media.utils;
public interface OnCompressListener {
void onCompressSuccess(byte[] data);
void onCompressFailed(String msg);
void onBeforeCompress();
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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 ;
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,9 @@
package com.mogo.module.media.widget.surfaceview;
import android.graphics.Bitmap;
public class LinkedBitmap {
public Bitmap bitmap;
public LinkedBitmap next;
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Some files were not shown because too many files have changed in this diff Show More