├── .gitignore ├── LICENSE.txt ├── P4MissionsDemo ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── dji │ │ │ └── P4MissionsDemo │ │ │ ├── DJIDemoApplication.java │ │ │ ├── DemoBaseActivity.java │ │ │ ├── MApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── MultiTrackingView.java │ │ │ ├── PointingTestActivity.java │ │ │ ├── TrackingTestActivity.java │ │ │ └── Utils.java │ │ └── res │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ ├── back_button_disable.png │ │ ├── back_button_normal.png │ │ ├── back_button_press.png │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ │ ├── drawable │ │ ├── black_rectangle.9.png │ │ ├── mission_other_icon.png │ │ ├── mission_stop.png │ │ ├── pointing_start.png │ │ ├── selector_back_button.xml │ │ ├── selector_button.xml │ │ ├── visual_point_fail.png │ │ ├── visual_point_now.png │ │ ├── visual_point_tag.png │ │ ├── visual_track_cannotconfirm.png │ │ ├── visual_track_highconfidence.png │ │ ├── visual_track_lowconfidence.png │ │ ├── visual_track_needconfirm.png │ │ ├── visual_track_now.9.png │ │ ├── visual_track_target_bg.png │ │ ├── visual_track_weak.9.png │ │ └── white_rect.9.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_pointing_test.xml │ │ ├── activity_tracking_test.xml │ │ ├── demo_info_item.xml │ │ └── layout_multi_tracking.xml │ │ ├── raw │ │ └── keep.xml │ │ ├── values-v11 │ │ └── styles.xml │ │ ├── values-v14 │ │ └── styles.xml │ │ └── values │ │ ├── color.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── local.properties.bak └── settings.gradle └── 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 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | Copyright (c) 2019 DJI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /P4MissionsDemo/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 22 | 23 | } 24 | 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | } 30 | debug { 31 | shrinkResources true 32 | minifyEnabled true 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | 37 | dexOptions { 38 | javaMaxHeapSize "4g" 39 | } 40 | 41 | packagingOptions { 42 | doNotStrip "*/*/libdjivideo.so" 43 | doNotStrip "*/*/libSDKRelativeJNI.so" 44 | doNotStrip "*/*/libFlyForbid.so" 45 | doNotStrip "*/*/libduml_vision_bokeh.so" 46 | doNotStrip "*/*/libyuv2.so" 47 | doNotStrip "*/*/libGroudStation.so" 48 | doNotStrip "*/*/libFRCorkscrew.so" 49 | doNotStrip "*/*/libUpgradeVerify.so" 50 | doNotStrip "*/*/libFR.so" 51 | doNotStrip "*/*/libDJIFlySafeCore.so" 52 | doNotStrip "*/*/libdjifs_jni.so" 53 | doNotStrip "*/*/libsfjni.so" 54 | doNotStrip "*/*/libDJICommonJNI.so" 55 | doNotStrip "*/*/libDJICSDKCommon.so" 56 | doNotStrip "*/*/libDJIUpgradeCore.so" 57 | doNotStrip "*/*/libDJIUpgradeJNI.so" 58 | exclude 'META-INF/rxjava.properties' 59 | } 60 | 61 | compileOptions { 62 | sourceCompatibility JavaVersion.VERSION_1_8 63 | targetCompatibility JavaVersion.VERSION_1_8 64 | } 65 | } 66 | 67 | 68 | dependencies { 69 | implementation 'androidx.multidex:multidex:2.0.1' 70 | implementation 'com.squareup:otto:1.3.8' 71 | implementation('com.dji:dji-sdk:4.15', { 72 | /** 73 | * Uncomment the "library-anti-distortion" if your app does not need Anti Distortion for Mavic 2 Pro and Mavic 2 Zoom. 74 | * Uncomment the "fly-safe-database" if you need database for release, or we will download it when DJISDKManager.getInstance().registerApp 75 | * is called. 76 | * Both will greatly reducing the size of the APK. 77 | */ 78 | exclude module: 'library-anti-distortion' 79 | //exclude module: 'fly-safe-database' 80 | }) 81 | compileOnly 'com.dji:dji-sdk-provided:4.15' 82 | 83 | implementation 'androidx.appcompat:appcompat:1.2.0' 84 | implementation 'androidx.core:core:1.3.2' 85 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 86 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 87 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 88 | implementation 'androidx.annotation:annotation:1.2.0' 89 | implementation fileTree(include: ['*.jar'], dir: 'libs') 90 | 91 | } 92 | -------------------------------------------------------------------------------- /P4MissionsDemo/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------------> -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 90 | 91 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/DJIDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 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 android.util.Log; 10 | import android.widget.Toast; 11 | 12 | import androidx.core.content.ContextCompat; 13 | 14 | import dji.sdk.base.BaseComponent; 15 | import dji.sdk.base.BaseProduct; 16 | import dji.sdk.camera.Camera; 17 | import dji.sdk.products.Aircraft; 18 | import dji.sdk.sdkmanager.DJISDKInitEvent; 19 | import dji.sdk.sdkmanager.DJISDKManager; 20 | import dji.common.error.DJIError; 21 | import dji.common.error.DJISDKError; 22 | 23 | public class DJIDemoApplication extends Application{ 24 | 25 | private static final String TAG = DJIDemoApplication.class.getName(); 26 | 27 | public static final String FLAG_CONNECTION_CHANGE = "dji_sdk_connection_change"; 28 | 29 | private DJISDKManager.SDKManagerCallback mDJISDKManagerCallback; 30 | private static BaseProduct mProduct; 31 | public Handler mHandler; 32 | 33 | private Application instance; 34 | 35 | public void setContext(Application application) { 36 | instance = application; 37 | } 38 | 39 | @Override 40 | public Context getApplicationContext() { 41 | return instance; 42 | } 43 | 44 | public DJIDemoApplication() { 45 | 46 | } 47 | 48 | public static synchronized BaseProduct getProductInstance() { 49 | if (null == mProduct) { 50 | mProduct = DJISDKManager.getInstance().getProduct(); 51 | } 52 | return mProduct; 53 | } 54 | 55 | public static synchronized Camera getCameraInstance() { 56 | 57 | if (getProductInstance() == null) return null; 58 | 59 | Camera camera = null; 60 | if (getProductInstance() instanceof Aircraft){ 61 | camera = ((Aircraft) getProductInstance()).getCamera(); 62 | } 63 | return camera; 64 | } 65 | 66 | @Override 67 | public void onCreate() { 68 | super.onCreate(); 69 | 70 | mHandler = new Handler(Looper.getMainLooper()); 71 | 72 | /** 73 | * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to 74 | * the SDK Registration result and the product changing. 75 | */ 76 | mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() { 77 | 78 | //Listens to the SDK registration result 79 | @Override 80 | public void onRegister(DJIError error) { 81 | 82 | if(error == DJISDKError.REGISTRATION_SUCCESS) { 83 | 84 | Handler handler = new Handler(Looper.getMainLooper()); 85 | handler.post(new Runnable() { 86 | @Override 87 | public void run() { 88 | Toast.makeText(getApplicationContext(), "Register Success", Toast.LENGTH_LONG).show(); 89 | } 90 | }); 91 | 92 | DJISDKManager.getInstance().startConnectionToProduct(); 93 | 94 | } else { 95 | 96 | Handler handler = new Handler(Looper.getMainLooper()); 97 | handler.post(new Runnable() { 98 | 99 | @Override 100 | public void run() { 101 | Toast.makeText(getApplicationContext(), "Register sdk fails, check network is available", Toast.LENGTH_LONG).show(); 102 | } 103 | }); 104 | 105 | } 106 | Log.e("TAG", error.toString()); 107 | } 108 | 109 | @Override 110 | public void onProductDisconnect() { 111 | Log.d("TAG", "onProductDisconnect"); 112 | notifyStatusChange(); 113 | } 114 | @Override 115 | public void onProductConnect(BaseProduct baseProduct) { 116 | Log.d("TAG", String.format("onProductConnect newProduct:%s", baseProduct)); 117 | notifyStatusChange(); 118 | 119 | } 120 | 121 | @Override 122 | public void onProductChanged(BaseProduct baseProduct) { 123 | 124 | } 125 | 126 | @Override 127 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent, 128 | BaseComponent newComponent) { 129 | if (newComponent != null) { 130 | newComponent.setComponentListener(new BaseComponent.ComponentListener() { 131 | 132 | @Override 133 | public void onConnectivityChange(boolean isConnected) { 134 | Log.d("TAG", "onComponentConnectivityChanged: " + isConnected); 135 | notifyStatusChange(); 136 | } 137 | }); 138 | } 139 | 140 | Log.d("TAG", 141 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s", 142 | componentKey, 143 | oldComponent, 144 | newComponent)); 145 | 146 | } 147 | @Override 148 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) { 149 | 150 | } 151 | 152 | @Override 153 | public void onDatabaseDownloadProgress(long l, long l1) { 154 | 155 | } 156 | }; 157 | //Check the permissions before registering the application for android system 6.0 above. 158 | int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE); 159 | int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE); 160 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (permissionCheck == 0 && permissionCheck2 == 0)) { 161 | //This is used to start SDK services and initiate SDK. 162 | DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback); 163 | Toast.makeText(getApplicationContext(), "registering, pls wait...", Toast.LENGTH_LONG).show(); 164 | 165 | } else { 166 | Toast.makeText(getApplicationContext(), "Please check if the permission is granted.", Toast.LENGTH_LONG).show(); 167 | } 168 | 169 | } 170 | 171 | private void notifyStatusChange() { 172 | mHandler.removeCallbacks(updateRunnable); 173 | mHandler.postDelayed(updateRunnable, 500); 174 | } 175 | 176 | private Runnable updateRunnable = new Runnable() { 177 | 178 | @Override 179 | public void run() { 180 | Intent intent = new Intent(FLAG_CONNECTION_CHANGE); 181 | getApplicationContext().sendBroadcast(intent); 182 | } 183 | }; 184 | 185 | } 186 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/DemoBaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.graphics.SurfaceTexture; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.TextureView; 11 | import android.view.TextureView.SurfaceTextureListener; 12 | import android.view.View; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import androidx.fragment.app.FragmentActivity; 17 | 18 | import java.util.ArrayList; 19 | import dji.sdk.camera.VideoFeeder; 20 | import dji.sdk.codec.DJICodecManager; 21 | import dji.common.product.Model; 22 | import dji.sdk.camera.Camera; 23 | import dji.sdk.base.BaseProduct; 24 | import dji.sdk.products.Aircraft; 25 | 26 | public class DemoBaseActivity extends FragmentActivity implements SurfaceTextureListener { 27 | 28 | private static final String TAG = MainActivity.class.getName(); 29 | protected VideoFeeder.VideoDataListener mReceivedVideoDataListener = null; 30 | protected DJICodecManager mCodecManager = null; 31 | private BaseProduct mProduct; 32 | 33 | //To store index chosen in PopupNumberPicker listener 34 | protected static int[] INDEX_CHOSEN = {-1, -1, -1}; 35 | 36 | protected TextView mConnectStatusTextView; 37 | 38 | protected TextureView mVideoSurface = null; 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | 44 | IntentFilter filter = new IntentFilter(); 45 | filter.addAction(DJIDemoApplication.FLAG_CONNECTION_CHANGE); 46 | registerReceiver(mReceiver, filter); 47 | 48 | mVideoSurface = (TextureView) findViewById(R.id.video_previewer_surface); 49 | mConnectStatusTextView = (TextView) findViewById(R.id.ConnectStatusTextView); 50 | 51 | if (null != mVideoSurface) { 52 | mVideoSurface.setSurfaceTextureListener(this); 53 | } 54 | 55 | // The callback for receiving the raw H264 video data for camera live view 56 | mReceivedVideoDataListener = new VideoFeeder.VideoDataListener() { 57 | 58 | @Override 59 | public void onReceive(byte[] videoBuffer, int size) { 60 | if(mCodecManager != null){ 61 | mCodecManager.sendDataToDecoder(videoBuffer, size); 62 | } 63 | } 64 | }; 65 | 66 | } 67 | 68 | protected BroadcastReceiver mReceiver = new BroadcastReceiver() { 69 | 70 | @Override 71 | public void onReceive(Context context, Intent intent) { 72 | updateTitleBar(); 73 | onProductChange(); 74 | } 75 | 76 | }; 77 | 78 | protected void onProductChange() { 79 | initPreviewer(); 80 | } 81 | 82 | @Override 83 | protected void onStart() { 84 | super.onStart(); 85 | 86 | } 87 | 88 | @Override 89 | protected void onResume() { 90 | Log.e(TAG, "onResume"); 91 | super.onResume(); 92 | updateTitleBar(); 93 | initPreviewer(); 94 | onProductChange(); 95 | 96 | if(mVideoSurface == null) { 97 | Log.e(TAG, "mVideoSurface is null"); 98 | } 99 | } 100 | 101 | @Override 102 | protected void onPause() { 103 | Log.e(TAG, "onPause"); 104 | uninitPreviewer(); 105 | super.onPause(); 106 | } 107 | 108 | @Override 109 | protected void onStop() { 110 | Log.e(TAG, "onStop"); 111 | super.onStop(); 112 | } 113 | 114 | @Override 115 | protected void onDestroy() { 116 | Log.e(TAG, "onDestroy"); 117 | unregisterReceiver(mReceiver); 118 | uninitPreviewer(); 119 | super.onDestroy(); 120 | } 121 | 122 | private void showToast(final String msg) { 123 | runOnUiThread(new Runnable() { 124 | public void run() { 125 | Toast.makeText(DemoBaseActivity.this, msg, Toast.LENGTH_SHORT).show(); 126 | } 127 | }); 128 | } 129 | 130 | private void initPreviewer() { 131 | try { 132 | mProduct = DJIDemoApplication.getProductInstance(); 133 | } catch (Exception exception) { 134 | mProduct = null; 135 | } 136 | 137 | if (mProduct == null || !mProduct.isConnected()) { 138 | Log.d(TAG, "Disconnect"); 139 | } else { 140 | if (null != mVideoSurface) { 141 | mVideoSurface.setSurfaceTextureListener(this); 142 | } 143 | 144 | if (!mProduct.getModel().equals(Model.UNKNOWN_AIRCRAFT)) { 145 | VideoFeeder.getInstance().getPrimaryVideoFeed().addVideoDataListener(mReceivedVideoDataListener); 146 | } 147 | } 148 | } 149 | 150 | private void uninitPreviewer() { 151 | Camera camera = DJIDemoApplication.getCameraInstance(); 152 | if (camera != null){ 153 | // Reset the callback 154 | VideoFeeder.getInstance().getPrimaryVideoFeed().removeVideoDataListener(mReceivedVideoDataListener); 155 | } 156 | } 157 | 158 | /** 159 | * @param surface 160 | * @param width 161 | * @param height 162 | * @see android.view.TextureView.SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, 163 | * int, int) 164 | */ 165 | @Override 166 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 167 | if (mCodecManager == null) { 168 | mCodecManager = new DJICodecManager(this, surface, width, height); 169 | } 170 | } 171 | 172 | /** 173 | * @param surface 174 | * @param width 175 | * @param height 176 | * @see android.view.TextureView.SurfaceTextureListener#onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, 177 | * int, int) 178 | */ 179 | @Override 180 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 181 | 182 | } 183 | 184 | /** 185 | * @param surface 186 | * @return 187 | * @see android.view.TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed(android.graphics.SurfaceTexture) 188 | */ 189 | @Override 190 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 191 | if (mCodecManager != null) 192 | mCodecManager.cleanSurface(); 193 | return false; 194 | } 195 | 196 | /** 197 | * @param surface 198 | * @see android.view.TextureView.SurfaceTextureListener#onSurfaceTextureUpdated(android.graphics.SurfaceTexture) 199 | */ 200 | @Override 201 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 202 | 203 | } 204 | 205 | private void updateTitleBar() { 206 | if(mConnectStatusTextView == null) return; 207 | boolean ret = false; 208 | BaseProduct product = DJIDemoApplication.getProductInstance(); 209 | if (product != null) { 210 | if(product.isConnected()) { 211 | mConnectStatusTextView.setText(DJIDemoApplication.getProductInstance().getModel().getDisplayName() + " Connected"); 212 | ret = true; 213 | } else { 214 | if(product instanceof Aircraft) { 215 | Aircraft aircraft = (Aircraft)product; 216 | if(aircraft.getRemoteController() != null) { 217 | } 218 | if(aircraft.getRemoteController() != null && aircraft.getRemoteController().isConnected()) { 219 | mConnectStatusTextView.setText("only RC Connected"); 220 | ret = true; 221 | } 222 | } 223 | } 224 | } 225 | 226 | if(!ret) { 227 | // mConnectStatusTextView.setText("Disconnected"); 228 | } 229 | } 230 | 231 | /** 232 | * @Description : RETURN BTN RESPONSE FUNCTION 233 | * @author : andy.zhao 234 | * @param view 235 | * @return : void 236 | */ 237 | public void onReturn(View view) { 238 | this.finish(); 239 | } 240 | 241 | public void resetIndex() { 242 | INDEX_CHOSEN = new int[3]; 243 | INDEX_CHOSEN[0] = -1; 244 | INDEX_CHOSEN[1] = -1; 245 | INDEX_CHOSEN[2] = -1; 246 | } 247 | 248 | public ArrayList makeListHelper(Object[] o) { 249 | ArrayList list = new ArrayList(); 250 | for (int i = 0; i < o.length - 1; i++) { 251 | list.add(o[i].toString()); 252 | } 253 | return list; 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/MApplication.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 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 demoApplication; 11 | @Override 12 | protected void attachBaseContext(Context paramContext) { 13 | super.attachBaseContext(paramContext); 14 | Helper.install(MApplication.this); 15 | if (demoApplication == null) { 16 | demoApplication = new DJIDemoApplication(); 17 | demoApplication.setContext(this); 18 | } 19 | } 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | demoApplication.onCreate(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | import android.Manifest; 4 | import android.annotation.SuppressLint; 5 | import android.app.AlertDialog; 6 | import android.content.DialogInterface; 7 | import android.content.Intent; 8 | import android.content.pm.PackageManager; 9 | import android.os.AsyncTask; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | import android.util.Log; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.AdapterView; 16 | import android.widget.AdapterView.OnItemClickListener; 17 | import android.widget.BaseAdapter; 18 | import android.widget.ListView; 19 | import android.widget.TextView; 20 | import android.widget.Toast; 21 | 22 | import androidx.annotation.NonNull; 23 | import androidx.core.app.ActivityCompat; 24 | import androidx.core.content.ContextCompat; 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.common.useraccount.UserAccountState; 33 | import dji.common.util.CommonCallbacks; 34 | import dji.log.DJILog; 35 | import dji.sdk.base.BaseComponent; 36 | import dji.sdk.base.BaseProduct; 37 | import dji.sdk.sdkmanager.DJISDKInitEvent; 38 | import dji.sdk.sdkmanager.DJISDKManager; 39 | import dji.sdk.useraccount.UserAccountManager; 40 | 41 | public class MainActivity extends DemoBaseActivity { 42 | 43 | public static final String TAG = MainActivity.class.getName(); 44 | 45 | public String mString = null; 46 | private BaseProduct mProduct; 47 | private ArrayList demos = new ArrayList(); 48 | private ListView mListView; 49 | private DemoListAdapter mDemoListAdapter = new DemoListAdapter(); 50 | private TextView mFirmwareVersionView; 51 | 52 | private static final String[] REQUIRED_PERMISSION_LIST = new String[]{ 53 | Manifest.permission.VIBRATE, 54 | Manifest.permission.INTERNET, 55 | Manifest.permission.ACCESS_WIFI_STATE, 56 | Manifest.permission.WAKE_LOCK, 57 | Manifest.permission.ACCESS_COARSE_LOCATION, 58 | Manifest.permission.ACCESS_NETWORK_STATE, 59 | Manifest.permission.ACCESS_FINE_LOCATION, 60 | Manifest.permission.CHANGE_WIFI_STATE, 61 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 62 | Manifest.permission.BLUETOOTH, 63 | Manifest.permission.BLUETOOTH_ADMIN, 64 | Manifest.permission.READ_EXTERNAL_STORAGE, 65 | Manifest.permission.READ_PHONE_STATE, 66 | }; 67 | private List missingPermission = new ArrayList<>(); 68 | private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false); 69 | private static final int REQUEST_PERMISSION_CODE = 125; 70 | 71 | @Override 72 | protected void onCreate(Bundle savedInstanceState) { 73 | super.onCreate(savedInstanceState); 74 | 75 | checkAndRequestPermissions(); 76 | 77 | setContentView(R.layout.activity_main); 78 | 79 | mConnectStatusTextView = (TextView) findViewById(R.id.ConnectStatusTextView); 80 | 81 | mListView = (ListView)findViewById(R.id.listView); 82 | mListView.setAdapter(mDemoListAdapter); 83 | 84 | mFirmwareVersionView = (TextView)findViewById(R.id.version_tv); 85 | 86 | loadDemoList(); 87 | 88 | mDemoListAdapter.notifyDataSetChanged(); 89 | 90 | updateVersion(); 91 | 92 | } 93 | 94 | /** 95 | * Checks if there is any missing permissions, and 96 | * requests runtime permission if needed. 97 | */ 98 | private void checkAndRequestPermissions() { 99 | // Check for permissions 100 | for (String eachPermission : REQUIRED_PERMISSION_LIST) { 101 | if (ContextCompat.checkSelfPermission(this, eachPermission) != PackageManager.PERMISSION_GRANTED) { 102 | missingPermission.add(eachPermission); 103 | } 104 | } 105 | // Request for missing permissions 106 | if (!missingPermission.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 107 | ActivityCompat.requestPermissions(this, 108 | missingPermission.toArray(new String[missingPermission.size()]), 109 | REQUEST_PERMISSION_CODE); 110 | } 111 | 112 | } 113 | 114 | /** 115 | * Result of runtime permission request 116 | */ 117 | @Override 118 | public void onRequestPermissionsResult(int requestCode, 119 | @NonNull String[] permissions, 120 | @NonNull int[] grantResults) { 121 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 122 | // Check for granted permission and remove from missing list 123 | if (requestCode == REQUEST_PERMISSION_CODE) { 124 | for (int i = grantResults.length - 1; i >= 0; i--) { 125 | if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { 126 | missingPermission.remove(permissions[i]); 127 | } 128 | } 129 | } 130 | // If there is enough permission, we will start the registration 131 | if (missingPermission.isEmpty()) { 132 | startSDKRegistration(); 133 | } else { 134 | showToast("Missing permissions!!!"); 135 | } 136 | } 137 | 138 | private void startSDKRegistration() { 139 | if (isRegistrationInProgress.compareAndSet(false, true)) { 140 | AsyncTask.execute(new Runnable() { 141 | @Override 142 | public void run() { 143 | showToast( "registering, pls wait..."); 144 | DJISDKManager.getInstance().registerApp(getApplicationContext(), new DJISDKManager.SDKManagerCallback() { 145 | @Override 146 | public void onRegister(DJIError djiError) { 147 | if (djiError == DJISDKError.REGISTRATION_SUCCESS) { 148 | DJILog.e("App registration", DJISDKError.REGISTRATION_SUCCESS.getDescription()); 149 | DJISDKManager.getInstance().startConnectionToProduct(); 150 | showToast("Register Success"); 151 | } else { 152 | showToast( "Register sdk fails, check network is available"); 153 | } 154 | Log.v(TAG, djiError.getDescription()); 155 | } 156 | 157 | @Override 158 | public void onProductDisconnect() { 159 | Log.d(TAG, "onProductDisconnect"); 160 | showToast("Product Disconnected"); 161 | 162 | } 163 | @Override 164 | public void onProductConnect(BaseProduct baseProduct) { 165 | Log.d(TAG, String.format("onProductConnect newProduct:%s", baseProduct)); 166 | showToast("Product Connected"); 167 | 168 | } 169 | 170 | @Override 171 | public void onProductChanged(BaseProduct baseProduct) { 172 | 173 | } 174 | 175 | @Override 176 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent, 177 | BaseComponent newComponent) { 178 | 179 | if (newComponent != null) { 180 | newComponent.setComponentListener(new BaseComponent.ComponentListener() { 181 | 182 | @Override 183 | public void onConnectivityChange(boolean isConnected) { 184 | Log.d(TAG, "onComponentConnectivityChanged: " + isConnected); 185 | } 186 | }); 187 | } 188 | Log.d(TAG, 189 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s", 190 | componentKey, 191 | oldComponent, 192 | newComponent)); 193 | 194 | } 195 | @Override 196 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) { 197 | 198 | } 199 | 200 | @Override 201 | public void onDatabaseDownloadProgress(long l, long l1) { 202 | 203 | } 204 | }); 205 | } 206 | }); 207 | } 208 | } 209 | 210 | private void showToast(final String toastMsg) { 211 | runOnUiThread(new Runnable() { 212 | @Override 213 | public void run() { 214 | Toast.makeText(getApplicationContext(), toastMsg, Toast.LENGTH_LONG).show(); 215 | 216 | } 217 | }); 218 | } 219 | 220 | private void loadDemoList() { 221 | mListView.setOnItemClickListener(new OnItemClickListener() { 222 | public void onItemClick(AdapterView arg0, View v, int index, long arg3) { 223 | onListItemClick(index); 224 | } 225 | }); 226 | demos.clear(); 227 | demos.add(new DemoInfo(R.string.title_activity_tracking_test, R.string.demo_desc_tracking, TrackingTestActivity.class)); 228 | demos.add(new DemoInfo(R.string.title_activity_pointing_test, R.string.demo_desc_pointing, PointingTestActivity.class)); 229 | } 230 | 231 | private void onListItemClick(int index) { 232 | Intent intent = null; 233 | intent = new Intent(MainActivity.this, demos.get(index).demoClass); 234 | this.startActivity(intent); 235 | } 236 | 237 | @Override 238 | protected void onDestroy() { 239 | super.onDestroy(); 240 | } 241 | 242 | public void onReturn(View view){ 243 | Log.d(TAG ,"onReturn"); 244 | this.finish(); 245 | } 246 | 247 | @SuppressLint("ViewHolder") 248 | private class DemoListAdapter extends BaseAdapter { 249 | public DemoListAdapter() { 250 | super(); 251 | } 252 | 253 | @Override 254 | public View getView(int index, View convertView, ViewGroup parent) { 255 | convertView = View.inflate(MainActivity.this, R.layout.demo_info_item, null); 256 | TextView title = (TextView)convertView.findViewById(R.id.title); 257 | TextView desc = (TextView)convertView.findViewById(R.id.desc); 258 | 259 | title.setText(demos.get(index).title); 260 | desc.setText(demos.get(index).desc); 261 | return convertView; 262 | } 263 | @Override 264 | public int getCount() { 265 | return demos.size(); 266 | } 267 | @Override 268 | public Object getItem(int index) { 269 | return demos.get(index); 270 | } 271 | 272 | @Override 273 | public long getItemId(int id) { 274 | return id; 275 | } 276 | } 277 | 278 | private static class DemoInfo{ 279 | private final int title; 280 | private final int desc; 281 | private final Class demoClass; 282 | 283 | public DemoInfo(int title , int desc,Class demoClass) { 284 | this.title = title; 285 | this.desc = desc; 286 | this.demoClass = demoClass; 287 | } 288 | } 289 | 290 | @Override 291 | protected void onProductChange() { 292 | super.onProductChange(); 293 | loadDemoList(); 294 | mDemoListAdapter.notifyDataSetChanged(); 295 | updateVersion(); 296 | loginAccount(); 297 | } 298 | 299 | private void setResultToToast(final String string) { 300 | MainActivity.this.runOnUiThread(new Runnable() { 301 | @Override 302 | public void run() { 303 | Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT).show(); 304 | } 305 | }); 306 | } 307 | 308 | private void loginAccount(){ 309 | 310 | UserAccountManager.getInstance().logIntoDJIUserAccount(this, new CommonCallbacks.CompletionCallbackWith() { 311 | @Override 312 | public void onSuccess(UserAccountState userAccountState) { 313 | Log.d(TAG ,"Login Success"); 314 | } 315 | 316 | @Override 317 | public void onFailure(DJIError djiError) { 318 | setResultToToast("Login Failed: " + djiError.getDescription()); 319 | } 320 | }); 321 | } 322 | 323 | String version = null; 324 | 325 | private void updateVersion() { 326 | 327 | BaseProduct product = DJISDKManager.getInstance().getProduct(); 328 | if(product != null) { 329 | version = product.getFirmwarePackageVersion(); 330 | } 331 | 332 | if(version == null) { 333 | version = "N/A"; 334 | } 335 | MainActivity.this.runOnUiThread(new Runnable() { 336 | @Override 337 | public void run() { 338 | mFirmwareVersionView.setText("Firmware version: " + version); 339 | } 340 | }); 341 | 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/MultiTrackingView.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | import android.content.Context; 4 | import android.graphics.RectF; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | 11 | import dji.common.mission.activetrack.ActiveTrackTargetState; 12 | import dji.common.mission.activetrack.SubjectSensingState; 13 | 14 | public class MultiTrackingView extends RelativeLayout { 15 | 16 | private TextView mValueIndex; 17 | private ImageView mRectF; 18 | 19 | public MultiTrackingView(Context context) { 20 | super(context); 21 | View view = LayoutInflater.from(context).inflate(R.layout.layout_multi_tracking, null); 22 | this.addView(view); 23 | mValueIndex = (TextView) findViewById(R.id.index_textview); 24 | mRectF = (ImageView) findViewById(R.id.tracking_rectf_iv); 25 | } 26 | 27 | public void updateView(SubjectSensingState information) { 28 | ActiveTrackTargetState targetState = information.getState(); 29 | 30 | if ((targetState == ActiveTrackTargetState.CANNOT_CONFIRM) 31 | || (targetState == ActiveTrackTargetState.UNKNOWN)) { 32 | mRectF.setImageResource(R.drawable.visual_track_cannotconfirm); 33 | } else if (targetState == ActiveTrackTargetState.WAITING_FOR_CONFIRMATION) { 34 | mRectF.setImageResource(R.drawable.visual_track_needconfirm); 35 | } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_LOW_CONFIDENCE) { 36 | mRectF.setImageResource(R.drawable.visual_track_lowconfidence); 37 | } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_HIGH_CONFIDENCE) { 38 | mRectF.setImageResource(R.drawable.visual_track_highconfidence); 39 | } 40 | 41 | mValueIndex.setText("" + information.getIndex()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/PointingTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | import dji.common.error.DJIError; 4 | import dji.common.mission.tapfly.TapFlyExecutionState; 5 | import dji.common.mission.tapfly.TapFlyMission; 6 | import dji.common.mission.tapfly.TapFlyMissionState; 7 | import dji.common.mission.tapfly.TapFlyMode; 8 | import dji.common.util.CommonCallbacks; 9 | import dji.sdk.mission.tapfly.TapFlyMissionEvent; 10 | import dji.sdk.mission.tapfly.TapFlyMissionOperator; 11 | import dji.sdk.mission.tapfly.TapFlyMissionOperatorListener; 12 | import dji.sdk.sdkmanager.DJISDKManager; 13 | 14 | import android.graphics.PointF; 15 | import android.os.Bundle; 16 | import android.util.Log; 17 | import android.view.MotionEvent; 18 | import android.view.View; 19 | import android.view.TextureView.SurfaceTextureListener; 20 | import android.view.View.OnClickListener; 21 | import android.view.View.OnTouchListener; 22 | import android.widget.Button; 23 | import android.widget.ImageButton; 24 | import android.widget.ImageView; 25 | import android.widget.RelativeLayout; 26 | import android.widget.SeekBar; 27 | import android.widget.SlidingDrawer; 28 | import android.widget.Switch; 29 | import android.widget.TextView; 30 | import android.widget.Toast; 31 | 32 | import androidx.annotation.Nullable; 33 | 34 | public class PointingTestActivity extends DemoBaseActivity implements SurfaceTextureListener, OnClickListener, OnTouchListener { 35 | 36 | private static final String TAG = "PointingTestActivity"; 37 | 38 | private TapFlyMission mTapFlyMission; 39 | 40 | private ImageButton mPushDrawerIb; 41 | private SlidingDrawer mPushDrawerSd; 42 | private Button mStartBtn; 43 | private ImageButton mStopBtn; 44 | private TextView mPushTv; 45 | private RelativeLayout mBgLayout; 46 | private ImageView mRstPointIv; 47 | private TextView mAssisTv; 48 | private Switch mAssisSw; 49 | private TextView mSpeedTv; 50 | private SeekBar mSpeedSb; 51 | 52 | private TapFlyMissionOperator getTapFlyOperator() { 53 | return DJISDKManager.getInstance().getMissionControl().getTapFlyMissionOperator(); 54 | } 55 | 56 | @Override 57 | protected void onCreate(Bundle savedInstanceState) { 58 | setContentView(R.layout.activity_pointing_test); 59 | super.onCreate(savedInstanceState); 60 | initUI(); 61 | getTapFlyOperator().addListener(new TapFlyMissionOperatorListener() { 62 | @Override 63 | public void onUpdate(@Nullable TapFlyMissionEvent aggregation) { 64 | TapFlyExecutionState executionState = aggregation.getExecutionState(); 65 | if (executionState != null){ 66 | showPointByTapFlyPoint(executionState.getImageLocation(), mRstPointIv); 67 | } 68 | 69 | StringBuffer sb = new StringBuffer(); 70 | String errorInformation = (aggregation.getError() == null ? "null" : aggregation.getError().getDescription()) + "\n"; 71 | String currentState = aggregation.getCurrentState() == null ? "null" : aggregation.getCurrentState().getName(); 72 | String previousState = aggregation.getPreviousState() == null ? "null" : aggregation.getPreviousState().getName(); 73 | Utils.addLineToSB(sb, "CurrentState: ", currentState); 74 | Utils.addLineToSB(sb, "PreviousState: ", previousState); 75 | Utils.addLineToSB(sb, "Error:", errorInformation); 76 | 77 | TapFlyExecutionState progressState = aggregation.getExecutionState(); 78 | 79 | if (progressState != null) { 80 | Utils.addLineToSB(sb, "Heading: ", progressState.getRelativeHeading()); 81 | Utils.addLineToSB(sb, "PointX: ", progressState.getImageLocation().x); 82 | Utils.addLineToSB(sb, "PointY: ", progressState.getImageLocation().y); 83 | Utils.addLineToSB(sb, "BypassDirection: ", progressState.getBypassDirection().name()); 84 | Utils.addLineToSB(sb, "VectorX: ", progressState.getDirection().getX()); 85 | Utils.addLineToSB(sb, "VectorY: ", progressState.getDirection().getY()); 86 | Utils.addLineToSB(sb, "VectorZ: ", progressState.getDirection().getZ()); 87 | setResultToText(sb.toString()); 88 | } 89 | 90 | TapFlyMissionState missionState = aggregation.getCurrentState(); 91 | if (!((missionState == TapFlyMissionState.EXECUTING) || (missionState == TapFlyMissionState.EXECUTION_PAUSED) 92 | || (missionState == TapFlyMissionState.EXECUTION_RESETTING))){ 93 | setVisible(mRstPointIv, false); 94 | setVisible(mStopBtn, false); 95 | }else 96 | { 97 | setVisible(mStopBtn, true); 98 | setVisible(mStartBtn, false); 99 | } 100 | } 101 | }); 102 | } 103 | 104 | @Override 105 | protected void onResume() { 106 | super.onResume(); 107 | initTapFlyMission(); 108 | } 109 | 110 | @Override 111 | protected void onDestroy() { 112 | 113 | if(mCodecManager != null){ 114 | mCodecManager.destroyCodec(); 115 | } 116 | 117 | super.onDestroy(); 118 | } 119 | 120 | /** 121 | * @Description : RETURN BTN RESPONSE FUNCTION 122 | */ 123 | public void onReturn(View view){ 124 | Log.d(TAG, "onReturn"); 125 | this.finish(); 126 | } 127 | 128 | private void setResultToToast(final String string) { 129 | PointingTestActivity.this.runOnUiThread(new Runnable() { 130 | @Override 131 | public void run() { 132 | Toast.makeText(PointingTestActivity.this, string, Toast.LENGTH_SHORT).show(); 133 | } 134 | }); 135 | } 136 | 137 | private void setResultToText(final String string) { 138 | if (mPushTv == null) { 139 | setResultToToast("Push info tv has not be init..."); 140 | } 141 | PointingTestActivity.this.runOnUiThread(new Runnable() { 142 | @Override 143 | public void run() { 144 | mPushTv.setText(string); 145 | } 146 | }); 147 | } 148 | 149 | private void setVisible(final View v, final boolean visible) { 150 | if (v == null) return; 151 | PointingTestActivity.this.runOnUiThread(new Runnable() { 152 | @Override 153 | public void run() { 154 | v.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); 155 | } 156 | }); 157 | } 158 | 159 | private void initUI() { 160 | mPushDrawerIb = (ImageButton)findViewById(R.id.pointing_drawer_control_ib); 161 | mPushDrawerSd = (SlidingDrawer)findViewById(R.id.pointing_drawer_sd); 162 | mStartBtn = (Button)findViewById(R.id.pointing_start_btn); 163 | mStopBtn = (ImageButton)findViewById(R.id.pointing_stop_btn); 164 | mPushTv = (TextView)findViewById(R.id.pointing_push_tv); 165 | mBgLayout = (RelativeLayout)findViewById(R.id.pointing_bg_layout); 166 | mRstPointIv = (ImageView)findViewById(R.id.pointing_rst_point_iv); 167 | mAssisTv = (TextView)findViewById(R.id.pointing_assistant_tv); 168 | mAssisSw = (Switch)findViewById(R.id.pointing_assistant_sw); 169 | mSpeedTv = (TextView)findViewById(R.id.pointing_speed_tv); 170 | mSpeedSb = (SeekBar)findViewById(R.id.pointing_speed_sb); 171 | 172 | mPushDrawerIb.setOnClickListener(this); 173 | mStartBtn.setOnClickListener(this); 174 | mStopBtn.setOnClickListener(this); 175 | mBgLayout.setOnTouchListener(this); 176 | mSpeedSb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 177 | @Override 178 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 179 | mSpeedTv.setText(progress + 1 + ""); 180 | } 181 | 182 | @Override 183 | public void onStartTrackingTouch(SeekBar seekBar) { 184 | 185 | } 186 | 187 | @Override 188 | public void onStopTrackingTouch(SeekBar seekBar) { 189 | getTapFlyOperator().setAutoFlightSpeed(getSpeed(), new CommonCallbacks.CompletionCallback() { 190 | @Override 191 | public void onResult(DJIError error) { 192 | setResultToToast(error == null ? "Set Auto Flight Speed Success" : error.getDescription()); 193 | } 194 | }); 195 | } 196 | }); 197 | } 198 | 199 | private void initTapFlyMission() { 200 | mTapFlyMission = new TapFlyMission(); 201 | mTapFlyMission.isHorizontalObstacleAvoidanceEnabled = mAssisSw.isChecked(); 202 | mTapFlyMission.tapFlyMode = TapFlyMode.FORWARD; 203 | } 204 | 205 | private PointF getTapFlyPoint(View iv) { 206 | if (iv == null) return null; 207 | View parent = (View)iv.getParent(); 208 | float centerX = iv.getLeft() + iv.getX() + ((float)iv.getWidth()) / 2; 209 | float centerY = iv.getTop() + iv.getY() + ((float)iv.getHeight()) / 2; 210 | centerX = centerX < 0 ? 0 : centerX; 211 | centerX = centerX > parent.getWidth() ? parent.getWidth() : centerX; 212 | centerY = centerY < 0 ? 0 : centerY; 213 | centerY = centerY > parent.getHeight() ? parent.getHeight() : centerY; 214 | 215 | return new PointF(centerX / parent.getWidth(), centerY / parent.getHeight()); 216 | } 217 | 218 | private void showPointByTapFlyPoint(final PointF point, final ImageView iv) { 219 | if (point == null || iv == null) { 220 | return; 221 | } 222 | final View parent = (View)iv.getParent(); 223 | PointingTestActivity.this.runOnUiThread(new Runnable() { 224 | 225 | @Override 226 | public void run() { 227 | iv.setX(point.x * parent.getWidth() - iv.getWidth() / 2); 228 | iv.setY(point.y * parent.getHeight() - iv.getHeight() / 2); 229 | iv.setVisibility(View.VISIBLE); 230 | iv.requestLayout(); 231 | } 232 | }); 233 | } 234 | 235 | private float getSpeed() { 236 | if (mSpeedSb == null) return Float.NaN; 237 | return mSpeedSb.getProgress() + 1; 238 | } 239 | 240 | @Override 241 | public boolean onTouch(View v, MotionEvent event) { 242 | if (v.getId() == R.id.pointing_bg_layout) { 243 | 244 | switch (event.getAction()) { 245 | case MotionEvent.ACTION_UP: 246 | if (mTapFlyMission != null) { 247 | mStartBtn.setVisibility(View.VISIBLE); 248 | mStartBtn.setX(event.getX() - mStartBtn.getWidth() / 2); 249 | mStartBtn.setY(event.getY() - mStartBtn.getHeight() / 2); 250 | mStartBtn.requestLayout(); 251 | mTapFlyMission.target = getTapFlyPoint(mStartBtn); 252 | } else { 253 | setResultToToast("TapFlyMission is null"); 254 | } 255 | break; 256 | 257 | default: 258 | break; 259 | } 260 | } 261 | return true; 262 | } 263 | 264 | @Override 265 | public void onClick(View v) { 266 | if (v.getId() == R.id.pointing_drawer_control_ib) { 267 | if (mPushDrawerSd.isOpened()) { 268 | mPushDrawerSd.animateClose(); 269 | } else { 270 | mPushDrawerSd.animateOpen(); 271 | } 272 | return; 273 | } 274 | if (getTapFlyOperator() != null) { 275 | switch (v.getId()) { 276 | case R.id.pointing_start_btn: 277 | getTapFlyOperator().startMission(mTapFlyMission, new CommonCallbacks.CompletionCallback() { 278 | @Override 279 | public void onResult(DJIError error) { 280 | setResultToToast(error == null ? "Start Mission Successfully" : error.getDescription()); 281 | if (error == null){ 282 | setVisible(mStartBtn, false); 283 | } 284 | } 285 | }); 286 | break; 287 | case R.id.pointing_stop_btn: 288 | getTapFlyOperator().stopMission(new CommonCallbacks.CompletionCallback() { 289 | @Override 290 | public void onResult(DJIError error) { 291 | setResultToToast(error == null ? "Stop Mission Successfully" : error.getDescription()); 292 | } 293 | }); 294 | break; 295 | default: 296 | break; 297 | } 298 | } else { 299 | setResultToToast("TapFlyMission Operator is null"); 300 | } 301 | } 302 | 303 | } 304 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/TrackingTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | import dji.common.camera.SettingsDefinitions; 4 | import dji.common.error.DJIError; 5 | import dji.common.mission.activetrack.ActiveTrackMission; 6 | import dji.common.mission.activetrack.ActiveTrackMissionEvent; 7 | import dji.common.mission.activetrack.ActiveTrackMode; 8 | import dji.common.mission.activetrack.ActiveTrackState; 9 | import dji.common.mission.activetrack.ActiveTrackTargetState; 10 | import dji.common.mission.activetrack.ActiveTrackTrackingState; 11 | import dji.common.mission.activetrack.SubjectSensingState; 12 | import dji.common.util.CommonCallbacks; 13 | import dji.keysdk.CameraKey; 14 | import dji.keysdk.callback.ActionCallback; 15 | import dji.keysdk.callback.SetCallback; 16 | import dji.sdk.mission.activetrack.ActiveTrackMissionOperatorListener; 17 | import dji.sdk.mission.activetrack.ActiveTrackOperator; 18 | import dji.sdk.sdkmanager.DJISDKManager; 19 | 20 | import android.graphics.Color; 21 | import android.graphics.RectF; 22 | import android.os.Bundle; 23 | import android.view.MotionEvent; 24 | import android.view.View; 25 | import android.view.TextureView.SurfaceTextureListener; 26 | import android.view.View.OnClickListener; 27 | import android.view.View.OnTouchListener; 28 | import android.widget.Button; 29 | import android.widget.CompoundButton; 30 | import android.widget.ImageButton; 31 | import android.widget.ImageView; 32 | import android.widget.RelativeLayout; 33 | import android.widget.SlidingDrawer; 34 | import android.widget.Switch; 35 | import android.widget.TextView; 36 | import android.widget.Toast; 37 | 38 | import androidx.annotation.NonNull; 39 | 40 | import dji.common.mission.activetrack.QuickShotMode; 41 | import dji.common.util.CommonCallbacks.CompletionCallback; 42 | import dji.common.util.CommonCallbacks.CompletionCallbackWith; 43 | import dji.keysdk.DJIKey; 44 | import dji.keysdk.FlightControllerKey; 45 | import dji.keysdk.KeyManager; 46 | import dji.log.DJILog; 47 | import dji.midware.media.DJIVideoDataRecver; 48 | import dji.sdk.mission.MissionControl; 49 | 50 | import java.util.ArrayList; 51 | import java.util.Iterator; 52 | import java.util.Map; 53 | import java.util.concurrent.ConcurrentHashMap; 54 | 55 | public class TrackingTestActivity extends DemoBaseActivity implements SurfaceTextureListener, OnClickListener, OnTouchListener, CompoundButton.OnCheckedChangeListener, ActiveTrackMissionOperatorListener { 56 | 57 | private static final String TAG = "TrackingTestActivity"; 58 | private static final int MAIN_CAMERA_INDEX = 0; 59 | private static final int INVAVID_INDEX = -1; 60 | private static final int MOVE_OFFSET = 20; 61 | 62 | private RelativeLayout.LayoutParams layoutParams; 63 | private Switch mAutoSensingSw; 64 | private Switch mQuickShotSw; 65 | private ImageButton mPushDrawerIb; 66 | private SlidingDrawer mPushInfoSd; 67 | private ImageButton mStopBtn; 68 | private ImageView mTrackingImage; 69 | private RelativeLayout mBgLayout; 70 | private TextView mPushInfoTv; 71 | private Switch mPushBackSw; 72 | private Switch mGestureModeSw; 73 | private ImageView mSendRectIV; 74 | private Button mConfigBtn; 75 | private Button mConfirmBtn; 76 | private Button mRejectBtn; 77 | 78 | private ActiveTrackOperator mActiveTrackOperator; 79 | private ActiveTrackMission mActiveTrackMission; 80 | private final DJIKey trackModeKey = FlightControllerKey.createFlightAssistantKey(FlightControllerKey.ACTIVE_TRACK_MODE); 81 | private ConcurrentHashMap targetViewHashMap = new ConcurrentHashMap<>(); 82 | private int trackingIndex = INVAVID_INDEX; 83 | private boolean isAutoSensingSupported = false; 84 | private ActiveTrackMode startMode = ActiveTrackMode.TRACE; 85 | private QuickShotMode quickShotMode = QuickShotMode.UNKNOWN; 86 | 87 | private boolean isDrawingRect = false; 88 | 89 | /** 90 | * Toast 91 | * 92 | * @param string 93 | */ 94 | private void setResultToToast(final String string) { 95 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 96 | @Override 97 | public void run() { 98 | Toast.makeText(TrackingTestActivity.this, string, Toast.LENGTH_SHORT).show(); 99 | } 100 | }); 101 | } 102 | 103 | /** 104 | * Push Status to TextView 105 | * 106 | * @param string 107 | */ 108 | private void setResultToText(final String string) { 109 | if (mPushInfoTv == null) { 110 | setResultToToast("Push info tv has not be init..."); 111 | } 112 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 113 | @Override 114 | public void run() { 115 | mPushInfoTv.setText(string); 116 | } 117 | }); 118 | } 119 | 120 | @Override 121 | protected void onCreate(Bundle savedInstanceState) { 122 | setContentView(R.layout.activity_tracking_test); 123 | super.onCreate(savedInstanceState); 124 | initUI(); 125 | } 126 | 127 | /** 128 | * InitUI 129 | */ 130 | private void initUI() { 131 | layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 132 | RelativeLayout.LayoutParams.MATCH_PARENT); 133 | mPushDrawerIb = (ImageButton) findViewById(R.id.tracking_drawer_control_ib); 134 | mPushInfoSd = (SlidingDrawer) findViewById(R.id.tracking_drawer_sd); 135 | mPushInfoTv = (TextView) findViewById(R.id.tracking_push_tv); 136 | mBgLayout = (RelativeLayout) findViewById(R.id.tracking_bg_layout); 137 | mSendRectIV = (ImageView) findViewById(R.id.tracking_send_rect_iv); 138 | mTrackingImage = (ImageView) findViewById(R.id.tracking_rst_rect_iv); 139 | mConfirmBtn = (Button) findViewById(R.id.confirm_btn); 140 | mStopBtn = (ImageButton) findViewById(R.id.tracking_stop_btn); 141 | mRejectBtn = (Button) findViewById(R.id.reject_btn); 142 | mConfigBtn = (Button) findViewById(R.id.recommended_configuration_btn); 143 | mAutoSensingSw = (Switch) findViewById(R.id.set_multitracking_enabled); 144 | mQuickShotSw = (Switch) findViewById(R.id.set_multiquickshot_enabled); 145 | mPushBackSw = (Switch) findViewById(R.id.tracking_pull_back_tb); 146 | mGestureModeSw = (Switch) findViewById(R.id.tracking_in_gesture_mode); 147 | 148 | mAutoSensingSw.setChecked(false); 149 | mGestureModeSw.setChecked(false); 150 | mQuickShotSw.setChecked(false); 151 | mPushBackSw.setChecked(false); 152 | 153 | mAutoSensingSw.setOnCheckedChangeListener(this); 154 | mQuickShotSw.setOnCheckedChangeListener(this); 155 | mPushBackSw.setOnCheckedChangeListener(this); 156 | mGestureModeSw.setOnCheckedChangeListener(this); 157 | 158 | mBgLayout.setOnTouchListener(this); 159 | mConfirmBtn.setOnClickListener(this); 160 | mStopBtn.setOnClickListener(this); 161 | mRejectBtn.setOnClickListener(this); 162 | mConfigBtn.setOnClickListener(this); 163 | mPushDrawerIb.setOnClickListener(this); 164 | } 165 | 166 | @Override 167 | protected void onResume() { 168 | super.onResume(); 169 | initMissionManager(); 170 | } 171 | 172 | /** 173 | * Init Mission parameter 174 | */ 175 | private void initMissionManager() { 176 | mActiveTrackOperator = MissionControl.getInstance().getActiveTrackOperator(); 177 | if (mActiveTrackOperator == null) { 178 | return; 179 | } 180 | 181 | mActiveTrackOperator.addListener(this); 182 | mAutoSensingSw.setChecked(mActiveTrackOperator.isAutoSensingEnabled()); 183 | mQuickShotSw.setChecked(mActiveTrackOperator.isAutoSensingForQuickShotEnabled()); 184 | mGestureModeSw.setChecked(mActiveTrackOperator.isGestureModeEnabled()); 185 | mActiveTrackOperator.getRetreatEnabled(new CompletionCallbackWith() { 186 | @Override 187 | public void onSuccess(final Boolean aBoolean) { 188 | runOnUiThread(new Runnable() { 189 | @Override 190 | public void run() { 191 | mPushBackSw.setChecked(aBoolean); 192 | } 193 | }); 194 | } 195 | 196 | @Override 197 | public void onFailure(DJIError error) { 198 | setResultToToast("can't get retreat enable state " + error.getDescription()); 199 | } 200 | }); 201 | } 202 | 203 | 204 | /** 205 | * @Description : RETURN BTN RESPONSE FUNCTION 206 | */ 207 | @Override 208 | public void onReturn(View view) { 209 | DJILog.d(TAG, "onReturn"); 210 | DJISDKManager.getInstance().getMissionControl().destroy(); 211 | this.finish(); 212 | } 213 | 214 | @Override 215 | protected void onDestroy() { 216 | isAutoSensingSupported = false; 217 | try { 218 | DJIVideoDataRecver.getInstance().setVideoDataListener(false, null); 219 | } catch (Exception e) { 220 | e.printStackTrace(); 221 | } 222 | 223 | if (mActiveTrackOperator != null) { 224 | mActiveTrackOperator.removeListener(this); 225 | } 226 | 227 | if (mCodecManager != null) { 228 | mCodecManager.destroyCodec(); 229 | } 230 | 231 | super.onDestroy(); 232 | } 233 | 234 | float downX; 235 | float downY; 236 | 237 | /** 238 | * Calculate distance 239 | * 240 | * @param point1X 241 | * @param point1Y 242 | * @param point2X 243 | * @param point2Y 244 | * @return 245 | */ 246 | private double calcManhattanDistance(double point1X, double point1Y, double point2X, 247 | double point2Y) { 248 | return Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y); 249 | } 250 | 251 | @Override 252 | public boolean onTouch(View v, MotionEvent event) { 253 | switch (event.getAction()) { 254 | case MotionEvent.ACTION_DOWN: 255 | isDrawingRect = false; 256 | downX = event.getX(); 257 | downY = event.getY(); 258 | break; 259 | 260 | case MotionEvent.ACTION_MOVE: 261 | if (calcManhattanDistance(downX, downY, event.getX(), event.getY()) < MOVE_OFFSET && !isDrawingRect) { 262 | trackingIndex = getTrackingIndex(downX, downY, targetViewHashMap); 263 | if (targetViewHashMap.get(trackingIndex) != null) { 264 | targetViewHashMap.get(trackingIndex).setBackgroundColor(Color.RED); 265 | } 266 | return true; 267 | } 268 | isDrawingRect = true; 269 | mSendRectIV.setVisibility(View.VISIBLE); 270 | int l = (int) (downX < event.getX() ? downX : event.getX()); 271 | int t = (int) (downY < event.getY() ? downY : event.getY()); 272 | int r = (int) (downX >= event.getX() ? downX : event.getX()); 273 | int b = (int) (downY >= event.getY() ? downY : event.getY()); 274 | mSendRectIV.setX(l); 275 | mSendRectIV.setY(t); 276 | mSendRectIV.getLayoutParams().width = r - l; 277 | mSendRectIV.getLayoutParams().height = b - t; 278 | mSendRectIV.requestLayout(); 279 | break; 280 | 281 | case MotionEvent.ACTION_UP: 282 | if (mGestureModeSw.isChecked()) { 283 | setResultToToast("Please try to start Gesture Mode!"); 284 | } else if (!isDrawingRect) { 285 | if (targetViewHashMap.get(trackingIndex) != null) { 286 | setResultToToast("Selected Index: " + trackingIndex + ",Please Confirm it!"); 287 | targetViewHashMap.get(trackingIndex).setBackgroundColor(Color.TRANSPARENT); 288 | } 289 | } else { 290 | RectF rectF = getActiveTrackRect(mSendRectIV); 291 | mActiveTrackMission = new ActiveTrackMission(rectF, startMode); 292 | if (startMode == ActiveTrackMode.QUICK_SHOT) { 293 | mActiveTrackMission.setQuickShotMode(quickShotMode); 294 | checkStorageStates(); 295 | } 296 | mActiveTrackOperator.startTracking(mActiveTrackMission, new CommonCallbacks.CompletionCallback() { 297 | @Override 298 | public void onResult(DJIError error) { 299 | if (error == null) { 300 | isDrawingRect = false; 301 | } 302 | setResultToToast("Start Tracking: " + (error == null 303 | ? "Success" 304 | : error.getDescription())); 305 | } 306 | }); 307 | mSendRectIV.setVisibility(View.INVISIBLE); 308 | clearCurrentView(); 309 | } 310 | break; 311 | 312 | default: 313 | break; 314 | } 315 | 316 | return true; 317 | } 318 | 319 | /** 320 | * @return 321 | */ 322 | private int getTrackingIndex(final float x, final float y, 323 | final ConcurrentHashMap multiTrackinghMap) { 324 | if (multiTrackinghMap == null || multiTrackinghMap.isEmpty()) { 325 | return INVAVID_INDEX; 326 | } 327 | 328 | float l, t, r, b; 329 | for (Map.Entry vo : multiTrackinghMap.entrySet()) { 330 | int key = vo.getKey().intValue(); 331 | MultiTrackingView view = vo.getValue(); 332 | l = view.getX(); 333 | t = view.getY(); 334 | r = (view.getX() + (view.getWidth() / 2)); 335 | b = (view.getY() + (view.getHeight() / 2)); 336 | 337 | if (x >= l && y >= t && x <= r && y <= b) { 338 | return key; 339 | } 340 | } 341 | return INVAVID_INDEX; 342 | } 343 | 344 | @Override 345 | public void onClick(View v) { 346 | if (mActiveTrackOperator == null) { 347 | return; 348 | } 349 | switch (v.getId()) { 350 | case R.id.recommended_configuration_btn: 351 | mActiveTrackOperator.setRecommendedConfiguration(new CompletionCallback() { 352 | @Override 353 | public void onResult(DJIError error) { 354 | setResultToToast("Set Recommended Config " + (error == null ? "Success" : error.getDescription())); 355 | } 356 | }); 357 | runOnUiThread(new Runnable() { 358 | @Override 359 | public void run() { 360 | mConfigBtn.setVisibility(View.GONE); 361 | } 362 | }); 363 | break; 364 | 365 | case R.id.confirm_btn: 366 | boolean isAutoTracking = 367 | isAutoSensingSupported && 368 | (mActiveTrackOperator.isAutoSensingEnabled() || 369 | mActiveTrackOperator.isAutoSensingForQuickShotEnabled()); 370 | if (isAutoTracking) { 371 | startAutoSensingMission(); 372 | runOnUiThread(new Runnable() { 373 | @Override 374 | public void run() { 375 | mStopBtn.setVisibility(View.VISIBLE); 376 | mRejectBtn.setVisibility(View.VISIBLE); 377 | mConfirmBtn.setVisibility(View.INVISIBLE); 378 | } 379 | }); 380 | } else { 381 | trackingIndex = INVAVID_INDEX; 382 | mActiveTrackOperator.acceptConfirmation(new CompletionCallback() { 383 | 384 | @Override 385 | public void onResult(DJIError error) { 386 | setResultToToast(error == null ? "Accept Confirm Success!" : error.getDescription()); 387 | } 388 | }); 389 | 390 | runOnUiThread(new Runnable() { 391 | @Override 392 | public void run() { 393 | mStopBtn.setVisibility(View.VISIBLE); 394 | mRejectBtn.setVisibility(View.VISIBLE); 395 | mConfirmBtn.setVisibility(View.INVISIBLE); 396 | } 397 | }); 398 | 399 | } 400 | break; 401 | 402 | case R.id.tracking_stop_btn: 403 | trackingIndex = INVAVID_INDEX; 404 | mActiveTrackOperator.stopTracking(new CompletionCallback() { 405 | 406 | @Override 407 | public void onResult(DJIError error) { 408 | setResultToToast(error == null ? "Stop track Success!" : error.getDescription()); 409 | } 410 | }); 411 | 412 | runOnUiThread(new Runnable() { 413 | @Override 414 | public void run() { 415 | if (mTrackingImage != null) { 416 | mTrackingImage.setVisibility(View.INVISIBLE); 417 | mSendRectIV.setVisibility(View.INVISIBLE); 418 | mStopBtn.setVisibility(View.INVISIBLE); 419 | mRejectBtn.setVisibility(View.INVISIBLE); 420 | mConfirmBtn.setVisibility(View.VISIBLE); 421 | } 422 | } 423 | }); 424 | break; 425 | 426 | case R.id.reject_btn: 427 | trackingIndex = INVAVID_INDEX; 428 | mActiveTrackOperator.rejectConfirmation(new CompletionCallback() { 429 | 430 | @Override 431 | public void onResult(DJIError error) { 432 | 433 | setResultToToast(error == null ? "Reject Confirm Success!" : error.getDescription()); 434 | } 435 | }); 436 | runOnUiThread(new Runnable() { 437 | @Override 438 | public void run() { 439 | mStopBtn.setVisibility(View.VISIBLE); 440 | mRejectBtn.setVisibility(View.VISIBLE); 441 | mConfirmBtn.setVisibility(View.INVISIBLE); 442 | } 443 | }); 444 | break; 445 | 446 | case R.id.tracking_drawer_control_ib: 447 | if (mPushInfoSd.isOpened()) { 448 | mPushInfoSd.animateClose(); 449 | } else { 450 | mPushInfoSd.animateOpen(); 451 | } 452 | break; 453 | 454 | default: 455 | break; 456 | } 457 | 458 | } 459 | 460 | @Override 461 | public void onCheckedChanged(CompoundButton compoundButton, final boolean isChecked) { 462 | if (mActiveTrackOperator == null) { 463 | return; 464 | } 465 | switch (compoundButton.getId()) { 466 | case R.id.set_multitracking_enabled: 467 | startMode = ActiveTrackMode.TRACE; 468 | quickShotMode = QuickShotMode.UNKNOWN; 469 | setAutoSensingEnabled(isChecked); 470 | break; 471 | case R.id.set_multiquickshot_enabled: 472 | startMode = ActiveTrackMode.QUICK_SHOT; 473 | quickShotMode = QuickShotMode.CIRCLE; 474 | checkStorageStates(); 475 | setAutoSensingForQuickShotEnabled(isChecked); 476 | break; 477 | case R.id.tracking_pull_back_tb: 478 | mActiveTrackOperator.setRetreatEnabled(isChecked, new CompletionCallback() { 479 | @Override 480 | public void onResult(DJIError error) { 481 | if (error != null) { 482 | runOnUiThread(new Runnable() { 483 | @Override 484 | public void run() { 485 | mPushBackSw.setChecked(!isChecked); 486 | } 487 | }); 488 | } 489 | setResultToToast("Set Retreat Enabled: " + (error == null 490 | ? "Success" 491 | : error.getDescription())); 492 | } 493 | }); 494 | break; 495 | case R.id.tracking_in_gesture_mode: 496 | mActiveTrackOperator.setGestureModeEnabled(isChecked, new CompletionCallback() { 497 | @Override 498 | public void onResult(DJIError error) { 499 | if (error != null) { 500 | runOnUiThread(new Runnable() { 501 | @Override 502 | public void run() { 503 | mGestureModeSw.setChecked(!isChecked); 504 | } 505 | }); 506 | } 507 | setResultToToast("Set GestureMode Enabled: " + (error == null 508 | ? "Success" 509 | : error.getDescription())); 510 | } 511 | }); 512 | break; 513 | default: 514 | break; 515 | } 516 | } 517 | 518 | @Override 519 | public void onUpdate(ActiveTrackMissionEvent event) { 520 | StringBuffer sb = new StringBuffer(); 521 | String errorInformation = (event.getError() == null ? "null" : event.getError().getDescription()) + "\n"; 522 | String currentState = event.getCurrentState() == null ? "null" : event.getCurrentState().getName(); 523 | String previousState = event.getPreviousState() == null ? "null" : event.getPreviousState().getName(); 524 | 525 | ActiveTrackTargetState targetState = ActiveTrackTargetState.UNKNOWN; 526 | if (event.getTrackingState() != null) { 527 | targetState = event.getTrackingState().getState(); 528 | } 529 | Utils.addLineToSB(sb, "CurrentState: ", currentState); 530 | Utils.addLineToSB(sb, "PreviousState: ", previousState); 531 | Utils.addLineToSB(sb, "TargetState: ", targetState); 532 | Utils.addLineToSB(sb, "Error:", errorInformation); 533 | 534 | Object value = KeyManager.getInstance().getValue(trackModeKey); 535 | if (value instanceof ActiveTrackMode) { 536 | Utils.addLineToSB(sb, "TrackingMode:", value.toString()); 537 | } 538 | 539 | ActiveTrackTrackingState trackingState = event.getTrackingState(); 540 | if (trackingState != null) { 541 | final SubjectSensingState[] targetSensingInformations = trackingState.getAutoSensedSubjects(); 542 | if (targetSensingInformations != null) { 543 | for (SubjectSensingState subjectSensingState : targetSensingInformations) { 544 | RectF trackingRect = subjectSensingState.getTargetRect(); 545 | if (trackingRect != null) { 546 | Utils.addLineToSB(sb, "Rect center x: ", trackingRect.centerX()); 547 | Utils.addLineToSB(sb, "Rect center y: ", trackingRect.centerY()); 548 | Utils.addLineToSB(sb, "Rect Width: ", trackingRect.width()); 549 | Utils.addLineToSB(sb, "Rect Height: ", trackingRect.height()); 550 | Utils.addLineToSB(sb, "Reason", trackingState.getReason().name()); 551 | Utils.addLineToSB(sb, "Target Index: ", subjectSensingState.getIndex()); 552 | Utils.addLineToSB(sb, "Target Type", subjectSensingState.getTargetType().name()); 553 | Utils.addLineToSB(sb, "Target State", subjectSensingState.getState().name()); 554 | isAutoSensingSupported = true; 555 | } 556 | } 557 | } else { 558 | RectF trackingRect = trackingState.getTargetRect(); 559 | if (trackingRect != null) { 560 | Utils.addLineToSB(sb, "Rect center x: ", trackingRect.centerX()); 561 | Utils.addLineToSB(sb, "Rect center y: ", trackingRect.centerY()); 562 | Utils.addLineToSB(sb, "Rect Width: ", trackingRect.width()); 563 | Utils.addLineToSB(sb, "Rect Height: ", trackingRect.height()); 564 | Utils.addLineToSB(sb, "Reason", trackingState.getReason().name()); 565 | Utils.addLineToSB(sb, "Target Index: ", trackingState.getTargetIndex()); 566 | Utils.addLineToSB(sb, "Target Type", trackingState.getType().name()); 567 | Utils.addLineToSB(sb, "Target State", trackingState.getState().name()); 568 | isAutoSensingSupported = false; 569 | } 570 | clearCurrentView(); 571 | } 572 | } 573 | 574 | setResultToText(sb.toString()); 575 | updateActiveTrackRect(mTrackingImage, event); 576 | updateButtonVisibility(event); 577 | } 578 | 579 | /** 580 | * Update ActiveTrack Rect 581 | * 582 | * @param iv 583 | * @param event 584 | */ 585 | private void updateActiveTrackRect(final ImageView iv, final ActiveTrackMissionEvent event) { 586 | if (iv == null || event == null) { 587 | return; 588 | } 589 | 590 | ActiveTrackTrackingState trackingState = event.getTrackingState(); 591 | if (trackingState != null) { 592 | if (trackingState.getAutoSensedSubjects() != null) { 593 | final SubjectSensingState[] targetSensingInformations = trackingState.getAutoSensedSubjects(); 594 | runOnUiThread(new Runnable() { 595 | @Override 596 | public void run() { 597 | updateMultiTrackingView(targetSensingInformations); 598 | } 599 | }); 600 | } else { 601 | RectF trackingRect = trackingState.getTargetRect(); 602 | ActiveTrackTargetState trackTargetState = trackingState.getState(); 603 | postResultRect(iv, trackingRect, trackTargetState); 604 | } 605 | } 606 | 607 | } 608 | 609 | private void updateButtonVisibility(final ActiveTrackMissionEvent event) { 610 | ActiveTrackState state = event.getCurrentState(); 611 | if (state == ActiveTrackState.AUTO_SENSING || 612 | state == ActiveTrackState.AUTO_SENSING_FOR_QUICK_SHOT || 613 | state == ActiveTrackState.WAITING_FOR_CONFIRMATION) { 614 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 615 | @Override 616 | public void run() { 617 | mStopBtn.setVisibility(View.VISIBLE); 618 | mStopBtn.setClickable(true); 619 | mConfirmBtn.setVisibility(View.VISIBLE); 620 | mConfirmBtn.setClickable(true); 621 | mRejectBtn.setVisibility(View.VISIBLE); 622 | mRejectBtn.setClickable(true); 623 | mConfigBtn.setVisibility(View.GONE); 624 | } 625 | }); 626 | } else if (state == ActiveTrackState.AIRCRAFT_FOLLOWING || 627 | state == ActiveTrackState.ONLY_CAMERA_FOLLOWING || 628 | state == ActiveTrackState.FINDING_TRACKED_TARGET || 629 | state == ActiveTrackState.CANNOT_CONFIRM || 630 | state == ActiveTrackState.PERFORMING_QUICK_SHOT) { 631 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 632 | 633 | @Override 634 | public void run() { 635 | mStopBtn.setVisibility(View.VISIBLE); 636 | mStopBtn.setClickable(true); 637 | mConfirmBtn.setVisibility(View.INVISIBLE); 638 | mConfirmBtn.setClickable(false); 639 | mRejectBtn.setVisibility(View.VISIBLE); 640 | mRejectBtn.setClickable(true); 641 | mConfigBtn.setVisibility(View.GONE); 642 | } 643 | }); 644 | } else { 645 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 646 | 647 | @Override 648 | public void run() { 649 | mStopBtn.setVisibility(View.INVISIBLE); 650 | mStopBtn.setClickable(false); 651 | mConfirmBtn.setVisibility(View.INVISIBLE); 652 | mConfirmBtn.setClickable(false); 653 | mRejectBtn.setVisibility(View.INVISIBLE); 654 | mRejectBtn.setClickable(false); 655 | mTrackingImage.setVisibility(View.INVISIBLE); 656 | } 657 | }); 658 | } 659 | } 660 | 661 | /** 662 | * Get ActiveTrack RectF 663 | * 664 | * @param iv 665 | * @return 666 | */ 667 | private RectF getActiveTrackRect(View iv) { 668 | View parent = (View) iv.getParent(); 669 | return new RectF( 670 | ((float) iv.getLeft() + iv.getX()) / (float) parent.getWidth(), 671 | ((float) iv.getTop() + iv.getY()) / (float) parent.getHeight(), 672 | ((float) iv.getRight() + iv.getX()) / (float) parent.getWidth(), 673 | ((float) iv.getBottom() + iv.getY()) / (float) parent.getHeight()); 674 | } 675 | 676 | /** 677 | * Post Result RectF 678 | * 679 | * @param iv 680 | * @param rectF 681 | * @param targetState 682 | */ 683 | private void postResultRect(final ImageView iv, final RectF rectF, 684 | final ActiveTrackTargetState targetState) { 685 | View parent = (View) iv.getParent(); 686 | RectF trackingRect = rectF; 687 | 688 | final int l = (int) ((trackingRect.centerX() - trackingRect.width() / 2) * parent.getWidth()); 689 | final int t = (int) ((trackingRect.centerY() - trackingRect.height() / 2) * parent.getHeight()); 690 | final int r = (int) ((trackingRect.centerX() + trackingRect.width() / 2) * parent.getWidth()); 691 | final int b = (int) ((trackingRect.centerY() + trackingRect.height() / 2) * parent.getHeight()); 692 | 693 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 694 | 695 | @Override 696 | public void run() { 697 | mTrackingImage.setVisibility(View.VISIBLE); 698 | if ((targetState == ActiveTrackTargetState.CANNOT_CONFIRM) 699 | || (targetState == ActiveTrackTargetState.UNKNOWN)) { 700 | iv.setImageResource(R.drawable.visual_track_cannotconfirm); 701 | } else if (targetState == ActiveTrackTargetState.WAITING_FOR_CONFIRMATION) { 702 | iv.setImageResource(R.drawable.visual_track_needconfirm); 703 | } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_LOW_CONFIDENCE) { 704 | iv.setImageResource(R.drawable.visual_track_lowconfidence); 705 | } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_HIGH_CONFIDENCE) { 706 | iv.setImageResource(R.drawable.visual_track_highconfidence); 707 | } 708 | iv.setX(l); 709 | iv.setY(t); 710 | iv.getLayoutParams().width = r - l; 711 | iv.getLayoutParams().height = b - t; 712 | iv.requestLayout(); 713 | } 714 | }); 715 | } 716 | 717 | /** 718 | * PostMultiResult 719 | * 720 | * @param iv 721 | * @param rectF 722 | * @param information 723 | */ 724 | private void postMultiResultRect(final MultiTrackingView iv, final RectF rectF, 725 | final SubjectSensingState information) { 726 | View parent = (View) iv.getParent(); 727 | RectF trackingRect = rectF; 728 | 729 | final int l = (int) ((trackingRect.centerX() - trackingRect.width() / 2) * parent.getWidth()); 730 | final int t = (int) ((trackingRect.centerY() - trackingRect.height() / 2) * parent.getHeight()); 731 | final int r = (int) ((trackingRect.centerX() + trackingRect.width() / 2) * parent.getWidth()); 732 | final int b = (int) ((trackingRect.centerY() + trackingRect.height() / 2) * parent.getHeight()); 733 | 734 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 735 | 736 | @Override 737 | public void run() { 738 | mTrackingImage.setVisibility(View.INVISIBLE); 739 | iv.setX(l); 740 | iv.setY(t); 741 | iv.getLayoutParams().width = r - l; 742 | iv.getLayoutParams().height = b - t; 743 | iv.requestLayout(); 744 | iv.updateView(information); 745 | } 746 | }); 747 | } 748 | 749 | /** 750 | * Update MultiTrackingView 751 | * 752 | * @param targetSensingInformations 753 | */ 754 | private void updateMultiTrackingView(final SubjectSensingState[] targetSensingInformations) { 755 | ArrayList indexs = new ArrayList<>(); 756 | for (SubjectSensingState target : targetSensingInformations) { 757 | indexs.add(target.getIndex()); 758 | if (targetViewHashMap.containsKey(target.getIndex())) { 759 | 760 | MultiTrackingView targetView = targetViewHashMap.get(target.getIndex()); 761 | postMultiResultRect(targetView, target.getTargetRect(), target); 762 | } else { 763 | MultiTrackingView trackingView = new MultiTrackingView(TrackingTestActivity.this); 764 | mBgLayout.addView(trackingView, layoutParams); 765 | targetViewHashMap.put(target.getIndex(), trackingView); 766 | } 767 | } 768 | 769 | ArrayList missingIndexs = new ArrayList<>(); 770 | for (Integer key : targetViewHashMap.keySet()) { 771 | boolean isDisappeared = true; 772 | for (Integer index : indexs) { 773 | if (index.equals(key)) { 774 | isDisappeared = false; 775 | break; 776 | } 777 | } 778 | 779 | if (isDisappeared) { 780 | missingIndexs.add(key); 781 | } 782 | } 783 | 784 | for (Integer i : missingIndexs) { 785 | MultiTrackingView view = targetViewHashMap.remove(i); 786 | mBgLayout.removeView(view); 787 | } 788 | } 789 | 790 | 791 | /** 792 | * Enable MultiTracking 793 | * 794 | * @param isChecked 795 | */ 796 | private void setAutoSensingEnabled(final boolean isChecked) { 797 | if (mActiveTrackOperator != null) { 798 | if (isChecked) { 799 | startMode = ActiveTrackMode.TRACE; 800 | mActiveTrackOperator.enableAutoSensing(new CompletionCallback() { 801 | @Override 802 | public void onResult(DJIError error) { 803 | if (error != null) { 804 | runOnUiThread(new Runnable() { 805 | @Override 806 | public void run() { 807 | mAutoSensingSw.setChecked(!isChecked); 808 | } 809 | }); 810 | } 811 | setResultToToast("Set AutoSensing Enabled " + (error == null ? "Success!" : error.getDescription())); 812 | } 813 | }); 814 | } else { 815 | disableAutoSensing(); 816 | } 817 | } 818 | } 819 | 820 | /** 821 | * Enable QuickShotMode 822 | * 823 | * @param isChecked 824 | */ 825 | private void setAutoSensingForQuickShotEnabled(final boolean isChecked) { 826 | if (mActiveTrackOperator != null) { 827 | if (isChecked) { 828 | mActiveTrackOperator.enableAutoSensingForQuickShot(new CompletionCallback() { 829 | @Override 830 | public void onResult(DJIError error) { 831 | if (error != null) { 832 | runOnUiThread(new Runnable() { 833 | @Override 834 | public void run() { 835 | mQuickShotSw.setChecked(!isChecked); 836 | } 837 | }); 838 | } 839 | setResultToToast("Set QuickShot Enabled " + (error == null ? "Success!" : error.getDescription())); 840 | } 841 | }); 842 | 843 | } else { 844 | disableAutoSensing(); 845 | } 846 | 847 | } 848 | } 849 | 850 | /** 851 | * Disable AutoSensing 852 | */ 853 | private void disableAutoSensing() { 854 | if (mActiveTrackOperator != null) { 855 | mActiveTrackOperator.disableAutoSensing(new CompletionCallback() { 856 | @Override 857 | public void onResult(DJIError error) { 858 | if (error == null) { 859 | runOnUiThread(new Runnable() { 860 | @Override 861 | public void run() { 862 | mConfirmBtn.setVisibility(View.INVISIBLE); 863 | mStopBtn.setVisibility(View.INVISIBLE); 864 | mRejectBtn.setVisibility(View.INVISIBLE); 865 | mConfigBtn.setVisibility(View.VISIBLE); 866 | isAutoSensingSupported = false; 867 | } 868 | }); 869 | clearCurrentView(); 870 | } 871 | setResultToToast(error == null ? "Disable Auto Sensing Success!" : error.getDescription()); 872 | } 873 | }); 874 | } 875 | } 876 | 877 | 878 | /** 879 | * Confim Mission by Index 880 | */ 881 | private void startAutoSensingMission() { 882 | if (trackingIndex != INVAVID_INDEX) { 883 | ActiveTrackMission mission = new ActiveTrackMission(null, startMode); 884 | mission.setQuickShotMode(quickShotMode); 885 | mission.setTargetIndex(trackingIndex); 886 | mActiveTrackOperator.startAutoSensingMission(mission, new CompletionCallback() { 887 | @Override 888 | public void onResult(DJIError error) { 889 | if (error == null) { 890 | setResultToToast("Accept Confim index: " + trackingIndex + " Success!"); 891 | trackingIndex = INVAVID_INDEX; 892 | } else { 893 | setResultToToast(error.getDescription()); 894 | } 895 | } 896 | }); 897 | } 898 | } 899 | 900 | 901 | /** 902 | * Change Storage Location 903 | */ 904 | private void switchStorageLocation(final SettingsDefinitions.StorageLocation storageLocation) { 905 | KeyManager keyManager = KeyManager.getInstance(); 906 | DJIKey storageLoactionkey = CameraKey.create(CameraKey.CAMERA_STORAGE_LOCATION, MAIN_CAMERA_INDEX); 907 | 908 | if (storageLocation == SettingsDefinitions.StorageLocation.INTERNAL_STORAGE) { 909 | keyManager.setValue(storageLoactionkey, SettingsDefinitions.StorageLocation.SDCARD, new SetCallback() { 910 | @Override 911 | public void onSuccess() { 912 | setResultToToast("Change to SD card Success!"); 913 | } 914 | 915 | @Override 916 | public void onFailure(@NonNull DJIError error) { 917 | setResultToToast(error.getDescription()); 918 | } 919 | }); 920 | } else { 921 | keyManager.setValue(storageLoactionkey, SettingsDefinitions.StorageLocation.INTERNAL_STORAGE, new SetCallback() { 922 | @Override 923 | public void onSuccess() { 924 | setResultToToast("Change to Interal Storage Success!"); 925 | } 926 | 927 | @Override 928 | public void onFailure(@NonNull DJIError error) { 929 | setResultToToast(error.getDescription()); 930 | } 931 | }); 932 | } 933 | } 934 | 935 | /** 936 | * determine SD Card is or not Ready 937 | * 938 | * @param index 939 | * @return 940 | */ 941 | private boolean isSDCardReady(int index) { 942 | KeyManager keyManager = KeyManager.getInstance(); 943 | 944 | return ((Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_INSERTED, index)) 945 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_INITIALIZING, index)) 946 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_READ_ONLY, index)) 947 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_HAS_ERROR, index)) 948 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_FULL, index)) 949 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_BUSY, index)) 950 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_FORMATTING, index)) 951 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_INVALID_FORMAT, index)) 952 | && (Boolean) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_IS_VERIFIED, index)) 953 | && (Long) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_AVAILABLE_CAPTURE_COUNT, index)) > 0L 954 | && (Integer) keyManager.getValue(CameraKey.create(CameraKey.SDCARD_AVAILABLE_RECORDING_TIME_IN_SECONDS, index)) > 0); 955 | } 956 | 957 | /** 958 | * determine Interal Storage is or not Ready 959 | * 960 | * @param index 961 | * @return 962 | */ 963 | private boolean isInteralStorageReady(int index) { 964 | KeyManager keyManager = KeyManager.getInstance(); 965 | 966 | boolean isInternalSupported = (boolean) 967 | keyManager.getValue(CameraKey.create(CameraKey.IS_INTERNAL_STORAGE_SUPPORTED, index)); 968 | if (isInternalSupported) { 969 | return ((Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_INSERTED, index)) 970 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_INITIALIZING, index)) 971 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_READ_ONLY, index)) 972 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_HAS_ERROR, index)) 973 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_FULL, index)) 974 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_BUSY, index)) 975 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_FORMATTING, index)) 976 | && !(Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_INVALID_FORMAT, index)) 977 | && (Boolean) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_IS_VERIFIED, index)) 978 | && (Long) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_AVAILABLE_CAPTURE_COUNT, index)) > 0L 979 | && (Integer) keyManager.getValue(CameraKey.create(CameraKey.INNERSTORAGE_AVAILABLE_RECORDING_TIME_IN_SECONDS, index)) > 0); 980 | } 981 | return false; 982 | } 983 | 984 | /** 985 | * Check Storage States 986 | */ 987 | private void checkStorageStates() { 988 | KeyManager keyManager = KeyManager.getInstance(); 989 | DJIKey storageLocationkey = CameraKey.create(CameraKey.CAMERA_STORAGE_LOCATION, MAIN_CAMERA_INDEX); 990 | Object storageLocationObj = keyManager.getValue(storageLocationkey); 991 | SettingsDefinitions.StorageLocation storageLocation = SettingsDefinitions.StorageLocation.INTERNAL_STORAGE; 992 | 993 | if (storageLocationObj instanceof SettingsDefinitions.StorageLocation){ 994 | storageLocation = (SettingsDefinitions.StorageLocation) storageLocationObj; 995 | } 996 | 997 | if (storageLocation == SettingsDefinitions.StorageLocation.INTERNAL_STORAGE) { 998 | if (!isInteralStorageReady(MAIN_CAMERA_INDEX) && isSDCardReady(MAIN_CAMERA_INDEX)) { 999 | switchStorageLocation(SettingsDefinitions.StorageLocation.SDCARD); 1000 | } 1001 | } 1002 | 1003 | if (storageLocation == SettingsDefinitions.StorageLocation.SDCARD) { 1004 | if (!isSDCardReady(MAIN_CAMERA_INDEX) && isInteralStorageReady(MAIN_CAMERA_INDEX)) { 1005 | switchStorageLocation(SettingsDefinitions.StorageLocation.INTERNAL_STORAGE); 1006 | } 1007 | } 1008 | 1009 | DJIKey isRecordingKey = CameraKey.create(CameraKey.IS_RECORDING, MAIN_CAMERA_INDEX); 1010 | Object isRecording = keyManager.getValue(isRecordingKey); 1011 | if (isRecording instanceof Boolean) { 1012 | if (((Boolean) isRecording).booleanValue()) { 1013 | keyManager.performAction(CameraKey.create(CameraKey.STOP_RECORD_VIDEO, MAIN_CAMERA_INDEX), new ActionCallback() { 1014 | @Override 1015 | public void onSuccess() { 1016 | setResultToToast("Stop Recording Success!"); 1017 | } 1018 | 1019 | @Override 1020 | public void onFailure(@NonNull DJIError error) { 1021 | setResultToToast("Stop Recording Fail,Error " + error.getDescription()); 1022 | } 1023 | }); 1024 | } 1025 | } 1026 | } 1027 | 1028 | /** 1029 | * Clear MultiTracking View 1030 | */ 1031 | private void clearCurrentView() { 1032 | if (targetViewHashMap != null && !targetViewHashMap.isEmpty()) { 1033 | Iterator> it = targetViewHashMap.entrySet().iterator(); 1034 | while (it.hasNext()) { 1035 | Map.Entry entry = it.next(); 1036 | final MultiTrackingView view = entry.getValue(); 1037 | it.remove(); 1038 | TrackingTestActivity.this.runOnUiThread(new Runnable() { 1039 | @Override 1040 | public void run() { 1041 | mBgLayout.removeView(view); 1042 | } 1043 | }); 1044 | } 1045 | } 1046 | } 1047 | } 1048 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/java/com/dji/P4MissionsDemo/Utils.java: -------------------------------------------------------------------------------- 1 | package com.dji.P4MissionsDemo; 2 | 3 | public class Utils { 4 | 5 | public static void addLineToSB(StringBuffer sb, String name, Object value) { 6 | if (sb == null) return; 7 | sb. 8 | append((name == null || "".equals(name)) ? "" : name + ": "). 9 | append(value == null ? "" : value + ""). 10 | append("\n"); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_disable.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_normal.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-mdpi/back_button_press.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/black_rectangle.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/black_rectangle.9.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/mission_other_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/mission_other_icon.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/mission_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/mission_stop.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/pointing_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/pointing_start.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/selector_back_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/selector_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_point_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_point_fail.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_point_now.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_point_now.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_point_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_point_tag.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_cannotconfirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_cannotconfirm.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_highconfidence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_highconfidence.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_lowconfidence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_lowconfidence.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_needconfirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_needconfirm.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_now.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_now.9.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_target_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_target_bg.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/visual_track_weak.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/visual_track_weak.9.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/drawable/white_rect.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions/9862ba4b2e94ef791c83349f939fa2955189d34e/P4MissionsDemo/app/src/main/res/drawable/white_rect.9.png -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 26 | 27 | 35 | 36 | 40 | 44 | 45 | -------------------------------------------------------------------------------- /P4MissionsDemo/app/src/main/res/layout/activity_pointing_test.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 23 | 24 | 32 | 33 | 43 | 44 | 45 | 52 | 53 | 54 | 64 | 65 | 69 | 70 | 76 | 77 | 85 | 86 | 93 | 94 | 95 | 96 | 97 | 104 | 105 |