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();
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/ServiceMediaHandler.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/ServiceMediaHandler.java
new file mode 100644
index 0000000000..0ea73dd478
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/ServiceMediaHandler.java
@@ -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;
+
+/**
+ *
+ * 持有服务接口实例
+ */
+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());
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/api/MediaDztService.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/api/MediaDztService.java
new file mode 100644
index 0000000000..0adfc59051
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/api/MediaDztService.java
@@ -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 selectByPrimaryKey(@QueryMap Map params);
+
+ /**
+ * 分享音乐
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST
+ Observable shareMusic(@Url String url, @Body RequestBody body);
+
+ /**
+ * 好友分享的歌
+ */
+ @GET("/sunflower/os/music/car/v1/getFriendsMusic")
+ Observable getFriendShareMusic(@QueryMap Map params);
+
+ /**
+ * 是否需要触发分享
+ */
+ @GET("/sunflower/os/music/car/v1/checkShare")
+ Observable getShouldPushShare(@QueryMap Map params);
+
+ /**
+ * 开始音乐
+ */
+ @FormUrlEncoded
+ @POST("/yycp-launcherSnapshot/mediaShare/mediaStart")
+ Observable startedMusic(@FieldMap Map params );
+
+ /**
+ * 停止音乐
+ */
+ @FormUrlEncoded
+ @POST("/yycp-launcherSnapshot/mediaShare/mediaPause")
+ Observable stopMusic(@FieldMap Map params );
+
+ /**
+ * 点赞分享
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST
+ Observable likeShare(@Url String url, @Body RequestBody body);
+
+ /**
+ * 获取附近分享的歌,传入一个type,单独拉取模块的markerdata
+ */
+ @FormUrlEncoded
+ @POST("/yycp-launcherSnapshot/launcherSnapshot/querySnapshotSync")
+ Observable getNearShareMusic(@FieldMap Map params );
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/BaseUrlConstants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/BaseUrlConstants.java
new file mode 100644
index 0000000000..b93b485722
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/BaseUrlConstants.java
@@ -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";
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/Constants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/Constants.java
new file mode 100644
index 0000000000..28eb9095d5
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/Constants.java
@@ -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";
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/EventConstants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/EventConstants.java
new file mode 100644
index 0000000000..46cfaef99a
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/EventConstants.java
@@ -0,0 +1,28 @@
+package com.mogo.module.media.constants;
+
+public interface EventConstants {
+ String EVENT_QQ_OPEN_SHARE_DIALOG_SHOW = "card_QQMusic_pop";//打开分享弹窗 type 1、click,2、小智语音
+ String EVENT_QQ_SHARE_DIALOG_OK = "card_QQMusic_affirm";//弹窗内选择“确认”
+ String EVENT_QQ_SHARE_DIALOG_CANCLE = "card_QQMusic_close";//弹窗内选择“取消”
+ String EVENT_QQ_MUSIC_START = "QQMusicBegin";// 音乐开始 type 1、click,2、小智语音,3、卡片
+ String EVENT_QQ_MUSIC_PAUSE = "QQMusicSuspend";// 音乐暂停 type 1、click,2、小智语音,3、卡片
+ String EVENT_QQ_LAST_PLAY = "QQMusicTheLast";//qq音乐上一章 type 1、click,2、小智语音,3、卡片
+ String EVENT_QQ_Next_PLAY = "QQMusicNext";//qq音乐下一章 type 1、click,2、小智语音,3、卡片
+
+ String EVENT_BOOK_OPEN_SHARE_DIALOG_SHOW = "card_Book_pop";//打开分享弹窗 type 1、click,2、小智语音
+ String EVENT_BOOK_SHARE_DIALOG_OK = "card_Book_affirm";//弹窗内选择“确认”
+ String EVENT_BOOK_SHARE_DIALOG_CANCLE = "card_Book_close";//弹窗内选择“取消”
+ String EVENT_BOOK_MUSIC_START = "BookBegin";// 书开始 type 1、click,2、小智语音,3、卡片
+ String EVENT_BOOK_MUSIC_PAUSE = "BookSuspend";// 书暂停 type 1、click,2、小智语音,3、卡片
+ String EVENT_BOOK_LAST_PLAY = "BookTheLast";//懒人听书上一章 type 1、click,2、小智语音,3、卡片
+ String EVENT_BOOK_Next_PLAY = "BookNext";//懒人听书下一章 type 1、click,2、小智语音,3、卡片
+
+ String EVENT_NEWS_OPEN_SHARE_DIALOG_SHOW = "card_News_pop";//打开分享弹窗 type 1、click,2、小智语音
+ String EVENT_NEWS_SHARE_DIALOG_OK = "card_News_affirm";//弹窗内选择“确认”
+ String EVENT_NEWS_SHARE_DIALOG_CANCLE = "card_News_close";//弹窗内选择“取消”
+ String EVENT_NEWS_MUSIC_START = "NewsBegin";// 新闻开始 type 1、click,2、小智语音,3、卡片
+ String EVENT_NEWS_MUSIC_PAUSE = "NewsSuspend";// 新闻暂停 type 1、click,2、小智语音,3、卡片
+ String EVENT_NEWS_LAST_PLAY = "NewsTheLast";//新闻上一章 type 1、click,2、小智语音,3、卡片
+ String EVENT_NEWS_Next_PLAY = "NewsNext";//新闻下一章 type 1、click,2、小智语音,3、卡片
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/LeTingFieldConstants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/LeTingFieldConstants.java
new file mode 100644
index 0000000000..68ecba4a7e
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/LeTingFieldConstants.java
@@ -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";//书本实例
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/QQMusicFieldConstants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/QQMusicFieldConstants.java
new file mode 100644
index 0000000000..8c6c8915ef
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/QQMusicFieldConstants.java
@@ -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";//专辑名
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/VoiceConstants.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/VoiceConstants.java
new file mode 100644
index 0000000000..ee00d72ce0
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/constants/VoiceConstants.java
@@ -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";
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/BaseDialogFragment.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/BaseDialogFragment.java
new file mode 100644
index 0000000000..f899862699
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/BaseDialogFragment.java
@@ -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);
+ }
+ }
+}
+
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/CustomDialog.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/CustomDialog.java
new file mode 100644
index 0000000000..2e11fbdbe2
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/CustomDialog.java
@@ -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;
+ }
+}
+
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/MediaShareDialogFragment.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/MediaShareDialogFragment.java
new file mode 100644
index 0000000000..9dbfd499fe
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/dialog/MediaShareDialogFragment.java
@@ -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 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 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 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 params = builder
+ .append(businessParams)
+ .build();
+ Observable 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(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();
+ }
+ }
+ }
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/MogoVoiceCmdCallBackImp.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/MogoVoiceCmdCallBackImp.java
new file mode 100644
index 0000000000..958debea23
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/MogoVoiceCmdCallBackImp.java
@@ -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) {
+
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/NoDoubleClickListener.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/NoDoubleClickListener.java
new file mode 100644
index 0000000000..006165855c
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/listener/NoDoubleClickListener.java
@@ -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);
+}
+
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LanRenInsertData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LanRenInsertData.java
new file mode 100644
index 0000000000..507bcf0754
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LanRenInsertData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LeTingNewsData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LeTingNewsData.java
new file mode 100644
index 0000000000..68bc3046ba
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/LeTingNewsData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoData.java
new file mode 100644
index 0000000000..aafffdbe03
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoDataEvent.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoDataEvent.java
new file mode 100644
index 0000000000..3849d03d76
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaInfoDataEvent.java
@@ -0,0 +1,7 @@
+package com.mogo.module.media.model;
+
+import java.io.Serializable;
+
+public class MediaInfoDataEvent implements Serializable {
+ public MediaInfoData data;
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaProcessEvent.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaProcessEvent.java
new file mode 100644
index 0000000000..64c3419e97
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/MediaProcessEvent.java
@@ -0,0 +1,7 @@
+package com.mogo.module.media.model;
+
+import java.io.Serializable;
+
+public class MediaProcessEvent implements Serializable {
+ public int process;
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/NearShareRequestParameter.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/NearShareRequestParameter.java
new file mode 100644
index 0000000000..18c7a6767c
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/NearShareRequestParameter.java
@@ -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 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 getDataType() {
+ return dataType;
+ }
+
+ public void setDataType(List 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;
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/QQMediaListData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/QQMediaListData.java
new file mode 100644
index 0000000000..916ba6da1e
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/QQMediaListData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareLikeData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareLikeData.java
new file mode 100644
index 0000000000..f6018c6241
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareLikeData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaJsonData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaJsonData.java
new file mode 100644
index 0000000000..3f70002032
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaJsonData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaMarkerInfoData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaMarkerInfoData.java
new file mode 100644
index 0000000000..68351b20a4
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareMediaMarkerInfoData.java
@@ -0,0 +1,47 @@
+package com.mogo.module.media.model;
+
+import com.mogo.commons.data.BaseData;
+import com.mogo.module.common.entity.MarkerShareMusic;
+
+import java.util.ArrayList;
+
+/**
+ MarkerShareMusic 结构说明:
+ * bookInfo : 懒人听书实体json串
+ * id : 100
+ * likeNumber : 99
+ * location : {"address":"北京市朝阳区三里屯街道108号","angle":"36.5","lat":"39.989368","lon":"116.480888"}
+ * mediaId : 音乐id
+ * mediaImg : 歌曲封面img url
+ * mediaName : 歌曲名
+ * mediaSinger : 歌手名
+ * mediaUrl : 歌曲url
+ * shareContentText : 分享的文字
+ * shareType : 1
+ * type : 卡片类型
+ * userInfo : {"age":"00后","gender":"男|女|无(也可以0|1|2根据实际库存返回即可)","sn":"018209312809312","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","userId":1,"userName":"用户昵称"}
+ */
+public class ShareMediaMarkerInfoData extends BaseData {
+
+ public ShareMediaMarkerInfoDataResult result;
+
+ public ShareMediaMarkerInfoDataResult getResult() {
+ return result;
+ }
+
+ public void setResult(ShareMediaMarkerInfoDataResult result) {
+ this.result = result;
+ }
+
+ public static class ShareMediaMarkerInfoDataResult{
+ public ArrayList shareMusic;
+
+ public ArrayList getShareMusic() {
+ return shareMusic;
+ }
+
+ public void setShareMusic(ArrayList shareMusic) {
+ this.shareMusic = shareMusic;
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareSuccessResult.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareSuccessResult.java
new file mode 100644
index 0000000000..9ad4338644
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShareSuccessResult.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShowShareData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShowShareData.java
new file mode 100644
index 0000000000..675299d556
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/ShowShareData.java
@@ -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;
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/url/UrlData.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/url/UrlData.java
new file mode 100644
index 0000000000..1143beba8a
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/model/url/UrlData.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/presenter/MediaPresenter.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/presenter/MediaPresenter.java
new file mode 100644
index 0000000000..292d9e1b0c
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/presenter/MediaPresenter.java
@@ -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 {
+
+ private static final String TAG = "MediaPresenter";
+ private ArrayList 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 parameters = builder.build();
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getFriendShareMusic(parameters);
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(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 hashMap = new HashMap<>();
+ hashMap.put("mediaType", mCurrentMusic.getType());
+ hashMap.put("shareData", mCurrentMusic);
+ builder.append("data", GsonUtil.jsonFromObject(hashMap));
+ Map parameters = builder.build();
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).startedMusic(parameters);
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(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 list = new ArrayList<>();
+ list.add(MediaConstants.MODULE_TYPE);
+ nearData.setDataType(list);
+ builder.append("data", GsonUtil.jsonFromObject(nearData));
+ Map parameters = builder.build();
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getNearShareMusic(parameters);
+ Disposable disposable = observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new Consumer() {
+ @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() {
+ @Override
+ public void accept(Throwable throwable) throws Exception {
+ TipToast.shortTip("获取附近的歌失败");
+ }
+ }
+ );
+
+ addDispose(disposable);
+ }
+
+ /**
+ * 停止音乐播放的接口
+ */
+ public void stopMusic() {
+ final ParamsProvider.Builder builder = new ParamsProvider.Builder(getContext());
+ Map parameters = builder.build();
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).stopMusic(parameters);
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(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 parameters = builder.build();
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).getShouldPushShare(parameters);
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(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 parameters = builder.build();
+
+ Observable observable = ServiceMediaHandler.getMogoNetWorkService().
+ create(MediaDztService.class, BaseUrlManager.getDztBaseUrl()).selectByPrimaryKey(parameters);
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(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 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 params = builder
+ .append(businessParams)
+ .build();
+
+
+ Observable 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(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 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 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 params = builder
+ .append(businessParams)
+ .build();
+ Observable 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(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;
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaProcessReceiver.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaProcessReceiver.java
new file mode 100644
index 0000000000..d6202fe0d9
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaProcessReceiver.java
@@ -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);
+ }
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaSpeechReceiver.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaSpeechReceiver.java
new file mode 100644
index 0000000000..5fecc7468d
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaSpeechReceiver.java
@@ -0,0 +1,86 @@
+package com.mogo.module.media.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.mogo.module.media.MediaCardViewFragment;
+import com.mogo.module.media.utils.MusicControlBroadCast;
+import com.mogo.utils.ActivityLifecycleManager;
+import com.mogo.utils.UiThreadHandler;
+import com.mogo.utils.logger.Logger;
+
+/**
+ * 我要听{歌手/歌名}:
+ * 语音通知桌面广播: com.speech.adapter.send 参数:music_model
+ * 桌面通过该action转发给QQ音乐:com.txznet.adapter.send 参数 :music_model
+ *
+ * 播放音乐:
+ * 语音通知桌面广播:com.zhidao.speech.awake.notify 参数:command == com.ileja.music.playapp
+ *
+ * 懒人听书:我要听书、听书 com.zhidao.speech.awake.notify 参数:command:com.zhidao.book.play
+ * 乐听头条:播放新闻、我要听新闻、我要听{类型}新闻、听新闻action:com.zhidao.mediacenter.voiceltnews 参数:category
+ */
+public class MediaSpeechReceiver extends BroadcastReceiver {
+ public static String mCategoryStr = "";
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ {
+ if (intent != null) {
+ String cmdAction = intent.getAction();
+ boolean appActive = ActivityLifecycleManager.getInstance().isAppActive();
+ appActive = MediaCardViewFragment.isMediaResume;
+ Logger.d("MediaSpeechReceiver"," "+cmdAction+" "+appActive);
+ if (cmdAction.equals("com.speech.adapter.send")){
+ //我要听{歌手/歌名}
+ Logger.d("MediaSpeechReceiver"," "+"type qq ");
+ String musicModel = intent.getStringExtra("music_model");
+ if (appActive){
+ MusicControlBroadCast.playSomeBodyMusic(musicModel);
+ MusicControlBroadCast.mediaCenterBroadcast();
+ }else {
+ MusicControlBroadCast.playSomeBodyMusic(musicModel);
+ UiThreadHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ MusicControlBroadCast.qqOpenQQMusic();
+ }
+ },300);
+ }
+ }else if (cmdAction.equals("com.zhidao.speech.awake.notify")){
+ //播放音乐
+ String musicCmd = intent.getStringExtra("command");
+ Logger.d("MediaSpeechReceiver"," "+"qq book"+musicCmd==null?"":musicCmd);
+ if (musicCmd.equals("com.ileja.music.playapp")){
+ //QQ音乐
+ if (appActive){
+ MusicControlBroadCast.qqPlayQQMusic();
+ MusicControlBroadCast.mediaCenterBroadcast();
+ }else{
+ MusicControlBroadCast.qqOpenQQMusic();
+ }
+ }else if (musicCmd.equals("com.zhidao.book.play")){
+ //懒人听书
+ if (appActive){
+ MusicControlBroadCast.controlLanRenPlayBack();
+ MusicControlBroadCast.mediaCenterBroadcast();
+ }else{
+ MusicControlBroadCast.openMediaApp(2);
+ }
+ }
+ }else if (cmdAction.equals("com.zhidao.mediacenter.voiceltnews")){
+ //新闻
+ try {
+ String category = intent.getStringExtra("category");
+ Logger.d("MediaSpeechReceiver"," "+"news "+category==null?"":category);
+ mCategoryStr = category;
+ MusicControlBroadCast.getNewsPayInfoState();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaStateReceiver.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaStateReceiver.java
new file mode 100644
index 0000000000..6d6bad8f7f
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/receiver/MediaStateReceiver.java
@@ -0,0 +1,135 @@
+package com.mogo.module.media.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.mogo.module.media.constants.LeTingFieldConstants;
+import com.mogo.module.media.constants.QQMusicFieldConstants;
+import com.mogo.module.media.model.LanRenInsertData;
+import com.mogo.module.media.model.MediaInfoData;
+import com.mogo.module.media.model.MediaInfoDataEvent;
+import com.mogo.module.media.utils.StorageManager;
+import com.mogo.module.media.utils.Utils;
+import com.mogo.utils.DateTimeUtils;
+import com.mogo.utils.ThreadPoolService;
+import com.mogo.utils.network.utils.GsonUtil;
+
+public class MediaStateReceiver extends BroadcastReceiver {
+ //action:com.zhidao.action.MEDIA_LRTS
+ //action:com.zhidao.action.MEDIA_LT_NEWS
+ //action:com.qq.music.status.change
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ {
+ MediaInfoData mMediaInfoData = new MediaInfoData();
+ if (intent != null) {
+ int type = intent.getIntExtra("type", -1);
+ int playState = intent.getIntExtra(QQMusicFieldConstants.playState, 0);
+
+ if (type == 1) {//qq音乐
+
+ int maxTime = intent.getIntExtra(QQMusicFieldConstants.maxTime, 0);
+ int curTime = intent.getIntExtra(QQMusicFieldConstants.curTime, 0);
+ String mediaName = intent.getStringExtra(QQMusicFieldConstants.mediaName);
+ String mediaUrl = intent.getStringExtra(QQMusicFieldConstants.mediaUrl);
+ String mediaSinger = intent.getStringExtra(QQMusicFieldConstants.mediaSinger);
+ String mediaImgUrl = intent.getStringExtra(QQMusicFieldConstants.mediaImgUrl);
+ String mediaType = intent.getStringExtra(QQMusicFieldConstants.mediaType);
+ String mediaMid = intent.getStringExtra(QQMusicFieldConstants.mediaMid);
+ int mediaPLayMode = intent.getIntExtra(QQMusicFieldConstants.mediaPlayMode, -1);
+ boolean isLocalMedia = intent.getBooleanExtra(QQMusicFieldConstants.isLocalMedia, false);
+
+ mMediaInfoData.setType(type);
+ mMediaInfoData.setPlayState(playState);
+ mMediaInfoData.setMaxTime(maxTime * 1000);
+ mMediaInfoData.setCurTime(curTime * 1000);
+ mMediaInfoData.setMediaName(mediaName);
+ mMediaInfoData.setMediaUrl(mediaUrl);
+ mMediaInfoData.setMediaId(mediaMid);
+ mMediaInfoData.setMediaImg(mediaImgUrl);
+ mMediaInfoData.setMediaSinger(mediaSinger);
+ mMediaInfoData.setMediaPlayMode(mediaPLayMode);
+ mMediaInfoData.setLocalMedia(isLocalMedia);
+ mMediaInfoData.setMediaType(mediaType);
+
+ } else if (type == 2) {//懒人听书
+ int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
+ int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
+
+ String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName);//章节数
+ String bookInfoStr = intent.getStringExtra(LeTingFieldConstants.bookInfo);
+ LanRenInsertData lanRenInsertData = GsonUtil.objectFromJson(bookInfoStr, LanRenInsertData.class);
+
+ String bookName = ""; // 书名 需要从bookinfo里面取
+ String cover = ""; //封面 bookinfo中取
+ String bookid = "";
+
+ try {
+ if (lanRenInsertData != null) {
+ bookName = lanRenInsertData.getName(); // 书名 需要从bookinfo里面取
+ cover = lanRenInsertData.getCover(); //封面 bookinfo中取
+ bookid = lanRenInsertData.getBookId() + "";
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ mMediaInfoData.setType(type);
+ mMediaInfoData.setPlayState(playState);
+ mMediaInfoData.setMaxTime(maxTime);
+ mMediaInfoData.setCurTime(curTime);
+ mMediaInfoData.setMediaName(bookName); //bookName 或者mediaName
+ mMediaInfoData.setMediaSinger(mediaName); //章节数
+ mMediaInfoData.setMediaImg(cover); //书籍封面
+ mMediaInfoData.setMediaId(bookid);//书籍的bookid int
+ mMediaInfoData.setBookInfo(bookInfoStr);
+ mMediaInfoData.setMediaUrl("");
+ mMediaInfoData.setLocalMedia(false);
+ mMediaInfoData.setMediaType("");
+
+ } else if (type == 3) {//乐听头条
+ int maxTime = intent.getIntExtra(LeTingFieldConstants.maxTime, 0);
+ int curTime = intent.getIntExtra(LeTingFieldConstants.curTime, 0);
+ String mediaName = intent.getStringExtra(LeTingFieldConstants.mediaName); //新闻title
+ String artist = intent.getStringExtra(LeTingFieldConstants.artist); //新闻来源,赋值给singer mediaSinger
+ String cover = intent.getStringExtra(LeTingFieldConstants.cover); //封面
+
+ mMediaInfoData.setType(type);
+ mMediaInfoData.setPlayState(playState);
+ mMediaInfoData.setMaxTime(maxTime);
+ mMediaInfoData.setCurTime(curTime);
+ mMediaInfoData.setMediaName(mediaName); //新闻标题
+ mMediaInfoData.setMediaSinger(artist); //新闻来源
+ mMediaInfoData.setMediaImg(cover); //新闻封面
+
+ mMediaInfoData.setMediaId("");//书籍的bookid int
+ mMediaInfoData.setBookInfo("");
+ mMediaInfoData.setMediaUrl("");
+ mMediaInfoData.setLocalMedia(true);
+ mMediaInfoData.setMediaType("");
+ }
+
+ MediaInfoDataEvent event = new MediaInfoDataEvent();
+ event.data = mMediaInfoData;
+ // EventBus.getDefault().post(event);
+
+ /* try {
+ if (mMediaInfoData != null) {
+ ThreadPoolService.execute(new Runnable() {
+ @Override
+ public void run() {
+ StorageManager.setLastListenMediaMusic(GsonUtil.jsonFromObject(mMediaInfoData));
+ }
+ });
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }*/
+ }
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BaseUrlManager.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BaseUrlManager.java
new file mode 100644
index 0000000000..c4a87c9c4f
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BaseUrlManager.java
@@ -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 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();
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BitmapHelper.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BitmapHelper.java
new file mode 100644
index 0000000000..89fd0ee6c0
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BitmapHelper.java
@@ -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.
+ *
+ * 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
+ *
+ * 将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
+ *
+ * 将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();
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BlurImageUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BlurImageUtils.java
new file mode 100644
index 0000000000..8463ae5299
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/BlurImageUtils.java
@@ -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;
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FastBlurUtil.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FastBlurUtil.java
new file mode 100644
index 0000000000..5de68b6240
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FastBlurUtil.java
@@ -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
+ // http://incubator.quasimondo.com
+ // created Feburary 29, 2004
+ // Android port : Yahel Bouaziz
+ // 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
+
+ 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);
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FileUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FileUtils.java
new file mode 100644
index 0000000000..8a06848283
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/FileUtils.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/IOUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/IOUtils.java
new file mode 100644
index 0000000000..4d7a17a7c2
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/IOUtils.java
@@ -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();
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Md5Utils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Md5Utils.java
new file mode 100644
index 0000000000..9bfe577832
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Md5Utils.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MediaAnalyticsUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MediaAnalyticsUtils.java
new file mode 100644
index 0000000000..25d6da3336
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MediaAnalyticsUtils.java
@@ -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 map){
+ Logger.d("MediaAnalyticsUtils","addLogger "+id);
+ ServiceMediaHandler.getMogoAnalytis().track(id,map);
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MusicControlBroadCast.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MusicControlBroadCast.java
new file mode 100644
index 0000000000..4a7a247c71
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/MusicControlBroadCast.java
@@ -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 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 shareList) {
+ ArrayList 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 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 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);
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnBitmapToLocalListener.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnBitmapToLocalListener.java
new file mode 100644
index 0000000000..9d72f24c1b
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnBitmapToLocalListener.java
@@ -0,0 +1,6 @@
+package com.mogo.module.media.utils;
+
+public interface OnBitmapToLocalListener {
+ void saveSuccess(String path);
+ void saveFailed();
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnCompressListener.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnCompressListener.java
new file mode 100644
index 0000000000..a9a8842e83
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/OnCompressListener.java
@@ -0,0 +1,9 @@
+package com.mogo.module.media.utils;
+
+public interface OnCompressListener {
+ void onCompressSuccess(byte[] data);
+
+ void onCompressFailed(String msg);
+
+ void onBeforeCompress();
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/SkipToAppUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/SkipToAppUtils.java
new file mode 100644
index 0000000000..b709983534
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/SkipToAppUtils.java
@@ -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();
+ }
+ }
+
+
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/StorageManager.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/StorageManager.java
new file mode 100644
index 0000000000..d6626621bf
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/StorageManager.java
@@ -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);
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/TimeUtils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/TimeUtils.java
new file mode 100644
index 0000000000..9c5e0817f5
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/TimeUtils.java
@@ -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;
+ }
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/ToastHelper.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/ToastHelper.java
new file mode 100644
index 0000000000..301b76de57
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/ToastHelper.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Utils.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Utils.java
new file mode 100644
index 0000000000..fdf9aaf338
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/utils/Utils.java
@@ -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 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 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;
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/view/MediaView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/view/MediaView.java
new file mode 100644
index 0000000000..17e35c5dff
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/view/MediaView.java
@@ -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 list);
+
+ void loadFriendShareMusicSuccess(List list);
+
+ void loadShareLikeDataResultSuccess(ShareLikeData.ShareLikeDataResult likeDataResult, String mediaId);
+
+ void likeShareSuccess();
+
+ void shareSuccessResult(boolean success, MarkerShareMusic markerShareMusic);
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimCircleImageView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimCircleImageView.java
new file mode 100644
index 0000000000..280aee83e1
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimCircleImageView.java
@@ -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;
+ }
+}
+
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimalJSurfaceView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimalJSurfaceView.java
new file mode 100644
index 0000000000..50af224904
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/AnimalJSurfaceView.java
@@ -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) {
+
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView.java
new file mode 100644
index 0000000000..bbbe5316c4
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView.java
@@ -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);
+
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView2.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView2.java
new file mode 100644
index 0000000000..dffbcfad90
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/CircleImageView2.java
@@ -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);
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/Corner.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/Corner.java
new file mode 100644
index 0000000000..ef7115fa65
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/Corner.java
@@ -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;
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/NoScrollSeekBar.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/NoScrollSeekBar.java
new file mode 100644
index 0000000000..d8f9186fbf
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/NoScrollSeekBar.java
@@ -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 ;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedDrawable.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedDrawable.java
new file mode 100644
index 0000000000..a7e8d6b780
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedDrawable.java
@@ -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 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);
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedImageView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedImageView.java
new file mode 100644
index 0000000000..b552bea0bb
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/RoundedImageView.java
@@ -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();
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/ScrollingTextView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/ScrollingTextView.java
new file mode 100644
index 0000000000..0ab1abb4fc
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/ScrollingTextView.java
@@ -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;
+ }
+}
+
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseSurfaceView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseSurfaceView.java
new file mode 100644
index 0000000000..fd9ddfd6f1
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseSurfaceView.java
@@ -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);
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseTextureView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseTextureView.java
new file mode 100644
index 0000000000..2a722748a8
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/BaseTextureView.java
@@ -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);
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameSurfaceView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameSurfaceView.java
new file mode 100644
index 0000000000..d2dc94e252
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameSurfaceView.java
@@ -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 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 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 bitmapIds;
+ private BitmapFactory.Options options;
+
+ public DecodeRunnable(int index, List 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;
+ }
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameTextureView.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameTextureView.java
new file mode 100644
index 0000000000..9af3fda6fa
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/FrameTextureView.java
@@ -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 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 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 bitmapIds;
+ private BitmapFactory.Options options;
+
+ public DecodeRunnable(int index, List 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;
+ }
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBitmap.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBitmap.java
new file mode 100644
index 0000000000..0b0f4c4491
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBitmap.java
@@ -0,0 +1,9 @@
+package com.mogo.module.media.widget.surfaceview;
+
+import android.graphics.Bitmap;
+
+public class LinkedBitmap {
+ public Bitmap bitmap;
+ public LinkedBitmap next;
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBlockingQueue.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBlockingQueue.java
new file mode 100644
index 0000000000..dc8b26a1d1
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/LinkedBlockingQueue.java
@@ -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;
+ }
+ }
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/MethodUtil.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/MethodUtil.java
new file mode 100644
index 0000000000..7ccb9dae6b
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/MethodUtil.java
@@ -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;
+ }
+
+}
diff --git a/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/NumberUtil.java b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/NumberUtil.java
new file mode 100644
index 0000000000..a4e8fc0b7d
--- /dev/null
+++ b/modules/mogo-module-media/src/main/java/com/mogo/module/media/widget/surfaceview/NumberUtil.java
@@ -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;
+ }
+}
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_choice_point.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_choice_point.png
new file mode 100644
index 0000000000..8ca4538285
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_choice_point.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_poi_location.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_poi_location.png
new file mode 100644
index 0000000000..25940d02c6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/ic_search_poi_location.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_blur_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_blur_default_icon.png
new file mode 100644
index 0000000000..30d5891d96
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_blur_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_full_screen.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_full_screen.png
new file mode 100644
index 0000000000..240f148149
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_full_screen.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_have_heart.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_have_heart.png
new file mode 100644
index 0000000000..f86d4f3fde
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_have_heart.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_head_default_img.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_head_default_img.png
new file mode 100644
index 0000000000..0597a02397
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_head_default_img.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_last_song.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_last_song.png
new file mode 100644
index 0000000000..eb4a4099a1
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_last_song.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_next_song.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_next_song.png
new file mode 100644
index 0000000000..03b6866112
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_next_song.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_heart.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_heart.png
new file mode 100644
index 0000000000..804057b9ca
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_heart.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_img_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_img_default_icon.png
new file mode 100644
index 0000000000..04f4e5c139
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_no_img_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_play.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_play.png
new file mode 100644
index 0000000000..1b16f5d635
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_play.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon.png
new file mode 100644
index 0000000000..a6ab1c9620
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon2.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon2.png
new file mode 100644
index 0000000000..2dbb8b6773
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_icon2.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_rect_icon.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_rect_icon.png
new file mode 100644
index 0000000000..fc0b6145b1
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_default_rect_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_fail.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_fail.png
new file mode 100644
index 0000000000..e15649f868
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_fail.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_normal.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_normal.png
new file mode 100644
index 0000000000..2562454404
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_normal.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_success.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_success.png
new file mode 100644
index 0000000000..2508848c10
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_share_success.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_suspend.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_suspend.png
new file mode 100644
index 0000000000..88df36ee6d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_suspend.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_pause.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_pause.png
new file mode 100644
index 0000000000..acf18155c0
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_pause.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_play.png b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_play.png
new file mode 100644
index 0000000000..9e4b9720ae
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-ldpi/module_media_window_pop_play.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_choice_point.png b/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_choice_point.png
new file mode 100644
index 0000000000..13ea311e83
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_choice_point.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_unshadow.png b/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_unshadow.png
new file mode 100644
index 0000000000..cd32e7f85f
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-mdpi/ic_search_unshadow.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_choice_point.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_choice_point.png
new file mode 100644
index 0000000000..9f75ac8e88
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_choice_point.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_poi_location.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_poi_location.png
new file mode 100644
index 0000000000..484f80efd5
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/ic_search_poi_location.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_blur_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_blur_default_icon.png
new file mode 100644
index 0000000000..7198c071db
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_blur_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen.png
new file mode 100644
index 0000000000..bc14feee50
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen_select.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen_select.png
new file mode 100644
index 0000000000..170785863b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_full_screen_select.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_have_heart.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_have_heart.png
new file mode 100644
index 0000000000..d660105c2d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_have_heart.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_head_default_img.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_head_default_img.png
new file mode 100644
index 0000000000..f2e5a03cab
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_head_default_img.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_icon_map_marker_music.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_icon_map_marker_music.png
new file mode 100644
index 0000000000..398912c0ea
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_icon_map_marker_music.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song.png
new file mode 100644
index 0000000000..f3a0b6f28e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song_click.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song_click.png
new file mode 100644
index 0000000000..80ec16e26f
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_last_song_click.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon1.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon1.png
new file mode 100644
index 0000000000..172a5934ae
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon1.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon10.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon10.png
new file mode 100644
index 0000000000..dc9589159b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon10.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon11.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon11.png
new file mode 100644
index 0000000000..d913d05154
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon11.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon12.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon12.png
new file mode 100644
index 0000000000..35702bc1ab
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon12.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon13.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon13.png
new file mode 100644
index 0000000000..94faa2ac0e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon13.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon14.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon14.png
new file mode 100644
index 0000000000..341e9ce7b9
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon14.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon15.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon15.png
new file mode 100644
index 0000000000..a271a09b42
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon15.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon16.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon16.png
new file mode 100644
index 0000000000..4ff5b09209
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon16.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon17.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon17.png
new file mode 100644
index 0000000000..1a96b0115a
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon17.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon18.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon18.png
new file mode 100644
index 0000000000..238f47d78c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon18.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon19.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon19.png
new file mode 100644
index 0000000000..b45536a4d1
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon19.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon2.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon2.png
new file mode 100644
index 0000000000..775d44e934
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon2.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon20.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon20.png
new file mode 100644
index 0000000000..b70e929788
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon20.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon21.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon21.png
new file mode 100644
index 0000000000..b17ef58d95
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon21.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon22.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon22.png
new file mode 100644
index 0000000000..28a667b077
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon22.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon23.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon23.png
new file mode 100644
index 0000000000..8fb205f65c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon23.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon24.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon24.png
new file mode 100644
index 0000000000..57216edd8b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon24.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon25.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon25.png
new file mode 100644
index 0000000000..bf1db703d9
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon25.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon26.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon26.png
new file mode 100644
index 0000000000..ff783cb414
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon26.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon27.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon27.png
new file mode 100644
index 0000000000..b8c70103a6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon27.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon28.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon28.png
new file mode 100644
index 0000000000..0b53d4e0cc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon28.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon29.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon29.png
new file mode 100644
index 0000000000..35910fc41e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon29.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon3.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon3.png
new file mode 100644
index 0000000000..f2aef2d862
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon3.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon30.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon30.png
new file mode 100644
index 0000000000..a8e76f4292
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon30.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon31.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon31.png
new file mode 100644
index 0000000000..2cfcb1239b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon31.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon32.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon32.png
new file mode 100644
index 0000000000..8a7e0eab0c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon32.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon33.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon33.png
new file mode 100644
index 0000000000..801817119d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon33.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon34.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon34.png
new file mode 100644
index 0000000000..0775b3aae6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon34.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon35.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon35.png
new file mode 100644
index 0000000000..d78c1ad2fc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon35.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon36.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon36.png
new file mode 100644
index 0000000000..00c647affa
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon36.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon37.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon37.png
new file mode 100644
index 0000000000..72d9a66e36
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon37.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon38.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon38.png
new file mode 100644
index 0000000000..36525eec91
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon38.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon39.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon39.png
new file mode 100644
index 0000000000..1ef84eba37
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon39.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon4.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon4.png
new file mode 100644
index 0000000000..8180b14e9a
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon4.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon40.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon40.png
new file mode 100644
index 0000000000..14e67a0b5a
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon40.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon41.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon41.png
new file mode 100644
index 0000000000..bc95f9f96c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon41.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon42.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon42.png
new file mode 100644
index 0000000000..ed0b6f76ce
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon42.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon43.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon43.png
new file mode 100644
index 0000000000..7e36135339
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon43.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon44.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon44.png
new file mode 100644
index 0000000000..eb86260b6d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon44.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon45.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon45.png
new file mode 100644
index 0000000000..4d2423aacc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon45.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon46.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon46.png
new file mode 100644
index 0000000000..ddf538ab6e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon46.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon47.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon47.png
new file mode 100644
index 0000000000..04e325d6c0
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon47.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon48.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon48.png
new file mode 100644
index 0000000000..6b029f0a17
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon48.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon49.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon49.png
new file mode 100644
index 0000000000..e329da91b6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon49.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon5.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon5.png
new file mode 100644
index 0000000000..4fda193c49
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon5.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon50.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon50.png
new file mode 100644
index 0000000000..d357202e6d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon50.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon51.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon51.png
new file mode 100644
index 0000000000..d3c5a2d346
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon51.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon52.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon52.png
new file mode 100644
index 0000000000..ca7c4220a9
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon52.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon53.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon53.png
new file mode 100644
index 0000000000..f3ee370442
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon53.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon54.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon54.png
new file mode 100644
index 0000000000..c9a047e05e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon54.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon55.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon55.png
new file mode 100644
index 0000000000..35d3b5a7c4
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon55.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon56.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon56.png
new file mode 100644
index 0000000000..44912aa767
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon56.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon57.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon57.png
new file mode 100644
index 0000000000..f87729a3fc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon57.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon58.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon58.png
new file mode 100644
index 0000000000..b031cda549
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon58.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon59.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon59.png
new file mode 100644
index 0000000000..37241888fc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon59.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon6.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon6.png
new file mode 100644
index 0000000000..74ff4016fc
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon6.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon60.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon60.png
new file mode 100644
index 0000000000..b8d636130d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon60.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon61.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon61.png
new file mode 100644
index 0000000000..f37807f227
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon61.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon62.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon62.png
new file mode 100644
index 0000000000..8e91f014c8
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon62.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon63.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon63.png
new file mode 100644
index 0000000000..eb93bf536c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon63.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon64.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon64.png
new file mode 100644
index 0000000000..5eee54dd42
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon64.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon65.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon65.png
new file mode 100644
index 0000000000..757cbb1047
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon65.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon66.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon66.png
new file mode 100644
index 0000000000..7ec3c175b6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon66.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon67.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon67.png
new file mode 100644
index 0000000000..89547994eb
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon67.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon68.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon68.png
new file mode 100644
index 0000000000..41ba271e26
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon68.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon69.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon69.png
new file mode 100644
index 0000000000..2e9f59de0a
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon69.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon7.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon7.png
new file mode 100644
index 0000000000..86cfdf616c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon7.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon70.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon70.png
new file mode 100644
index 0000000000..d9cc30556d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon70.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon71.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon71.png
new file mode 100644
index 0000000000..b996b8de6b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon71.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon72.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon72.png
new file mode 100644
index 0000000000..a93bb38648
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon72.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon73.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon73.png
new file mode 100644
index 0000000000..a3089c41eb
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon73.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon74.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon74.png
new file mode 100644
index 0000000000..a3d862aa22
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon74.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon75.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon75.png
new file mode 100644
index 0000000000..18e155874b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon75.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon8.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon8.png
new file mode 100644
index 0000000000..946405b451
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon8.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon9.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon9.png
new file mode 100644
index 0000000000..43622cdd9c
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_music_animal_icon9.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song.png
new file mode 100644
index 0000000000..d692431fa8
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song_click.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song_click.png
new file mode 100644
index 0000000000..6194927beb
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_next_song_click.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_heart.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_heart.png
new file mode 100644
index 0000000000..4c1d667884
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_heart.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_img_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_img_default_icon.png
new file mode 100644
index 0000000000..d1978ce559
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_no_img_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_play.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_play.png
new file mode 100644
index 0000000000..d46389d86e
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_play.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_click.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_click.png
new file mode 100644
index 0000000000..246b92c4a9
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_click.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon.png
new file mode 100644
index 0000000000..bfaed8e0f5
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon1.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon1.png
new file mode 100644
index 0000000000..38c4a43636
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_icon1.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_rect_icon.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_rect_icon.png
new file mode 100644
index 0000000000..51d4b92fe8
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_default_rect_icon.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_fail.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_fail.png
new file mode 100644
index 0000000000..b70bfed8c1
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_fail.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_normal.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_normal.png
new file mode 100644
index 0000000000..dcc359bf47
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_normal.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_success.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_success.png
new file mode 100644
index 0000000000..0005916564
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_share_success.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_suspend.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_suspend.png
new file mode 100644
index 0000000000..3dfa5da5c6
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_suspend.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_next.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_next.png
new file mode 100644
index 0000000000..d23e33246b
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_next.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_pause.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_pause.png
new file mode 100644
index 0000000000..967dfe701d
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_pause.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_play.png b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_play.png
new file mode 100644
index 0000000000..21a77a0c44
Binary files /dev/null and b/modules/mogo-module-media/src/main/res/drawable-xhdpi/module_media_window_pop_play.png differ
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_bottom_revert_trianle_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_bottom_revert_trianle_bg.xml
new file mode 100644
index 0000000000..19bc1f9d13
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_bottom_revert_trianle_bg.xml
@@ -0,0 +1,18 @@
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_card_back.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_card_back.xml
new file mode 100644
index 0000000000..71b9ee964e
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_card_back.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_card_tran_img_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_card_tran_img_bg.xml
new file mode 100644
index 0000000000..fc072d2f97
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_card_tran_img_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_click_poi_bg_top.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_click_poi_bg_top.xml
new file mode 100644
index 0000000000..df19595e70
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_click_poi_bg_top.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_demo_selector.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_demo_selector.xml
new file mode 100644
index 0000000000..d17daeaa24
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_demo_selector.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_misic_progress_bar.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_misic_progress_bar.xml
new file mode 100644
index 0000000000..eb04bda3a3
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_misic_progress_bar.xml
@@ -0,0 +1,35 @@
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_progress_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_progress_bg.xml
new file mode 100644
index 0000000000..11e0a400c7
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_progress_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_progress_pop_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_progress_pop_bg.xml
new file mode 100644
index 0000000000..a8e74c1033
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_progress_pop_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_bg.xml
new file mode 100644
index 0000000000..222dea52a8
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_left_btn_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_left_btn_bg.xml
new file mode 100644
index 0000000000..fad92a439a
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_left_btn_bg.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_right_btn_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_right_btn_bg.xml
new file mode 100644
index 0000000000..111ff2af99
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_right_btn_bg.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_title_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_title_bg.xml
new file mode 100644
index 0000000000..9037314b49
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_share_dialog_title_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_share_toast_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_share_toast_bg.xml
new file mode 100644
index 0000000000..c3ade0a821
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_share_toast_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_user_share_music_back.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_user_share_music_back.xml
new file mode 100644
index 0000000000..42bde49ed3
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_user_share_music_back.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_window_alert_bg.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_window_alert_bg.xml
new file mode 100644
index 0000000000..7a098d5118
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_window_alert_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/drawable/module_media_window_progress_bar.xml b/modules/mogo-module-media/src/main/res/drawable/module_media_window_progress_bar.xml
new file mode 100644
index 0000000000..a62ffcda8f
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/drawable/module_media_window_progress_bar.xml
@@ -0,0 +1,32 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_bubble_marker.xml b/modules/mogo-module-media/src/main/res/layout/module_media_bubble_marker.xml
new file mode 100644
index 0000000000..0fc5b67336
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_bubble_marker.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_card_fragment_view.xml b/modules/mogo-module-media/src/main/res/layout/module_media_card_fragment_view.xml
new file mode 100644
index 0000000000..2223bb6dbf
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_card_fragment_view.xml
@@ -0,0 +1,375 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_dialog_cutom_layout.xml b/modules/mogo-module-media/src/main/res/layout/module_media_dialog_cutom_layout.xml
new file mode 100644
index 0000000000..e6aaae273c
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_dialog_cutom_layout.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_music_window_alert_layout.xml b/modules/mogo-module-media/src/main/res/layout/module_media_music_window_alert_layout.xml
new file mode 100644
index 0000000000..3da345be7b
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_music_window_alert_layout.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_share_fragment_view.xml b/modules/mogo-module-media/src/main/res/layout/module_media_share_fragment_view.xml
new file mode 100644
index 0000000000..6389fdef75
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_share_fragment_view.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/main/res/layout/module_media_share_toast_view.xml b/modules/mogo-module-media/src/main/res/layout/module_media_share_toast_view.xml
new file mode 100644
index 0000000000..73fc49ae04
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/layout/module_media_share_toast_view.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/main/res/values-ldpi/colors.xml b/modules/mogo-module-media/src/main/res/values-ldpi/colors.xml
new file mode 100644
index 0000000000..69b22338c6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-ldpi/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/modules/mogo-module-media/src/main/res/values-ldpi/dimens.xml b/modules/mogo-module-media/src/main/res/values-ldpi/dimens.xml
new file mode 100644
index 0000000000..6a2e0256b5
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-ldpi/dimens.xml
@@ -0,0 +1,123 @@
+
+
+ 483px
+ 573px
+
+
+ 352px
+ 352px
+ 10.67px
+ 12px
+ 36px
+ 36px
+ 36px
+ 5px
+ 12px
+ 62px
+ 16px
+ 78px
+ 10.6px
+ 16px
+ 48px
+ 48px
+ 11px
+ 12px
+ 12px
+ 14px
+ 16px
+ 8px
+ 36px
+ 36px
+ 12px
+ 18px
+ 30px
+ 30px
+ 67.2px
+ 3px
+ 62px
+ 62px
+ 12px
+ 20px
+ 15px
+
+
+
+ 421px
+ 280px
+ 28px
+ 32.5px
+ 11.5px
+ 72.5px
+ 10.7px
+ 72.5px
+ 10px
+ 22px
+ 16px
+ 18px
+ 22px
+ 32px
+ 51px
+ 68px
+ 2px
+ 3.2px
+
+ 322px
+ 66.7px
+ 60px
+ 12px
+ 48px
+ 123px
+ 13px
+ 18px
+ 14px
+ 30px
+ 21px
+ 4px
+ 8px
+ 7px
+
+ 267px
+ 187px
+ 10px
+ 64px
+ 18px
+ 11px
+
+ 352px
+ 352px
+ 10.5px
+ 11px
+ 11.5px
+ 175px
+ 175px
+ 114px
+ 114px
+ 20px
+ 15px
+ 4px
+ 2px
+ 6px
+ 12px
+ 11px
+ 4px
+ 1px
+
+ 8px
+ 44px
+ 62px
+ 28px
+ 1px
+ 35px
+ 3.2px
+ 6.4px
+ 3px
+ 4px
+ 96px
+
+ 32px
+ 400px
+ 80px
+ 150px
+ 16px
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/values-ldpi/strings.xml b/modules/mogo-module-media/src/main/res/values-ldpi/strings.xml
new file mode 100644
index 0000000000..952949198b
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-ldpi/strings.xml
@@ -0,0 +1,3 @@
+
+ mogo-module-media
+
diff --git a/modules/mogo-module-media/src/main/res/values-ldpi/styles.xml b/modules/mogo-module-media/src/main/res/values-ldpi/styles.xml
new file mode 100644
index 0000000000..5885930df6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-ldpi/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/main/res/values-xhdpi/colors.xml b/modules/mogo-module-media/src/main/res/values-xhdpi/colors.xml
new file mode 100644
index 0000000000..69b22338c6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-xhdpi/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/modules/mogo-module-media/src/main/res/values-xhdpi/dimens.xml b/modules/mogo-module-media/src/main/res/values-xhdpi/dimens.xml
new file mode 100644
index 0000000000..2ecf743e04
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-xhdpi/dimens.xml
@@ -0,0 +1,123 @@
+
+
+ 881px
+ 1067px
+
+
+ 660px
+ 660px
+ 20px
+ 23px
+ 67.5px
+ 67.5px
+ 67.5px
+ 10px
+ 23px
+ 116px
+ 30px
+ 145px
+ 20px
+ 30px
+ 90px
+ 90px
+ 21px
+ 24px
+ 23px
+ 26px
+ 30px
+ 16px
+ 68px
+ 68px
+ 23px
+ 35px
+ 56px
+ 56px
+ 126px
+ 3px
+ 116px
+ 116px
+ 22px
+ 37.5px
+ 28px
+
+
+
+ 790px
+ 525px
+ 55px
+ 61px
+ 20px
+ 136px
+ 20px
+ 136px
+ 34px
+ 40px
+ 30px
+ 34px
+ 40px
+ 60px
+ 96px
+ 130px
+ 4px
+ 6px
+
+ 580px
+ 120px
+ 112px
+ 20px
+ 90px
+ 230px
+ 20px
+ 35px
+ 24px
+ 56px
+ 40px
+ 8px
+ 16px
+ 16px
+ 500px
+ 350px
+ 20px
+ 120px
+ 36px
+ 20px
+
+ 660px
+ 660px
+ 20px
+ 22px
+ 22px
+ 348px
+ 348px
+ 226px
+ 226px
+ 36px
+ 28px
+ 4px
+ 2px
+ 11px
+ 22px
+ 21px
+ 4px
+ 6px
+ 2px
+
+ 15px
+ 78px
+ 107px
+ 53px
+ 2px
+ 64px
+ 6px
+ 12px
+ 6px
+ 8px
+ 180px
+
+ 60px
+ 750px
+ 120px
+ 270px
+ 30px
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/values-xhdpi/strings.xml b/modules/mogo-module-media/src/main/res/values-xhdpi/strings.xml
new file mode 100644
index 0000000000..952949198b
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-xhdpi/strings.xml
@@ -0,0 +1,3 @@
+
+ mogo-module-media
+
diff --git a/modules/mogo-module-media/src/main/res/values-xhdpi/styles.xml b/modules/mogo-module-media/src/main/res/values-xhdpi/styles.xml
new file mode 100644
index 0000000000..5885930df6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values-xhdpi/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/main/res/values/attrs.xml b/modules/mogo-module-media/src/main/res/values/attrs.xml
new file mode 100644
index 0000000000..80f3c0bd3d
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values/attrs.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/values/colors.xml b/modules/mogo-module-media/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..69b22338c6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/modules/mogo-module-media/src/main/res/values/dimens.xml b/modules/mogo-module-media/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..2ecf743e04
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values/dimens.xml
@@ -0,0 +1,123 @@
+
+
+ 881px
+ 1067px
+
+
+ 660px
+ 660px
+ 20px
+ 23px
+ 67.5px
+ 67.5px
+ 67.5px
+ 10px
+ 23px
+ 116px
+ 30px
+ 145px
+ 20px
+ 30px
+ 90px
+ 90px
+ 21px
+ 24px
+ 23px
+ 26px
+ 30px
+ 16px
+ 68px
+ 68px
+ 23px
+ 35px
+ 56px
+ 56px
+ 126px
+ 3px
+ 116px
+ 116px
+ 22px
+ 37.5px
+ 28px
+
+
+
+ 790px
+ 525px
+ 55px
+ 61px
+ 20px
+ 136px
+ 20px
+ 136px
+ 34px
+ 40px
+ 30px
+ 34px
+ 40px
+ 60px
+ 96px
+ 130px
+ 4px
+ 6px
+
+ 580px
+ 120px
+ 112px
+ 20px
+ 90px
+ 230px
+ 20px
+ 35px
+ 24px
+ 56px
+ 40px
+ 8px
+ 16px
+ 16px
+ 500px
+ 350px
+ 20px
+ 120px
+ 36px
+ 20px
+
+ 660px
+ 660px
+ 20px
+ 22px
+ 22px
+ 348px
+ 348px
+ 226px
+ 226px
+ 36px
+ 28px
+ 4px
+ 2px
+ 11px
+ 22px
+ 21px
+ 4px
+ 6px
+ 2px
+
+ 15px
+ 78px
+ 107px
+ 53px
+ 2px
+ 64px
+ 6px
+ 12px
+ 6px
+ 8px
+ 180px
+
+ 60px
+ 750px
+ 120px
+ 270px
+ 30px
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-media/src/main/res/values/strings.xml b/modules/mogo-module-media/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..913d27b8a0
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values/strings.xml
@@ -0,0 +1,12 @@
+
+ mogo-module-media
+
+ 来自
+ 的分享
+ 是否确认分享此歌曲?
+ 是否确认分享此书?
+ 是否确认分享此新闻?
+ 分享成功
+ 分享失败
+
+
diff --git a/modules/mogo-module-media/src/main/res/values/styles.xml b/modules/mogo-module-media/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..5885930df6
--- /dev/null
+++ b/modules/mogo-module-media/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/modules/mogo-module-media/src/test/java/com/mogo/module/media/ExampleUnitTest.java b/modules/mogo-module-media/src/test/java/com/mogo/module/media/ExampleUnitTest.java
new file mode 100644
index 0000000000..7a2aef7111
--- /dev/null
+++ b/modules/mogo-module-media/src/test/java/com/mogo/module/media/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.mogo.module.media;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 740e53b4aa..0b2d10e11d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,5 +1,3 @@
-include ':main-extensions:mogo-module-main-independent'
-include ':main-extensions:mogo-module-main-launcher'
rootProject.name = 'MogoLauncher'
include ':app'
include ':foudations:mogo-utils'
@@ -11,14 +9,12 @@ include ':modules:mogo-module-map'
include ':modules:mogo-module-common'
include ':modules:mogo-module-main'
include ':modules:mogo-module-search'
-//include ':modules:mogo-module-tanlu'
include ':modules:mogo-module-share'
include ':modules:mogo-module-service'
include ':modules:mogo-module-back'
include ':modules:mogo-module-authorize'
include ':modules:mogo-module-guide'
include ':libraries:map-amap'
-//include ':libraries:map-baidu'
include ':libraries:mogo-map-api'
include ':modules:mogo-module-apps'
include ':modules:mogo-module-extensions'
@@ -27,3 +23,6 @@ include ':modules:mogo-module-gps-simulator'
include ':modules:mogo-module-gps-simulator-debug'
include ':modules:mogo-module-gps-simulator-noop'
include ':libraries:map-autonavi'
+include ':modules:mogo-module-media'
+include ':main-extensions:mogo-module-main-independent'
+include ':main-extensions:mogo-module-main-launcher'