Merge remote-tracking branch 'origin/feature/v1.0.0' into feature/v1.0.0

# Conflicts:
#	modules/mogo-module-common/src/main/java/com/mogo/module/common/MogoModulePaths.java
This commit is contained in:
zhangyuanzhen
2020-01-06 14:18:44 +08:00
329 changed files with 8519 additions and 7810 deletions

View File

@@ -14,6 +14,7 @@ import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.module.common.MogoModulePaths;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
/**
* @author congtaowang
@@ -57,7 +58,7 @@ public class AppsFragmentProvider implements IMogoModuleProvider {
@Override
public int getType() {
return IMogoModuleProvider.TYPE_FRAGMENT;
return ModuleType.TYPE_APP_LIST;
}
@Override

View File

@@ -9,6 +9,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="false"
app:behavior_peekHeight="50dp"
app:behavior_peekHeight="76dp"
app:layout_behavior="@string/bottom_sheet_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -7,8 +7,8 @@
<ImageView
android:id="@+id/module_apps_id_app_icon"
android:layout_width="75dp"
android:layout_height="75dp" />
android:layout_width="60dp"
android:layout_height="60dp" />
<TextView
android:id="@+id/module_apps_id_app_name"

View File

@@ -0,0 +1,51 @@
package com.mogo.module.common;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 模块类型
*/
public interface ModuleType {
/**
* 卡片类型 - fragment
*/
int TYPE_CARD_FRAGMENT = 1;
/**
* 卡片类型 - view
*/
@Deprecated
int TYPE_CARD_VIEW = 2;
/**
* 服务类型的模块
*/
int TYPE_SERVICE = 3;
/**
* APP 列表模块
*/
int TYPE_APP_LIST = 4;
/**
* 小智语音形象
*/
int TYPE_VOICE = 5;
/**
* 地图模块
*/
int TYPE_MAP = 6;
/**
* 导航模块
*/
int TYPE_NAVI = 7;
/**
* 小智、天气、时间等
*/
int TYPE_EXTENSION = 8;
}

View File

@@ -18,6 +18,10 @@ public class MogoModule {
*/
private String mName;
/**
* @param path 模块加载路径
* @param name 模块名称
*/
public MogoModule( String path, String name ) {
this.mPath = path;
this.mName = name;

View File

@@ -29,22 +29,26 @@ public class MogoModulePaths {
@Keep
public static final String PATH_MODULE_APPS = "/appslist/ui";
/**
* 添加卡片模块
*
* @param path
*/
@Deprecated
public static void addModule( String path ) {
throw new IllegalArgumentException( "this method can't be invoked." );
}
/**
* 搜索页面模块实例化路径
*/
@Keep
public static final String PATH_MODULE_SEARCH= "navi/search/ui";
public static void addModule( String path ) {
if ( TextUtils.isEmpty( path.replace( " ", "" ) ) ) {
throw new IllegalArgumentException( "module path can't be empty or null or blank" );
}
mMogoModules.add( new MogoModule( path, "" ) );
}
/**
* 添加卡片模块
*
* @param module
*/
public static void addModule( MogoModule module ) {
if ( module == null || TextUtils.isEmpty( module.getPath().replace( " ", "" ) ) ) {
throw new IllegalArgumentException( "module path can't be empty or null or blank" );

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,9 @@
# launcher头部模块
## 小智语音
## 通知
## 天气
## 时间

View File

@@ -0,0 +1,60 @@
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.rxjava
implementation rootProject.ext.dependencies.rxandroid
if (Boolean.valueOf(RELEASE)) {
api rootProject.ext.dependencies.mogomap
api rootProject.ext.dependencies.mogomapapi
api rootProject.ext.dependencies.mogoutils
api rootProject.ext.dependencies.mogocommons
api rootProject.ext.dependencies.mogoserviceapi
implementation rootProject.ext.dependencies.modulecommon
} else {
api project(":libraries:mogo-map")
api project(":libraries:mogo-map-api")
api project(":foudations:mogo-utils")
api project(":foudations:mogo-commons")
api project(':services:mogo-service-api')
implementation project(':modules:mogo-module-common')
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

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

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,27 @@
package com.mogo.module.extensions;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith( AndroidJUnit4.class )
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals( "com.mogo.module.extensions.test", appContext.getPackageName() );
}
}

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.module.extensions" />

View File

@@ -0,0 +1,105 @@
package com.mogo.module.extensions;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.mogo.commons.mvp.MvpFragment;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
public class ExtensionsFragment extends MvpFragment< ExtensionsView, ExtensionsPresenter > implements ExtensionsView {
private View mVoiceIcon;
private View mVoiceMsg;
private TextView mTime;
private TextView mDate;
private View mWeatherContainer;
private ImageView mWeatherIcon;
private TextView mWeatherTemp;
private TextView mWeatherDesc;
private View mMsgContainer;
private TextView mMsgCounter;
@Override
protected int getLayoutId() {
return R.layout.module_ext_layout_extensions;
}
@Override
protected void initViews() {
mVoiceIcon = findViewById( R.id.module_ext_id_voice );
mVoiceMsg = findViewById( R.id.module_ext_id_voice_msg );
mVoiceIcon.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
mVoiceMsg.performClick();
}
} );
mVoiceMsg.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
}
} );
mTime = findViewById( R.id.module_ext_id_time );
mDate = findViewById( R.id.module_ext_id_date );
mWeatherContainer = findViewById( R.id.module_ext_id_weather_container );
mWeatherIcon = findViewById( R.id.module_ext_id_weather_icon );
mWeatherTemp = findViewById( R.id.module_ext_id_weather_temp );
mWeatherDesc = findViewById( R.id.module_ext_id_weather_desc );
mMsgContainer = findViewById( R.id.module_ext_id_msg );
mMsgCounter = findViewById( R.id.module_ext_id_msg_counter );
}
@NonNull
@Override
protected ExtensionsPresenter createPresenter() {
return new ExtensionsPresenter( this );
}
@Override
public void onActivityCreated( @Nullable Bundle savedInstanceState ) {
super.onActivityCreated( savedInstanceState );
}
@Override
public void renderTime( String date, String time ) {
mDate.setText( date );
mTime.setText( time );
}
@Override
public void renderWeatherInfo( String temp, String desc, int iconId ) {
boolean hidden = false;
if ( iconId != 0 ) {
mWeatherIcon.setImageResource( iconId );
mWeatherIcon.setVisibility( View.VISIBLE );
} else {
mWeatherIcon.setVisibility( View.GONE );
hidden |= true;
}
hidden |= TextUtils.isEmpty( temp );
hidden |= TextUtils.isEmpty( desc );
mWeatherTemp.setText( temp );
mWeatherDesc.setText( desc );
mWeatherContainer.setVisibility( hidden ? View.GONE : View.VISIBLE );
}
}

View File

@@ -0,0 +1,16 @@
package com.mogo.module.extensions;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
public class ExtensionsModuleConst {
public static final String PATH_EXTENSION = "/extension/ui";
public static final String TYPE = "extension";
}

View File

@@ -0,0 +1,74 @@
package com.mogo.module.extensions;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.map.listener.IMogoMapListener;
import com.mogo.map.location.IMogoLocationListener;
import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
@Route( path = ExtensionsModuleConst.PATH_EXTENSION )
public class ExtensionsModuleProvider implements IMogoModuleProvider {
@Override
public Fragment createFragment( Context context, Bundle data ) {
ExtensionsFragment fragment = new ExtensionsFragment();
fragment.setArguments( data );
return fragment;
}
@Override
public View createView( Context context ) {
return null;
}
@NonNull
@Override
public String getModuleName() {
return ExtensionsModuleConst.TYPE;
}
@Override
public IMogoModuleLifecycle getCardLifecycle() {
return null;
}
@Override
public IMogoMapListener getMapListener() {
return null;
}
@Override
public int getType() {
return ModuleType.TYPE_EXTENSION;
}
@Override
public IMogoNaviListener getNaviListener() {
return null;
}
@Override
public IMogoLocationListener getLocationListener() {
return null;
}
@Override
public void init( Context context ) {
}
}

View File

@@ -0,0 +1,111 @@
package com.mogo.module.extensions;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.mvp.Presenter;
import com.mogo.module.extensions.weather.Phenomena;
import com.mogo.module.extensions.weather.WeatherCallback;
import com.mogo.module.extensions.weather.WeatherInfo;
import com.mogo.module.extensions.weather.WeatherModel;
import com.mogo.utils.logger.Logger;
import java.util.Calendar;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
public class ExtensionsPresenter extends Presenter< ExtensionsView > implements WeatherCallback {
private static final String TAG = "ExtensionsPresenter";
private String[] mWeeks;
private WeatherModel mWeatherModel;
/**
* 接收时间变化的广播
*/
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive( Context context, Intent intent ) {
try {
refreshTimeAndDate();
} catch ( Exception e ) {
Logger.e( TAG, "error. ", e );
}
}
};
public ExtensionsPresenter( ExtensionsView view ) {
super( view );
mWeeks = getContext().getResources().getStringArray( R.array.module_ext_str_arr_week );
mWeatherModel = new WeatherModel( getContext() );
}
@Override
public void onCreate( @NonNull LifecycleOwner owner ) {
super.onCreate( owner );
registerTimerReceiver();
mWeatherModel.init( this );
mWeatherModel.queryWeatherInformation();
refreshTimeAndDate();
}
/**
* 注册时间变化监听
*/
private void registerTimerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction( Intent.ACTION_TIME_TICK );
filter.addAction( Intent.ACTION_TIME_CHANGED );
filter.addAction( Intent.ACTION_TIMEZONE_CHANGED );
filter.addAction( Intent.ACTION_CONFIGURATION_CHANGED );
getContext().registerReceiver( mReceiver, filter );
}
private void refreshTimeAndDate() {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get( Calendar.HOUR_OF_DAY );
int minute = calendar.get( Calendar.MINUTE );
int month = calendar.get( Calendar.MONTH );
int day = calendar.get( Calendar.DAY_OF_MONTH );
int week = calendar.get( Calendar.DAY_OF_WEEK );
String timeStr = getContext().getResources().getString( R.string.module_ext_str_time_format, hour, minute > 9 ? String.valueOf( minute ) : "0" + minute );
String dateStr = getContext().getResources().getString( R.string.module_ext_str_date_format, month + 1, day, mWeeks[week - 1] );
mView.renderTime( dateStr, timeStr );
}
@Override
public void onWeatherLoaded( WeatherInfo weatherInfo ) {
if ( weatherInfo == null ) {
return;
}
String temp = getContext().getResources().getString( R.string.module_ext_str_weather_temp_format, weatherInfo.getTemperature() );
Phenomena phenomena = Phenomena.getById( weatherInfo.getPhenomena() );
String desc = phenomena == null ? "" : phenomena.nameCn;
int resId = 0;
mView.renderWeatherInfo( temp, desc, resId );
}
@Override
public void onDestroy( @NonNull LifecycleOwner owner ) {
super.onDestroy( owner );
if ( mWeatherModel != null ) {
mWeatherModel.destroy();
}
}
}

View File

@@ -0,0 +1,30 @@
package com.mogo.module.extensions;
import com.mogo.commons.mvp.IView;
import com.mogo.module.extensions.weather.WeatherInfo;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
public interface ExtensionsView extends IView {
/**
* 刷新日期、时间
*
* @param date 日期
* @param time 时间
*/
void renderTime( String date, String time );
/**
* 天气信息
*
* @param desc 天气描述:晴转多云
* @param temp 温度
* @param iconId 图标
*/
void renderWeatherInfo( String temp, String desc, int iconId );
}

View File

