├── .gitignore ├── GSDemo ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── dji │ │ │ └── GSDemo │ │ │ └── GoogleMap │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── dji │ │ │ │ └── GSDemo │ │ │ │ └── GoogleMap │ │ │ │ ├── ConnectionActivity.java │ │ │ │ ├── DJIDemoApplication.java │ │ │ │ ├── MApplication.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── Tools.java │ │ │ │ ├── Waypoint1Activity.java │ │ │ │ ├── Waypoint2Activity.java │ │ │ │ ├── WaypointActionAdapter.java │ │ │ │ ├── WaypointV2ActionDialog.java │ │ │ │ └── fragment │ │ │ │ ├── actuator │ │ │ │ ├── AircraftActuatorFragment.java │ │ │ │ ├── CameraActuatorFragment.java │ │ │ │ ├── GimbalActuatorFragment.java │ │ │ │ └── IActuatorCallback.java │ │ │ │ └── trigger │ │ │ │ ├── AssociateTriggerFragment.java │ │ │ │ ├── BaseTriggerFragment.java │ │ │ │ ├── ITriggerCallback.java │ │ │ │ ├── ReachPointTriggerFragment.java │ │ │ │ ├── SimpleIntervalTriggerFragment.java │ │ │ │ └── TrajectoryTriggerFragment.java │ │ └── res │ │ │ ├── drawable │ │ │ ├── aircraft.png │ │ │ ├── ic_launcher.png │ │ │ ├── round_btn.xml │ │ │ ├── round_btn_disable.xml │ │ │ ├── round_btn_normal.xml │ │ │ ├── round_btn_pressed.xml │ │ │ └── selector_white_gray.xml │ │ │ ├── layout │ │ │ ├── activity_connection.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_waypoint1.xml │ │ │ ├── activity_waypoint2.xml │ │ │ ├── dialog_waypoint2setting.xml │ │ │ ├── dialog_waypoint_v2.xml │ │ │ ├── dialog_waypointsetting.xml │ │ │ ├── fragment_aircraft_actuator.xml │ │ │ ├── fragment_associate_trigger.xml │ │ │ ├── fragment_camera_actuator.xml │ │ │ ├── fragment_gimbal_actuator.xml │ │ │ ├── fragment_simple_interval_trigger.xml │ │ │ ├── fragment_simple_reach_point_trigger.xml │ │ │ ├── fragment_trajectory_trigger.xml │ │ │ └── item_waypoint_action.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── raw │ │ │ └── keep.xml │ │ │ ├── values-v21 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── dji │ │ └── GSDemo │ │ └── GoogleMap │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt └── settings.gradle ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | obj/ 15 | DJI-SDK-LIB_3.1/build/ 16 | build/ 17 | 18 | # generated file 19 | lint.xml 20 | 21 | # Local configuration file (sdk/lib path, etc) 22 | local.properties 23 | project.properties 24 | 25 | # Eclipse project files 26 | .classpath 27 | .settings/ 28 | 29 | # Proguard folder generated by Eclipse 30 | proguard/ 31 | 32 | # Intellij project files 33 | *.iml 34 | *.ipr 35 | *.iws 36 | .idea/ 37 | 38 | # Mac files 39 | .DS_Store 40 | 41 | # Gradle generated files 42 | .gradle/ 43 | 44 | # Signing files 45 | .signing/ 46 | 47 | # User-specific configurations 48 | .idea/libraries/ 49 | .idea/workspace.xml 50 | .idea/tasks.xml 51 | .idea/.name 52 | .idea/compiler.xml 53 | .idea/copyright/profiles_settings.xml 54 | .idea/encodings.xml 55 | .idea/misc.xml 56 | .idea/modules.xml 57 | .idea/scopes/scope_settings.xml 58 | .idea/vcs.xml 59 | *.iml 60 | 61 | # OS-specific files 62 | .DS_Store 63 | .DS_Store? 64 | ._* 65 | .Spotlight-V100 66 | .Trashes 67 | ehthumbs.db 68 | Thumbs.db 69 | 70 | # Import summary file 71 | import-summary.txt 72 | -------------------------------------------------------------------------------- /GSDemo/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /GSDemo/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | repositories { 4 | mavenLocal() 5 | } 6 | 7 | android { 8 | compileSdkVersion 30 9 | buildToolsVersion '30.0.2' 10 | useLibrary 'org.apache.http.legacy' 11 | 12 | defaultConfig { 13 | minSdkVersion 19 14 | targetSdkVersion 30 15 | multiDexEnabled true 16 | ndk { 17 | // On x86 devices that run Android API 23 or above, if the application is targeted with API 23 or 18 | // above, FFmpeg lib might lead to runtime crashes or warnings. 19 | abiFilters 'armeabi-v7a', 'arm64-v8a' 20 | } 21 | multiDexEnabled true //Mention in the doc 22 | } 23 | 24 | buildTypes { 25 | release { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | debug { 30 | shrinkResources true 31 | minifyEnabled true 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | 36 | dexOptions { 37 | incremental = true 38 | preDexLibraries = false 39 | javaMaxHeapSize "4g" 40 | } 41 | 42 | packagingOptions { 43 | doNotStrip "*/*/libdjivideo.so" 44 | doNotStrip "*/*/libSDKRelativeJNI.so" 45 | doNotStrip "*/*/libFlyForbid.so" 46 | doNotStrip "*/*/libduml_vision_bokeh.so" 47 | doNotStrip "*/*/libyuv2.so" 48 | doNotStrip "*/*/libGroudStation.so" 49 | doNotStrip "*/*/libFRCorkscrew.so" 50 | doNotStrip "*/*/libUpgradeVerify.so" 51 | doNotStrip "*/*/libFR.so" 52 | doNotStrip "*/*/libDJIFlySafeCore.so" 53 | doNotStrip "*/*/libdjifs_jni.so" 54 | doNotStrip "*/*/libsfjni.so" 55 | doNotStrip "*/*/libDJICommonJNI.so" 56 | doNotStrip "*/*/libDJICSDKCommon.so" 57 | doNotStrip "*/*/libDJIUpgradeCore.so" 58 | doNotStrip "*/*/libDJIUpgradeJNI.so" 59 | exclude 'META-INF/rxjava.properties' 60 | } 61 | 62 | compileOptions { 63 | sourceCompatibility JavaVersion.VERSION_1_8 64 | targetCompatibility JavaVersion.VERSION_1_8 65 | } 66 | } 67 | 68 | 69 | dependencies { 70 | implementation 'androidx.multidex:multidex:2.0.1' 71 | implementation 'com.squareup:otto:1.3.8' 72 | implementation('com.dji:dji-sdk:4.15', { 73 | /** 74 | * Uncomment the "library-anti-distortion" if your app does not need Anti Distortion for Mavic 2 Pro and Mavic 2 Zoom. 75 | * Uncomment the "fly-safe-database" if you need database for release, or we will download it when DJISDKManager.getInstance().registerApp 76 | * is called. 77 | * Both will greatly reducing the size of the APK. 78 | */ 79 | exclude module: 'library-anti-distortion' 80 | //exclude module: 'fly-safe-database' 81 | }) 82 | compileOnly 'com.dji:dji-sdk-provided:4.15' 83 | 84 | implementation 'androidx.appcompat:appcompat:1.2.0' 85 | implementation 'androidx.core:core:1.3.2' 86 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 87 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 88 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 89 | implementation 'androidx.annotation:annotation:1.2.0' 90 | 91 | implementation fileTree(include: ['*.jar'], dir: 'libs') 92 | testImplementation 'junit:junit:4.13.2' 93 | implementation 'com.google.android.material:material:1.2.1' 94 | implementation 'com.google.android.gms:play-services:10.2.1' 95 | implementation 'com.google.android.gms:play-services-ads:10.2.1' 96 | implementation 'com.google.android.gms:play-services-auth:10.2.1' 97 | implementation 'com.google.android.gms:play-services-gcm:10.2.1' 98 | implementation 'com.jakewharton:butterknife:10.1.0' 99 | annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0' 100 | } 101 | -------------------------------------------------------------------------------- /GSDemo/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes Exceptions,InnerClasses,*Annotation*,Signature,EnclosingMethod 2 | 3 | -dontoptimize 4 | -dontpreverify 5 | -dontwarn okio.** 6 | -dontwarn org.bouncycastle.** 7 | -dontwarn dji.** 8 | -dontwarn com.dji.** 9 | -dontwarn sun.** 10 | -dontwarn java.** 11 | -dontwarn com.amap.api.** 12 | -dontwarn com.here.** 13 | -dontwarn com.mapbox.** 14 | -dontwarn okhttp3.** 15 | -dontwarn retrofit2.** 16 | 17 | -keepclassmembers enum * { 18 | public static ; 19 | } 20 | 21 | -keepnames class * implements java.io.Serializable 22 | -keepclassmembers class * implements java.io.Serializable { 23 | static final long serialVersionUID; 24 | private static final java.io.ObjectStreamField[] serialPersistentFields; 25 | !static !transient ; 26 | private void writeObject(java.io.ObjectOutputStream); 27 | private void readObject(java.io.ObjectInputStream); 28 | java.lang.Object writeReplace(); 29 | java.lang.Object readResolve(); 30 | } 31 | -keep class * extends android.os.Parcelable { 32 | public static final android.os.Parcelable$Creator *; 33 | } 34 | 35 | -keep,allowshrinking class * extends dji.publics.DJIUI.** { 36 | public ; 37 | } 38 | 39 | -keep class net.sqlcipher.** { *; } 40 | 41 | -keep class net.sqlcipher.database.* { *; } 42 | 43 | -keep class dji.** { *; } 44 | 45 | -keep class com.dji.** { *; } 46 | 47 | -keep class com.google.** { *; } 48 | 49 | -keep class org.bouncycastle.** { *; } 50 | 51 | -keep,allowshrinking class org.** { *; } 52 | 53 | -keep class com.squareup.wire.** { *; } 54 | 55 | -keep class sun.misc.Unsafe { *; } 56 | 57 | -keep class com.secneo.** { *; } 58 | 59 | -keep class org.greenrobot.eventbus.**{*;} 60 | 61 | -keep class it.sauronsoftware.ftp4j.**{*;} 62 | 63 | -keepclasseswithmembers,allowshrinking class * { 64 | native ; 65 | } 66 | 67 | -keep class * implements com.google.gson.TypeAdapterFactory 68 | -keep class * implements com.google.gson.JsonSerializer 69 | -keep class * implements com.google.gson.JsonDeserializer 70 | 71 | -keep class androidx.appcompat.widget.SearchView { *; } 72 | 73 | -keepclassmembers class * extends android.app.Service 74 | -keepclassmembers public class * extends android.view.View { 75 | void set*(***); 76 | *** get*(); 77 | } 78 | -keepclassmembers class * extends android.app.Activity { 79 | public void *(android.view.View); 80 | } 81 | -keep class androidx.** { *; } 82 | -keep class android.media.** { *; } 83 | -keep class okio.** { *; } 84 | -keep class com.lmax.disruptor.** { *; } 85 | -keep class com.qx.wz.dj.rtcm.* { *; } 86 | 87 | -dontwarn com.mapbox.services.android.location.LostLocationEngine 88 | -dontwarn com.mapbox.services.android.location.MockLocationEngine 89 | -keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver { 90 | (...); 91 | } 92 | # ViewModel's empty constructor is considered to be unused by proguard 93 | -keepclassmembers class * extends android.arch.lifecycle.ViewModel { 94 | (...); 95 | } 96 | # keep Lifecycle State and Event enums values 97 | -keepclassmembers class android.arch.lifecycle.Lifecycle$State { *; } 98 | -keepclassmembers class android.arch.lifecycle.Lifecycle$Event { *; } 99 | # keep methods annotated with @OnLifecycleEvent even if they seem to be unused 100 | # (Mostly for LiveData.LifecycleBoundObserver.onStateChange(), but who knows) 101 | -keepclassmembers class * { 102 | @android.arch.lifecycle.OnLifecycleEvent *; 103 | } 104 | 105 | -keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver { 106 | (...); 107 | } 108 | 109 | -keep class * implements android.arch.lifecycle.LifecycleObserver { 110 | (...); 111 | } 112 | -keepclassmembers class android.arch.** { *; } 113 | -keep class android.arch.** { *; } 114 | -dontwarn android.arch.** 115 | 116 | -keep class org.apache.commons.** {*;} 117 | 118 | 119 | #<------------ utmiss config start------------> 120 | -keep class dji.sdk.utmiss.** { *; } 121 | -keep class utmisslib.** { *; } 122 | #<------------ utmiss config end------------> -------------------------------------------------------------------------------- /GSDemo/app/src/androidTest/java/com/dji/GSDemo/GoogleMap/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | //TODO: Enter your app key here 51 | //TODO: Enter your Google API Key here 54 | 57 | 58 | 59 | 60 | 61 | 62 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 83 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/ConnectionActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.content.pm.PackageManager; 10 | import android.os.AsyncTask; 11 | import android.os.Build; 12 | import android.os.Bundle; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.core.app.ActivityCompat; 16 | import androidx.core.content.ContextCompat; 17 | import android.util.Log; 18 | import android.view.View; 19 | import android.widget.Button; 20 | import android.widget.TextView; 21 | import android.widget.Toast; 22 | 23 | import com.google.android.gms.common.ConnectionResult; 24 | import com.google.android.gms.common.GooglePlayServicesUtil; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | import java.util.concurrent.atomic.AtomicBoolean; 29 | 30 | import dji.common.error.DJIError; 31 | import dji.common.error.DJISDKError; 32 | import dji.log.DJILog; 33 | import dji.sdk.base.BaseComponent; 34 | import dji.sdk.base.BaseProduct; 35 | import dji.sdk.products.Aircraft; 36 | import dji.sdk.sdkmanager.DJISDKInitEvent; 37 | import dji.sdk.sdkmanager.DJISDKManager; 38 | 39 | public class ConnectionActivity extends Activity implements View.OnClickListener { 40 | 41 | private static final String TAG = ConnectionActivity.class.getName(); 42 | 43 | private TextView mTextConnectionStatus; 44 | private TextView mTextProduct; 45 | private TextView mVersionTv; 46 | private Button mBtnOpen; 47 | private static final String[] REQUIRED_PERMISSION_LIST = new String[]{ 48 | Manifest.permission.VIBRATE, 49 | Manifest.permission.INTERNET, 50 | Manifest.permission.ACCESS_WIFI_STATE, 51 | Manifest.permission.WAKE_LOCK, 52 | Manifest.permission.ACCESS_COARSE_LOCATION, 53 | Manifest.permission.ACCESS_NETWORK_STATE, 54 | Manifest.permission.ACCESS_FINE_LOCATION, 55 | Manifest.permission.CHANGE_WIFI_STATE, 56 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 57 | Manifest.permission.BLUETOOTH, 58 | Manifest.permission.BLUETOOTH_ADMIN, 59 | Manifest.permission.READ_EXTERNAL_STORAGE, 60 | Manifest.permission.READ_PHONE_STATE, 61 | }; 62 | private List missingPermission = new ArrayList<>(); 63 | private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false); 64 | private static final int REQUEST_PERMISSION_CODE = 12345; 65 | 66 | @Override 67 | protected void onCreate(Bundle savedInstanceState) { 68 | super.onCreate(savedInstanceState); 69 | checkAndRequestPermissions(); 70 | setContentView(R.layout.activity_connection); 71 | 72 | initUI(); 73 | 74 | // Register the broadcast receiver for receiving the device connection's changes. 75 | IntentFilter filter = new IntentFilter(); 76 | filter.addAction(DJIDemoApplication.FLAG_CONNECTION_CHANGE); 77 | registerReceiver(mReceiver, filter); 78 | } 79 | 80 | /** 81 | * Checks if there is any missing permissions, and 82 | * requests runtime permission if needed. 83 | */ 84 | private void checkAndRequestPermissions() { 85 | // Check for permissions 86 | for (String eachPermission : REQUIRED_PERMISSION_LIST) { 87 | if (ContextCompat.checkSelfPermission(this, eachPermission) != PackageManager.PERMISSION_GRANTED) { 88 | missingPermission.add(eachPermission); 89 | } 90 | } 91 | // Request for missing permissions 92 | if (!missingPermission.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 93 | ActivityCompat.requestPermissions(this, 94 | missingPermission.toArray(new String[missingPermission.size()]), 95 | REQUEST_PERMISSION_CODE); 96 | } 97 | 98 | } 99 | 100 | 101 | /** 102 | * Result of runtime permission request 103 | */ 104 | @Override 105 | public void onRequestPermissionsResult(int requestCode, 106 | @NonNull String[] permissions, 107 | @NonNull int[] grantResults) { 108 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 109 | // Check for granted permission and remove from missing list 110 | if (requestCode == REQUEST_PERMISSION_CODE) { 111 | for (int i = grantResults.length - 1; i >= 0; i--) { 112 | if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { 113 | missingPermission.remove(permissions[i]); 114 | } 115 | } 116 | } 117 | // If there is enough permission, we will start the registration 118 | if (missingPermission.isEmpty()) { 119 | startSDKRegistration(); 120 | } else { 121 | showToast("Missing permissions!!!"); 122 | } 123 | } 124 | 125 | private void startSDKRegistration() { 126 | if (isRegistrationInProgress.compareAndSet(false, true)) { 127 | AsyncTask.execute(new Runnable() { 128 | @Override 129 | public void run() { 130 | showToast( "registering, pls wait..."); 131 | DJISDKManager.getInstance().registerApp(getApplicationContext(), new DJISDKManager.SDKManagerCallback() { 132 | @Override 133 | public void onRegister(DJIError djiError) { 134 | if (djiError == DJISDKError.REGISTRATION_SUCCESS) { 135 | DJILog.e("App registration", DJISDKError.REGISTRATION_SUCCESS.getDescription()); 136 | DJISDKManager.getInstance().startConnectionToProduct(); 137 | showToast("Register Success"); 138 | } else { 139 | showToast( "Register sdk fails, check network is available"); 140 | } 141 | Log.v(TAG, djiError.getDescription()); 142 | } 143 | 144 | @Override 145 | public void onProductDisconnect() { 146 | Log.d(TAG, "onProductDisconnect"); 147 | showToast("Product Disconnected"); 148 | 149 | } 150 | @Override 151 | public void onProductConnect(BaseProduct baseProduct) { 152 | Log.d(TAG, String.format("onProductConnect newProduct:%s", baseProduct)); 153 | showToast("Product Connected"); 154 | 155 | } 156 | 157 | @Override 158 | public void onProductChanged(BaseProduct baseProduct) { 159 | 160 | } 161 | 162 | @Override 163 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent, 164 | BaseComponent newComponent) { 165 | 166 | if (newComponent != null) { 167 | newComponent.setComponentListener(new BaseComponent.ComponentListener() { 168 | 169 | @Override 170 | public void onConnectivityChange(boolean isConnected) { 171 | Log.d(TAG, "onComponentConnectivityChanged: " + isConnected); 172 | } 173 | }); 174 | } 175 | Log.d(TAG, 176 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s", 177 | componentKey, 178 | oldComponent, 179 | newComponent)); 180 | 181 | } 182 | @Override 183 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) { 184 | 185 | } 186 | 187 | @Override 188 | public void onDatabaseDownloadProgress(long l, long l1) { 189 | 190 | } 191 | }); 192 | } 193 | }); 194 | } 195 | } 196 | 197 | @Override 198 | public void onResume() { 199 | Log.e(TAG, "onResume"); 200 | super.onResume(); 201 | } 202 | 203 | @Override 204 | public void onPause() { 205 | Log.e(TAG, "onPause"); 206 | super.onPause(); 207 | } 208 | 209 | @Override 210 | public void onStop() { 211 | Log.e(TAG, "onStop"); 212 | super.onStop(); 213 | } 214 | 215 | public void onReturn(View view){ 216 | Log.e(TAG, "onReturn"); 217 | this.finish(); 218 | } 219 | 220 | @Override 221 | protected void onDestroy() { 222 | Log.e(TAG, "onDestroy"); 223 | unregisterReceiver(mReceiver); 224 | super.onDestroy(); 225 | } 226 | 227 | private void initUI() { 228 | 229 | mTextConnectionStatus = (TextView) findViewById(R.id.text_connection_status); 230 | mTextProduct = (TextView) findViewById(R.id.text_product_info); 231 | mBtnOpen = (Button) findViewById(R.id.btn_open); 232 | mBtnOpen.setOnClickListener(this); 233 | mBtnOpen.setEnabled(false); 234 | 235 | mVersionTv = (TextView) findViewById(R.id.textView2); 236 | mVersionTv.setText(getResources().getString(R.string.sdk_version, DJISDKManager.getInstance().getSDKVersion())); 237 | } 238 | 239 | protected BroadcastReceiver mReceiver = new BroadcastReceiver() { 240 | 241 | @Override 242 | public void onReceive(Context context, Intent intent) { 243 | refreshSDKRelativeUI(); 244 | } 245 | }; 246 | 247 | private void refreshSDKRelativeUI() { 248 | BaseProduct mProduct = DJIDemoApplication.getProductInstance(); 249 | 250 | if (null != mProduct && mProduct.isConnected()) { 251 | Log.v(TAG, "refreshSDK: True"); 252 | mBtnOpen.setEnabled(true); 253 | 254 | String str = mProduct instanceof Aircraft ? "DJIAircraft" : "DJIHandHeld"; 255 | mTextConnectionStatus.setText("Status: " + str + " connected"); 256 | 257 | if (null != mProduct.getModel()) { 258 | mTextProduct.setText("" + mProduct.getModel().getDisplayName()); 259 | } else { 260 | mTextProduct.setText(R.string.product_information); 261 | } 262 | 263 | } else { 264 | Log.v(TAG, "refreshSDK: False"); 265 | mBtnOpen.setEnabled(false); 266 | 267 | mTextProduct.setText(R.string.product_information); 268 | mTextConnectionStatus.setText(R.string.connection_loose); 269 | } 270 | } 271 | 272 | @Override 273 | public void onClick(View v) { 274 | switch (v.getId()) { 275 | 276 | case R.id.btn_open: { 277 | int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext()); 278 | if(status != ConnectionResult.SUCCESS) { 279 | GooglePlayServicesUtil.getErrorDialog(status, this, status); 280 | showToast("Cannot run without Google Play, please check!"); 281 | } else { 282 | Intent intent = new Intent(this, MainActivity.class); 283 | startActivity(intent); 284 | } 285 | break; 286 | } 287 | default: 288 | break; 289 | } 290 | } 291 | 292 | private void showToast(final String toastMsg) { 293 | runOnUiThread(new Runnable() { 294 | @Override 295 | public void run() { 296 | Toast.makeText(getApplicationContext(), toastMsg, Toast.LENGTH_LONG).show(); 297 | 298 | } 299 | }); 300 | } 301 | 302 | } 303 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/DJIDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Build; 7 | import android.os.Handler; 8 | import android.os.Looper; 9 | import androidx.core.content.ContextCompat; 10 | import androidx.multidex.MultiDex; 11 | 12 | import android.util.Log; 13 | import android.widget.Toast; 14 | 15 | import dji.sdk.base.BaseComponent; 16 | import dji.sdk.base.BaseProduct; 17 | import dji.sdk.sdkmanager.DJISDKInitEvent; 18 | import dji.sdk.sdkmanager.DJISDKManager; 19 | import dji.common.error.DJIError; 20 | import dji.common.error.DJISDKError; 21 | 22 | public class DJIDemoApplication extends Application { 23 | 24 | private static final String TAG = DJIDemoApplication.class.getName(); 25 | 26 | public static final String FLAG_CONNECTION_CHANGE = "dji_sdk_connection_change"; 27 | 28 | private DJISDKManager.SDKManagerCallback mDJISDKManagerCallback; 29 | private static BaseProduct mProduct; 30 | public Handler mHandler; 31 | 32 | private Application instance; 33 | 34 | public void setContext(Application application) { 35 | instance = application; 36 | } 37 | 38 | @Override 39 | public Context getApplicationContext() { 40 | return instance; 41 | } 42 | 43 | public DJIDemoApplication() { 44 | 45 | } 46 | 47 | public static synchronized BaseProduct getProductInstance() { 48 | if (null == mProduct) { 49 | mProduct = DJISDKManager.getInstance().getProduct(); 50 | } 51 | return mProduct; 52 | } 53 | 54 | @Override 55 | public void onCreate() { 56 | super.onCreate(); 57 | 58 | mHandler = new Handler(Looper.getMainLooper()); 59 | 60 | /** 61 | * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to 62 | * the SDK Registration result and the product changing. 63 | */ 64 | mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() { 65 | 66 | //Listens to the SDK registration result 67 | @Override 68 | public void onRegister(DJIError error) { 69 | 70 | if(error == DJISDKError.REGISTRATION_SUCCESS) { 71 | 72 | Handler handler = new Handler(Looper.getMainLooper()); 73 | handler.post(new Runnable() { 74 | @Override 75 | public void run() { 76 | Toast.makeText(getApplicationContext(), "Register Success", Toast.LENGTH_LONG).show(); 77 | } 78 | }); 79 | 80 | DJISDKManager.getInstance().startConnectionToProduct(); 81 | 82 | } else { 83 | 84 | Handler handler = new Handler(Looper.getMainLooper()); 85 | handler.post(new Runnable() { 86 | 87 | @Override 88 | public void run() { 89 | Toast.makeText(getApplicationContext(), "Register sdk fails, check network is available", Toast.LENGTH_LONG).show(); 90 | } 91 | }); 92 | 93 | } 94 | Log.e("TAG", error.toString()); 95 | } 96 | 97 | @Override 98 | public void onProductDisconnect() { 99 | Log.d("TAG", "onProductDisconnect"); 100 | notifyStatusChange(); 101 | } 102 | @Override 103 | public void onProductConnect(BaseProduct baseProduct) { 104 | Log.d("TAG", String.format("onProductConnect newProduct:%s", baseProduct)); 105 | notifyStatusChange(); 106 | 107 | } 108 | 109 | @Override 110 | public void onProductChanged(BaseProduct baseProduct) { 111 | Log.d("TAG", String.format("onProductChanged newProduct:%s", baseProduct)); 112 | notifyStatusChange(); 113 | } 114 | 115 | @Override 116 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent, 117 | BaseComponent newComponent) { 118 | if (newComponent != null) { 119 | newComponent.setComponentListener(new BaseComponent.ComponentListener() { 120 | 121 | @Override 122 | public void onConnectivityChange(boolean isConnected) { 123 | Log.d("TAG", "onComponentConnectivityChanged: " + isConnected); 124 | notifyStatusChange(); 125 | } 126 | }); 127 | } 128 | 129 | Log.d("TAG", 130 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s", 131 | componentKey, 132 | oldComponent, 133 | newComponent)); 134 | 135 | } 136 | @Override 137 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) { 138 | 139 | } 140 | 141 | @Override 142 | public void onDatabaseDownloadProgress(long l, long l1) { 143 | 144 | } 145 | }; 146 | //Check the permissions before registering the application for android system 6.0 above. 147 | int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE); 148 | int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE); 149 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (permissionCheck == 0 && permissionCheck2 == 0)) { 150 | //This is used to start SDK services and initiate SDK. 151 | DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback); 152 | Toast.makeText(getApplicationContext(), "registering, pls wait...", Toast.LENGTH_LONG).show(); 153 | 154 | } else { 155 | Toast.makeText(getApplicationContext(), "Please check if the permission is granted.", Toast.LENGTH_LONG).show(); 156 | } 157 | 158 | } 159 | 160 | protected void attachBaseContext(Context base){ 161 | super.attachBaseContext(base); 162 | MultiDex.install(this); 163 | } 164 | 165 | private void notifyStatusChange() { 166 | mHandler.removeCallbacks(updateRunnable); 167 | mHandler.postDelayed(updateRunnable, 500); 168 | } 169 | 170 | private Runnable updateRunnable = new Runnable() { 171 | 172 | @Override 173 | public void run() { 174 | Intent intent = new Intent(FLAG_CONNECTION_CHANGE); 175 | getApplicationContext().sendBroadcast(intent); 176 | } 177 | }; 178 | 179 | } 180 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/MApplication.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.secneo.sdk.Helper; 7 | 8 | public class MApplication extends Application { 9 | 10 | private DJIDemoApplication fpvDemoApplication; 11 | @Override 12 | protected void attachBaseContext(Context paramContext) { 13 | super.attachBaseContext(paramContext); 14 | Helper.install(MApplication.this); 15 | if (fpvDemoApplication == null) { 16 | fpvDemoApplication = new DJIDemoApplication(); 17 | fpvDemoApplication.setContext(this); 18 | } 19 | } 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | fpvDemoApplication.onCreate(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | private View.OnClickListener clickListener = v -> { 13 | switch (v.getId()) { 14 | case R.id.btn_waypoint1: 15 | startActivity(MainActivity.this, Waypoint1Activity.class); 16 | break; 17 | case R.id.btn_waypoint2: 18 | startActivity(MainActivity.this, Waypoint2Activity.class); 19 | break; 20 | } 21 | }; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_main); 27 | findViewById(R.id.btn_waypoint1).setOnClickListener(clickListener); 28 | findViewById(R.id.btn_waypoint2).setOnClickListener(clickListener); 29 | } 30 | 31 | public static void startActivity(Context context, Class activity) { 32 | Intent intent = new Intent(context, activity); 33 | context.startActivity(intent); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/Tools.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.app.Activity; 4 | import android.widget.Toast; 5 | 6 | public class Tools { 7 | public static int getInt(String str, int defaultValue) { 8 | try { 9 | return Integer.valueOf(str); 10 | } catch (Exception e) { 11 | return defaultValue; 12 | } 13 | } 14 | 15 | public static float getFloat(String str, float defaultValue) { 16 | try { 17 | return Float.valueOf(str); 18 | } catch (Exception e) { 19 | return defaultValue; 20 | } 21 | } 22 | 23 | public static void showToast(final Activity activity, final String msg) { 24 | activity.runOnUiThread(new Runnable() { 25 | @Override 26 | public void run() { 27 | Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show(); 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/Waypoint1Activity.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.Manifest; 4 | import android.app.AlertDialog; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.content.IntentFilter; 10 | import android.os.Build; 11 | import androidx.annotation.Nullable; 12 | import androidx.core.app.ActivityCompat; 13 | import androidx.fragment.app.FragmentActivity; 14 | import android.os.Bundle; 15 | import android.util.Log; 16 | import android.view.View; 17 | import android.widget.Button; 18 | import android.widget.LinearLayout; 19 | import android.widget.RadioGroup; 20 | import android.widget.TextView; 21 | import android.widget.Toast; 22 | 23 | import com.google.android.gms.maps.CameraUpdate; 24 | import com.google.android.gms.maps.CameraUpdateFactory; 25 | import com.google.android.gms.maps.GoogleMap; 26 | import com.google.android.gms.maps.OnMapReadyCallback; 27 | import com.google.android.gms.maps.SupportMapFragment; 28 | import com.google.android.gms.maps.model.BitmapDescriptorFactory; 29 | import com.google.android.gms.maps.model.LatLng; 30 | import com.google.android.gms.maps.model.Marker; 31 | import com.google.android.gms.maps.model.MarkerOptions; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | import java.util.Map; 36 | import java.util.concurrent.ConcurrentHashMap; 37 | 38 | import dji.common.flightcontroller.FlightControllerState; 39 | import dji.common.mission.waypoint.Waypoint; 40 | import dji.common.mission.waypoint.WaypointMission; 41 | import dji.common.mission.waypoint.WaypointMissionDownloadEvent; 42 | import dji.common.mission.waypoint.WaypointMissionExecutionEvent; 43 | import dji.common.mission.waypoint.WaypointMissionFinishedAction; 44 | import dji.common.mission.waypoint.WaypointMissionFlightPathMode; 45 | import dji.common.mission.waypoint.WaypointMissionHeadingMode; 46 | import dji.common.mission.waypoint.WaypointMissionUploadEvent; 47 | import dji.common.useraccount.UserAccountState; 48 | import dji.common.util.CommonCallbacks; 49 | import dji.sdk.base.BaseProduct; 50 | import dji.sdk.flightcontroller.FlightController; 51 | import dji.common.error.DJIError; 52 | import dji.sdk.mission.waypoint.WaypointMissionOperator; 53 | import dji.sdk.mission.waypoint.WaypointMissionOperatorListener; 54 | import dji.sdk.products.Aircraft; 55 | import dji.sdk.sdkmanager.DJISDKManager; 56 | import dji.sdk.useraccount.UserAccountManager; 57 | 58 | public class Waypoint1Activity extends FragmentActivity implements View.OnClickListener, GoogleMap.OnMapClickListener, OnMapReadyCallback { 59 | 60 | protected static final String TAG = "GSDemoActivity"; 61 | 62 | private GoogleMap gMap; 63 | 64 | private Button locate, add, clear; 65 | private Button config, upload, start, stop; 66 | 67 | private boolean isAdd = false; 68 | 69 | private double droneLocationLat = 181, droneLocationLng = 181; 70 | private final Map mMarkers = new ConcurrentHashMap(); 71 | private Marker droneMarker = null; 72 | 73 | private float altitude = 100.0f; 74 | private float mSpeed = 10.0f; 75 | 76 | private List waypointList = new ArrayList<>(); 77 | 78 | public static WaypointMission.Builder waypointMissionBuilder; 79 | private FlightController mFlightController; 80 | private WaypointMissionOperator instance; 81 | private WaypointMissionFinishedAction mFinishedAction = WaypointMissionFinishedAction.NO_ACTION; 82 | private WaypointMissionHeadingMode mHeadingMode = WaypointMissionHeadingMode.AUTO; 83 | 84 | @Override 85 | protected void onResume(){ 86 | super.onResume(); 87 | initFlightController(); 88 | } 89 | 90 | @Override 91 | protected void onPause(){ 92 | super.onPause(); 93 | } 94 | 95 | @Override 96 | protected void onDestroy(){ 97 | unregisterReceiver(mReceiver); 98 | removeListener(); 99 | super.onDestroy(); 100 | } 101 | 102 | /** 103 | * @Description : RETURN Button RESPONSE FUNCTION 104 | */ 105 | public void onReturn(View view){ 106 | Log.d(TAG, "onReturn"); 107 | this.finish(); 108 | } 109 | 110 | private void setResultToToast(final String string){ 111 | Waypoint1Activity.this.runOnUiThread(new Runnable() { 112 | @Override 113 | public void run() { 114 | Toast.makeText(Waypoint1Activity.this, string, Toast.LENGTH_SHORT).show(); 115 | } 116 | }); 117 | } 118 | 119 | private void initUI() { 120 | 121 | locate = (Button) findViewById(R.id.locate); 122 | add = (Button) findViewById(R.id.add); 123 | clear = (Button) findViewById(R.id.clear); 124 | config = (Button) findViewById(R.id.config); 125 | upload = (Button) findViewById(R.id.upload); 126 | start = (Button) findViewById(R.id.start); 127 | stop = (Button) findViewById(R.id.stop); 128 | 129 | locate.setOnClickListener(this); 130 | add.setOnClickListener(this); 131 | clear.setOnClickListener(this); 132 | config.setOnClickListener(this); 133 | upload.setOnClickListener(this); 134 | start.setOnClickListener(this); 135 | stop.setOnClickListener(this); 136 | 137 | } 138 | 139 | @Override 140 | protected void onCreate(Bundle savedInstanceState) { 141 | super.onCreate(savedInstanceState); 142 | 143 | // When the compile and target version is higher than 22, please request the 144 | // following permissions at runtime to ensure the 145 | // SDK work well. 146 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 147 | ActivityCompat.requestPermissions(this, 148 | new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.VIBRATE, 149 | Manifest.permission.INTERNET, Manifest.permission.ACCESS_WIFI_STATE, 150 | Manifest.permission.WAKE_LOCK, Manifest.permission.ACCESS_COARSE_LOCATION, 151 | Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.ACCESS_FINE_LOCATION, 152 | Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, 153 | Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.SYSTEM_ALERT_WINDOW, 154 | Manifest.permission.READ_PHONE_STATE, 155 | } 156 | , 1); 157 | } 158 | 159 | setContentView(R.layout.activity_waypoint1); 160 | 161 | IntentFilter filter = new IntentFilter(); 162 | filter.addAction(DJIDemoApplication.FLAG_CONNECTION_CHANGE); 163 | registerReceiver(mReceiver, filter); 164 | 165 | initUI(); 166 | 167 | SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() 168 | .findFragmentById(R.id.map); 169 | mapFragment.getMapAsync(this); 170 | 171 | addListener(); 172 | 173 | } 174 | 175 | protected BroadcastReceiver mReceiver = new BroadcastReceiver() { 176 | 177 | @Override 178 | public void onReceive(Context context, Intent intent) { 179 | onProductConnectionChange(); 180 | } 181 | }; 182 | 183 | private void onProductConnectionChange() 184 | { 185 | initFlightController(); 186 | loginAccount(); 187 | } 188 | 189 | private void loginAccount(){ 190 | 191 | UserAccountManager.getInstance().logIntoDJIUserAccount(this, 192 | new CommonCallbacks.CompletionCallbackWith() { 193 | @Override 194 | public void onSuccess(final UserAccountState userAccountState) { 195 | Log.e(TAG, "Login Success"); 196 | } 197 | @Override 198 | public void onFailure(DJIError error) { 199 | setResultToToast("Login Error:" 200 | + error.getDescription()); 201 | } 202 | }); 203 | } 204 | 205 | private void initFlightController() { 206 | 207 | BaseProduct product = DJIDemoApplication.getProductInstance(); 208 | if (product != null && product.isConnected()) { 209 | if (product instanceof Aircraft) { 210 | mFlightController = ((Aircraft) product).getFlightController(); 211 | } 212 | } 213 | 214 | if (mFlightController != null) { 215 | mFlightController.setStateCallback(new FlightControllerState.Callback() { 216 | 217 | @Override 218 | public void onUpdate(FlightControllerState djiFlightControllerCurrentState) { 219 | droneLocationLat = djiFlightControllerCurrentState.getAircraftLocation().getLatitude(); 220 | droneLocationLng = djiFlightControllerCurrentState.getAircraftLocation().getLongitude(); 221 | updateDroneLocation(); 222 | } 223 | }); 224 | } 225 | } 226 | 227 | //Add Listener for WaypointMissionOperator 228 | private void addListener() { 229 | if (getWaypointMissionOperator() != null){ 230 | getWaypointMissionOperator().addListener(eventNotificationListener); 231 | } 232 | } 233 | 234 | private void removeListener() { 235 | if (getWaypointMissionOperator() != null) { 236 | getWaypointMissionOperator().removeListener(eventNotificationListener); 237 | } 238 | } 239 | 240 | private WaypointMissionOperatorListener eventNotificationListener = new WaypointMissionOperatorListener() { 241 | @Override 242 | public void onDownloadUpdate(WaypointMissionDownloadEvent downloadEvent) { 243 | 244 | } 245 | 246 | @Override 247 | public void onUploadUpdate(WaypointMissionUploadEvent uploadEvent) { 248 | 249 | } 250 | 251 | @Override 252 | public void onExecutionUpdate(WaypointMissionExecutionEvent executionEvent) { 253 | 254 | } 255 | 256 | @Override 257 | public void onExecutionStart() { 258 | 259 | } 260 | 261 | @Override 262 | public void onExecutionFinish(@Nullable final DJIError error) { 263 | setResultToToast("Execution finished: " + (error == null ? "Success!" : error.getDescription())); 264 | } 265 | }; 266 | 267 | public WaypointMissionOperator getWaypointMissionOperator() { 268 | if (instance == null) { 269 | if (DJISDKManager.getInstance().getMissionControl() != null){ 270 | instance = DJISDKManager.getInstance().getMissionControl().getWaypointMissionOperator(); 271 | } 272 | } 273 | return instance; 274 | } 275 | 276 | private void setUpMap() { 277 | gMap.setOnMapClickListener(this);// add the listener for click for amap object 278 | 279 | } 280 | 281 | @Override 282 | public void onMapClick(LatLng point) { 283 | if (isAdd == true){ 284 | markWaypoint(point); 285 | Waypoint mWaypoint = new Waypoint(point.latitude, point.longitude, altitude); 286 | //Add Waypoints to Waypoint arraylist; 287 | if (waypointMissionBuilder != null) { 288 | waypointList.add(mWaypoint); 289 | waypointMissionBuilder.waypointList(waypointList).waypointCount(waypointList.size()); 290 | }else 291 | { 292 | waypointMissionBuilder = new WaypointMission.Builder(); 293 | waypointList.add(mWaypoint); 294 | waypointMissionBuilder.waypointList(waypointList).waypointCount(waypointList.size()); 295 | } 296 | }else{ 297 | setResultToToast("Cannot Add Waypoint"); 298 | } 299 | } 300 | 301 | public static boolean checkGpsCoordination(double latitude, double longitude) { 302 | return (latitude > -90 && latitude < 90 && longitude > -180 && longitude < 180) && (latitude != 0f && longitude != 0f); 303 | } 304 | 305 | // Update the drone location based on states from MCU. 306 | private void updateDroneLocation(){ 307 | 308 | LatLng pos = new LatLng(droneLocationLat, droneLocationLng); 309 | //Create MarkerOptions object 310 | final MarkerOptions markerOptions = new MarkerOptions(); 311 | markerOptions.position(pos); 312 | markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.aircraft)); 313 | 314 | runOnUiThread(new Runnable() { 315 | @Override 316 | public void run() { 317 | if (droneMarker != null) { 318 | droneMarker.remove(); 319 | } 320 | 321 | if (checkGpsCoordination(droneLocationLat, droneLocationLng)) { 322 | droneMarker = gMap.addMarker(markerOptions); 323 | } 324 | } 325 | }); 326 | } 327 | 328 | private void markWaypoint(LatLng point){ 329 | //Create MarkerOptions object 330 | MarkerOptions markerOptions = new MarkerOptions(); 331 | markerOptions.position(point); 332 | markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); 333 | Marker marker = gMap.addMarker(markerOptions); 334 | mMarkers.put(mMarkers.size(), marker); 335 | } 336 | 337 | @Override 338 | public void onClick(View v) { 339 | switch (v.getId()) { 340 | case R.id.locate:{ 341 | updateDroneLocation(); 342 | cameraUpdate(); // Locate the drone's place 343 | break; 344 | } 345 | case R.id.add:{ 346 | enableDisableAdd(); 347 | break; 348 | } 349 | case R.id.clear:{ 350 | runOnUiThread(new Runnable() { 351 | @Override 352 | public void run() { 353 | gMap.clear(); 354 | } 355 | 356 | }); 357 | waypointList.clear(); 358 | waypointMissionBuilder.waypointList(waypointList); 359 | updateDroneLocation(); 360 | break; 361 | } 362 | case R.id.config:{ 363 | showSettingDialog(); 364 | break; 365 | } 366 | case R.id.upload:{ 367 | uploadWayPointMission(); 368 | break; 369 | } 370 | case R.id.start:{ 371 | startWaypointMission(); 372 | break; 373 | } 374 | case R.id.stop:{ 375 | stopWaypointMission(); 376 | break; 377 | } 378 | default: 379 | break; 380 | } 381 | } 382 | 383 | private void cameraUpdate(){ 384 | LatLng pos = new LatLng(droneLocationLat, droneLocationLng); 385 | float zoomlevel = (float) 18.0; 386 | CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(pos, zoomlevel); 387 | gMap.moveCamera(cu); 388 | 389 | } 390 | 391 | private void enableDisableAdd(){ 392 | if (isAdd == false) { 393 | isAdd = true; 394 | add.setText("Exit"); 395 | }else{ 396 | isAdd = false; 397 | add.setText("Add"); 398 | } 399 | } 400 | 401 | private void showSettingDialog(){ 402 | LinearLayout wayPointSettings = (LinearLayout)getLayoutInflater().inflate(R.layout.dialog_waypointsetting, null); 403 | 404 | final TextView wpAltitude_TV = (TextView) wayPointSettings.findViewById(R.id.altitude); 405 | RadioGroup speed_RG = (RadioGroup) wayPointSettings.findViewById(R.id.speed); 406 | RadioGroup actionAfterFinished_RG = (RadioGroup) wayPointSettings.findViewById(R.id.actionAfterFinished); 407 | RadioGroup heading_RG = (RadioGroup) wayPointSettings.findViewById(R.id.heading); 408 | 409 | speed_RG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){ 410 | 411 | @Override 412 | public void onCheckedChanged(RadioGroup group, int checkedId) { 413 | if (checkedId == R.id.lowSpeed){ 414 | mSpeed = 3.0f; 415 | } else if (checkedId == R.id.MidSpeed){ 416 | mSpeed = 5.0f; 417 | } else if (checkedId == R.id.HighSpeed){ 418 | mSpeed = 10.0f; 419 | } 420 | } 421 | 422 | }); 423 | 424 | actionAfterFinished_RG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 425 | 426 | @Override 427 | public void onCheckedChanged(RadioGroup group, int checkedId) { 428 | Log.d(TAG, "Select finish action"); 429 | if (checkedId == R.id.finishNone){ 430 | mFinishedAction = WaypointMissionFinishedAction.NO_ACTION; 431 | } else if (checkedId == R.id.finishGoHome){ 432 | mFinishedAction = WaypointMissionFinishedAction.GO_HOME; 433 | } else if (checkedId == R.id.finishAutoLanding){ 434 | mFinishedAction = WaypointMissionFinishedAction.AUTO_LAND; 435 | } else if (checkedId == R.id.finishToFirst){ 436 | mFinishedAction = WaypointMissionFinishedAction.GO_FIRST_WAYPOINT; 437 | } 438 | } 439 | }); 440 | 441 | heading_RG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 442 | 443 | @Override 444 | public void onCheckedChanged(RadioGroup group, int checkedId) { 445 | Log.d(TAG, "Select heading"); 446 | 447 | if (checkedId == R.id.headingNext) { 448 | mHeadingMode = WaypointMissionHeadingMode.AUTO; 449 | } else if (checkedId == R.id.headingInitDirec) { 450 | mHeadingMode = WaypointMissionHeadingMode.USING_INITIAL_DIRECTION; 451 | } else if (checkedId == R.id.headingRC) { 452 | mHeadingMode = WaypointMissionHeadingMode.CONTROL_BY_REMOTE_CONTROLLER; 453 | } else if (checkedId == R.id.headingWP) { 454 | mHeadingMode = WaypointMissionHeadingMode.USING_WAYPOINT_HEADING; 455 | } 456 | } 457 | }); 458 | 459 | new AlertDialog.Builder(this) 460 | .setTitle("") 461 | .setView(wayPointSettings) 462 | .setPositiveButton("Finish",new DialogInterface.OnClickListener(){ 463 | public void onClick(DialogInterface dialog, int id) { 464 | 465 | String altitudeString = wpAltitude_TV.getText().toString(); 466 | altitude = Integer.parseInt(nulltoIntegerDefalt(altitudeString)); 467 | Log.e(TAG,"altitude "+altitude); 468 | Log.e(TAG,"speed "+mSpeed); 469 | Log.e(TAG, "mFinishedAction "+mFinishedAction); 470 | Log.e(TAG, "mHeadingMode "+mHeadingMode); 471 | configWayPointMission(); 472 | } 473 | 474 | }) 475 | .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 476 | public void onClick(DialogInterface dialog, int id) { 477 | dialog.cancel(); 478 | } 479 | 480 | }) 481 | .create() 482 | .show(); 483 | } 484 | 485 | String nulltoIntegerDefalt(String value){ 486 | if(!isIntValue(value)) value="0"; 487 | return value; 488 | } 489 | 490 | boolean isIntValue(String val) 491 | { 492 | try { 493 | val=val.replace(" ",""); 494 | Integer.parseInt(val); 495 | } catch (Exception e) {return false;} 496 | return true; 497 | } 498 | 499 | private void configWayPointMission(){ 500 | 501 | if (waypointMissionBuilder == null){ 502 | 503 | waypointMissionBuilder = new WaypointMission.Builder().finishedAction(mFinishedAction) 504 | .headingMode(mHeadingMode) 505 | .autoFlightSpeed(mSpeed) 506 | .maxFlightSpeed(mSpeed) 507 | .flightPathMode(WaypointMissionFlightPathMode.NORMAL); 508 | 509 | }else 510 | { 511 | waypointMissionBuilder.finishedAction(mFinishedAction) 512 | .headingMode(mHeadingMode) 513 | .autoFlightSpeed(mSpeed) 514 | .maxFlightSpeed(mSpeed) 515 | .flightPathMode(WaypointMissionFlightPathMode.NORMAL); 516 | 517 | } 518 | 519 | if (waypointMissionBuilder.getWaypointList().size() > 0){ 520 | 521 | for (int i=0; i< waypointMissionBuilder.getWaypointList().size(); i++){ 522 | waypointMissionBuilder.getWaypointList().get(i).altitude = altitude; 523 | } 524 | 525 | setResultToToast("Set Waypoint attitude successfully"); 526 | } 527 | 528 | DJIError error = getWaypointMissionOperator().loadMission(waypointMissionBuilder.build()); 529 | if (error == null) { 530 | setResultToToast("loadWaypoint succeeded"); 531 | } else { 532 | setResultToToast("loadWaypoint failed " + error.getDescription()); 533 | } 534 | } 535 | 536 | private void uploadWayPointMission(){ 537 | 538 | getWaypointMissionOperator().uploadMission(new CommonCallbacks.CompletionCallback() { 539 | @Override 540 | public void onResult(DJIError error) { 541 | if (error == null) { 542 | setResultToToast("Mission upload successfully!"); 543 | } else { 544 | setResultToToast("Mission upload failed, error: " + error.getDescription() + " retrying..."); 545 | getWaypointMissionOperator().retryUploadMission(null); 546 | } 547 | } 548 | }); 549 | 550 | } 551 | 552 | private void startWaypointMission(){ 553 | 554 | getWaypointMissionOperator().startMission(new CommonCallbacks.CompletionCallback() { 555 | @Override 556 | public void onResult(DJIError error) { 557 | setResultToToast("Mission Start: " + (error == null ? "Successfully" : error.getDescription())); 558 | } 559 | }); 560 | } 561 | 562 | private void stopWaypointMission(){ 563 | 564 | getWaypointMissionOperator().stopMission(new CommonCallbacks.CompletionCallback() { 565 | @Override 566 | public void onResult(DJIError error) { 567 | setResultToToast("Mission Stop: " + (error == null ? "Successfully" : error.getDescription())); 568 | } 569 | }); 570 | 571 | } 572 | 573 | @Override 574 | public void onMapReady(GoogleMap googleMap) { 575 | if (gMap == null) { 576 | gMap = googleMap; 577 | setUpMap(); 578 | } 579 | 580 | LatLng shenzhen = new LatLng(22.5362, 113.9454); 581 | gMap.addMarker(new MarkerOptions().position(shenzhen).title("Marker in Shenzhen")); 582 | gMap.moveCamera(CameraUpdateFactory.newLatLng(shenzhen)); 583 | } 584 | 585 | } 586 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/WaypointActionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import java.util.List; 12 | 13 | import dji.common.mission.waypointv2.Action.WaypointV2Action; 14 | 15 | public class WaypointActionAdapter extends RecyclerView.Adapter { 16 | private List data; 17 | private LayoutInflater mInflater; 18 | 19 | public WaypointActionAdapter(Context context, List data) { 20 | this.mInflater = LayoutInflater.from(context); 21 | this.data = data; 22 | } 23 | 24 | public void addItem(WaypointV2Action action) { 25 | if (action == null || data == null) { 26 | return; 27 | } 28 | data.add(action); 29 | notifyItemInserted(getItemCount() - 1); 30 | } 31 | 32 | public List getData() { 33 | return data; 34 | } 35 | 36 | @Override 37 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 38 | return new ViewHolder(mInflater.inflate(R.layout.item_waypoint_action, parent, false)); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(ViewHolder holder, int position) { 43 | holder.setData(data.get(position)); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return data == null ? 0 : data.size(); 49 | } 50 | 51 | public class ViewHolder extends RecyclerView.ViewHolder { 52 | private TextView triggerTv; 53 | private TextView actuatorTv; 54 | private TextView actionIdTv; 55 | 56 | public ViewHolder(View itemView) { 57 | super(itemView); 58 | triggerTv = itemView.findViewById(R.id.tv_trigger); 59 | actuatorTv = itemView.findViewById(R.id.tv_actuator); 60 | actionIdTv = itemView.findViewById(R.id.tv_action_id); 61 | } 62 | 63 | public void setData(WaypointV2Action data) { 64 | if (data.getTrigger() != null) { 65 | triggerTv.setText("Trigger: " + data.getTrigger().getTriggerType().name()); 66 | } 67 | if (data.getActuator() != null) { 68 | actuatorTv.setText("Actuator: " + data.getActuator().getActuatorType().name()); 69 | } 70 | actionIdTv.setText("ActionId:" + data.getActionID()); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/WaypointV2ActionDialog.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap; 2 | 3 | import android.os.Bundle; 4 | import android.util.DisplayMetrics; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.ArrayAdapter; 10 | import android.widget.FrameLayout; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | 14 | import androidx.annotation.IdRes; 15 | import androidx.annotation.NonNull; 16 | import androidx.annotation.Nullable; 17 | import androidx.appcompat.widget.AppCompatSpinner; 18 | import androidx.constraintlayout.widget.ConstraintLayout; 19 | import androidx.core.widget.NestedScrollView; 20 | import androidx.fragment.app.DialogFragment; 21 | import androidx.fragment.app.Fragment; 22 | import androidx.fragment.app.FragmentTransaction; 23 | import androidx.recyclerview.widget.DividerItemDecoration; 24 | import androidx.recyclerview.widget.LinearLayoutManager; 25 | import androidx.recyclerview.widget.RecyclerView; 26 | 27 | import com.dji.GSDemo.GoogleMap.fragment.actuator.AircraftActuatorFragment; 28 | import com.dji.GSDemo.GoogleMap.fragment.actuator.CameraActuatorFragment; 29 | import com.dji.GSDemo.GoogleMap.fragment.actuator.GimbalActuatorFragment; 30 | import com.dji.GSDemo.GoogleMap.fragment.actuator.IActuatorCallback; 31 | import com.dji.GSDemo.GoogleMap.fragment.trigger.AssociateTriggerFragment; 32 | import com.dji.GSDemo.GoogleMap.fragment.trigger.BaseTriggerFragment; 33 | import com.dji.GSDemo.GoogleMap.fragment.trigger.ITriggerCallback; 34 | import com.dji.GSDemo.GoogleMap.fragment.trigger.ReachPointTriggerFragment; 35 | import com.dji.GSDemo.GoogleMap.fragment.trigger.SimpleIntervalTriggerFragment; 36 | import com.dji.GSDemo.GoogleMap.fragment.trigger.TrajectoryTriggerFragment; 37 | 38 | import java.util.ArrayList; 39 | import java.util.List; 40 | 41 | import butterknife.BindView; 42 | import butterknife.ButterKnife; 43 | import butterknife.OnClick; 44 | import butterknife.Unbinder; 45 | import dji.common.mission.waypointv2.Action.ActionTypes; 46 | import dji.common.mission.waypointv2.Action.WaypointActuator; 47 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 48 | import dji.common.mission.waypointv2.Action.WaypointV2Action; 49 | 50 | public class WaypointV2ActionDialog extends DialogFragment implements ITriggerCallback { 51 | @BindView(R.id.tv_title) 52 | TextView tvTitle; 53 | @BindView(R.id.view_division) 54 | View viewDivision; 55 | @BindView(R.id.rv_added_action) 56 | RecyclerView rvAddedAction; 57 | @BindView(R.id.nsv_action_detail) 58 | NestedScrollView nsvActionDetail; 59 | @BindView(R.id.tv_ok) 60 | TextView tvOk; 61 | Unbinder unbinder; 62 | @BindView(R.id.tv_trigger_title) 63 | TextView tvTriggerTitle; 64 | @BindView(R.id.cl_trigger) 65 | ConstraintLayout clTrigger; 66 | @BindView(R.id.spinner_trigger_type) 67 | AppCompatSpinner spinnerTriggerType; 68 | @BindView(R.id.fl_trigger_info) 69 | FrameLayout flTriggerInfo; 70 | @BindView(R.id.tv_actuator_title) 71 | TextView tvActuatorTitle; 72 | @BindView(R.id.spinner_actuator_type) 73 | AppCompatSpinner spinnerActuatorType; 74 | @BindView(R.id.fl_actuator_info) 75 | FrameLayout flActuatorInfo; 76 | 77 | private WaypointActionAdapter actionAdapter; 78 | 79 | List triggerType; 80 | List actuatorType; 81 | List actuatorNames; 82 | 83 | private AssociateTriggerFragment associateTriggerFragment; 84 | private SimpleIntervalTriggerFragment simpleIntervalTriggerFragment; 85 | private ReachPointTriggerFragment reachPointTriggerFragment; 86 | private TrajectoryTriggerFragment trajectoryTriggerFragment; 87 | 88 | private AircraftActuatorFragment aircraftActuatorFragment; 89 | private CameraActuatorFragment cameraActuatorFragment; 90 | private GimbalActuatorFragment gimbalActuatorFragment; 91 | 92 | private Fragment currentTriggerFragment; 93 | private Fragment currentActuatorFragment; 94 | 95 | private IActionCallback actionCallback; 96 | ArrayAdapter actuatorAdapter; 97 | 98 | private int position; 99 | private int size; 100 | 101 | 102 | public void setActionCallback(IActionCallback actionCallback) { 103 | this.actionCallback = actionCallback; 104 | } 105 | 106 | public void setSize(int size) { 107 | this.size = size; 108 | } 109 | 110 | @Nullable 111 | @Override 112 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 113 | View root = inflater.inflate(R.layout.dialog_waypoint_v2, container, false); 114 | unbinder = ButterKnife.bind(this, root); 115 | initData(); 116 | initView(); 117 | return root; 118 | } 119 | 120 | private void initData() { 121 | triggerType = new ArrayList<>(); 122 | actuatorType = new ArrayList<>(); 123 | triggerType.add("Please select trigger type"); 124 | for (ActionTypes.ActionTriggerType type : ActionTypes.ActionTriggerType.values()) { 125 | if (type == ActionTypes.ActionTriggerType.COMPLEX_REACH_POINTS) { 126 | // not support 127 | continue; 128 | } 129 | triggerType.add(type.name()); 130 | } 131 | actuatorNames = new ArrayList(); 132 | actuatorNames.add("Please select actuator type"); 133 | actuatorNames.add(ActionTypes.ActionActuatorType.GIMBAL.name()); 134 | actuatorNames.add(ActionTypes.ActionActuatorType.CAMERA.name()); 135 | actuatorNames.add(ActionTypes.ActionActuatorType.AIRCRAFT_CONTROL.name()); 136 | actuatorType.addAll(actuatorNames); 137 | } 138 | 139 | private void initView() { 140 | rvAddedAction.setLayoutManager(new LinearLayoutManager(getContext())); 141 | rvAddedAction.addItemDecoration(new DividerItemDecoration(getContext(), LinearLayout.HORIZONTAL)); 142 | 143 | actionAdapter = new WaypointActionAdapter(getContext(), new ArrayList<>()); 144 | rvAddedAction.setAdapter(actionAdapter); 145 | 146 | ArrayAdapter triggerAdapter = new ArrayAdapter(getActivity(), 147 | android.R.layout.simple_spinner_dropdown_item, triggerType); 148 | spinnerTriggerType.setAdapter(triggerAdapter); 149 | spinnerTriggerType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 150 | @Override 151 | public void onItemSelected(AdapterView parent, View view, int position, long id) { 152 | if (position == 0) { 153 | hideTriggerFragment(); 154 | return; 155 | } 156 | switch (ActionTypes.ActionTriggerType.valueOf(triggerType.get(position))) { 157 | case ASSOCIATE: 158 | if (associateTriggerFragment == null) { 159 | associateTriggerFragment = AssociateTriggerFragment.newInstance(); 160 | } 161 | associateTriggerFragment.setSize(actionAdapter.getData().size()); 162 | showFragment(associateTriggerFragment, R.id.fl_trigger_info); 163 | currentTriggerFragment = associateTriggerFragment; 164 | break; 165 | case SIMPLE_INTERVAL: 166 | if (simpleIntervalTriggerFragment == null) { 167 | simpleIntervalTriggerFragment = SimpleIntervalTriggerFragment.newInstance(); 168 | } 169 | simpleIntervalTriggerFragment.setSize(size); 170 | showFragment(simpleIntervalTriggerFragment, R.id.fl_trigger_info); 171 | currentTriggerFragment = simpleIntervalTriggerFragment; 172 | break; 173 | case REACH_POINT: 174 | if (reachPointTriggerFragment == null) { 175 | reachPointTriggerFragment = ReachPointTriggerFragment.newInstance(); 176 | } 177 | reachPointTriggerFragment.setSize(size); 178 | showFragment(reachPointTriggerFragment, R.id.fl_trigger_info); 179 | currentTriggerFragment = reachPointTriggerFragment; 180 | break; 181 | case TRAJECTORY: 182 | if (trajectoryTriggerFragment == null) { 183 | trajectoryTriggerFragment = TrajectoryTriggerFragment.newInstance(); 184 | } 185 | trajectoryTriggerFragment.setSize(size); 186 | showFragment(trajectoryTriggerFragment, R.id.fl_trigger_info); 187 | currentTriggerFragment = trajectoryTriggerFragment; 188 | break; 189 | case UNKNOWN: 190 | hideTriggerFragment(); 191 | break; 192 | } 193 | hideActuatorFragment(); 194 | changeActuatorAdapter(ActionTypes.ActionTriggerType.valueOf(triggerType.get(position))); 195 | } 196 | 197 | @Override 198 | public void onNothingSelected(AdapterView parent) { 199 | 200 | } 201 | }); 202 | actuatorAdapter = new ArrayAdapter(getActivity(), 203 | android.R.layout.simple_spinner_dropdown_item, actuatorType); 204 | spinnerActuatorType.setAdapter(actuatorAdapter); 205 | spinnerActuatorType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 206 | @Override 207 | public void onItemSelected(AdapterView parent, View view, int position, long id) { 208 | if (position == 0) { 209 | hideActuatorFragment(); 210 | return; 211 | } 212 | switch (ActionTypes.ActionActuatorType.valueOf(actuatorType.get(position))) { 213 | case SPRAY: 214 | // 暂不支持 215 | Tools.showToast(getActivity(), "Not Support"); 216 | hideActuatorFragment(); 217 | break; 218 | case CAMERA: 219 | if (cameraActuatorFragment == null) { 220 | cameraActuatorFragment = CameraActuatorFragment.newInstance(); 221 | } 222 | showFragment(cameraActuatorFragment, R.id.fl_actuator_info); 223 | currentActuatorFragment = cameraActuatorFragment; 224 | break; 225 | case PLAYLOAD: 226 | Tools.showToast(getActivity(), "Not Support"); 227 | hideActuatorFragment(); 228 | break; 229 | case GIMBAL: 230 | if (gimbalActuatorFragment == null) { 231 | gimbalActuatorFragment = GimbalActuatorFragment.newInstance(WaypointV2ActionDialog.this); 232 | } 233 | showFragment(gimbalActuatorFragment, R.id.fl_actuator_info); 234 | currentActuatorFragment = gimbalActuatorFragment; 235 | gimbalActuatorFragment.flush(); 236 | break; 237 | case AIRCRAFT_CONTROL: 238 | if (aircraftActuatorFragment == null) { 239 | aircraftActuatorFragment = AircraftActuatorFragment.newInstance(); 240 | } 241 | showFragment(aircraftActuatorFragment, R.id.fl_actuator_info); 242 | currentActuatorFragment = aircraftActuatorFragment; 243 | break; 244 | case NAVIGATION: 245 | Tools.showToast(getActivity(), "Not Support"); 246 | hideActuatorFragment(); 247 | break; 248 | case UNKNOWN: 249 | hideActuatorFragment(); 250 | break; 251 | } 252 | } 253 | 254 | @Override 255 | public void onNothingSelected(AdapterView parent) { 256 | 257 | } 258 | }); 259 | } 260 | 261 | private void changeActuatorAdapter(ActionTypes.ActionTriggerType triggerType) { 262 | switch (triggerType) { 263 | case COMPLEX_REACH_POINTS: 264 | flushActuator(); 265 | break; 266 | case ASSOCIATE: 267 | flushActuator(); 268 | break; 269 | case SIMPLE_INTERVAL: 270 | flushActuator(); 271 | break; 272 | case REACH_POINT: 273 | flushActuator(); 274 | break; 275 | case TRAJECTORY: 276 | // this trigger is one by one with ActionTypes.GimbalOperationType#AIRCRAFT_CONTROL_GIMBAL. 277 | actuatorType.removeAll(actuatorNames); 278 | actuatorType.add("Please select actuator type"); 279 | actuatorType.add(ActionTypes.ActionActuatorType.GIMBAL.name()); 280 | break; 281 | default: 282 | break; 283 | } 284 | } 285 | 286 | private void flushActuator() { 287 | actuatorType.clear(); 288 | actuatorType.addAll(actuatorNames); 289 | actionAdapter.notifyDataSetChanged(); 290 | } 291 | 292 | private void hideActuatorFragment() { 293 | if (currentActuatorFragment == null) { 294 | return; 295 | } 296 | FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); 297 | transaction.hide(currentActuatorFragment); 298 | transaction.commit(); 299 | } 300 | 301 | 302 | private void showFragment(Fragment fragment, @IdRes int id) { 303 | if (fragment == null || fragment.isVisible()) { 304 | return; 305 | } 306 | 307 | FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); 308 | if (fragment.isAdded()) { 309 | if (fragment instanceof BaseTriggerFragment && currentTriggerFragment != null) { 310 | transaction.hide(currentTriggerFragment); 311 | } else if (fragment instanceof IActuatorCallback && currentActuatorFragment != null) { 312 | transaction.hide(currentActuatorFragment); 313 | } 314 | transaction.show(fragment); 315 | } else { 316 | transaction.replace(id, fragment); 317 | } 318 | transaction.commit(); 319 | } 320 | 321 | private void hideTriggerFragment() { 322 | if (currentTriggerFragment == null) { 323 | return; 324 | } 325 | FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); 326 | transaction.hide(currentTriggerFragment); 327 | transaction.commit(); 328 | } 329 | 330 | @Override 331 | public void onStart() { 332 | super.onStart(); 333 | DisplayMetrics dm = new DisplayMetrics(); 334 | getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); 335 | getDialog().getWindow().setLayout((int) (dm.widthPixels * 0.9), (int) (dm.heightPixels * 0.9)); 336 | 337 | } 338 | 339 | @Override 340 | public void onDestroyView() { 341 | super.onDestroyView(); 342 | unbinder.unbind(); 343 | } 344 | 345 | @OnClick({R.id.tv_ok, R.id.tv_add}) 346 | public void onViewClick(View v) { 347 | switch (v.getId()) { 348 | case R.id.tv_ok: 349 | if (actionCallback != null) { 350 | actionCallback.getActions(actionAdapter.getData()); 351 | } 352 | dismiss(); 353 | position = 0; 354 | break; 355 | case R.id.tv_add: 356 | WaypointTrigger trigger = getWaypointTrigger(); 357 | WaypointActuator actuator = getWaypointActuator(); 358 | boolean result = verifyAction(trigger, actuator); 359 | if (!result) { 360 | break; 361 | } 362 | WaypointV2Action action = new WaypointV2Action.Builder() 363 | .setTrigger(trigger) 364 | .setActuator(actuator) 365 | .setActionID(++position) 366 | .build(); 367 | actionAdapter.addItem(action); 368 | updateSize(); 369 | break; 370 | } 371 | } 372 | 373 | private boolean verifyAction(WaypointTrigger trigger, WaypointActuator actuator) { 374 | if (trigger == null || actuator == null) { 375 | Tools.showToast(getActivity(), "add fail"); 376 | return false; 377 | } 378 | if (actuator.getActuatorType() == ActionTypes.ActionActuatorType.GIMBAL 379 | && actuator.getGimbalActuatorParam().getOperationType() == ActionTypes.GimbalOperationType.AIRCRAFT_CONTROL_GIMBAL) { 380 | if (trigger.getTriggerType() != ActionTypes.ActionTriggerType.TRAJECTORY) { 381 | Tools.showToast(getActivity(), "this trigger `TRAJECTORY` is one by one with `ActionTypes.GimbalOperationType.AIRCRAFT_CONTROL_GIMBAL`"); 382 | return false; 383 | } 384 | } 385 | if (trigger.getTriggerType() == ActionTypes.ActionTriggerType.TRAJECTORY) { 386 | if (actuator.getActuatorType() != ActionTypes.ActionActuatorType.GIMBAL 387 | || actuator.getGimbalActuatorParam().getOperationType() != ActionTypes.GimbalOperationType.AIRCRAFT_CONTROL_GIMBAL) { 388 | Tools.showToast(getActivity(), "this trigger `TRAJECTORY` is one by one with `ActionTypes.GimbalOperationType.AIRCRAFT_CONTROL_GIMBAL`"); 389 | return false; 390 | } 391 | } 392 | return true; 393 | } 394 | 395 | private void updateSize() { 396 | if (reachPointTriggerFragment != null) { 397 | reachPointTriggerFragment.setSize(actionAdapter.getItemCount()); 398 | } 399 | if (associateTriggerFragment != null) { 400 | associateTriggerFragment.setSize(actionAdapter.getItemCount()); 401 | } 402 | if (simpleIntervalTriggerFragment != null) { 403 | simpleIntervalTriggerFragment.setSize(actionAdapter.getItemCount()); 404 | } 405 | if (trajectoryTriggerFragment != null) { 406 | trajectoryTriggerFragment.setSize(actionAdapter.getItemCount()); 407 | } 408 | } 409 | 410 | private WaypointActuator getWaypointActuator() { 411 | if (currentActuatorFragment == null) { 412 | return null; 413 | } 414 | if (currentActuatorFragment instanceof IActuatorCallback) { 415 | return ((IActuatorCallback) currentActuatorFragment).getActuator(); 416 | } 417 | return null; 418 | } 419 | 420 | private WaypointTrigger getWaypointTrigger() { 421 | if (currentTriggerFragment == null) { 422 | return null; 423 | } 424 | if (currentTriggerFragment instanceof ITriggerCallback) { 425 | return ((ITriggerCallback) currentTriggerFragment).getTrigger(); 426 | } 427 | return null; 428 | } 429 | 430 | @Override 431 | public WaypointTrigger getTrigger() { 432 | return getWaypointTrigger(); 433 | } 434 | 435 | public interface IActionCallback { 436 | void getActions(List actions); 437 | } 438 | } 439 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/actuator/AircraftActuatorFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.actuator; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.RadioButton; 8 | import android.widget.RadioGroup; 9 | import android.widget.TextView; 10 | 11 | import androidx.appcompat.widget.AppCompatCheckBox; 12 | import androidx.constraintlayout.widget.ConstraintLayout; 13 | import androidx.fragment.app.Fragment; 14 | 15 | import com.dji.GSDemo.GoogleMap.R; 16 | import com.dji.GSDemo.GoogleMap.Tools; 17 | 18 | import butterknife.BindView; 19 | import butterknife.ButterKnife; 20 | import butterknife.Unbinder; 21 | import dji.common.mission.waypointv2.Action.ActionTypes; 22 | import dji.common.mission.waypointv2.Action.WaypointActuator; 23 | import dji.common.mission.waypointv2.Action.WaypointAircraftControlParam; 24 | import dji.common.mission.waypointv2.Action.WaypointAircraftControlRotateYawParam; 25 | import dji.common.mission.waypointv2.Action.WaypointAircraftControlStartStopFlyParam; 26 | import dji.common.mission.waypointv2.WaypointV2MissionTypes; 27 | 28 | /** 29 | * A simple {@link Fragment} subclass. 30 | * Use the {@link AircraftActuatorFragment#newInstance} factory method to 31 | * create an instance of this fragment. 32 | */ 33 | public class AircraftActuatorFragment extends Fragment implements IActuatorCallback { 34 | 35 | 36 | Unbinder unbinder; 37 | @BindView(R.id.rb_rotate_yaw) 38 | RadioButton rbRotateYaw; 39 | @BindView(R.id.rb_start_stop_fly) 40 | RadioButton rbStartStopFly; 41 | @BindView(R.id.radio_type) 42 | RadioGroup radioType; 43 | @BindView(R.id.tv_tip_yaw) 44 | TextView tvTipYaw; 45 | @BindView(R.id.box_yaw_relative) 46 | AppCompatCheckBox boxYawRelative; 47 | @BindView(R.id.box_yaw_clockwise) 48 | AppCompatCheckBox boxYawClockwise; 49 | @BindView(R.id.cl_yaw) 50 | ConstraintLayout clYaw; 51 | @BindView(R.id.box_start_stop_fly) 52 | AppCompatCheckBox boxStartStopFly; 53 | @BindView(R.id.cl_start_stop) 54 | ConstraintLayout clStartStop; 55 | @BindView(R.id.et_yaw_angle) 56 | TextView yawAngle; 57 | 58 | private ActionTypes.AircraftControlType type = ActionTypes.AircraftControlType.UNKNOWN; 59 | 60 | public static AircraftActuatorFragment newInstance() { 61 | AircraftActuatorFragment fragment = new AircraftActuatorFragment(); 62 | return fragment; 63 | } 64 | 65 | @Override 66 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 67 | View root = inflater.inflate(R.layout.fragment_aircraft_actuator, container, false); 68 | unbinder = ButterKnife.bind(this, root); 69 | radioType.setOnCheckedChangeListener((group, checkedId) -> { 70 | switch (checkedId) { 71 | case R.id.rb_rotate_yaw: 72 | clYaw.setVisibility(View.VISIBLE); 73 | clStartStop.setVisibility(View.GONE); 74 | type = ActionTypes.AircraftControlType.ROTATE_YAW; 75 | break; 76 | case R.id.rb_start_stop_fly: 77 | clStartStop.setVisibility(View.VISIBLE); 78 | clYaw.setVisibility(View.GONE); 79 | type = ActionTypes.AircraftControlType.START_STOP_FLY; 80 | break; 81 | } 82 | }); 83 | return root; 84 | } 85 | 86 | @Override 87 | public void onDestroyView() { 88 | super.onDestroyView(); 89 | unbinder.unbind(); 90 | } 91 | 92 | @Override 93 | public WaypointActuator getActuator() { 94 | float yaw = Tools.getFloat(yawAngle.getText().toString(), 0); 95 | WaypointAircraftControlRotateYawParam yawParam = new WaypointAircraftControlRotateYawParam.Builder() 96 | .setDirection(boxYawClockwise.isChecked() ? WaypointV2MissionTypes.WaypointV2TurnMode.CLOCKWISE : WaypointV2MissionTypes.WaypointV2TurnMode.COUNTER_CLOCKWISE) 97 | .setRelative(boxYawRelative.isChecked()) 98 | .setYawAngle(yaw) 99 | .build(); 100 | WaypointAircraftControlStartStopFlyParam startParam = new WaypointAircraftControlStartStopFlyParam.Builder() 101 | .setStartFly(boxStartStopFly.isChecked()) 102 | .build(); 103 | WaypointAircraftControlParam controlParam = new WaypointAircraftControlParam.Builder() 104 | .setAircraftControlType(type) 105 | .setFlyControlParam(startParam) 106 | .setRotateYawParam(yawParam) 107 | .build(); 108 | 109 | return new WaypointActuator.Builder() 110 | .setActuatorType(ActionTypes.ActionActuatorType.AIRCRAFT_CONTROL) 111 | .setAircraftControlActuatorParam(controlParam) 112 | .build(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/actuator/CameraActuatorFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.actuator; 2 | 3 | import android.graphics.PointF; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.EditText; 9 | import android.widget.RadioButton; 10 | import android.widget.RadioGroup; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | import androidx.fragment.app.Fragment; 15 | 16 | import com.dji.GSDemo.GoogleMap.R; 17 | import com.dji.GSDemo.GoogleMap.Tools; 18 | 19 | import butterknife.BindView; 20 | import butterknife.ButterKnife; 21 | import butterknife.Unbinder; 22 | import dji.common.mission.waypointv2.Action.ActionTypes; 23 | import dji.common.mission.waypointv2.Action.WaypointActuator; 24 | import dji.common.mission.waypointv2.Action.WaypointCameraActuatorParam; 25 | import dji.common.mission.waypointv2.Action.WaypointCameraFocusParam; 26 | import dji.common.mission.waypointv2.Action.WaypointCameraZoomParam; 27 | 28 | /** 29 | * A simple {@link Fragment} subclass. 30 | * Use the {@link CameraActuatorFragment#newInstance} factory method to 31 | * create an instance of this fragment. 32 | */ 33 | public class CameraActuatorFragment extends Fragment implements IActuatorCallback{ 34 | 35 | @BindView(R.id.rb_shoot_single_photo) 36 | RadioButton rbShootSinglePhoto; 37 | @BindView(R.id.rb_start_record_video) 38 | RadioButton rbStartRecordVideo; 39 | @BindView(R.id.rb_stop_record_video) 40 | RadioButton rbStopRecordVideo; 41 | @BindView(R.id.rb_focus) 42 | RadioButton rbFocus; 43 | @BindView(R.id.rb_zoom) 44 | RadioButton rbZoom; 45 | @BindView(R.id.radio_camera_type) 46 | RadioGroup radioCameraType; 47 | @BindView(R.id.et_zoom) 48 | EditText etZoom; 49 | 50 | @BindView(R.id.et_focus_target_x) 51 | EditText etFocusTargetX; 52 | @BindView(R.id.et_focus_target_y) 53 | EditText etFocusTargetY; 54 | 55 | Unbinder unbinder; 56 | 57 | public static CameraActuatorFragment newInstance() { 58 | CameraActuatorFragment fragment = new CameraActuatorFragment(); 59 | return fragment; 60 | } 61 | 62 | @Override 63 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 64 | View root = inflater.inflate(R.layout.fragment_camera_actuator, container, false); 65 | unbinder = ButterKnife.bind(this, root); 66 | return root; 67 | } 68 | 69 | @Override 70 | public void onDestroyView() { 71 | super.onDestroyView(); 72 | unbinder.unbind(); 73 | } 74 | 75 | @Override 76 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 77 | super.onViewCreated(view, savedInstanceState); 78 | radioCameraType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 79 | @Override 80 | public void onCheckedChanged(RadioGroup group, int checkedId) { 81 | switch (checkedId) { 82 | case R.id.rb_shoot_single_photo: 83 | hide(R.id.et_focus_target_x, R.id.et_focus_target_y, R.id.et_zoom); 84 | break; 85 | case R.id.rb_start_record_video: 86 | hide(R.id.et_focus_target_x, R.id.et_focus_target_y, R.id.et_zoom); 87 | break; 88 | case R.id.rb_stop_record_video: 89 | hide(R.id.et_focus_target_x, R.id.et_focus_target_y, R.id.et_zoom); 90 | break; 91 | case R.id.rb_focus: 92 | hide(R.id.et_zoom); 93 | show(R.id.et_focus_target_x, R.id.et_focus_target_y); 94 | break; 95 | case R.id.rb_zoom: 96 | show(R.id.et_zoom); 97 | hide(R.id.et_focus_target_x, R.id.et_focus_target_y); 98 | break; 99 | } 100 | } 101 | }); 102 | } 103 | 104 | private void hide(int... ids) { 105 | for (int id : ids) { 106 | getView().findViewById(id).setVisibility(View.GONE); 107 | } 108 | } 109 | 110 | private void show(int... ids) { 111 | for (int id : ids) { 112 | getView().findViewById(id).setVisibility(View.VISIBLE); 113 | } 114 | } 115 | 116 | @Override 117 | public WaypointActuator getActuator() { 118 | int focalLength = Tools.getInt(etZoom.getText().toString(), 10); 119 | ActionTypes.CameraOperationType type = getType(); 120 | WaypointCameraFocusParam focusParam = new WaypointCameraFocusParam.Builder() 121 | .focusTarget(new PointF(Tools.getFloat(etFocusTargetX.getText().toString(), 0.5f), Tools.getFloat(etFocusTargetY.getText().toString(), 0.5f))) 122 | .build(); 123 | WaypointCameraZoomParam zoomParam = new WaypointCameraZoomParam.Builder() 124 | .setFocalLength(focalLength) 125 | .build(); 126 | WaypointCameraActuatorParam actuatorParam = new WaypointCameraActuatorParam.Builder() 127 | .setCameraOperationType(type) 128 | .setFocusParam(focusParam) 129 | .setZoomParam(zoomParam) 130 | .build(); 131 | return new WaypointActuator.Builder() 132 | .setActuatorType(ActionTypes.ActionActuatorType.CAMERA) 133 | .setCameraActuatorParam(actuatorParam) 134 | .build(); 135 | } 136 | 137 | public ActionTypes.CameraOperationType getType() { 138 | switch (radioCameraType.getCheckedRadioButtonId()) { 139 | case R.id.rb_shoot_single_photo: 140 | return ActionTypes.CameraOperationType.SHOOT_SINGLE_PHOTO; 141 | case R.id.rb_start_record_video: 142 | return ActionTypes.CameraOperationType.START_RECORD_VIDEO; 143 | case R.id.rb_stop_record_video: 144 | return ActionTypes.CameraOperationType.STOP_RECORD_VIDEO; 145 | case R.id.rb_focus: 146 | return ActionTypes.CameraOperationType.FOCUS; 147 | case R.id.rb_zoom: 148 | return ActionTypes.CameraOperationType.ZOOM; 149 | } 150 | return ActionTypes.CameraOperationType.SHOOT_SINGLE_PHOTO; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/actuator/GimbalActuatorFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.actuator; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.EditText; 8 | import android.widget.RadioButton; 9 | import android.widget.RadioGroup; 10 | import android.widget.TextView; 11 | import android.widget.Toast; 12 | 13 | import androidx.appcompat.widget.AppCompatCheckBox; 14 | import androidx.fragment.app.Fragment; 15 | 16 | import com.dji.GSDemo.GoogleMap.R; 17 | import com.dji.GSDemo.GoogleMap.Tools; 18 | import com.dji.GSDemo.GoogleMap.fragment.trigger.ITriggerCallback; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | import butterknife.Unbinder; 23 | import dji.common.gimbal.Rotation; 24 | import dji.common.gimbal.RotationMode; 25 | import dji.common.mission.waypointv2.Action.ActionTypes; 26 | import dji.common.mission.waypointv2.Action.WaypointActuator; 27 | import dji.common.mission.waypointv2.Action.WaypointGimbalActuatorParam; 28 | 29 | /** 30 | * A simple {@link Fragment} subclass. 31 | * Use the {@link GimbalActuatorFragment#newInstance} factory method to 32 | * create an instance of this fragment. 33 | */ 34 | public class GimbalActuatorFragment extends Fragment implements IActuatorCallback { 35 | private ITriggerCallback callback; 36 | 37 | Unbinder unbinder; 38 | @BindView(R.id.tv_title) 39 | TextView tvTitle; 40 | @BindView(R.id.rb_rotate_gimbal) 41 | RadioButton rbRotateGimbal; 42 | @BindView(R.id.rb_aircraft_control_gimbal) 43 | RadioButton rbAircraftControlGimbal; 44 | @BindView(R.id.radio_gimbal_type) 45 | RadioGroup radioGimbalType; 46 | @BindView(R.id.et_gimbal_roll) 47 | EditText etGimbalRoll; 48 | @BindView(R.id.et_gimbal_pitch) 49 | EditText etGimbalPitch; 50 | @BindView(R.id.et_gimbal_yaw) 51 | EditText etGimbalYaw; 52 | @BindView(R.id.et_duration_time) 53 | EditText etDurationTime; 54 | @BindView(R.id.box_absulote) 55 | AppCompatCheckBox boxAbsulote; 56 | @BindView(R.id.box_rollIgnore) 57 | AppCompatCheckBox boxRollIgnore; 58 | @BindView(R.id.box_pitch_ignore) 59 | AppCompatCheckBox boxPitchIgnore; 60 | @BindView(R.id.box_yaw_igore) 61 | AppCompatCheckBox boxYawIgore; 62 | @BindView(R.id.box_abs_yaw_ref) 63 | AppCompatCheckBox boxAbsYawRef; 64 | 65 | public static GimbalActuatorFragment newInstance(ITriggerCallback callback) { 66 | GimbalActuatorFragment fragment = new GimbalActuatorFragment(callback); 67 | return fragment; 68 | } 69 | 70 | private GimbalActuatorFragment(ITriggerCallback callback) { 71 | this.callback = callback; 72 | } 73 | 74 | @Override 75 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 76 | View root = inflater.inflate(R.layout.fragment_gimbal_actuator, container, false); 77 | unbinder = ButterKnife.bind(this, root); 78 | flush(); 79 | return root; 80 | } 81 | 82 | @Override 83 | public void onDestroyView() { 84 | super.onDestroyView(); 85 | unbinder.unbind(); 86 | } 87 | 88 | public void flush() { 89 | if (getContext() == null) { 90 | return; 91 | } 92 | if (callback.getTrigger() == null) { 93 | Toast.makeText(getContext(), "please select trigger.", Toast.LENGTH_SHORT).show(); 94 | rbAircraftControlGimbal.setVisibility(View.GONE); 95 | rbRotateGimbal.setVisibility(View.VISIBLE); 96 | return; 97 | } 98 | if (callback.getTrigger().getTriggerType() == ActionTypes.ActionTriggerType.TRAJECTORY) { 99 | rbAircraftControlGimbal.setVisibility(View.VISIBLE); 100 | rbRotateGimbal.setVisibility(View.GONE); 101 | } else { 102 | rbAircraftControlGimbal.setVisibility(View.GONE); 103 | rbRotateGimbal.setVisibility(View.VISIBLE); 104 | } 105 | } 106 | 107 | @Override 108 | public WaypointActuator getActuator() { 109 | float roll = Tools.getFloat(etGimbalRoll.getText().toString(), 0.1f); 110 | float pitch = Tools.getFloat(etGimbalPitch.getText().toString(), 0.2f); 111 | float yaw = Tools.getFloat(etGimbalYaw.getText().toString(), 0.3f); 112 | int duration = Tools.getInt(etDurationTime.getText().toString(), 10); 113 | ActionTypes.GimbalOperationType type = getType(); 114 | 115 | Rotation.Builder rotationBuilder = new Rotation.Builder(); 116 | if (!boxRollIgnore.isChecked()) { 117 | rotationBuilder.roll(roll); 118 | } 119 | if (!boxPitchIgnore.isChecked()) { 120 | rotationBuilder.pitch(pitch); 121 | } 122 | if (!boxYawIgore.isChecked()) { 123 | rotationBuilder.yaw(yaw); 124 | } 125 | if (boxAbsulote.isChecked()) { 126 | rotationBuilder.mode(RotationMode.ABSOLUTE_ANGLE); 127 | } else { 128 | rotationBuilder.mode(RotationMode.RELATIVE_ANGLE); 129 | } 130 | rotationBuilder.time(duration); 131 | WaypointGimbalActuatorParam actuatorParam = new WaypointGimbalActuatorParam.Builder() 132 | .operationType(type) 133 | .rotation(rotationBuilder.build()) 134 | .build(); 135 | return new WaypointActuator.Builder() 136 | .setActuatorType(ActionTypes.ActionActuatorType.GIMBAL) 137 | .setGimbalActuatorParam(actuatorParam) 138 | .build(); 139 | } 140 | 141 | public ActionTypes.GimbalOperationType getType() { 142 | switch (radioGimbalType.getCheckedRadioButtonId()) { 143 | case R.id.rb_rotate_gimbal: 144 | return ActionTypes.GimbalOperationType.ROTATE_GIMBAL; 145 | case R.id.rb_aircraft_control_gimbal: 146 | // Rotates the gimbal. Only valid when the trigger type is `TRAJECTORY`. 147 | return ActionTypes.GimbalOperationType.AIRCRAFT_CONTROL_GIMBAL; 148 | } 149 | return ActionTypes.GimbalOperationType.UNKNOWN; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/actuator/IActuatorCallback.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.actuator; 2 | 3 | import dji.common.mission.waypointv2.Action.WaypointActuator; 4 | 5 | public interface IActuatorCallback { 6 | WaypointActuator getActuator(); 7 | } 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/AssociateTriggerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.EditText; 8 | import android.widget.RadioGroup; 9 | 10 | import androidx.appcompat.widget.AppCompatRadioButton; 11 | 12 | import com.dji.GSDemo.GoogleMap.R; 13 | import com.dji.GSDemo.GoogleMap.Tools; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import butterknife.Unbinder; 18 | import dji.common.mission.waypointv2.Action.ActionTypes; 19 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 20 | import dji.common.mission.waypointv2.Action.WaypointV2AssociateTriggerParam; 21 | 22 | public class AssociateTriggerFragment extends BaseTriggerFragment implements ITriggerCallback { 23 | 24 | 25 | @BindView(R.id.et_wait_time) 26 | EditText etWaitTime; 27 | Unbinder unbinder; 28 | @BindView(R.id.radio_group_type) 29 | RadioGroup radioGroupType; 30 | @BindView(R.id.rb_sync) 31 | AppCompatRadioButton rbSync; 32 | @BindView(R.id.rb_after) 33 | AppCompatRadioButton rbAfter; 34 | @BindView(R.id.et_action_id) 35 | EditText etActionId; 36 | 37 | public AssociateTriggerFragment() { 38 | } 39 | 40 | public static AssociateTriggerFragment newInstance() { 41 | AssociateTriggerFragment fragment = new AssociateTriggerFragment(); 42 | return fragment; 43 | } 44 | 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 47 | View root = inflater.inflate(R.layout.fragment_associate_trigger, container, false); 48 | unbinder = ButterKnife.bind(this, root); 49 | return root; 50 | } 51 | 52 | @Override 53 | public void onDestroyView() { 54 | super.onDestroyView(); 55 | unbinder.unbind(); 56 | } 57 | 58 | @Override 59 | public WaypointTrigger getTrigger() { 60 | float waitTime = Tools.getFloat(etWaitTime.getText().toString(), 1); 61 | ActionTypes.AssociatedTimingType type = rbSync.isChecked() 62 | ? ActionTypes.AssociatedTimingType.SIMULTANEOUSLY : ActionTypes.AssociatedTimingType.AFTER_FINISHED; 63 | int actionId = Tools.getInt(etActionId.getText().toString(), 1); 64 | 65 | if (actionId > size) { 66 | Tools.showToast(getActivity(), "actionId can`t bigger existed action size, size=" + size); 67 | return null; 68 | } 69 | 70 | WaypointV2AssociateTriggerParam param = new WaypointV2AssociateTriggerParam.Builder() 71 | .setAssociateType(type) 72 | .setWaitingTime(waitTime) 73 | .setAssociateActionID(actionId) 74 | .build(); 75 | return new WaypointTrigger.Builder() 76 | .setTriggerType(ActionTypes.ActionTriggerType.ASSOCIATE) 77 | .setAssociateParam(param) 78 | .build(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/BaseTriggerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | import androidx.fragment.app.Fragment; 4 | 5 | public class BaseTriggerFragment extends Fragment { 6 | protected int size; 7 | 8 | public void setSize(int size) { 9 | this.size = size; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/ITriggerCallback.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 4 | 5 | public interface ITriggerCallback { 6 | WaypointTrigger getTrigger(); 7 | } 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/ReachPointTriggerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.EditText; 9 | 10 | import androidx.fragment.app.Fragment; 11 | 12 | import com.dji.GSDemo.GoogleMap.R; 13 | import com.dji.GSDemo.GoogleMap.Tools; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import butterknife.Unbinder; 18 | import dji.common.mission.waypointv2.Action.ActionTypes; 19 | import dji.common.mission.waypointv2.Action.WaypointReachPointTriggerParam; 20 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 21 | 22 | /** 23 | * A simple {@link Fragment} subclass. 24 | * Use the {@link ReachPointTriggerFragment#newInstance} factory method to 25 | * create an instance of this fragment. 26 | */ 27 | public class ReachPointTriggerFragment extends BaseTriggerFragment implements ITriggerCallback { 28 | 29 | 30 | @BindView(R.id.et_start_index) 31 | EditText etStartIndex; 32 | @BindView(R.id.et_auto_terminate_count) 33 | EditText etAutoTerminateCount; 34 | Unbinder unbinder; 35 | 36 | public static ReachPointTriggerFragment newInstance() { 37 | ReachPointTriggerFragment fragment = new ReachPointTriggerFragment(); 38 | return fragment; 39 | } 40 | 41 | @Override 42 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 43 | View root = inflater.inflate(R.layout.fragment_simple_reach_point_trigger, container, false); 44 | unbinder = ButterKnife.bind(this, root); 45 | return root; 46 | } 47 | 48 | @Override 49 | public WaypointTrigger getTrigger() { 50 | int start = Tools.getInt(etStartIndex.getText().toString(), 1); 51 | int count = Tools.getInt(etAutoTerminateCount.getText().toString(), 1); 52 | 53 | if (start > size) { 54 | Tools.showToast(getActivity(), "start can`t bigger waypoint mission size, size=" + size); 55 | return null; 56 | } 57 | 58 | WaypointReachPointTriggerParam param = new WaypointReachPointTriggerParam.Builder() 59 | .setAutoTerminateCount(count) 60 | .setStartIndex(start) 61 | .build(); 62 | return new WaypointTrigger.Builder() 63 | .setTriggerType(ActionTypes.ActionTriggerType.REACH_POINT) 64 | .setReachPointParam(param) 65 | .build(); 66 | } 67 | 68 | @Override 69 | public void onDestroyView() { 70 | super.onDestroyView(); 71 | unbinder.unbind(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/SimpleIntervalTriggerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.EditText; 8 | import android.widget.RadioGroup; 9 | 10 | import androidx.appcompat.widget.AppCompatRadioButton; 11 | import androidx.fragment.app.Fragment; 12 | 13 | import com.dji.GSDemo.GoogleMap.R; 14 | import com.dji.GSDemo.GoogleMap.Tools; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import butterknife.Unbinder; 19 | import dji.common.mission.waypointv2.Action.ActionTypes; 20 | import dji.common.mission.waypointv2.Action.WaypointIntervalTriggerParam; 21 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 22 | 23 | /** 24 | * A simple {@link Fragment} subclass. 25 | * Use the {@link SimpleIntervalTriggerFragment#newInstance} factory method to 26 | * create an instance of this fragment. 27 | */ 28 | public class SimpleIntervalTriggerFragment extends BaseTriggerFragment implements ITriggerCallback { 29 | 30 | 31 | @BindView(R.id.et_start_index) 32 | EditText etStartIndex; 33 | @BindView(R.id.radio_group_type) 34 | RadioGroup radioGroupType; 35 | @BindView(R.id.et_value) 36 | EditText etValue; 37 | @BindView(R.id.rb_distance) 38 | AppCompatRadioButton rbDistance; 39 | @BindView(R.id.rb_time) 40 | AppCompatRadioButton rbTime; 41 | 42 | Unbinder unbinder; 43 | 44 | public static SimpleIntervalTriggerFragment newInstance() { 45 | SimpleIntervalTriggerFragment fragment = new SimpleIntervalTriggerFragment(); 46 | return fragment; 47 | } 48 | 49 | @Override 50 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 51 | View root = inflater.inflate(R.layout.fragment_simple_interval_trigger, container, false); 52 | unbinder = ButterKnife.bind(this, root); 53 | return root; 54 | } 55 | 56 | @Override 57 | public WaypointTrigger getTrigger() { 58 | float value = Tools.getFloat(etValue.getText().toString(), 1.1f); 59 | int start = Tools.getInt(etStartIndex.getText().toString(), 1); 60 | 61 | if (start > size) { 62 | Tools.showToast(getActivity(), "start can`t bigger waypoint mission size, size=" + size); 63 | return null; 64 | } 65 | 66 | ActionTypes.ActionIntervalType type = rbDistance.isChecked() 67 | ? ActionTypes.ActionIntervalType.DISTANCE : ActionTypes.ActionIntervalType.TIME; 68 | WaypointIntervalTriggerParam param = new WaypointIntervalTriggerParam.Builder() 69 | .setStartIndex(start) 70 | .setInterval(value) 71 | .setType(type) 72 | .build(); 73 | return new WaypointTrigger.Builder() 74 | .setTriggerType(ActionTypes.ActionTriggerType.SIMPLE_INTERVAL) 75 | .setIntervalTriggerParam(param) 76 | .build(); 77 | } 78 | 79 | @Override 80 | public void onDestroyView() { 81 | super.onDestroyView(); 82 | unbinder.unbind(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/java/com/dji/GSDemo/GoogleMap/fragment/trigger/TrajectoryTriggerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dji.GSDemo.GoogleMap.fragment.trigger; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.EditText; 9 | 10 | import androidx.fragment.app.Fragment; 11 | 12 | import com.dji.GSDemo.GoogleMap.R; 13 | import com.dji.GSDemo.GoogleMap.Tools; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import butterknife.Unbinder; 18 | import dji.common.mission.waypointv2.Action.ActionTypes; 19 | import dji.common.mission.waypointv2.Action.WaypointTrajectoryTriggerParam; 20 | import dji.common.mission.waypointv2.Action.WaypointTrigger; 21 | 22 | /** 23 | * A simple {@link Fragment} subclass. 24 | * Use the {@link TrajectoryTriggerFragment#newInstance} factory method to 25 | * create an instance of this fragment. 26 | */ 27 | public class TrajectoryTriggerFragment extends BaseTriggerFragment implements ITriggerCallback { 28 | 29 | @BindView(R.id.et_start_index) 30 | EditText etStartIndex; 31 | @BindView(R.id.et_end_index) 32 | EditText etEndIndex; 33 | Unbinder unbinder; 34 | 35 | public static TrajectoryTriggerFragment newInstance() { 36 | TrajectoryTriggerFragment fragment = new TrajectoryTriggerFragment(); 37 | return fragment; 38 | } 39 | 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 42 | View root = inflater.inflate(R.layout.fragment_trajectory_trigger, container, false); 43 | unbinder = ButterKnife.bind(this, root); 44 | return root; 45 | } 46 | 47 | @Override 48 | public WaypointTrigger getTrigger() { 49 | int start = Tools.getInt(etStartIndex.getText().toString(), 1); 50 | int end = Tools.getInt(etEndIndex.getText().toString(), 1); 51 | 52 | WaypointTrajectoryTriggerParam param = new WaypointTrajectoryTriggerParam.Builder() 53 | .setEndIndex(end) 54 | .setStartIndex(start) 55 | .build(); 56 | return new WaypointTrigger.Builder() 57 | .setTriggerType(ActionTypes.ActionTriggerType.TRAJECTORY) 58 | .setTrajectoryParam(param) 59 | .build(); 60 | } 61 | 62 | @Override 63 | public void onDestroyView() { 64 | super.onDestroyView(); 65 | unbinder.unbind(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/aircraft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-GSDemo-GoogleMap/9f0ad963b9512af2408c5dd3419aa8321534a75d/GSDemo/app/src/main/res/drawable/aircraft.png -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-GSDemo-GoogleMap/9f0ad963b9512af2408c5dd3419aa8321534a75d/GSDemo/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/round_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/round_btn_disable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/round_btn_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/round_btn_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/drawable/selector_white_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /GSDemo/app/src/main/res/layout/activity_connection.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 33 | 34 |