@@ -0,0 +1,97 @@
package com.mogo.module.extensions.weather;
import android.text.TextUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author Lzq
*/
public enum Phenomena {
Sunny( "00", "", "Sunny" ),
Cloudy( "01", "多云", "Cloudy" ),
Overcast( "02", "", "Overcast" ),
Shower( "03", "阵雨", "Shower" ),
Thundershower( "04", "雷阵雨", "Thundershower" ),
ThundershowerWithHail( "05", "雷阵雨伴有冰雹", "Thundershower with hail" ),
Sleet( "06", "雨夹雪", "Sleet" ),
LightRain( "07", "小雨", "Light rain" ),
ModerateRain( "08", "中雨", "Moderate rain" ),
HeavyRain( "09", "大雨", "Heavy rain" ),
Storm( "10", "暴雨", "Storm" ),
HeavyStorm( "11", "大暴雨", "Heavy storm" ),
SevereStorm( "12", "特大暴雨", "Severe storm" ),
SnowFlurry( "13", "阵雪", "Snow flurry" ),
LightSnow( "14", "小雪", "Light snow" ),
ModerateSnow( "15", "中雪", "Moderate snow" ),
HeavySnow( "16", "大雪", "Heavy snow" ),
Snowstorm( "17", "暴雪", "Snowstorm" ),
Foggy( "18", "", "Foggy" ),
IceRain( "19", "冻雨", "Ice rain" ),
Duststorm( "20", "沙尘暴", "Duststorm" ),
LightToModerateRain( "21", "小到中雨", "Light to moderate rain" ),
ModerateToHeavyRain( "22", "中到大雨", "Moderate to heavy rain" ),
HeavyRainToStorm( "23", "大到大雨", "Heavy rain to storm" ),
StormToHeavyStorm( "24", "暴雨到大暴雨", "Storm to heavy storm" ),
HeavyToSevereStorm( "25", "大暴雨到特大暴雨", "Heavy to severe storm" ),
LightToModerateSnow( "26", "小到中雪", "Light to moderate snow" ),
ModerateToHeavySnow( "27", "中到大雪", "Moderate to heavy snow" ),
HeavySnowToSnowStorm( "28", "大到暴雪", "Heavy snow to snowstorm" ),
Dust( "29", "浮尘", "Dust" ),
Sand( "30", "扬沙", "Sand" ),
SandStorm( "31", "强沙尘暴", "Sandstorm" ),
Densefog( "32", "浓雾", "Dense fog" ),
StrongFog( "49", "强浓雾", "Strong fog" ),
DenseFog( "57", "大雾", "Dense fog" ),
ExtraHeavyFog( "58", "特强浓雾", "Extra heavy fog" ),
Haze( "53", "", "Haze" ),
ModerateHaze( "54", "中度霾", "Moderate haze" ),
Severehaze( "55", "重度霾", "Severe haze" ),
SevereHaze( "56", "严重霾", "Severe haze" ),
Unknown( "99", "", "Unknown" ),
Rain( "301", "", "rain" ),
Snow( "302", "", "snow" );
public final String id;
public final String nameCn;
public final String nameEn;
Phenomena( String id, String nameCn, String nameEn ) {
this.id = id;
this.nameCn = nameCn;
this.nameEn = nameEn;
}
static Map< String, Phenomena > mPhenomenas;
static {
if ( mPhenomenas == null ) {
synchronized ( Phenomena.class ) {
if ( mPhenomenas == null ) {
mPhenomenas = new HashMap<>();
for ( Phenomena weather : Phenomena.values() ) {
mPhenomenas.put( weather.id, weather );
}
}
}
}
}
public static synchronized Phenomena getById( String id ) {
if ( TextUtils.isEmpty( id ) ) {
return null;
}
return mPhenomenas.get( id );
}
}

View File

@@ -0,0 +1,5 @@
package com.mogo.module.extensions.weather;
public interface WeatherCallback {
void onWeatherLoaded( WeatherInfo weatherInfo );
}

View File

@@ -0,0 +1,32 @@
package com.mogo.module.extensions.weather;
/**
* 天气
*/
public class WeatherConstants {
public final static String WEATHER_URI = "content://com.zhidao.weather/weatherinfo";
/**
* 天气
*/
public static final String TEMPERATURE = "observetemperature";
/**
* 气象
*/
public static final String PHENOMENA = "observephenomena";
/**
* 风向
*/
public static final String WIND_DIRECTION = "observewinddirection";
/**
* 风力
*/
public static final String WIND_FORCE = "observewindforce";
/**
* 天气消息加载完毕
*/
public static final int MSG_WEATHER_LOADED = 0x1000;
}

View File

@@ -0,0 +1,142 @@
package com.mogo.module.extensions.weather;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.util.Objects;
/**
* 天气
*/
public class WeatherInfo implements Parcelable {
/**
* 温度
*/
private String temperature;
/**
* 描述信息
*/
private String phenomena;
/**
* 风向
*/
private String windDirection;
/**
* 风力
*/
private String windForce;
@Override
public String toString() {
return "WeatherInfo{" +
"temperature='" + temperature + '\'' +
", phenomena='" + phenomena + '\'' +
", windDirection='" + windDirection + '\'' +
", windForce='" + windForce + '\'' +
'}';
}
@Override
public boolean equals( Object o ) {
if ( this == o ) {
return true;
}
if ( !( o instanceof WeatherInfo ) ) {
return false;
}
WeatherInfo that = ( WeatherInfo ) o;
return Objects.equals( temperature, that.temperature ) &&
Objects.equals( phenomena, that.phenomena ) &&
Objects.equals( windDirection, that.windDirection ) &&
Objects.equals( windForce, that.windForce );
}
@Override
public int hashCode() {
return Objects.hash( temperature, phenomena, windDirection, windForce );
}
public WeatherInfo() {
}
public WeatherInfo( String temperature, String phenomena, String windDirection, String windForce ) {
this.temperature = temperature;
this.phenomena = phenomena;
this.windDirection = windDirection;
this.windForce = windForce;
}
public String getTemperature() {
return temperature;
}
public void setTemperature( String temperature ) {
this.temperature = temperature;
}
public String getPhenomena() {
return phenomena;
}
public void setPhenomena( String phenomena ) {
this.phenomena = phenomena;
}
public String getWindDirection() {
return windDirection;
}
public void setWindDirection( String windDirection ) {
this.windDirection = windDirection;
}
public String getWindForce() {
return windForce;
}
public void setWindForce( String windForce ) {
this.windForce = windForce;
}
public boolean isLegal() {
return !TextUtils.isEmpty( phenomena )
&& !TextUtils.isEmpty( temperature );
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel( Parcel dest, int flags ) {
dest.writeString( this.temperature );
dest.writeString( this.phenomena );
dest.writeString( this.windDirection );
dest.writeString( this.windForce );
}
protected WeatherInfo( Parcel in ) {
this.temperature = in.readString();
this.phenomena = in.readString();
this.windDirection = in.readString();
this.windForce = in.readString();
}
public static final Creator< WeatherInfo > CREATOR = new Creator< WeatherInfo >() {
@Override
public WeatherInfo createFromParcel( Parcel source ) {
return new WeatherInfo( source );
}
@Override
public WeatherInfo[] newArray( int size ) {
return new WeatherInfo[size];
}
};
}

View File

@@ -0,0 +1,136 @@
package com.mogo.module.extensions.weather;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import com.mogo.utils.ThreadPoolService;
import com.mogo.utils.logger.Logger;
/**
* @author congtaowang
* @since 2020-01-05
* <p>
* 描述
*/
public class WeatherModel {
private static final String TAG = "WeatherModel";
private Context mContext;
private Uri mWeatherUri;
private Handler mHandler;
private ContentResolver mContentResolver;
private ContentObserver mContentObserver;
private WeatherCallback mCallback;
public WeatherModel( Context context ) {
this.mContext = context;
}
public void init( WeatherCallback callback ) {
mCallback = callback;
mWeatherUri = Uri.parse( WeatherConstants.WEATHER_URI );
mContentResolver = mContext.getContentResolver();
mHandler = new Handler( Looper.getMainLooper() ) {
@Override
public void handleMessage( @NonNull Message msg ) {
if ( msg.what == WeatherConstants.MSG_WEATHER_LOADED ) {
if ( mCallback != null ) {
mCallback.onWeatherLoaded( ( ( WeatherInfo ) msg.obj ) );
}
}
}
};
mContentObserver = new ContentObserver( mHandler ) {
@Override
public void onChange( boolean selfChange, Uri uri ) {
super.onChange( selfChange, uri );
try {
queryWeatherInformation();
} catch ( Exception e ) {
Logger.e( TAG, "error. ", e );
}
}
};
try {
mContentResolver.registerContentObserver( mWeatherUri, false, mContentObserver );
} catch ( Exception e ) {
Logger.e( TAG, "error when query weather info.", e );
}
}
public void queryWeatherInformation() {
if ( mCallback == null ) {
Logger.e( TAG, "WeatherModel#init should invoked " );
return;
}
startNewThreadToQuery();
}
private void startNewThreadToQuery() {
ThreadPoolService.execute( new Runnable() {
@Override
public void run() {
if ( mContentResolver == null ) {
return;
}
Cursor cursor = null;
try {
cursor = mContentResolver.query( mWeatherUri, null, null, null, null, null );
} catch ( Exception e ) {
return;
}
if ( cursor == null ) {
return;
}
WeatherInfo weatherInfo = new WeatherInfo();
if ( cursor.moveToFirst() ) {
int index = cursor.getColumnIndex( WeatherConstants.TEMPERATURE );
if ( index != -1 ) {
weatherInfo.setTemperature( cursor.getString( index ) );
}
index = cursor.getColumnIndex( WeatherConstants.PHENOMENA );
if ( index != -1 ) {
weatherInfo.setPhenomena( cursor.getString( index ) );
}
index = cursor.getColumnIndex( WeatherConstants.WIND_DIRECTION );
if ( index != -1 ) {
weatherInfo.setWindDirection( cursor.getString( index ) );
}
index = cursor.getColumnIndex( WeatherConstants.WIND_FORCE );
if ( index != -1 ) {
weatherInfo.setWindForce( cursor.getString( index ) );
}
Message msg = Message.obtain();
msg.obj = weatherInfo;
msg.what = WeatherConstants.MSG_WEATHER_LOADED;
mHandler.sendMessage( msg );
}
cursor.close();
}
} );
}
public void destroy() {
if ( mContentResolver != null && mContentObserver != null ) {
mContentResolver.unregisterContentObserver( mContentObserver );
}
mContext = null;
mWeatherUri = null;
mHandler = null;
mContentResolver = null;
mContentObserver = null;
mCallback = null;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<corners android:radius="90dp" />
<solid android:color="#DA2E55" />
</shape>
</item>
</selector>

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="vertical"
android:paddingLeft="35dp"
android:paddingRight="35dp">
<ImageView
android:id="@+id/module_ext_id_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/module_ext_ic_voice"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/module_ext_id_voice_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="@string/module_ext_str_voice_msg"
android:textColor="@color/module_ext_color_voice_text"
android:textSize="16dp"
app:layout_constraintBottom_toBottomOf="@+id/module_ext_id_voice"
app:layout_constraintLeft_toRightOf="@+id/module_ext_id_voice"
app:layout_constraintTop_toTopOf="@+id/module_ext_id_voice" />
<TextView
android:id="@+id/module_ext_id_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textColor="#FFFFFF"
android:textSize="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="10:10" />
<TextView
android:id="@+id/module_ext_id_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="40dp"
android:gravity="center_vertical"
android:textColor="#FFFFFF"
android:textSize="14dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@+id/module_ext_id_time"
app:layout_constraintTop_toTopOf="parent"
tools:text="11月20日 周三" />
<LinearLayout
android:id="@+id/module_ext_id_weather_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="13dp"
android:gravity="center"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@+id/module_ext_id_date"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/module_ext_id_weather_icon"
android:layout_width="22dp"
android:layout_height="22dp"
tools:src="@drawable/module_ext_ic_voice" />
<TextView
android:id="@+id/module_ext_id_weather_temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="9dp"
android:textColor="#FFFFFF"
android:textSize="17dp"
tools:text="28°" />
<TextView
android:id="@+id/module_ext_id_weather_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="13dp"
android:textColor="#FFFFFF"
android:textSize="14dp"
tools:text="晴转多云" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"
android:textColor="#FFFFFF" />
</LinearLayout>
<FrameLayout
android:id="@+id/module_ext_id_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="14dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@+id/module_ext_id_weather_container"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/module_ext_ic_message" />
<TextView
android:id="@+id/module_ext_id_msg_counter"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_gravity="right"
android:background="@drawable/module_ext_drawable_msg_bkg"
android:gravity="center"
android:textColor="#FFFFFF"
android:visibility="invisible"
android:textSize="10dp"
tools:text="···" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="module_ext_color_voice_text">#FFFFFF</color>
</resources>

View File

@@ -0,0 +1,16 @@
<resources>
<string name="app_name">mogo-module-extensions</string>
<string name="module_ext_str_voice_msg">你好蘑菇2.0开启智慧互联新世界</string>
<string name="module_ext_str_date_format">%1$d月%2$d日 %3$s</string>
<string name="module_ext_str_time_format">%1$d:%2$s</string>
<string name="module_ext_str_weather_temp_format">%s° </string>
<string-array name="module_ext_str_arr_week">
<item>周日</item>
<item>周一</item>
<item>周二</item>
<item>周三</item>
<item>周四</item>
<item>周五</item>
<item>周六</item>
</string-array>
</resources>

View File

@@ -0,0 +1,17 @@
package com.mogo.module.extensions;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals( 4, 2 + 2 );
}
}

View File

@@ -42,17 +42,21 @@ dependencies {
implementation rootProject.ext.dependencies.modulemap
implementation rootProject.ext.dependencies.mogoserviceapi
implementation rootProject.ext.dependencies.mogoservice
implementation rootProject.ext.dependencies.moduleservice
implementation rootProject.ext.dependencies.moduleapps
implementation rootProject.ext.dependencies.mogoconnection
implementation rootProject.ext.dependencies.moduleextensions
} else {
implementation project(":foudations:mogo-utils")
implementation project(":foudations:mogo-commons")
implementation project(':modules:mogo-module-common')
implementation project(':modules:mogo-module-map')
implementation project(':modules:mogo-module-service')
implementation project(':services:mogo-service-api')
implementation project(':services:mogo-service')
implementation project(':modules:mogo-module-apps')
implementation project(':foudations:mogo-connection')
implementation project(':modules:mogo-module-extensions')
}
}

View File

@@ -13,11 +13,15 @@ import com.mogo.map.location.IMogoLocationListener;
import com.mogo.map.location.MogoLocation;
import com.mogo.map.marker.IMogoMarker;
import com.mogo.map.marker.IMogoMarkerClickListener;
import com.mogo.module.common.MogoModule;
import com.mogo.module.common.MogoModulePaths;
import com.mogo.module.extensions.ExtensionsModuleConst;
import com.mogo.module.main.cards.CardModulesAdapter;
import com.mogo.module.main.cards.MogoModulesHandler;
import com.mogo.module.main.cards.MogoModulesManager;
import com.mogo.module.main.cards.OrientedViewPager;
import com.mogo.module.main.cards.VerticalStackTransformer;
import com.mogo.module.service.ServiceConst;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.connection.IMogoSocketManager;
import com.mogo.service.map.IMogoMapService;
@@ -99,11 +103,20 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme
protected void onCreate( @Nullable Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
MogoModulePaths.addModule( new MogoModule( MogoModulePaths.PATH_MODULE_APPS, MogoModulePaths.PATH_MODULE_APPS ) );
MogoModulePaths.addModule( new MogoModule( MogoModulePaths.PATH_MODULE_MAP, MogoModulePaths.PATH_MODULE_MAP ) );
MogoModulePaths.addModule( new MogoModule( ServiceConst.PATH_REFRESH_STRATEGY, ServiceConst.PATH_REFRESH_STRATEGY ) );
MogoModulePaths.addModule( new MogoModule( ExtensionsModuleConst.PATH_EXTENSION, ExtensionsModuleConst.TYPE ) );
mMogoModuleHandler = new MogoModulesManager( this );
mMogoMapService = ( IMogoMapService ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_MAP ).navigation();
if ( mMogoMapService != null ) {
mMogoMapService.getHostListenerRegister().registerHostMapListener( mMogoModuleHandler );
mMogoMapService.getHostListenerRegister().registerHostNaviListener( mMogoModuleHandler );
mMogoMapService.getHostListenerRegister().registerMarkerClickListener( this );
}
mMogoSocketManager = ( IMogoSocketManager ) ARouter.getInstance().build( MogoServicePaths.PATH_SOCKET_MANAGER ).navigation();
mMogoSocketManager.init( getApplicationContext(), AppConstants.SOCKET_APP_ID );
mMogoModuleHandler.loadModules();
mMogoModuleHandler.onMapLoadedCallback( new Runnable() {
@Override
public void run() {
@@ -111,21 +124,17 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme
loadModules();
}
} );
mMogoMapService = ( IMogoMapService ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_MAP ).navigation();
if ( mMogoMapService != null ) {
mMogoMapService.getHostListenerRegister().registerHostMapListener( mMogoModuleHandler );
mMogoMapService.getHostListenerRegister().registerHostNaviListener( mMogoModuleHandler );
mMogoMapService.getHostListenerRegister().registerMarkerClickListener( this );
}
// 加载地图,触发地图加载完毕回调,在初始化其他卡片模块,保证卡片模块可以正确获取地图相关服务。
mMogoModuleHandler.loadMap( R.id.module_main_id_map_fragment_container );
mMogoModuleHandler.loadAppsList( R.id.module_main_id_fragment_container );
mMogoModuleHandler.loadExtensions( R.id.module_main_id_header_fragment_container );
mLocationClient = mMogoMapService.getSingletonLocationClient( getApplicationContext() );
mLocationClient.addLocationListener( this );
mLocationClient.start();
mMogoModuleHandler.loadAppsList( R.id.module_main_id_fragment_container );
mMogoSocketManager = ( IMogoSocketManager ) ARouter.getInstance().build( MogoServicePaths.PATH_SOCKET_MANAGER ).navigation();
mMogoSocketManager.init( getApplicationContext(), AppConstants.SOCKET_APP_ID );
}
private void loadModules() {

View File

@@ -24,6 +24,8 @@ public interface MogoModulesHandler extends IMogoMapListener,
void onMapLoadedCallback( Runnable callback );
void loadModules();
/**
* 加载卡片
*
@@ -31,20 +33,6 @@ public interface MogoModulesHandler extends IMogoMapListener,
*/
List< IMogoModuleProvider > loadCardsModule();
/**
* 加载小智语音
*
* @param containerId 容器id
*/
void loadAIAssist( int containerId );
/**
* 加载天气
*
* @param containerId 容器id
*/
void loadWeather( int containerId );
/**
* 加载地图
*
@@ -59,6 +47,13 @@ public interface MogoModulesHandler extends IMogoMapListener,
*/
void loadAppsList( int containerId );
/**
* 加载头部信息
*
* @param containerId
*/
void loadExtensions( int containerId );
/**
* 设置某一个module可用
*

View File

@@ -1,6 +1,9 @@
package com.mogo.module.main.cards;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.text.TextUtils;
import android.view.MotionEvent;
@@ -18,8 +21,11 @@ import com.mogo.map.uicontroller.EnumMapUI;
import com.mogo.module.common.MogoModule;
import com.mogo.module.common.MogoModulePaths;
import com.mogo.module.main.MainActivity;
import com.mogo.module.main.receiver.MogoReceiver;
import com.mogo.module.service.ServiceConst;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
import com.mogo.utils.ResourcesHelper;
import com.mogo.utils.logger.Logger;
@@ -43,17 +49,20 @@ public class MogoModulesManager implements MogoModulesHandler,
private static final String TAG = "MogoModulesManager";
private MainActivity mActivity;
private final Map< String, IMogoModuleProvider > mCardProviders = new HashMap<>();
private IMogoModuleProvider mMapProvider;
private IMogoModuleProvider mAppsListProvider;
private Map< MogoModule, IMogoModuleProvider > mModuleProviders = new HashMap<>();
private String mEnableModuleName = null;
private Runnable mMapLoadedCallback;
private BroadcastReceiver mReceiver;
public MogoModulesManager( MainActivity activity ) {
if ( activity == null ) {
throw new NullPointerException( "activity can't be null." );
}
this.mActivity = activity;
registerReceiver();
}
private Context getContext() {
@@ -64,6 +73,19 @@ public class MogoModulesManager implements MogoModulesHandler,
return mActivity.getApplicationContext();
}
@Override
public void loadModules() {
final List< MogoModule > modules = MogoModulePaths.getModules();
if ( modules != null && !modules.isEmpty() ) {
for ( MogoModule module : modules ) {
IMogoModuleProvider provider = load( module.getPath() );
if ( provider != null ) {
mModuleProviders.put( module, provider );
}
}
}
}
@Override
public void onMapLoadedCallback( Runnable callback ) {
mMapLoadedCallback = callback;
@@ -73,40 +95,40 @@ public class MogoModulesManager implements MogoModulesHandler,
public List< IMogoModuleProvider > loadCardsModule() {
final List< MogoModule > modules = MogoModulePaths.getModules();
final ArrayList< IMogoModuleProvider > providers = new ArrayList<>();
if ( modules != null && !modules.isEmpty() ) {
for ( MogoModule module : modules ) {
IMogoModuleProvider provider = load( module.getPath() );
for ( MogoModule module : modules ) {
IMogoModuleProvider provider = mModuleProviders.get( module );
if ( provider.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
providers.add( provider );
mCardProviders.put( provider.getModuleName(), provider );
}
}
return providers;
}
@Override
public void loadAIAssist( int containerId ) {
}
@Override
public void loadWeather( int containerId ) {
}
private IMogoModuleProvider getModuleProvider( String tag ) {
return mCardProviders.get( tag );
}
@Override
public void loadMap( int containerId ) {
mMapProvider = load( MogoModulePaths.PATH_MODULE_MAP );
addFragment( mMapProvider, containerId );
loadModuleByType( ModuleType.TYPE_MAP, containerId );
}
@Override
public void loadAppsList( int containerId ) {
mAppsListProvider = load( MogoModulePaths.PATH_MODULE_APPS );
addFragment( mAppsListProvider, containerId );
loadModuleByType( ModuleType.TYPE_APP_LIST, containerId );
}
@Override
public void loadExtensions( int containerId ) {
loadModuleByType( ModuleType.TYPE_EXTENSION, containerId );
}
private void loadModuleByType( int type, int containerId ) {
if ( mModuleProviders.isEmpty() ) {
return;
}
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == type ) {
addFragment( value, containerId );
return;
}
}
}
private IMogoModuleProvider load( String path ) {
@@ -131,14 +153,18 @@ public class MogoModulesManager implements MogoModulesHandler,
@Override
public void setEnable( String module ) {
mEnableModuleName = module;
final Set< Map.Entry< String, IMogoModuleProvider > > entries = mCardProviders.entrySet();
final Set< Map.Entry< MogoModule, IMogoModuleProvider > > entries = mModuleProviders.entrySet();
if ( !entries.isEmpty() ) {
for ( Map.Entry< String, IMogoModuleProvider > entry : entries ) {
final String key = entry.getKey();
for ( Map.Entry< MogoModule, IMogoModuleProvider > entry : entries ) {
final MogoModule key = entry.getKey();
final IMogoModuleProvider provider = entry.getValue();
if ( provider.getType() != ModuleType.TYPE_CARD_FRAGMENT ) {
// 仅卡片需要生命周期
continue;
}
final IMogoModuleLifecycle lifecycle = provider.getCardLifecycle();
if ( lifecycle != null ) {
if ( TextUtils.equals( key, mEnableModuleName ) ) {
if ( TextUtils.equals( key.getName(), mEnableModuleName ) ) {
lifecycle.onPerform();
} else {
lifecycle.onDisable();
@@ -151,134 +177,259 @@ public class MogoModulesManager implements MogoModulesHandler,
@Override
public void onMapLoaded() {
if ( mMapLoadedCallback != null ) {
mMapLoadedCallback.run();
mMapLoadedCallback = null;
}
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onMapLoaded();
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapLoaded();
}
}
}
@Override
public void onTouch( MotionEvent motionEvent ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onTouch( motionEvent );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onTouch( motionEvent );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onTouch( motionEvent );
}
}
}
}
@Override
public void onPOIClick( MogoPoi poi ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onPOIClick( poi );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onPOIClick( poi );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onPOIClick( poi );
}
}
}
}
@Override
public void onMapClick( MogoLatLng latLng ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onMapClick( latLng );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapClick( latLng );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapClick( latLng );
}
}
}
}
@Override
public void onLockMap( boolean isLock ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onLockMap( isLock );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onLockMap( isLock );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onLockMap( isLock );
}
}
}
}
@Override
public void onMapModeChanged( EnumMapUI ui ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getMapListener() != null ) {
provider.getMapListener().onMapModeChanged( ui );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapModeChanged( ui );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapModeChanged( ui );
}
}
}
}
@Override
public void onMapChanged( MogoLatLng location, float zoom, float tilt, float bearing ) {
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapChanged( location, zoom, tilt, bearing );
}
}
} else {
if ( value.getMapListener() != null ) {
value.getMapListener().onMapChanged( location, zoom, tilt, bearing );
}
}
}
}
@Override
public void onInitNaviFailure() {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getNaviListener() != null ) {
provider.getNaviListener().onInitNaviFailure();
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onInitNaviFailure();
}
}
} else {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onInitNaviFailure();
}
}
}
}
@Override
public void onInitNaviSuccess() {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getNaviListener() != null ) {
provider.getNaviListener().onInitNaviSuccess();
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onInitNaviSuccess();
}
}
} else {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onInitNaviSuccess();
}
}
}
}
@Override
public void onNaviInfoUpdate( MogoNaviInfo naviinfo ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getNaviListener() != null ) {
provider.getNaviListener().onNaviInfoUpdate( naviinfo );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onNaviInfoUpdate( naviinfo );
}
}
} else {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onNaviInfoUpdate( naviinfo );
}
}
}
}
@Override
public void onStartNavi() {
Logger.i( TAG, "导航已开始" );
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getNaviListener() != null ) {
provider.getNaviListener().onStartNavi();
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onStartNavi();
}
}
} else {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onStartNavi();
}
}
}
}
@Override
public void onStopNavi() {
Logger.i( TAG, "导航已停止" );
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getNaviListener() != null ) {
provider.getNaviListener().onStopNavi();
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onStopNavi();
}
}
} else {
if ( value.getNaviListener() != null ) {
value.getNaviListener().onStopNavi();
}
}
}
}
@Override
public void onLocationChanged( MogoLocation location ) {
if ( mEnableModuleName != null ) {
IMogoModuleProvider provider = getModuleProvider( mEnableModuleName );
if ( provider != null && provider.getLocationListener() != null ) {
provider.getLocationListener().onLocationChanged( location );
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getType() == ModuleType.TYPE_CARD_FRAGMENT ) {
if ( mEnableModuleName != null && TextUtils.equals( value.getModuleName(), mEnableModuleName ) ) {
if ( value.getLocationListener() != null ) {
value.getLocationListener().onLocationChanged( location );
}
}
} else {
if ( value.getLocationListener() != null ) {
value.getLocationListener().onLocationChanged( location );
}
}
}
}
public void registerReceiver() {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive( Context context, Intent intent ) {
final String action = intent.getAction();
if ( TextUtils.equals( action, Intent.ACTION_POWER_CONNECTED ) ) {
for ( IMogoModuleProvider value : mModuleProviders.values() ) {
if ( value.getCardLifecycle() != null ) {
value.getCardLifecycle().accOn();
}
}
}
if ( TextUtils.equals( action, Intent.ACTION_POWER_DISCONNECTED ) ) {
}
}
};
IntentFilter inputFilter = new IntentFilter();
inputFilter.addAction( Intent.ACTION_POWER_CONNECTED );
inputFilter.addAction( Intent.ACTION_POWER_DISCONNECTED );
getApplicationContext().registerReceiver( mReceiver, inputFilter );
}
@Override
public void destroy() {
if ( mReceiver != null ) {
try {
getApplicationContext().unregisterReceiver( mReceiver );
} catch ( Exception e ) {
}
}
mReceiver = null;
mActivity = null;
if ( mModuleProviders != null ) {
mModuleProviders.clear();
}
mModuleProviders = null;
mMapLoadedCallback = null;
mEnableModuleName = null;
}
}

View File

@@ -19,6 +19,7 @@ import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.module.main.R;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
/**
* @author congtaowang
@@ -80,7 +81,7 @@ public class PlaceholderFragmentProvider implements IMogoModuleProvider {
@Override
public int getType() {
return TYPE_FRAGMENT;
return ModuleType.TYPE_CARD_FRAGMENT;
}
@Override

View File

@@ -5,6 +5,10 @@ import android.view.View;
import androidx.viewpager.widget.ViewPager;
/**
* Created by Nate on 2016/7/22.
*/
public abstract class VerticalBaseTransformer implements ViewPager.PageTransformer {
/**
* Called each {@link #transformPage(View, float)}.
@@ -13,7 +17,7 @@ public abstract class VerticalBaseTransformer implements ViewPager.PageTransform
* @param position Position of page relative to the current front-and-center position of the pager. 0 is front and
* center. 1 is one full page position to the right, and -1 is one page position to the left.
*/
protected abstract void onTransform( View page, float position );
protected abstract void onTransform(View page, float position);
/**
* Apply a property transformation to the given page. For most use cases, this method should not be overridden.
@@ -24,10 +28,10 @@ public abstract class VerticalBaseTransformer implements ViewPager.PageTransform
* center. 1 is one full page position to the right, and -1 is one page position to the left.
*/
@Override
public void transformPage( View page, float position ) {
onPreTransform( page, position );
onTransform( page, position );
onPostTransform( page, position );
public void transformPage(View page, float position) {
onPreTransform(page, position);
onTransform(page, position);
onPostTransform(page, position);
}
/**
@@ -61,24 +65,24 @@ public abstract class VerticalBaseTransformer implements ViewPager.PageTransform
* @param position Position of page relative to the current front-and-center position of the pager. 0 is front and
* center. 1 is one full page position to the right, and -1 is one page position to the left.
*/
protected void onPreTransform( View page, float position ) {
protected void onPreTransform(View page, float position) {
final float width = page.getWidth();
final float height = page.getHeight();
page.setRotationX( 0 );
page.setRotationY( 0 );
page.setRotation( 0 );
page.setScaleX( 1 );
page.setScaleY( 1 );
page.setPivotX( 0 );
page.setPivotY( 0 );
page.setTranslationX( 0 );
page.setTranslationY( isPagingEnabled() ? 0f : -height * position );
page.setRotationX(0);
page.setRotationY(0);
page.setRotation(0);
page.setScaleX(1);
page.setScaleY(1);
page.setPivotX(0);
page.setPivotY(0);
page.setTranslationX(0);
page.setTranslationY(isPagingEnabled() ? 0f : -height * position);
if ( hideOffscreenPages() ) {
page.setAlpha( position <= -1f || position >= 1f ? 0f : 1f );
if (hideOffscreenPages()) {
page.setAlpha(position <= -1f || position >= 1f ? 0f : 1f);
} else {
page.setAlpha( 1f );
page.setAlpha(1f);
}
/*final float normalizedposition = Math.abs(Math.abs(position) - 1);
@@ -92,7 +96,7 @@ public abstract class VerticalBaseTransformer implements ViewPager.PageTransform
* @param position Position of page relative to the current front-and-center position of the pager. 0 is front and
* center. 1 is one full page position to the right, and -1 is one page position to the left.
*/
protected void onPostTransform( View page, float position ) {
protected void onPostTransform(View page, float position) {
}
/**
@@ -102,7 +106,7 @@ public abstract class VerticalBaseTransformer implements ViewPager.PageTransform
* @param min
* @return
*/
protected static final float min( float val, float min ) {
protected static final float min(float val, float min) {
return val < min ? min : val;
}
}

View File

@@ -9,8 +9,8 @@ import com.mogo.utils.WindowUtils;
public class VerticalStackTransformer extends VerticalBaseTransformer {
private Context context;
private int spaceBetweenFirAndSecWith = 10 * 2;//第一张卡片和第二张卡片宽度差 dp单位
private int spaceBetweenFirAndSecHeight = 10;//第一张卡片和第二张卡片高度差 dp单位
private int spaceBetweenFirAndSecWith = 5 * 2;//第一张卡片和第二张卡片宽度差 dp单位
private int spaceBetweenFirAndSecHeight = 5;//第一张卡片和第二张卡片高度差 dp单位
public VerticalStackTransformer( Context context ) {
this.context = context;
@@ -26,10 +26,12 @@ public class VerticalStackTransformer extends VerticalBaseTransformer {
protected void onTransform( View page, float position ) {
if ( position <= 0.0f ) {
page.setAlpha( 1.0f );
Log.e( "onTransform", "position <= 0.0f ==>" + position );
page.setTranslationY( 0f );
//控制停止滑动切换的时候,只有最上面的一张卡片可以点击
page.setClickable( true );
} else if ( position <= 3.0f ) {
} else {
Log.e( "onTransform", "position <= 3.0f ==>" + position );
float scale = ( float ) ( page.getWidth() - WindowUtils.dip2px( context, spaceBetweenFirAndSecWith * position ) ) / ( float ) ( page.getWidth() );
//控制下面卡片的可见度
page.setAlpha( 1.0f );

View File

@@ -0,0 +1,40 @@
package com.mogo.module.main.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.text.TextUtils;
/**
* @author congtaowang
* @since 2020-01-02
* <p>
* 广播接收者
* <p>
* {@link Intent#ACTION_POWER_CONNECTED}
* {@link Intent#ACTION_POWER_DISCONNECTED}
*/
public class MogoReceiver extends BroadcastReceiver {
public static void register( Context context ) {
if ( context == null ) {
return;
}
IntentFilter inputFilter = new IntentFilter();
inputFilter.addAction( Intent.ACTION_POWER_CONNECTED );
inputFilter.addAction( Intent.ACTION_POWER_DISCONNECTED );
context.getApplicationContext().registerReceiver( new MogoReceiver(), inputFilter );
}
@Override
public void onReceive( Context context, Intent intent ) {
final String action = intent.getAction();
if ( TextUtils.equals( action, Intent.ACTION_POWER_CONNECTED ) ) {
}
if ( TextUtils.equals( action, Intent.ACTION_POWER_DISCONNECTED ) ) {
}
}
}

View File

@@ -3,26 +3,28 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0C0C0C"
android:orientation="vertical">
<!-- 小智语音-->
<FrameLayout
android:id="@+id/module_main_id_ai_fragment_container"
android:id="@+id/module_main_id_header_fragment_container"
android:layout_width="match_parent"
android:layout_height="75dp"
android:background="#f00"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_marginLeft="35dp"
android:layout_marginTop="5dp">
<!-- 卡片-->
<FrameLayout
android:id="@+id/module_main_id_fragment_container"
android:layout_width="0dp"
android:layout_width="@dimen/dp_660"
android:layout_height="match_parent"
android:layout_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -30,17 +32,16 @@
android:id="@+id/module_main_id_cards_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dp"
android:padding="10dp" />
android:layout_marginBottom="90dp"
android:clipToPadding="false"
android:paddingBottom="10dp" />
</FrameLayout>
<!-- 地图-->
<FrameLayout
android:id="@+id/module_main_id_map_fragment_container"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
app:layout_constraintLeft_toRightOf="@+id/module_main_id_fragment_container"
app:layout_constraintRight_toRightOf="parent" />
</LinearLayout>

View File

@@ -102,7 +102,7 @@ public class MapFragment extends MvpFragment< MapView, MapPresenter > implements
//设置拖拽手势是否可用。
uiSettings.setScrollGesturesEnabled( true );
//设置倾斜手势是否可用。
uiSettings.setTiltGesturesEnabled( false );
uiSettings.setTiltGesturesEnabled( true );
//设置缩放按钮是否可见。
uiSettings.setZoomControlsEnabled( false );
//设置双指缩放手势是否可用。

View File

@@ -14,6 +14,7 @@ import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.module.common.MogoModulePaths;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
/**
* @author congtaowang
@@ -46,7 +47,7 @@ public class MapFragmentProvider implements IMogoModuleProvider {
@Override
public int getType() {
return IMogoModuleProvider.TYPE_FRAGMENT;
return ModuleType.TYPE_MAP;
}

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,60 @@
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.rxjava
implementation rootProject.ext.dependencies.rxandroid
if (Boolean.valueOf(RELEASE)) {
api rootProject.ext.dependencies.mogomap
api rootProject.ext.dependencies.mogomapapi
api rootProject.ext.dependencies.mogoutils
api rootProject.ext.dependencies.mogocommons
api rootProject.ext.dependencies.mogoserviceapi
implementation rootProject.ext.dependencies.modulecommon
} else {
api project(":libraries:mogo-map")
api project(":libraries:mogo-map-api")
api project(":foudations:mogo-utils")
api project(":foudations:mogo-commons")
api project(':services:mogo-service-api')
implementation project(':modules:mogo-module-common')
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

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

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.module.service" />

View File

@@ -0,0 +1,48 @@
package com.mogo.module.service;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 自动刷新策略
*/
public class AutoRefreshStrategy {
public static final long ONE_MINUTE = 5 * 1_000L;
/**
* 距离(米)
*/
private int distance = 2_000;
/**
* 时间间距s
*/
private long interval = 3 * ONE_MINUTE;
/**
* 用户打断后的延时s
*/
private long interruptInterval = 1 * ONE_MINUTE;
/**
* 距离(米)
*/
public int getDistance() {
return distance;
}
/**
* 时间间距s
*/
public long getInterval() {
return interval;
}
/**
* 用户打断后的延时
*/
public long getInterruptInterval() {
return interruptInterval;
}
}

View File

@@ -0,0 +1,19 @@
package com.mogo.module.service;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 手动刷新策略
*/
public class CustomRefreshStrategy {
/**
* 缩小倍数
*/
private float zoomOutLevel = 2;
public float getZoomOutLevel() {
return zoomOutLevel;
}
}

View File

@@ -0,0 +1,431 @@
package com.mogo.module.service;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.map.MogoLatLng;
import com.mogo.map.listener.IMogoMapListener;
import com.mogo.map.location.IMogoLocationListener;
import com.mogo.map.location.MogoLocation;
import com.mogo.map.marker.IMogoMarker;
import com.mogo.map.marker.IMogoMarkerManager;
import com.mogo.map.marker.MogoMarkerOptions;
import com.mogo.map.model.MogoPoi;
import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.map.navi.MogoNaviInfo;
import com.mogo.map.uicontroller.EnumMapUI;
import com.mogo.map.uicontroller.IMogoMapUIController;
import com.mogo.module.service.network.RefreshCallback;
import com.mogo.module.service.network.RefreshModel;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.map.IMogoMapService;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
import com.mogo.service.statusmanager.IMogoStatusChangedListener;
import com.mogo.service.statusmanager.IMogoStatusManager;
import com.mogo.service.statusmanager.StatusDescriptor;
import com.mogo.utils.logger.Logger;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 数据刷新策略
*/
@Route( path = ServiceConst.PATH_REFRESH_STRATEGY )
public class MogoServiceProvider implements IMogoModuleProvider,
IMogoMapListener,
IMogoLocationListener,
IMogoNaviListener,
IMogoStatusChangedListener {
private static final String TAG = "MogoRefreshStrategyProvider";
/**
* 自动刷新策略
*/
private AutoRefreshStrategy mAutoRefreshStrategy = new AutoRefreshStrategy();
private MogoLatLng mLastAutoRefreshLocation = null;
private long mLastRefreshTime = 0;
private IMogoMarkerManager mMarkerManager;
private IMogoMapUIController mUiController;
/**
* 是否已计算出地图显示状态
*/
private boolean mIsMapStatusOk = false;
/**
* 地图显示是横屏还是竖屏:根据地图右上角和左下角坐标计算
*/
boolean mIsVertical = false;
/**
* 手动刷新策略
*/
private CustomRefreshStrategy mCustomRefreshStrategy = new CustomRefreshStrategy();
private float mLastZoomLevel = 0;
private RefreshModel mRefreshModel;
private long mRefreshRemainingTime = Long.MAX_VALUE;
// 上次手动操作的中心点坐标
private MogoLatLng mLastCustomRefreshCenterLocation;
private IMogoMapService mMogoMapService;
private IMogoMarker mCameraCenterMarker = null;
private IMogoStatusManager mStatusManager;
/**
* 地图视图初始化
*/
private boolean mIsCameraInited = true;
private Handler mHandler = new Handler( Looper.getMainLooper() ) {
@Override
public void handleMessage( @NonNull Message msg ) {
super.handleMessage( msg );
switch ( msg.what ) {
case ServiceConst.MSG_TYPE_REFRESH_DECREASE:
mRefreshRemainingTime -= ServiceConst.DECREASE_INTERVAL;
if ( mRefreshRemainingTime == 0 ) {
notifyRefreshData( mAutoRefreshCallback );
} else {
mHandler.sendEmptyMessageDelayed( msg.what, ServiceConst.DECREASE_INTERVAL );
}
break;
}
}
};
private Context mContext;
/**
* 地图视图西南角坐标
*/
private MogoLatLng mCameraSouthWestPosition;
/**
* 地图视图东北角坐标
*/
private MogoLatLng mCameraNorthEastPosition;
/**
* 手动刷新回调
*/
private RefreshCallback mCustomRefreshCallback = new RefreshCallback() {
@Override
public void onSuccess() {
// 用户手动操作地图刷新成功后,设置状态为 true引发延时策略
mStatusManager.setUserInteractionStatus( ServiceConst.TYPE, true, true );
mStatusManager.setUserInteractionStatus( ServiceConst.TYPE, false, false );
}
@Override
public void onFail() {
}
};
/**
* 自动刷新回调
*/
private RefreshCallback mAutoRefreshCallback = new RefreshCallback() {
@Override
public void onSuccess() {
invokeAutoRefreshStrategy();
}
@Override
public void onFail() {
invokeAutoRefreshStrategy();
}
private void invokeAutoRefreshStrategy() {
mRefreshRemainingTime = mAutoRefreshStrategy.getInterval();
mHandler.removeMessages( ServiceConst.MSG_TYPE_REFRESH_DECREASE );
mHandler.sendEmptyMessageDelayed( ServiceConst.MSG_TYPE_REFRESH_DECREASE, ServiceConst.DECREASE_INTERVAL );
}
};
@Override
public final Fragment createFragment( Context context, Bundle data ) {
return null;
}
@Override
public final View createView( Context context ) {
return null;
}
@Override
public final IMogoModuleLifecycle getCardLifecycle() {
return null;
}
@Override
public IMogoMapListener getMapListener() {
return this;
}
@Override
public int getType() {
return ModuleType.TYPE_SERVICE;
}
@Override
public IMogoNaviListener getNaviListener() {
return this;
}
@Override
public IMogoLocationListener getLocationListener() {
return this;
}
@NonNull
@Override
public String getModuleName() {
return ServiceConst.TYPE;
}
@Override
public void init( Context context ) {
mContext = context;
mRefreshModel = new RefreshModel( context );
mMogoMapService = ( IMogoMapService ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_MAP ).navigation( context );
mMarkerManager = mMogoMapService.getMarkerManager( context );
mUiController = mMogoMapService.getMapUIController();
mStatusManager = ( IMogoStatusManager ) ARouter.getInstance().build( MogoServicePaths.PATH_STATUS_MANAGER ).navigation( context );
mStatusManager.registerStatusChangedListener( ServiceConst.TYPE, StatusDescriptor.USER_INTERACTED, this );
}
@Override
public void onMapLoaded() {
refreshCameraPosition();
}
private void initMapStatus() {
if ( mIsMapStatusOk ) {
return;
}
try {
float width = getMapCameraFactWidth();
float height = getMapCameraFactHeight();
mIsVertical = width < height;
Logger.i( TAG, "map status is vertical : " + mIsVertical );
mIsMapStatusOk = true;
} catch ( Exception e ) {
}
}
/**
* 地图视图对应的实际宽度
*
* @return
*/
private float getMapCameraFactWidth() {
return Utils.calculateLineDistance( mCameraNorthEastPosition, new MogoLatLng( mCameraNorthEastPosition.lat, mCameraSouthWestPosition.lng ) );
}
/**
* 地图视图对应的实际高度
*
* @return
*/
private float getMapCameraFactHeight() {
return Utils.calculateLineDistance( mCameraSouthWestPosition, new MogoLatLng( mCameraNorthEastPosition.lat, mCameraSouthWestPosition.lng ) );
}
/**
* 刷新视图范围坐标
*/
private void refreshCameraPosition() {
mCameraSouthWestPosition = mUiController.getCameraSouthWestPosition();
mCameraNorthEastPosition = mUiController.getCameraNorthEastPosition();
initMapStatus();
if ( mIsVertical ) {
float width = getMapCameraFactWidth();
Logger.i( TAG, "current zoom level width: %f m", width );
} else {
float height = getMapCameraFactHeight();
Logger.i( TAG, "current zoom level height: %f m", height );
}
}
@Override
public void onTouch( MotionEvent motionEvent ) {
switch ( motionEvent.getActionMasked() ) {
case MotionEvent.ACTION_DOWN:
if ( mLastZoomLevel == 0 ) {
mLastZoomLevel = mUiController.getZoomLevel();
Logger.i( TAG, "初始化缩放级别 为:%f", mLastZoomLevel );
}
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void stopAutoRefreshStrategy() {
mHandler.removeMessages( ServiceConst.MSG_TYPE_REFRESH_DECREASE );
}
@Override
public void onPOIClick( MogoPoi poi ) {
}
@Override
public void onMapClick( MogoLatLng latLng ) {
}
@Override
public void onLockMap( boolean isLock ) {
}
@Override
public void onMapModeChanged( EnumMapUI ui ) {
}
@Override
public void onMapChanged( MogoLatLng latLng, float zoom, float tilt, float bearing ) {
if ( mIsCameraInited ) {
mLastCustomRefreshCenterLocation = latLng;
mIsCameraInited = false;
return;
}
if ( mCameraCenterMarker == null ) {
mCameraCenterMarker = mMarkerManager.addMarker( ServiceConst.TYPE,
new MogoMarkerOptions()
.icon( BitmapFactory.decodeResource( mContext.getResources(), R.drawable.ic_search_poi_location ) )
.latitude( latLng.lat )
.longitude( latLng.lng )
.owner( ServiceConst.TYPE )
);
} else {
mCameraCenterMarker.setPosition( latLng.lat, latLng.lng );
}
if ( mLastZoomLevel != zoom ) {
refreshCameraPosition();
}
// 手动刷新触发
if ( mLastZoomLevel - zoom > mCustomRefreshStrategy.getZoomOutLevel() ) {
// 缩放级别缩小
notifyRefreshData( mCustomRefreshCallback );
mLastCustomRefreshCenterLocation = latLng;
mLastZoomLevel = zoom;
} else if ( mLastZoomLevel == zoom ) {
// 手动平移
if ( invokeRefreshWhenTranslationByUser( latLng ) ) {
notifyRefreshData( mCustomRefreshCallback );
mLastCustomRefreshCenterLocation = latLng;
}
}
Logger.d( TAG, "current map status: %s, zoom = %f, tilt = %f, bearing = %f", latLng, zoom, tilt, bearing );
}
/**
* 平移地图刷新策略
*
* @return
*/
private boolean invokeRefreshWhenTranslationByUser( MogoLatLng latLng ) {
try {
float factor = 0.0f;
if ( mIsVertical ) {
factor = getMapCameraFactWidth();
} else {
factor = getMapCameraFactHeight();
}
if ( factor == 0.0f ) {
return false;
}
float distance = Utils.calculateLineDistance( latLng, mLastCustomRefreshCenterLocation );
return distance > factor;
} catch ( Exception e ) {
Logger.w( TAG, "warming. ", e );
return false;
}
}
@Override
public void onLocationChanged( MogoLocation location ) {
if ( location == null ) {
return;
}
// 自动刷新触发
if ( mLastAutoRefreshLocation == null ) {
mLastAutoRefreshLocation = new MogoLatLng( location.getLatitude(), location.getLongitude() );
notifyRefreshData( mAutoRefreshCallback );
} else {
float distance = Utils.calculateLineDistance( mLastAutoRefreshLocation, new MogoLatLng( location.getLatitude(), location.getLongitude() ) );
if ( distance > mAutoRefreshStrategy.getDistance() ) {
notifyRefreshData( mAutoRefreshCallback );
}
}
}
/**
* 刷新数据
*/
private void notifyRefreshData( RefreshCallback callback ) {
Logger.d( TAG, mAutoRefreshCallback == callback ? "触发自动刷新" : "触发手动刷新" );
mRefreshModel.refreshData( callback );
}
@Override
public void onInitNaviFailure() {
}
@Override
public void onInitNaviSuccess() {
}
@Override
public void onNaviInfoUpdate( MogoNaviInfo naviinfo ) {
}
@Override
public void onStartNavi() {
}
@Override
public void onStopNavi() {
}
@Override
public void onStatusChanged( StatusDescriptor descriptor, boolean isTrue ) {
if ( descriptor == StatusDescriptor.USER_INTERACTED && isTrue ) {
Logger.i( TAG, "用户状态改变,自动刷新时间延时" );
mRefreshRemainingTime += mAutoRefreshStrategy.getInterruptInterval();
}
}
}

View File

@@ -0,0 +1,29 @@
package com.mogo.module.service;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 描述
*/
public class ServiceConst {
/**
* 类型
*/
public static final String TYPE = "STRATEGY_REFRESH";
/**
* 刷新策略模块地址
*/
public static final String PATH_REFRESH_STRATEGY = "/strategy/refresh";
/**
* 倒计时消息
*/
public static final int MSG_TYPE_REFRESH_DECREASE = 0x100;
/**
* 倒计时间隔
*/
public static final int DECREASE_INTERVAL = 1_000;
}

View File

@@ -0,0 +1,51 @@
package com.mogo.module.service;
import com.amap.api.maps.AMapException;
import com.amap.api.maps.model.LatLng;
import com.mogo.map.MogoLatLng;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 描述
*/
public class Utils {
public static float calculateLineDistance( MogoLatLng point1, MogoLatLng point2 ) {
if ( point1 != null && point2 != null ) {
try {
double var2 = point1.lng;
double var4 = point1.lat;
double var6 = point2.lng;
double var8 = point2.lat;
var2 *= 0.01745329251994329D;
var4 *= 0.01745329251994329D;
var6 *= 0.01745329251994329D;
var8 *= 0.01745329251994329D;
double var10 = Math.sin( var2 );
double var12 = Math.sin( var4 );
double var14 = Math.cos( var2 );
double var16 = Math.cos( var4 );
double var18 = Math.sin( var6 );
double var20 = Math.sin( var8 );
double var22 = Math.cos( var6 );
double var24 = Math.cos( var8 );
double[] var28 = new double[3];
double[] var29 = new double[3];
var28[0] = var16 * var14;
var28[1] = var16 * var10;
var28[2] = var12;
var29[0] = var24 * var22;
var29[1] = var24 * var18;
var29[2] = var20;
return ( float ) ( Math.asin( Math.sqrt( ( var28[0] - var29[0] ) * ( var28[0] - var29[0] ) + ( var28[1] - var29[1] ) * ( var28[1] - var29[1] ) + ( var28[2] - var29[2] ) * ( var28[2] - var29[2] ) ) / 2.0D ) * 1.27420015798544E7D );
} catch ( Throwable var26 ) {
var26.printStackTrace();
return 0.0F;
}
} else {
return 0.0F;
}
}
}

View File

@@ -0,0 +1,22 @@
package com.mogo.module.service.network;
import com.mogo.commons.data.BaseData;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.Single;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 接口描述
*/
public interface RefreshApiService {
@GET( "" )
Observable< BaseData > refreshData( @QueryMap Map< String, Object > params );
}

View File

@@ -0,0 +1,14 @@
package com.mogo.module.service.network;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 刷新回调
*/
public interface RefreshCallback {
void onSuccess();
void onFail();
}

View File

@@ -0,0 +1,65 @@
package com.mogo.module.service.network;
import android.content.Context;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.commons.data.BaseData;
import com.mogo.commons.network.ParamsProvider;
import com.mogo.commons.network.SubscribeImpl;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.network.IMogoNetwork;
import com.mogo.utils.network.RequestOptions;
import java.util.Map;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* @author congtaowang
* @since 2020-01-03
* <p>
* 刷新数据
*/
public class RefreshModel {
private final Context mContext;
private RefreshApiService mRefreshApiService;
public RefreshModel( Context context ) {
this.mContext = context;
IMogoNetwork network = ( IMogoNetwork ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_NETWORK ).navigation( context );
this.mRefreshApiService = network.create( RefreshApiService.class, "http://www.baidu.com/" );
}
public void refreshData( final RefreshCallback callback ) {
if ( callback != null ) {
callback.onSuccess();
return;
}
if ( mRefreshApiService != null ) {
final Map< String, Object > params = new ParamsProvider.Builder( mContext ).build();
mRefreshApiService.refreshData( params )
.subscribeOn( Schedulers.io() )
.observeOn( AndroidSchedulers.mainThread() )
.subscribe( new SubscribeImpl< BaseData >( RequestOptions.create( mContext ) ) {
@Override
public void onSuccess( BaseData o ) {
super.onSuccess( o );
if ( callback != null ) {
callback.onSuccess();
}
}
@Override
public void onError( String message, int code ) {
super.onError( message, code );
if ( callback != null ) {
callback.onFail();
}
}
} );
}
}
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">mogo-module-service</string>
</resources>

1
modules/mogo-module-tanlu/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,70 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
if (Boolean.valueOf(RELEASE)) {
implementation rootProject.ext.dependencies.mogomap
implementation rootProject.ext.dependencies.mogoutils
implementation rootProject.ext.dependencies.mogocommons
implementation rootProject.ext.dependencies.mogoserviceapi
implementation rootProject.ext.dependencies.modulecommon
} else {
implementation project(":libraries:mogo-map")
implementation project(":foudations:mogo-utils")
api project(":foudations:mogo-commons")
implementation project(':services:mogo-service-api')
implementation project(':modules:mogo-module-common')
}
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
implementation 'com.shuyu:gsyVideoPlayer-armv7a:7.1.1'
implementation 'com.shuyu:gsyVideoPlayer-arm64:7.1.1'
implementation 'com.shuyu:gsyVideoPlayer-java:7.1.1'
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
repositories {
mavenCentral()
}

View File

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

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,27 @@
package com.zhidao.tanlu;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.zhidao.tanlu.test", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.tanlu">
<application>
<activity
android:name=".video.FullMediaActivity"
android:hardwareAccelerated="true">
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,8 @@
package com.mogo.tanlu.constant
const val REQUESTCODE_MAINACTIVITY = 0
const val REQUESTCODE_MEDIAACTIVITY = 1
//EXTRA_STATE
const val AUTO_NAVI_START = 8 //开始导航
const val AUTO_NAVI_END = 9 //结束导航

View File

@@ -0,0 +1,13 @@
package com.mogo.tanlu.constant;
/**
* @author congtaowang
* @since 2019-12-24
* <p>
* 描述
*/
public class TanluConstants {
public static final String TAG = "/tanlu/ui";
}

View File

@@ -0,0 +1,262 @@
package com.mogo.tanlu.fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.commons.mvp.IView;
import com.mogo.commons.mvp.MvpFragment;
import com.mogo.commons.mvp.Presenter;
import com.mogo.map.MogoLatLng;
import com.mogo.map.listener.IMogoMapListener;
import com.mogo.map.location.IMogoLocationListener;
import com.mogo.map.location.MogoLocation;
import com.mogo.map.marker.IMogoMarker;
import com.mogo.map.marker.IMogoMarkerClickListener;
import com.mogo.map.model.MogoPoi;
import com.mogo.map.search.geo.MogoPoiItem;
import com.mogo.map.search.poisearch.IMogoPoiSearchListener;
import com.mogo.map.search.poisearch.MogoPoiResult;
import com.mogo.map.uicontroller.EnumMapUI;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.imageloader.IMogoImageloader;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.tanlu.R;
import com.mogo.tanlu.video.FullMediaActivity;
import com.mogo.tanlu.video.SimpleCoverVideoPlayer;
import com.mogo.tanlu.view.AutoZoomInImageView;
import com.mogo.utils.TipToast;
import com.mogo.utils.logger.Logger;
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
import static com.mogo.tanlu.video.VideoInitKt.initVideo;
/**
* @author lixiaopeng
* @description 探路卡片
* @since 2020-01-02
*/
public class TanluCardViewFragment extends MvpFragment<IView, Presenter<IView>>
implements IView,
IMogoMarkerClickListener,
IMogoModuleLifecycle,
IMogoMapListener,
IMogoPoiSearchListener,
IMogoLocationListener,
View.OnClickListener {
private static final String TAG = "liyz";
//map
private IMogoMarker mPoiMarker;
private int position = -1;
//media
private GSYVideoOptionBuilder gsyVideoOptionBuilder = new GSYVideoOptionBuilder();
// private String videoUrl = "";
private String videoUrl = "http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8";
private String imageUrl = "https://oimagec4.ydstatic.com/image?id=-5397300958976572132&product=adpublish&w=520&h=347";
SimpleCoverVideoPlayer simpleCoverVideoPlayer;
AutoZoomInImageView autoZoomInImageView;
private IMogoImageloader mogoImageloader;
private TextView mPreviousTv;
private TextView mNextTv;
@Override
protected int getLayoutId() {
return R.layout.tanlu_item_main_media_recycler;
}
@Override
protected void initViews() {
initVideo();
position = getArguments().getInt("position");
simpleCoverVideoPlayer = findViewById(R.id.video_player_main);
autoZoomInImageView = findViewById(R.id.tanlu_photo_imageView);
mPreviousTv = findViewById(R.id.tv_previous_res);
mNextTv = findViewById(R.id.tv_next_res);
mPreviousTv.setOnClickListener(this);
mNextTv.setOnClickListener(this);
simpleCoverVideoPlayer.setVisibility(View.VISIBLE);
autoZoomInImageView.setVisibility(View.GONE);
//视频配置
gsyVideoOptionBuilder.setUrl(videoUrl).setCacheWithPlay(false).setPlayTag(TAG)
.build(simpleCoverVideoPlayer);
// simpleCoverVideoPlayer.getStartButton().performClick();
simpleCoverVideoPlayer.getStartButton().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Logger.d(TAG, "simpleCoverVideoPlayer onClick -------> ");
FullMediaActivity.Companion.launch(getActivity(), videoUrl, "image");
}
});
//图片配置
mogoImageloader = (IMogoImageloader) ARouter.getInstance().build(MogoServicePaths.PATH_UTILS_IMAGE_LOADER).navigation();
//当前定位信息
TanluServiceHandler.getPoiSearch().setPoiSearchListener(this);
// mLocation = TanluServiceHandler.getLocationClient().getLastKnowLocation();
TanluServiceHandler.getLocationClient().addLocationListener(new IMogoLocationListener() {
@Override
public void onLocationChanged(MogoLocation location) {
// mLocation = location;
Logger.d(TAG, "demo模块定位定位间隔4s");
}
});
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getViewLifecycleOwner().getLifecycle().addObserver(mPresenter);
}
/**
* TODO
*
* @param view
*/
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.tv_previous_res) { //上一个
//判断是图片还是视频,第一个时,上一个不可点击
simpleCoverVideoPlayer.setVisibility(View.VISIBLE);
autoZoomInImageView.setVisibility(View.GONE);
//视频配置
gsyVideoOptionBuilder.setUrl(videoUrl).setCacheWithPlay(false).setPlayTag(TAG)
.build(simpleCoverVideoPlayer);
} else if (id == R.id.tv_next_res) { //下一个
//判断是图片还是视频,最后一个时,下一个不可点击
//图片显示
autoZoomInImageView.setVisibility(View.VISIBLE);
simpleCoverVideoPlayer.setVisibility(View.GONE);
mogoImageloader.displayImage(imageUrl, autoZoomInImageView);
}
}
/**
* marker点击事件 TODO
*
* @param marker
* @return
*/
@Override
public boolean onMarkerClicked(IMogoMarker marker) {
marker.getObject();
return true;
}
@NonNull
@Override
protected Presenter createPresenter() {
return new Presenter(this) {
};
}
//TODO C位事件,如何获取数据,需要有默认数据
@Override
public void onPerform() {
Logger.d(TAG, "卡片2有效");
}
//TODO 离开C位事件
@Override
public void onDisable() {
Logger.d(TAG, "卡片2无效");
}
@Override
public void accOn() {
}
@Override
public void onMapLoaded() {
Logger.d(TAG, "地图加载事件");
}
@Override
public void onTouch(MotionEvent motionEvent) {
// Logger.d( TAG, "地图触摸事件" );
}
@Override
public void onPOIClick(MogoPoi poi) {
if (poi != null) {
TipToast.shortTip(poi.getName());
}
TanluServiceHandler.getPoiSearch().searchPOIIdAsyn(poi.getPoiId());
}
@Override
public void onPoiSearched(MogoPoiResult result, int errorCode) {
}
@Override
public void onPoiItemSearched(MogoPoiItem item, int errorCode) {
if (item == null) {
return;
}
}
@Override
public void onLocationChanged(MogoLocation location) {
// if (location.getErrCode() == 0) {
// Logger.d(TAG, "onLocationChanged 当前位置 -->" + location.getAddress());
// } else {
// Logger.d(TAG, "onLocationChanged 定位失败 -->" + location.getErrInfo());
// }
}
@Override
public void onMapClick(MogoLatLng latLng) {
}
@Override
public void onLockMap(boolean isLock) {
}
@Override
public void onMapModeChanged(EnumMapUI ui) {
Logger.d(TAG, ui.name());
}
@Override
public void onMapChanged(MogoLatLng location, float zoom, float tilt, float bearing) {
}
@Override
public void onDestroyView() {
Logger.w(TAG, "onDestroyView position=" + position);
super.onDestroyView();
getViewLifecycleOwner().getLifecycle().removeObserver(mPresenter);
TanluServiceHandler.getLocationClient().removeLocationListener(this);
}
}

View File

@@ -0,0 +1,80 @@
package com.mogo.tanlu.fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.map.listener.IMogoMapListener;
import com.mogo.map.location.IMogoLocationListener;
import com.mogo.map.navi.IMogoNaviListener;
import com.mogo.service.module.IMogoModuleLifecycle;
import com.mogo.service.module.IMogoModuleProvider;
import com.mogo.service.module.ModuleType;
import com.mogo.tanlu.constant.TanluConstants;
import com.mogo.utils.logger.Logger;
/**
* @author congtaowang
* @since 2019-12-24
* <p>
* 描述
*/
@Route( path = TanluConstants.TAG )
public class TanluCardViewProvider implements IMogoModuleProvider {
private static final String TAG = "TanluCardViewProvider";
private TanluCardViewFragment fragment;
@Override
public Fragment createFragment( Context context, Bundle data ) {
fragment = new TanluCardViewFragment();
fragment.setArguments( data );
Logger.i( TAG, "createFragment" );
return fragment;
}
@Override
public void init( Context context ) {
TanluServiceHandler.init( context );
}
@Override
public String getModuleName() {
return "CARD_TYPE_ROAD_CODITION";
}
@Override
public IMogoModuleLifecycle getCardLifecycle() {
return fragment;
}
@Override
public View createView( Context context ) {
// don't
return null;
}
@Override
public IMogoMapListener getMapListener() {
return fragment;
}
@Override
public int getType() {
return ModuleType.TYPE_CARD_FRAGMENT;
}
@Override
public IMogoNaviListener getNaviListener() {
return null;
}
@Override
public IMogoLocationListener getLocationListener() {
return fragment;
}
}

View File

@@ -0,0 +1,131 @@
package com.mogo.tanlu.fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.mogo.map.marker.IMogoInfoWindowAdapter;
import com.mogo.map.marker.IMogoMarker;
import com.mogo.map.marker.MogoMarkerOptions;
import com.mogo.map.navi.IMogoNavi;
import com.mogo.map.navi.MogoNaviConfig;
import com.mogo.map.search.geo.MogoPoiItem;
import com.mogo.service.imageloader.IMogoImageLoaderListener;
import com.mogo.service.imageloader.IMogoImageloader;
import com.mogo.service.imageloader.MogoImageView;
import com.mogo.tanlu.R;
import com.mogo.utils.WindowUtils;
import com.mogo.utils.logger.Logger;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author congtaowang
* @since 2019-12-24
* <p>
* 描述
*/
public class TanluInfoWindowAdapter implements IMogoInfoWindowAdapter {
private static final String TAG = "DemoInfoWindowAdapter";
private Context mContext;
private IMogoNavi mNavi;
private IMogoImageloader mImageloader;
public TanluInfoWindowAdapter(Context mContext, IMogoNavi mNavi, IMogoImageloader iMogoImageloader ) {
this.mContext = mContext;
this.mNavi = mNavi;
this.mImageloader = iMogoImageloader;
}
@Override
public View getInfoWindow( IMogoMarker marker ) {
if ( marker.getObject() instanceof MogoPoiItem ) {
View view = LayoutInflater.from( mContext ).inflate( R.layout.tanlu_poi_info_window, null );
renderPoiVew( view, marker, ( ( MogoPoiItem ) marker.getObject() ) );
return view;
} else {
View view = LayoutInflater.from( mContext ).inflate( R.layout.tanlu_info_window, null );
renderView( view, marker );
return view;
}
}
private void renderView( View view, final IMogoMarker marker ) {
final TextView time = view.findViewById( R.id.demo_module_id_iw_time );
Button refresh = view.findViewById( R.id.demo_module_id_iw_refresh );
time.setText( new SimpleDateFormat( "yyyyMMdd HHMMSS" ).format( new Date() ) );
refresh.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
marker.showInfoWindow();
}
} );
Button navi2 = view.findViewById( R.id.demo_module_id_iw_navito );
navi2.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
if ( mNavi != null ) {
mNavi.naviTo( marker.getPosition(), new MogoNaviConfig() );
}
}
} );
Button stopNavi = view.findViewById( R.id.demo_module_id_iw_navi_stop );
stopNavi.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
if ( mNavi != null ) {
mNavi.stopNavi();
}
}
} );
}
private void renderPoiVew( View view, final IMogoMarker marker, MogoPoiItem item ) {
final TextView time = view.findViewById( R.id.demo_module_id_iw_poi_title );
time.setText( item.getTitle() );
Button navi2 = view.findViewById( R.id.demo_module_id_iw_poi_navito );
navi2.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
if ( mNavi != null ) {
mNavi.naviTo( marker.getPosition(), new MogoNaviConfig() );
}
marker.hideInfoWindow();
marker.remove();
}
} );
}
public View getMarkerView( final MogoMarkerOptions options ) {
final View view = LayoutInflater.from( mContext ).inflate( R.layout.tanlu_bubble_marker, null );
final MogoImageView icon = view.findViewById( R.id.icon );
mImageloader.displayImage( "http://imgnews.gmw.cn/attachement/jpg/site2/20191229/00d86176ed0b1f71f4580f.jpg", icon, WindowUtils.dip2px( mContext, 50 ), WindowUtils.dip2px( mContext, 50 ),
new IMogoImageLoaderListener() {
@Override
public void onStart() {
}
@Override
public void onCompleted( Bitmap bitmap ) {
// 刷新图标
Logger.d( TAG, "loaded." );
options.icon( view );
options.notifyObservers();
}
@Override
public void onFailure( Exception e ) {
}
} );
return view;
}
}

View File

@@ -0,0 +1,70 @@
package com.mogo.tanlu.fragment;
import android.content.Context;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.map.location.IMogoLocationClient;
import com.mogo.map.marker.IMogoMarkerManager;
import com.mogo.map.navi.IMogoNavi;
import com.mogo.map.search.poisearch.IMogoPoiSearch;
import com.mogo.map.search.poisearch.query.MogoPoiSearchQuery;
import com.mogo.map.uicontroller.IMogoMapUIController;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.imageloader.IMogoImageloader;
import com.mogo.service.map.IMogoMapService;
/**
* @author congtaowang
* @since 2019-12-30
* <p>
* 持有服务接口实例
*/
public class TanluServiceHandler {
private static IMogoMapService mMapService;
private static IMogoPoiSearch mPoiSearch;
private static IMogoLocationClient mLocationClient;
private static IMogoMarkerManager mMarkerManager;
private static IMogoNavi mNavi;
private static IMogoMapUIController mMapUIController;
private static IMogoImageloader mImageloader;
public static void init( Context context ) {
mMapService = ( IMogoMapService ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_MAP ).navigation( context );
mMapService = ( IMogoMapService ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICES_MAP ).navigation( context );
mImageloader = ( IMogoImageloader ) ARouter.getInstance().build( MogoServicePaths.PATH_UTILS_IMAGE_LOADER ).navigation( context );
mPoiSearch = mMapService.getPoiSearch( context, new MogoPoiSearchQuery() );
mLocationClient = mMapService.getLocationClient( context );
mMarkerManager = mMapService.getMarkerManager( context );
mNavi = mMapService.getNavi( context );
mMapUIController = mMapService.getMapUIController();
}
public static IMogoMapService getMapService() {
return mMapService;
}
public static IMogoPoiSearch getPoiSearch() {
return mPoiSearch;
}
public static IMogoLocationClient getLocationClient() {
return mLocationClient;
}
public static IMogoMarkerManager getMarkerManager() {
return mMarkerManager;
}
public static IMogoNavi getNavi() {
return mNavi;
}
public static IMogoMapUIController getMapUIController() {
return mMapUIController;
}
public static IMogoImageloader getImageloader() {
return mImageloader;
}
}

View File

@@ -0,0 +1,72 @@
package com.mogo.tanlu.model;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
/**
* @author lixiaopeng
* @description 列表数据
* @since 2020-01-05
*/
public class Information implements Parcelable {
private int type;
private Double lon;
private Double lat;
private String addr;
private Long generateTime;
private String cityName;
private ArrayList<Items> items;
private int distance;
private String nickName;
private String headImgUrl;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.type);
dest.writeValue(this.lon);
dest.writeValue(this.lat);
dest.writeString(this.addr);
dest.writeValue(this.generateTime);
dest.writeString(this.cityName);
dest.writeTypedList(this.items);
dest.writeInt(this.distance);
dest.writeString(this.nickName);
dest.writeString(this.headImgUrl);
}
public Information() {
}
protected Information(Parcel in) {
this.type = in.readInt();
this.lon = (Double) in.readValue(Double.class.getClassLoader());
this.lat = (Double) in.readValue(Double.class.getClassLoader());
this.addr = in.readString();
this.generateTime = (Long) in.readValue(Long.class.getClassLoader());
this.cityName = in.readString();
this.items = in.createTypedArrayList(Items.CREATOR);
this.distance = in.readInt();
this.nickName = in.readString();
this.headImgUrl = in.readString();
}
public static final Creator<Information> CREATOR = new Creator<Information>() {
@Override
public Information createFromParcel(Parcel source) {
return new Information(source);
}
@Override
public Information[] newArray(int size) {
return new Information[size];
}
};
}

View File

@@ -0,0 +1,67 @@
package com.mogo.tanlu.model
import android.os.Parcel
import android.os.Parcelable
import com.amap.api.maps.model.LatLng
fun Informations.toLatLng(): LatLng {
return LatLng(lat, lon)
}
class Informations(
var type: Int,
var lon: Double,
var lat: Double,
var addr: String?,
var generateTime: Long,
var cityName: String?,
// var items: ArrayList<Items>,
var distance: Int,
var nickName: String?,
var headImgUrl: String?
) :
Parcelable {
var position = 0
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readDouble(),
parcel.readDouble(),
parcel.readString(),
parcel.readLong(),
parcel.readString(),
// parcel.readArrayList(Items::class.java.classLoader) as ArrayList<Items>,
parcel.readInt(),
parcel.readString(),
parcel.readString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(type)
parcel.writeDouble(lon)
parcel.writeDouble(lat)
parcel.writeString(addr)
parcel.writeLong(generateTime)
parcel.writeString(cityName)
// parcel.writeList(items)
parcel.writeInt(distance)
parcel.writeString(nickName)
parcel.writeString(headImgUrl)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Informations> {
override fun createFromParcel(parcel: Parcel): Informations {
return Informations(parcel)
}
override fun newArray(size: Int): Array<Informations?> {
return arrayOfNulls(size)
}
}
}

View File

@@ -0,0 +1,33 @@
package com.mogo.tanlu.model
import android.os.Parcel
import android.os.Parcelable
class Items(var url: String? = null, var thumbnail: String? = null) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(url)
parcel.writeString(thumbnail)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Items> {
override fun createFromParcel(parcel: Parcel): Items {
return Items(parcel)
}
override fun newArray(size: Int): Array<Items?> {
return arrayOfNulls(size)
}
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.tanlu.model.global
import com.mogo.tanlu.model.Information
import java.util.ArrayList
/**
* @author congtaowang
* @since 2019-12-02
*
* 共享的情报列表避免在点击大屏查看视频时intent序列化造成的开销
*/
object GlobalSharedInformation {
var informationList: ArrayList<Information>? = null
}

View File

@@ -0,0 +1,30 @@
package com.mogo.tanlu.util
const val SPACE_TIME = 1000
var lastClickTime = 0L
var viewId: Int = 0
fun isDoubleClick(view: Int): Boolean {
val time = System.currentTimeMillis()
val timeD = time - lastClickTime
if (timeD < SPACE_TIME && viewId == view) {
return true
}
lastClickTime = time
viewId = view
return false
}
fun isDoubleClickTime(view: Int,spaceTime:Int): Boolean {
val time = System.currentTimeMillis()
val timeD = time - lastClickTime
if (timeD < spaceTime && viewId == view) {
return true
}
lastClickTime = time
viewId = view
return false
}

View File

@@ -0,0 +1,71 @@
package com.mogo.tanlu.util
import android.os.Message
import android.view.View
import androidx.constraintlayout.widget.Group
class HideControl {
companion object {
const val MSG_HIDE = 0x01
}
private var mHideHandler: HideHandler = HideHandler()
var view1: Group? = null
var view2: Group? = null
val hideRunable = Runnable {
mHideHandler.obtainMessage(MSG_HIDE).sendToTarget()
}
private inner class HideHandler : android.os.Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
MSG_HIDE -> {
view1?.let {
it.visibility = View.GONE
}
view2?.let {
it.visibility = View.GONE
}
}
}
}
}
fun startHideTimer(view1: Group,view2: Group? = null) {
this.view1 = view1
this.view2 = view2
mHideHandler.removeCallbacks(hideRunable)
if (view1.visibility == View.GONE) {
view1.visibility = View.VISIBLE
}
if (view2?.visibility == View.GONE) {
view2.visibility = View.VISIBLE
}
mHideHandler.postDelayed(hideRunable, 3000)
}
fun resetHideTimer() {
if(view1 != null){
view1!!.visibility = View.VISIBLE
}
if(view2 != null){
view2!!.visibility = View.VISIBLE
}
mHideHandler.removeCallbacks(hideRunable)
mHideHandler.postDelayed(hideRunable, 3000)
}
fun endHideTime() {
mHideHandler.removeCallbacks(hideRunable)
if (view1 != null) {
view1 = null
}
if (view2 != null) {
view2 = null
}
}
}

View File

@@ -0,0 +1,147 @@
package com.mogo.tanlu.video
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mogo.tanlu.R
import com.mogo.tanlu.model.Informations
import com.mogo.tanlu.util.HideControl
import com.mogo.utils.logger.Logger
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import kotlinx.android.synthetic.main.tanlu_activity_media_full.*
import java.util.*
/**
* 全屏显示适配
*/
class FullMediaActivity : AppCompatActivity(), View.OnClickListener {
companion object {
const val PARAM_MEDIA_DATA = "PARAM_MEDIA_DATA"
const val PARAM_MEDIA_POSITION_CALLBACK = "PARAM_MEDIA_POSITION_CALLBACK"
const val TAG = "FullMediaActivity"
const val PARAM_VIDEO_URL = "param_video_url"
const val PARAM_THUMB_URL = "param_thumb_url"
// fun launch(context: Activity, strategyInfo: List<Informations>, position: Int) {
// val intent = Intent(context, FullMediaActivity::class.java)
// intent.putExtra(PARAM_MEDIA_POSITION, position)
// // 使用全局静态对象代替,避免序列化开销
// GlobalSharedInformation.informationList = strategyInfo as ArrayList<Informations>
// context.startActivityForResult(intent, REQUESTCODE_MAINACTIVITY)
// context.overridePendingTransition(0, 0)
// }
fun launch(context: Activity, videoUrl: String, thumbnail: String) {
val intent = Intent(context, FullMediaActivity::class.java)
intent.putExtra(PARAM_VIDEO_URL, videoUrl)
intent.putExtra(PARAM_THUMB_URL, thumbnail)
context.startActivity(intent)
context.overridePendingTransition(0, 0)
}
}
private var strategyInfo: ArrayList<Informations> = arrayListOf()
private var currentImgPosition: Int = 0
private var currentPosition: Int = 50
private var control = HideControl()
private var gsyVideoOptionBuilder = GSYVideoOptionBuilder()
private var videoUrl: String? = null
private var thumbUrl: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.tanlu_activity_media_full)
handleIntent()
setListener()
}
private fun handleIntent() {
var intent = intent
videoUrl = intent.getStringExtra(PARAM_VIDEO_URL)
thumbUrl = intent.getStringExtra(PARAM_THUMB_URL)
Logger.e("liyz", "videoUrl = $videoUrl --->thumbUrl = $thumbUrl")
}
override fun onResume() {
super.onResume()
updateInformation()
GSYVideoManager.onResume()
}
override fun onPause() {
super.onPause()
GSYVideoManager.onPause()
}
//需要监听完成事件
private fun setListener() {
iv_media_back.setOnClickListener(this)
//重置timer
video_view.addSingleClickListener(object :
MediaCoverVideoPlayer.SingleClickListener {
override fun onClick() {
control.resetHideTimer()
}
})
//视频播放完成
video_view.onCompletionListener(object :
MediaCoverVideoPlayer.CompletionListener {
override fun onCompletion() {
GSYVideoManager.releaseAllVideos()
finish()
}
})
video_view.loadCoverImage(thumbUrl!!)
//设置url点击播放
gsyVideoOptionBuilder.setUrl(videoUrl).setCacheWithPlay(true)
.setPlayTag(TAG).build(video_view)
video_view.startButton.performClick()
}
private fun updateInformation() {
tv_media_title_content.text = "北京市"
tv_media_title_time.text = "2020-1-6"
}
override fun onClick(view: View) {
view?.let {
when (view) {
iv_media_back -> {
handleBack()
}
}
}
}
override fun onDestroy() {
super.onDestroy()
GSYVideoManager.releaseAllVideos()
overridePendingTransition(0, 0)
}
private fun handleBack() {
Logger.d("liyz", "handleBack ------> finish ")
finish()
}
override fun onBackPressed() {
super.onBackPressed()
handleBack()
}
}

View File

@@ -0,0 +1,159 @@
package com.mogo.tanlu.video
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.mogo.tanlu.R
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
/**
* 全屏播放
*/
class MediaCoverVideoPlayer : StandardGSYVideoPlayer {
private lateinit var coverImage: ImageView
private lateinit var start: ImageView
private lateinit var fullscreen: ImageView
private lateinit var singleClickListener: SingleClickListener
private lateinit var completionListener: CompletionListener
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, fullFlag: Boolean?) : super(context, fullFlag)
interface SingleClickListener {
fun onClick()
}
interface CompletionListener {
fun onCompletion()
}
override fun init(context: Context) {
super.init(context)
coverImage = findViewById(R.id.thumbImage)
start = findViewById(R.id.start)
fullscreen = findViewById(R.id.fullscreen)
if (mThumbImageViewLayout != null
&& (mCurrentState == -1 || mCurrentState == GSYVideoView.CURRENT_STATE_NORMAL || mCurrentState == GSYVideoView.CURRENT_STATE_ERROR)
) {
mThumbImageViewLayout.visibility = View.VISIBLE
}
}
fun addSingleClickListener(singleClickListener: SingleClickListener) {
this.singleClickListener = singleClickListener
}
fun onCompletionListener(completionListener: CompletionListener) {
this.completionListener = completionListener
}
override fun getLayoutId(): Int {
return R.layout.tanlu_item_video_cover_media
}
override fun getGSYVideoManager(): GSYVideoViewBridge {
GSYVideoManager.instance().initContext(context.applicationContext)
return GSYVideoManager.instance()
}
override fun setProgressAndTime(
progress: Int,
secProgress: Int,
currentTime: Int,
totalTime: Int
) {
super.setProgressAndTime(progress, secProgress, currentTime, totalTime)
if (progress != 0) {
mProgressBar.progress = progress
}
}
fun loadCoverImage(url: String) {
Glide.with(context)
.load(url)
.into(coverImage)
}
override fun updateStartImage() {
when (mCurrentState) {
GSYVideoView.CURRENT_STATE_PLAYING -> start.setImageResource(R.drawable.selector_bg_btn_pause)
GSYVideoView.CURRENT_STATE_ERROR -> start.setImageResource(R.mipmap.main_video_refresh_btn)
else -> start.setImageResource(R.drawable.selector_bg_btn_play)
}
}
fun setFullClickListener(listener: OnClickListener) {
fullscreen.setOnClickListener(listener)
}
override fun onClickUiToggle() {
super.onClickUiToggle()
singleClickListener.let {
it.onClick()
}
}
override fun changeUiToCompleteShow() {
super.changeUiToCompleteShow()
setViewShowState(mBottomContainer, View.INVISIBLE)
}
override fun onAutoCompletion() {
super.onAutoCompletion()
mProgressBar.progress = 0
}
override fun showWifiDialog() {
//直接播放不显示WIFI对话框
startPlayLogic()
}
override fun onClick(v: View?) {
super.onClick(v)
v?.let {
when (v) {
start -> {
}
else -> {
}
}
}
}
override fun onPrepared() {
super.onPrepared()
}
/**
* 多次回调? TODO
*/
override fun onCompletion() {
Log.d("liyz", "onCompletion --------->")
// completionListener.let {
// it.onCompletion()
// }
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mFullPauseBitmap?.let {
if (!it.isRecycled) {
it.recycle()
}
}
mFullPauseBitmap = null
Log.d("MediaCoverVideoPlayer", "recycle.")
}
}

View File

@@ -0,0 +1,134 @@
package com.mogo.tanlu.video
import android.content.Context
import android.util.AttributeSet
import android.view.Surface
import android.view.View
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.mogo.tanlu.R
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
class SimpleCoverVideoPlayer : StandardGSYVideoPlayer {
private lateinit var coverImage: ImageView
private lateinit var start: ImageView
private lateinit var fullscreen: ImageView
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, fullFlag: Boolean?) : super(context, fullFlag)
override fun init(context: Context) {
super.init(context)
coverImage = findViewById(R.id.thumbImage)
start = findViewById(R.id.start)
fullscreen = findViewById(R.id.fullscreen)
if (mThumbImageViewLayout != null
&& (mCurrentState == -1 || mCurrentState == GSYVideoView.CURRENT_STATE_NORMAL || mCurrentState == GSYVideoView.CURRENT_STATE_ERROR)
) {
mThumbImageViewLayout.visibility = View.VISIBLE
}
}
override fun getLayoutId(): Int {
return R.layout.tanlu_item_video_cover
}
override fun getGSYVideoManager(): GSYVideoViewBridge {
GSYVideoManager.instance().initContext(context.applicationContext)
return GSYVideoManager.instance()
}
override fun setProgressAndTime(
progress: Int,
secProgress: Int,
currentTime: Int,
totalTime: Int
) {
super.setProgressAndTime(progress, secProgress, currentTime, totalTime)
if (progress != 0) {
mProgressBar.progress = progress
}
}
// fun loadCoverImage(url: String, mContext: Context) {
// Glide.with(mContext.applicationContext)
// .load(url)
// .error(R.color.color_303447)
// .into(coverImage)
// }
override fun updateStartImage() {
when (mCurrentState) {
GSYVideoView.CURRENT_STATE_PLAYING -> start.setImageResource(R.drawable.selector_bg_btn_pause)
GSYVideoView.CURRENT_STATE_ERROR -> start.setImageResource(R.mipmap.main_video_refresh_btn)
else -> start.setImageResource(R.drawable.selector_bg_btn_play)
}
}
fun setFullClickListener(listener: OnClickListener) {
fullscreen.setOnClickListener(listener)
}
override fun changeUiToCompleteShow() {
super.changeUiToCompleteShow()
setViewShowState(mBottomContainer, View.INVISIBLE)
}
override fun onAutoCompletion() {
super.onAutoCompletion()
mProgressBar.progress = 0
}
override fun showWifiDialog() {
//直接播放不显示WIFI对话框
startPlayLogic()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mProgressBar.progress = 0
mFullPauseBitmap = null
}
override fun onClick(v: View?) {
super.onClick(v)
}
override fun onPrepared() {
super.onPrepared()
}
override fun onCompletion() {
}
override fun onSurfaceUpdated(surface: Surface) {
super.onSurfaceUpdated(surface)
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
mThumbImageViewLayout.visibility = View.INVISIBLE
}
}
override fun setViewShowState(view: View?, visibility: Int) {
if (view === mThumbImageViewLayout && visibility != View.VISIBLE) {
return
}
super.setViewShowState(view, visibility)
}
override fun onSurfaceAvailable(surface: Surface) {
super.onSurfaceAvailable(surface)
if (GSYVideoType.getRenderType() != GSYVideoType.TEXTURE) {
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
mThumbImageViewLayout.visibility = View.INVISIBLE
}
}
}
}

View File

@@ -0,0 +1,22 @@
package com.mogo.tanlu.video
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.cache.CacheFactory
import com.shuyu.gsyvideoplayer.cache.ProxyCacheManager
import com.shuyu.gsyvideoplayer.model.VideoOptionModel
import com.shuyu.gsyvideoplayer.player.IjkPlayerManager
import com.shuyu.gsyvideoplayer.player.PlayerFactory
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import tv.danmaku.ijk.media.player.IjkMediaPlayer
fun initVideo() {
PlayerFactory.setPlayManager(IjkPlayerManager::class.java)
CacheFactory.setCacheManager(ProxyCacheManager::class.java)
var list = mutableListOf<VideoOptionModel>()
list.add(VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1))
list.add(VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "videotoolbox", 0))
GSYVideoManager.instance().optionModelList = list
GSYVideoType.enableMediaCodec()
GSYVideoType.enableMediaCodecTexture()
}

View File

@@ -0,0 +1,222 @@
package com.mogo.tanlu.view
import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Matrix
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.ImageView
import com.mogo.service.imageloader.MogoImageView
class AutoZoomInImageView : MogoImageView {
companion object {
const val TAG = "AutoZoomInImageView"
}
private var mDrawableW: Int = 0
private var mDrawableH: Int = 0
private var mImageViewW: Int = 0
private var mImageViewH: Int = 0
private var mDurationMillis = 3000L
private var mValues = FloatArray(9)
var isInit: Boolean = false
private var mScaleDelta = 0.2f
private var va: ValueAnimator = ValueAnimator.ofFloat(0f, mScaleDelta)
private lateinit var mDrawable: Drawable
private lateinit var mMatrix: Matrix
private var onStart: (View.() -> Unit)? = null
private var onUpdate: ((view: View, progress: Float) -> Unit)? = null
private var onEnd: (View.() -> Unit)? = null
infix fun onStart(onStart: View.() -> Unit) :AutoZoomInImageView{
this.onStart = onStart
return this
}
infix fun onUpdate(onUpdate: (view: View, progress: Float) -> Unit) :AutoZoomInImageView{
this.onUpdate = onUpdate
return this
}
infix fun onEnd(onEnd: View.() -> Unit):AutoZoomInImageView {
this.onEnd = onEnd
return this
}
constructor(context: Context?) : super(context) {
this.scaleType = ScaleType.MATRIX
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
this.scaleType = ScaleType.MATRIX
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
this.scaleType = ScaleType.MATRIX
}
fun init(): AutoZoomInImageView {
initInternalValues()
initPicturePosition()
isInit = true
return this
}
fun init(drawable: Drawable) {
initInternalValues(drawable)
initPicturePosition()
}
private fun initInternalValues() {
mDrawable = drawable
mDrawableW = mDrawable.intrinsicWidth
mDrawableH = mDrawable.intrinsicHeight
mImageViewW = measuredWidth
mImageViewH = measuredHeight
mMatrix = imageMatrix
mMatrix.getValues(mValues)
}
private fun initInternalValues(drawable: Drawable) {
mDrawable = drawable
mDrawableW = mDrawable.intrinsicWidth
mDrawableH = mDrawable.intrinsicHeight
mImageViewW = measuredWidth
mImageViewH = measuredHeight
mMatrix = imageMatrix
mMatrix.getValues(mValues)
}
private fun initPicturePosition() {
updateMatrixValuesOrigin(
mMatrix,
mValues,
mDrawableW.toFloat(),
mDrawableH.toFloat(),
mImageViewW.toFloat(),
mImageViewH.toFloat()
)
imageMatrix = mMatrix
}
fun setDurationMillis(durationMillis: Long): AutoZoomInImageView {
mDurationMillis = durationMillis
return this
}
fun startZoomInByScaleDelta(scaleDelta: Float = 0.2f, duration: Long = 3000) {
val oriScaleX = mValues[0]
val oriScaleY = mValues[4]
va.addUpdateListener { animation ->
val value = animation.animatedValue as Float
onUpdate?.invoke(this@AutoZoomInImageView, value / scaleDelta)
updateMatrixValuesSpan(
mValues,
mDrawableW.toFloat(),
mDrawableH.toFloat(),
mImageViewW.toFloat(),
mImageViewH.toFloat(),
oriScaleX,
oriScaleY,
value
)
mMatrix.setValues(mValues)
imageMatrix = mMatrix
}
va.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
onStart?.invoke(this@AutoZoomInImageView)
}
override fun onAnimationEnd(animation: Animator) {
onEnd?.invoke(this@AutoZoomInImageView)
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
va.duration = duration
va.start()
}
fun zoomPause() {
if (va.isRunning) {
Log.d(TAG, "pause")
va.pause()
}
}
fun zoomResume() {
if (va.isStarted && va.isPaused) {
Log.d(TAG, "resume")
va.resume()
} else {
Log.d(TAG, "restart")
va.start()
}
}
private fun updateMatrixValuesOrigin(
outMatrix: Matrix?,
outValues: FloatArray?,
drawW: Float,
drawH: Float,
imageW: Float,
imageH: Float
) {
if (outMatrix == null || outValues == null) {
throw IllegalArgumentException("please set the source of AutoZoomInImageView's matrix and values")
}
outMatrix.reset()
if (imageH * drawW > drawH * imageW) {
val scale1 = imageH / drawH
val offset1 = (drawW * scale1 - imageW) / 2
outMatrix.postScale(scale1, scale1)
outMatrix.postTranslate(-offset1, 0f)
} else {
val scale2 = imageW / drawW
val offset2 = (drawH * scale2 - imageH) / 2
outMatrix.postScale(scale2, scale2)
outMatrix.postTranslate(0f, -offset2)
}
outMatrix.getValues(outValues)
}
private fun updateMatrixValuesSpan(
outValues: FloatArray,
drawW: Float, drawH: Float,
imageW: Float, imageH: Float,
oriScaleX: Float, oriScaleY: Float,
scaleDelta: Float
) {
outValues[0] = oriScaleX * (1 + scaleDelta)
outValues[4] = oriScaleY * (1 + scaleDelta)
val offsetwidth = (drawW * outValues[0] - imageW) / 2
outValues[2] = -offsetwidth
val offsetHeight = (drawH * outValues[4] - imageH) / 2
outValues[5] = -offsetHeight
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

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