基于MobileSDKV4版固件开发大疆无人机手机端遥控器(2)

原创 美男子玩编程 2023-06-08 12:00

点击上方蓝色字体,关注我们


上一篇文章(基于Mobile SDK V4版固件开发大疆无人机手机端遥控器(1))因为时间原因介绍了一部分内容,如果已经完成上一篇内容的操作就可以进行下面功能方面的制作了。自己开发的APP功能不是很多,但是已经将大疆无人机的常用功能进行了结合,同大家一起进行学习~


1


应用程序激活与绑定


如果在中国使用DJI飞行器固件,则需要使用该用户的DJI帐户激活控制DJI飞行器的移动应用程序。这将确保大疆能根据飞行器的地理位置和用户个人资料,为飞行器配置正确的地理空间信息和飞行功能集。激活系统的主要是:

  • 中国用户必须在每三个月至少登录一次DJI帐户以遍激活应用程序。

  • 激活信息将存储在应用程序中,直到用户注销为止。

  • 登录DJI帐号需要连接互联网。

  • 在中国境外,SDK会自动激活应用程序,无需用户登录。

  • 另外,中国用户必须将飞机绑定到DJI官方app中的用户帐户。这仅需要一次。如果未激活应用程序,未绑定飞机(如果需要)或使用旧版SDK(<4.1),则会禁用相机视频流,并且飞行限制在直径100m和高度30m的区域中,以确保飞机停留在视线范围内。


2


为应用程序创建UI

编写MApplication、ReceiverApplication和RegistrationActivity文件(此处粘贴部分代码)。

public class MApplication extends MultiDexApplication {
    private ReceiverApplication receiverApplication;

    @Override
    protected void attachBaseContext(Context paramContext) {
        super.attachBaseContext(paramContext);
        CrashHandler.getInstance().init(this);
        Helper.install(MApplication.this);
        if (receiverApplication == null) {
            receiverApplication = new ReceiverApplication();
            receiverApplication.setContext(this);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        receiverApplication.onCreate();
    }
}

上面的代码实现了绑定当前APP,将后续需要用到的类函数封装到ReceiverApplication 中,在ReceiverApplication 中也能够进行账户登录的操作。

public class ReceiverApplication extends MultiDexApplication {
    public static final String FLAG_CONNECTION_CHANGE = "activation_connection_change";

    private static BaseProduct mProduct;
    public Handler mHandler;

    private Application instance;

    public void setContext(Application application) {
        instance = application;
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        Helper.install(this);
    }

    @Override
    public Context getApplicationContext() {
        return instance;
    }

    public ReceiverApplication() {

    }

    /**
     * This function is used to get the instance of DJIBaseProduct.
     * If no product is connected, it returns null.
     */

    public static synchronized BaseProduct getProductInstance() {
        if (null == mProduct) {
            mProduct = DJISDKManager.getInstance().getProduct();
        }
        return mProduct;
    }

    public static synchronized Aircraft getAircraftInstance() {
        if (!isAircraftConnected()) return null;
        return (Aircraft) getProductInstance();
    }

    public static synchronized Camera getCameraInstance() {

        if (getProductInstance() == nullreturn null;

        Camera camera = null;

        if (getProductInstance() instanceof Aircraft){
            camera = ((Aircraft) getProductInstance()).getCamera();

        } else if (getProductInstance() instanceof HandHeld) {
            camera = ((HandHeld) getProductInstance()).getCamera();
        }

        return camera;
    }

    public static boolean isAircraftConnected() {
        return getProductInstance() != null && getProductInstance() instanceof Aircraft;
    }

    public static boolean isHandHeldConnected() {
        return getProductInstance() != null && getProductInstance() instanceof HandHeld;
    }

    public static boolean isProductModuleAvailable() {
        return (null != ReceiverApplication.getProductInstance());
    }

    public static boolean isCameraModuleAvailable() {
        return isProductModuleAvailable() &&
                (null != ReceiverApplication.getProductInstance().getCamera());
    }

    public static boolean isPlaybackAvailable() {
        return isCameraModuleAvailable() &&
                (null != ReceiverApplication.getProductInstance().getCamera().getPlaybackManager());
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mHandler = new Handler(Looper.getMainLooper());

        /**
         * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to
         * the SDK Registration result and the product changing.
         */

        //Listens to the SDK registration result
        DJISDKManager.SDKManagerCallback mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() {

            //Listens to the SDK registration result
            @Override
            public void onRegister(DJIError error) {

                if (error == DJISDKError.REGISTRATION_SUCCESS) {

                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
//                            ToastUtils.showToast(getApplicationContext(), "注册成功");
//                            Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_LONG).show();
//                            loginAccount();
                        }
                    });

                    DJISDKManager.getInstance().startConnectionToProduct();

                } else {

                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {

                        @Override
                        public void run() {
//                            ToastUtils.showToast(getApplicationContext(), "注册sdk失败,请检查网络是否可用");
//                            Toast.makeText(getApplicationContext(), "注册sdk失败,请检查网络是否可用", Toast.LENGTH_LONG).show();
                        }
                    });

                }
                Log.e("TAG", error.toString());
            }

            @Override
            public void onProductDisconnect() {
                Log.d("TAG""设备连接");
                notifyStatusChange();
            }

            @Override
            public void onProductConnect(BaseProduct baseProduct) {
                Log.d("TAG", String.format("新设备连接:%s", baseProduct));
                notifyStatusChange();
            }

            @Override
            public void onProductChanged(BaseProduct baseProduct) {

            }

            @Override
            public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
                                          BaseComponent newComponent)
 
{
                if (newComponent != null) {
                    newComponent.setComponentListener(new BaseComponent.ComponentListener() {

                        @Override
                        public void onConnectivityChange(boolean isConnected) {
                            Log.d("TAG""设备连接已更改: " + isConnected);
                            notifyStatusChange();
                        }
                    });
                }

                Log.d("TAG",
                        String.format("设备改变 key:%s, 旧设备:%s, 新设备:%s",
                                componentKey,
                                oldComponent,
                                newComponent));

            }

            @Override
            public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {

            }

            @Override
            public void onDatabaseDownloadProgress(long l, long l1) {

            }
        };
        //Check the permissions before registering the application for android system 6.0 above.
        int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (permissionCheck == 0 && permissionCheck2 == 0)) {
            //This is used to start SDK services and initiate SDK.
            DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback);
//            ToastUtils.showToast(getApplicationContext(), "正在注册,请等待...");
//            Toast.makeText(getApplicationContext(), "正在注册,请等待...", Toast.LENGTH_LONG).show();

        } else {
//            ToastUtils.showToast(getApplicationContext(), "请检查是否授予了权限");
//            Toast.makeText(getApplicationContext(), "请检查是否授予了权限。", Toast.LENGTH_LONG).show();
        }

    }

    private void notifyStatusChange() {
        mHandler.removeCallbacks(updateRunnable);
        mHandler.postDelayed(updateRunnable, 500);
    }

    private Runnable updateRunnable = new Runnable() {

        @Override
        public void run() {
            Intent intent = new Intent(FLAG_CONNECTION_CHANGE);
            getApplicationContext().sendBroadcast(intent);
        }
    };

}

上面的代码是对BaseProduct、Aircraft和Camera类进行实例化,在后续使用中不用再去进行重复的实例化工作,减少内存的消耗。

@Layout(R.layout.activity_registration)
public class RegistrationActivity extends BaseActivity implements View.OnClickListener{

    private static final String TAG = RegistrationActivity.class.getName();
    private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false);

    private static final String[] permissions = new String[]{
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
            Manifest.permission.VIBRATE,
            Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_WIFI_STATE,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_NETWORK_STATE,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.CHANGE_WIFI_STATE,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_STATE,
    };


    @Override
    public void initViews() {
        isPermission();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ReceiverApplication.FLAG_CONNECTION_CHANGE);
        registerReceiver(mReceiver, filter);
    }

    @Override
    public void initDatas() {
        startSDKRegistration();
    }

    @Override
    protected void requestData() {
        
    }


    @Override
    protected void onResume() {
        super.onResume();
    }



    private void isPermission() {
        requestRunTimePermission(permissions, new IPermission() {
            @Override
            public void onGranted() {
            }

            @Override
            public void onDenied(List deniedPermissions) {

            }
        });
    }

  

    //无人机首次注册
        private void startSDKRegistration() {
            if (isRegistrationInProgress.compareAndSet(falsetrue)) {
                AsyncTask.execute(new Runnable() {
                    @Override
                    public void run() {
//                      showToasts("注册中,请等待...");
                        DJISDKManager.getInstance().registerApp(getApplicationContext(), new DJISDKManager.SDKManagerCallback() {
                            @Override
                            public void onRegister(DJIError djiError) {
                                if (djiError == DJISDKError.REGISTRATION_SUCCESS) {
                                    DJILog.e("App 注册", DJISDKError.REGISTRATION_SUCCESS.getDescription());
                                    DJISDKManager.getInstance().startConnectionToProduct();
    //                                showToasts("注册成功");
                                    loginAccount();

                                } else {
                                    showToasts("注册sdk失败,请检查网络是否可用");
                                }
                                Log.v(TAG, djiError.getDescription());
                            }

                            @Override
                            public void onProductDisconnect() {
                                Log.d(TAG, "产品断开连接");
    //                            showToasts("产品断开连接");

                            }

                            @Override
                            public void onProductConnect(BaseProduct baseProduct) {
                                Log.d(TAG, String.format("新产品连接:%s", baseProduct));
    //                            showToasts("产品连接");

                            }

                            @Override
                            public void onProductChanged(BaseProduct baseProduct) {

                            }

                            @Override
                            public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
                                                          BaseComponent newComponent)
 
{
                                if (newComponent != null) {
                                    newComponent.setComponentListener(new BaseComponent.ComponentListener() {

                                        @Override
                                        public void onConnectivityChange(boolean isConnected) {
                                            Log.d(TAG, "组件连接已更改: " + isConnected);
                                        }
                                    });
                                }
                                Log.d(TAG, String.format("改变设备Key:%s, " + "旧设备:%s, " + "新设备:%s",
                                        componentKey, oldComponent, newComponent));
                            }

                            @Override
                            public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {

                            }

                            @Override
                            public void onDatabaseDownloadProgress(long l, long l1) {

                            }
                        });
                    }
                });
            }
        }

    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            refreshSDKRelativeUI();
        }
    };

    private void refreshSDKRelativeUI() {
        BaseProduct mProduct = ReceiverApplication.getProductInstance();
        if (null != mProduct && mProduct.isConnected()) {
            Log.v(TAG, "刷新SDK: True");
            mButtonFlightTask.setEnabled(true);
            mButtonSettingRoute.setEnabled(true);
            mButtonFileManagement.setEnabled(true);
        } else {
            Log.v(TAG, "刷新SDK: False");
//            mButtonOpen.setEnabled(false);
//            mButtonSettingRoute.setEnabled(false);
//            mButtonFileManagement.setEnabled(false);
//            startSDKRegistration();
        }
    }

    protected long exitTime;   //记录第一次点击时的时间

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                showToast("再按一次退出程序");
                exitTime = System.currentTimeMillis();
            } else {
                RegistrationActivity.this.finish();
                System.exit(0);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }


        private void loginAccount() {
            UserAccountManager.getInstance().logIntoDJIUserAccount(thisnew CommonCallbacks.CompletionCallbackWith() {
                @Override
                public void onSuccess(UserAccountState userAccountState) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mButtonFlightTask.setEnabled(true);
                            mButtonSettingRoute.setEnabled(true);
                            mButtonFileManagement.setEnabled(true);
                        }
                    });
                }

                @Override
                public void onFailure(DJIError djiError) {

                }
            });
        }

}

上面的代码就要进行第一次注册登录了,当然你不需要自己去设计登录注册页面,大疆会调取自己的登录注册页面供你使用。

安装提示注册登录即可。

上面的这些做完后,恭喜你!现在,您的移动应用程序和飞机可以在中国使用而没有任何问题。换句话说,您的应用程序现在可以看到飞机的视频流,并且飞行将不仅限于直径为100m和高度为30m的圆柱体区域。


3


飞行界面使用


虽然说可以正常飞行了,但是飞行需要设计飞行界面。那么创建一下飞行界面的UI及逻辑处理文件。逻辑处理文件中包含了获取飞机的实时姿态信息,代码中有注释内容,描述的内容就不多说了。


导入UX SDK依赖

上一节有说过集成部分,其中内容有导入UxSDk 的操作,这里再顺便提一下。再build.gradle文件中加入implementation "com.dji:dji-uxsdk:4.16"依赖,等待安装即可。


设计界面UI

创建MainActivity文件及activity_main.xml。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_blue"
    android:id="@+id/root_view"
    tools:context=".ui.MainActivity">


    
    <RelativeLayout
        android:id="@+id/fpv_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <dji.ux.widget.FPVWidget
            android:id="@+id/fpv_widget"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            custom:sourceCameraNameVisibility="false" />


    RelativeLayout>

    <dji.ux.widget.FPVOverlayWidget
        android:id="@+id/fpv_overlay_widget"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="40dp"
        android:layout_toRightOf="@+id/TakeOffReturnPanel"
        android:layout_toLeftOf="@+id/CameraCapturePanel"
        android:layout_below="@+id/camera"
        tools:ignore="RtlHardcoded">


        <dji.ux.widget.RadarWidget
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>


    RelativeLayout>

    
    <LinearLayout
        android:id="@+id/TakeOffReturnPanel"
        android:layout_width="40dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="12dp"
        android:layout_marginBottom="4dp"
        android:layout_marginTop="50dp"
        android:orientation="vertical"
        android:gravity="center">


        <ImageView
            android:id="@+id/img_show_back"
            android:layout_width="match_parent"
            android:layout_height="38dp"
            android:src="@mipmap/ic_back_36dp"
            android:layout_marginBottom="10dp">ImageView
>

        <dji.ux.widget.TakeOffWidget
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginBottom="5dp" />


        <dji.ux.widget.ReturnHomeWidget
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"/>

        <ImageView
            android:id="@+id/img_live"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:src="@mipmap/ic_live_write_36dp">ImageView
>
    LinearLayout>

    <FrameLayout
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:id="@+id/secondary_video_view"
        android:layout_marginLeft="12dp"
        android:layout_marginBottom="7dp"
        android:layout_marginTop="50dp"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/TakeOffReturnPanel"
        android:background="@color/black">

        <dji.ux.widget.FPVWidget
            android:id="@+id/secondary_fpv_widget"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            custom:sourceCameraNameVisibility="false"
            custom:videoSource="secondary"/>

    FrameLayout>

    <dji.ux.workflow.CompassCalibratingWorkFlow
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


    <dji.ux.workflow.CameraSensorCleaningWorkFlow
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


    <dji.ux.widget.RemainingFlightTimeWidget
        android:layout_alignParentTop="true"
        android:layout_marginTop="18dp"
        android:layout_width="match_parent"
        android:id="@+id/remaining_flight_time"
        android:background="@color/transparent"
        android:layout_height="20dp"/>


    <LinearLayout
        android:id="@+id/camera"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/signal"
        android:layout_marginTop="15dp"
        android:background="@color/dark_gray"
        android:orientation="horizontal">


        <dji.ux.widget.config.CameraConfigISOAndEIWidget
            android:layout_width="50dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.config.CameraConfigShutterWidget
            android:layout_width="50dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.config.CameraConfigApertureWidget
            android:layout_width="50dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.config.CameraConfigEVWidget
            android:layout_width="50dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.config.CameraConfigWBWidget
            android:layout_width="60dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.config.CameraConfigStorageWidget
            android:layout_width="108dp"
            android:layout_height="25dp"/>

        <dji.ux.widget.config.CameraConfigSSDWidget
            android:layout_width="125dp"
            android:layout_height="25dp"/>

    LinearLayout>
    <LinearLayout
        android:id="@+id/camera2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_below="@id/camera"
        android:layout_toLeftOf="@+id/CameraCapturePanel"
        android:background="@color/dark_gray"
        android:orientation="horizontal">

        <dji.ux.widget.SpeakerWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.AutoExposureLockWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.FocusModeWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.FocusExposureSwitchWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.BeaconWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.SpotlightWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <dji.ux.widget.AccessLockerWidget
            android:layout_width="35dp"
            android:layout_height="35dp"/>

    LinearLayout>
    <dji.ux.widget.ManualFocusWidget
        android:layout_alignTop="@+id/camera2"
        android:layout_toLeftOf="@+id/camera2"

        android:layout_width="50dp"
        android:layout_height="210dp"
        tools:ignore="RtlHardcoded"/>


    <dji.ux.widget.MapWidget
        android:id="@+id/map_widget"
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:layout_marginRight="12dp"
        android:layout_marginBottom="12dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"/>


    

    <dji.ux.widget.controls.CameraControlsWidget
        android:id="@+id/CameraCapturePanel"
        android:layout_alignParentRight="true"
        android:layout_below="@id/camera"
        android:layout_width="50dp"
        android:layout_height="213dp"
        android:layout_marginTop="5dp"
        tools:ignore="RtlHardcoded"/>


    
    <LinearLayout
        android:id="@+id/signal"
        android:layout_width="match_parent"
        android:layout_height="25dp"
        android:background="@color/dark_gray"
        android:orientation="horizontal">


        <dji.ux.widget.PreFlightStatusWidget
            android:layout_width="180dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.FlightModeWidget
            android:layout_width="103dp"
            android:layout_height="22dp"/>


        <dji.ux.widget.GPSSignalWidget
            android:layout_width="44dp"
            android:layout_height="22dp"/>


        <dji.ux.widget.VisionWidget
            android:layout_width="22dp"
            android:layout_height="22dp"/>


        <dji.ux.widget.RemoteControlSignalWidget
            android:layout_width="38dp"
            android:layout_height="22dp"/>


        <dji.ux.widget.VideoSignalWidget
            android:layout_width="38dp"
            android:layout_height="22dp"/>


        <dji.ux.widget.WiFiSignalWidget
            android:layout_width="32dp"
            android:layout_height="25dp"/>


        <dji.ux.widget.BatteryWidget
            android:layout_width="96dp"
            android:layout_height="22dp"
            custom:excludeView="singleVoltage"/>


        <dji.ux.widget.ConnectionWidget
            android:layout_marginTop="3dp"
            android:layout_width="18dp"
            android:layout_height="18dp"/>

    LinearLayout>

    <LinearLayout
        android:id="@+id/dashboard_widget"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:padding="12dp">


        <dji.ux.widget.dashboard.DashboardWidget
            android:id="@+id/Compass"
            android:layout_width="405dp"
            android:layout_height="91dp"
            android:layout_marginRight="12dp"
            tools:ignore="RtlHardcoded" />


    LinearLayout>




    
    <dji.ux.widget.HistogramWidget
        android:layout_width="150dp"
        android:layout_height="75dp"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/TakeOffReturnPanel"
        tools:ignore="RtlHardcoded" />


    <dji.ux.panel.CameraSettingExposurePanel
        android:layout_width="180dp"
        android:layout_below="@id/camera"
        android:layout_toLeftOf="@+id/CameraCapturePanel"
        android:gravity="center"
        android:layout_height="263dp"
        android:visibility="gone"
        tools:ignore="RtlHardcoded"/>


    <dji.ux.panel.CameraSettingAdvancedPanel
        android:layout_width="180dp"
        android:layout_height="263dp"
        android:layout_below="@id/camera"
        android:layout_toLeftOf="@+id/CameraCapturePanel"
        android:gravity="center"
        android:visibility="gone"
        tools:ignore="RtlHardcoded"/>


    <dji.ux.panel.RTKStatusPanel
        android:id="@+id/rtk_panel"
        android:layout_width="500dp"
        android:layout_height="350dp"
        android:layout_below="@id/signal"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:visibility="gone"/>


    <dji.ux.widget.ColorWaveformWidget
        android:layout_width="394dp"
        android:layout_height="300dp"
        android:layout_below="@+id/camera"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:visibility="gone"/>


    
    <dji.ux.panel.PreFlightCheckListPanel
        android:id="@+id/pre_flight_check_list"
        android:layout_width="400dp"
        android:layout_height="wrap_content"
        android:layout_below="@id/signal"
        custom:excludeItem="ESCStatus"
        android:visibility="gone"/>


    <dji.ux.panel.SpotlightPanel
        android:id="@+id/spotlight_panel"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_below="@id/camera2"
        android:layout_alignRight="@+id/camera2"
        android:visibility="gone"
        android:gravity="center" />


    <dji.ux.panel.SpeakerPanel
        android:id="@+id/speaker_panel"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/signal"
        android:visibility="gone"
        android:gravity="center" />


RelativeLayout>
@Layout(R.layout.activity_main)
public class MainActivity extends BaseActivity implements View.OnClickListener {

    @BindView(R.id.img_live)
    ImageView mImageViewLive;

    private MapWidget mapWidget;
    private DJIMap aMap;
    private ViewGroup parentView;
    private FPVWidget fpvWidget;
    private FPVWidget secondaryFPVWidget;
    private RelativeLayout primaryVideoView;
    private FrameLayout secondaryVideoView;
    private boolean isMapMini = true;
    private String liveShowUrl = "";

    private int height;
    private int width;
    private int margin;
    private int deviceWidth;
    private int deviceHeight;

    private SharedPreUtils mSharedPreUtils;
    //unix时间戳
    private String dateStr = "";
    //飞行器管理器
    private FlightController controller;
    //经纬度
    private double lat = 0, lon = 0;
    //高度
    private float high = 0;
    //飞机的姿态
    private Attitude attitude;
    //俯仰角、滚转、偏航值
    private double pitch = 0, roll = 0, yaw = 0;
    //飞机的速度
    private float velocity_X = 0, velocity_Y = 0, velocity_Z = 0;
    //飞机/控制器电池管理器
    private Battery battery;
    //电池电量、温度
    private int power = 0;
    private float temperature = 0;
    //云台管理器
    private Gimbal gimbal;
    //云台的姿态
    private dji.common.gimbal.Attitude g_attitude;
    //俯仰角、滚转、偏航值
    private double g_pitch = 0, g_roll = 0, g_yaw = 0;

    private Camera camera;
    private List lens = new ArrayList<>();

    private List djiList = new ArrayList<>();

    //手柄控制器
    private HandheldController handheldController;
    //手柄电量
    private int h_power = 0;

    private static List list = new ArrayList<>();

    private static List getList = new ArrayList<>();

    private MediaManager mMediaManager;

    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;

    private List arrayList = new ArrayList<>();

    private List startList = new ArrayList<>();

    private List endList = new ArrayList<>();

    private boolean isStartLive = false;

    private boolean isFlying = false;

    private boolean start = false;

    private BaseProduct mProduct;

    private String posName = "";

    //webSocket
    private JWebSocketClient client;
    private Map params = new HashMap<>();
    Map mapData = new HashMap<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        height = ToolKit.dip2px(this100);
        width = ToolKit.dip2px(this150);
        margin = ToolKit.dip2px(this12);

        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        final Display display = windowManager.getDefaultDisplay();
        Point outPoint = new Point();
        display.getRealSize(outPoint);
        deviceHeight = outPoint.y;
        deviceWidth = outPoint.x;
        parentView = (ViewGroup) findViewById(R.id.root_view);
        fpvWidget = findViewById(R.id.fpv_widget);
        fpvWidget.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onViewClick(fpvWidget);
            }
        });
        primaryVideoView = (RelativeLayout) findViewById(R.id.fpv_container);
        secondaryVideoView = (FrameLayout) findViewById(R.id.secondary_video_view);
        secondaryFPVWidget = findViewById(R.id.secondary_fpv_widget);
        secondaryFPVWidget.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                swapVideoSource();
            }
        });
        if (VideoFeeder.getInstance() != null) {
            //If secondary video feed is already initialized, get video source
            updateSecondaryVideoVisibility(VideoFeeder.getInstance().getSecondaryVideoFeed().getVideoSource() != PhysicalSource.UNKNOWN);
            //If secondary video feed is not yet initialized, wait for active status
            VideoFeeder.getInstance().getSecondaryVideoFeed()
                    .addVideoActiveStatusListener(isActive ->
                            runOnUiThread(() -> updateSecondaryVideoVisibility(isActive)));
        }
        mSharedPreUtils = SharedPreUtils.getInStance(this);
        this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        mapWidget = findViewById(R.id.map_widget);
        mapWidget.setFlightPathColor(Color.parseColor("#2fa8e7"));
        mapWidget.setFlightPathWidth(15);
        mapWidget.setDirectionToHomeVisible(false);
        mapWidget.initAMap(new MapWidget.OnMapReadyListener() {
            @Override
            public void onMapReady(@NonNull DJIMap djiMap) {
                djiMap.setOnMapClickListener(new DJIMap.OnMapClickListener() {
                    @Override
                    public void onMapClick(DJILatLng latLng) {
                        onViewClick(mapWidget);
                    }
                });
                djiMap.getUiSettings().setZoomControlsEnabled(false);
            }
        });
        if (aMap == null) {
            aMap = mapWidget.getMap();
        }
        mapWidget.onCreate(savedInstanceState);

        mProduct = ReceiverApplication.getProductInstance();
        if (null != mProduct && mProduct.isConnected()) {
            flyInformation(mProduct);
            batteryInformation(mProduct);
            cameraInformation(mProduct);
            camera(mProduct);
        }

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Message msg = new Message();
                if (isFlying && !start) {
                    start = true;
                    
            
                }
                if (!isFlying && start) {
                    start = false;
              
                }
                if (isFlying && high >= 0) {
                    msg.what = 1;
                }
                mHandler.sendMessage(msg);
            }
        }, 200200);
    }

    Handler mHandler = new Handler() {
        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case 1:
                    Long time = System.currentTimeMillis();
//                    MyLog.d("时间:"+time);
                    RecordModule module = new RecordModule(String.valueOf(projectId), String.valueOf(planeId),
                            trajectoryId, time, String.valueOf(lon), String.valueOf(lat),
                            String.valueOf(high), String.valueOf(yaw), String.valueOf(pitch), String.valueOf(roll),
                            String.valueOf(""), String.valueOf(velocity_X), String.valueOf(velocity_Y),
                            String.valueOf(velocity_Z), String.valueOf(g_yaw), String.valueOf(g_roll), String.valueOf(g_pitch));
                    http.getHttp(INSERT_DATA, GsonUtil.GsonString(module));
                    break;
                case 2:
                    MyLog.d("飞机移动的数据:"+msg.obj.toString());
                    ControlModule control = GsonUtil.GsonToBean(msg.obj.toString(),ControlModule.class);
                    if (controller!=null&&isFlying){
                        if (control.getContent().isBack()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(-10,0,0,0),null);
                        }
                        if (control.getContent().isFront()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(10,0,0,0),null);
                        }
                        if (control.getContent().isDown()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(0,0,0,-4),null);
                        }
                        if (control.getContent().isUp()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(0,0,0,4),null);
                        }
                        if (control.getContent().isLeft()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(0,-10,0,0),null);
                        }
                        if (control.getContent().isRight()){
                            controller.sendVirtualStickFlightControlData(new FlightControlData(0,10,0,0),null);
                        }
                    }else {
                        MyLog.d("controller控制器为空");
                    }
                    break;
            }
        }
    };

    @Override
    public void initViews() {
        mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();
        getFileList("start");
    }

    @Override
    public void onComplete(String url, String jsonStr) {
        super.onComplete(url, jsonStr);
     
    }
    @Override
    public void initDatas() {

    }

    private void onViewClick(View view) {
        if (view == fpvWidget && !isMapMini) {
            resizeFPVWidget(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT, 00);
            reorderCameraCapturePanel();
            ResizeAnimation mapViewAnimation = new ResizeAnimation(mapWidget, deviceWidth, deviceHeight, width, height, margin);
            mapWidget.startAnimation(mapViewAnimation);
            isMapMini = true;
        } else if (view == mapWidget && isMapMini) {
            hidePanels();
            resizeFPVWidget(width, height, margin, 12);
            reorderCameraCapturePanel();
            ResizeAnimation mapViewAnimation = new ResizeAnimation(mapWidget, width, height, deviceWidth, deviceHeight, 0);
            mapWidget.startAnimation(mapViewAnimation);
            isMapMini = false;
        }
    }

    private void resizeFPVWidget(int width, int height, int margin, int fpvInsertPosition) {
        RelativeLayout.LayoutParams fpvParams = (RelativeLayout.LayoutParams) primaryVideoView.getLayoutParams();
        fpvParams.height = height;
        fpvParams.width = width;
        fpvParams.rightMargin = margin;
        fpvParams.bottomMargin = margin;
        if (isMapMini) {
            fpvParams.addRule(RelativeLayout.CENTER_IN_PARENT, 0);
            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        } else {
            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0);
            fpvParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
        }
        primaryVideoView.setLayoutParams(fpvParams);

        parentView.removeView(primaryVideoView);
        parentView.addView(primaryVideoView, fpvInsertPosition);
    }

    private void reorderCameraCapturePanel() {
        View cameraCapturePanel = findViewById(R.id.CameraCapturePanel);
        parentView.removeView(cameraCapturePanel);
        parentView.addView(cameraCapturePanel, isMapMini ? 9 : 13);
    }

    private void swapVideoSource() {
        if (secondaryFPVWidget.getVideoSource() == FPVWidget.VideoSource.SECONDARY) {
            fpvWidget.setVideoSource(FPVWidget.VideoSource.SECONDARY);
            secondaryFPVWidget.setVideoSource(FPVWidget.VideoSource.PRIMARY);
        } else {
            fpvWidget.setVideoSource(FPVWidget.VideoSource.PRIMARY);
            secondaryFPVWidget.setVideoSource(FPVWidget.VideoSource.SECONDARY);
        }
    }

    private void updateSecondaryVideoVisibility(boolean isActive) {
        if (isActive) {
            secondaryVideoView.setVisibility(View.VISIBLE);
        } else {
            secondaryVideoView.setVisibility(View.GONE);
        }
    }

    private void hidePanels() {
        //These panels appear based on keys from the drone itself.
        if (KeyManager.getInstance() != null) {
            KeyManager.getInstance().setValue(CameraKey.create(CameraKey.HISTOGRAM_ENABLED), falsenull);
            KeyManager.getInstance().setValue(CameraKey.create(CameraKey.COLOR_WAVEFORM_ENABLED), falsenull);
        }

        //These panels have buttons that toggle them, so call the methods to make sure the button state is correct.
        CameraControlsWidget controlsWidget = findViewById(R.id.CameraCapturePanel);
        controlsWidget.setAdvancedPanelVisibility(false);
        controlsWidget.setExposurePanelVisibility(false);

        //These panels don't have a button state, so we can just hide them.
        findViewById(R.id.pre_flight_check_list).setVisibility(View.GONE);
        findViewById(R.id.rtk_panel).setVisibility(View.GONE);
        findViewById(R.id.spotlight_panel).setVisibility(View.GONE);
        findViewById(R.id.speaker_panel).setVisibility(View.GONE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Hide both the navigation bar and the status bar.
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        mapWidget.onResume();
        if (client == null) {
            MyLog.e("``````````````````````onResume");
//            initWebSocket();
        } else if (!client.isOpen()) {
            reconnectWs();//进入页面发现断开开启重连
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        MyLog.e("``````````````````````````````onStop");
    }

    @Override
    protected void onPause() {
        mapWidget.onPause();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        mapWidget.onDestroy();
        super.onDestroy();
        MyLog.e( "`````````````````````````onDestroy");
        closeConnect();
    }

    @Override
    protected void requestData() {

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapWidget.onSaveInstanceState(outState);
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapWidget.onLowMemory();
    }

    private class ResizeAnimation extends Animation {

        private View mView;
        private int mToHeight;
        private int mFromHeight;

        private int mToWidth;
        private int mFromWidth;
        private int mMargin;

        private ResizeAnimation(View v, int fromWidth, int fromHeight, int toWidth, int toHeight, int margin) {
            mToHeight = toHeight;
            mToWidth = toWidth;
            mFromHeight = fromHeight;
            mFromWidth = fromWidth;
            mView = v;
            mMargin = margin;
            setDuration(300);
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            float height = (mToHeight - mFromHeight) * interpolatedTime + mFromHeight;
            float width = (mToWidth - mFromWidth) * interpolatedTime + mFromWidth;
            RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) mView.getLayoutParams();
            p.height = (int) height;
            p.width = (int) width;
            p.rightMargin = mMargin;
            p.bottomMargin = mMargin;
            mView.requestLayout();
        }
    }


    //直播流推送
    @RequiresApi(api = Build.VERSION_CODES.O)
    @OnClick({R.id.img_live, R.id.img_show_back})
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.img_live:
                params.clear();
                mapData.clear();
                if (!isStartLive) {
                    if (!TextUtils.isEmpty(mSharedPreUtils.getStringSharePre("rtmp_url"))) {
                        liveShowUrl = mSharedPreUtils.getStringSharePre("rtmp_url") + trajectoryId;
//                        LiveModule module = new LiveModule("liveStreamStateChanged","plane",planeId,true,trajectoryId+"");
                        MyLog.d("地址:"+liveShowUrl);
                        startLiveShow();
                        isStartLive = true;
                        showToast("开始推流");
                    } else {
                        showToast("请先进行系统设置(RTMP)。");
                    }
                } else {
                    stopLiveShow();
                    isStartLive = false;
                }
                break;
            case R.id.img_show_back:
//                controller = null;
                closeConnect();
                MainActivity.this.finish();
                break;
        }
    }

    private boolean isLiveStreamManagerOn() {
        if (DJISDKManager.getInstance().getLiveStreamManager() == null) {
            return false;
        }
        return true;
    }

    private void startLiveShow() {
        if (!isLiveStreamManagerOn()) {
            return;
        }
        if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
            return;
        }
        new Thread() {
            @Override
            public void run() {
                DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl(liveShowUrl);
                DJISDKManager.getInstance().getLiveStreamManager().setAudioStreamingEnabled(true);
                int result = DJISDKManager.getInstance().getLiveStreamManager().startStream();
                DJISDKManager.getInstance().getLiveStreamManager().setStartTime();
            }
        }.start();
    }

    private void stopLiveShow() {
        AlertDialog.Builder Builder = new AlertDialog.Builder(MainActivity.this);
        Builder.setTitle("提示");
        Builder.setMessage("是否结束推流?");
        Builder.setIcon(android.R.drawable.ic_dialog_alert);
        Builder.setPositiveButton("确定"new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (!isLiveStreamManagerOn()) {
                    return;
                }
                DJISDKManager.getInstance().getLiveStreamManager().stopStream();

                showToast("结束推流");
            }
        });
        Builder.setNegativeButton("取消"null);
        Builder.show();
    }


    //获取飞机信息、云台信息
    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            BaseProduct mProduct = ReceiverApplication.getProductInstance();
            if (null != mProduct && mProduct.isConnected()) {
                flyInformation(mProduct);
                batteryInformation(mProduct);
                cameraInformation(mProduct);
                camera(mProduct);
//                MobileRemote(mProduct);
            }
        }
    };

//    private void MobileRemote(BaseProduct mProduct) {
//        if (null != mProduct && mProduct.isConnected()) {
//            mobileController = ((Aircraft) mProduct).getMobileRemoteController();
//        }
//    }

    //获取飞机信息
    private void flyInformation(BaseProduct mProduct) {
        if (null != mProduct && mProduct.isConnected()) {
            controller = ((Aircraft) mProduct).getFlightController();
        }
        if (controller != null) {
            controller.setStateCallback(new FlightControllerState.Callback() {
                @RequiresApi(api = Build.VERSION_CODES.O)
                @Override
                public void onUpdate(@NonNull FlightControllerState flightControllerState) {
                    //纬度、经度、高度、俯仰角、滚转、偏航值、速度
                    lat = flightControllerState.getAircraftLocation().getLatitude();
                    lon = flightControllerState.getAircraftLocation().getLongitude();
                    high = flightControllerState.getAircraftLocation().getAltitude();
                    attitude = flightControllerState.getAttitude();
                    pitch = attitude.pitch;
                    roll = attitude.roll;
                    yaw = attitude.yaw;
                    velocity_X = flightControllerState.getVelocityX();
                    velocity_Y = flightControllerState.getVelocityY();
                    velocity_Z = flightControllerState.getVelocityZ();
                    isFlying = flightControllerState.isFlying();
                    //                    MyLog.d("经度:" + lat + ",纬度:" + lon + ",高度:" + high + ",角度:" + pitch + ",速度:" + velocity_X + "," + velocity_Y + "," + velocity_Z);
                }
            });
            controller.setVirtualStickAdvancedModeEnabled(true);
            controller.setRollPitchCoordinateSystem(FlightCoordinateSystem.BODY);
            controller.setVerticalControlMode(VerticalControlMode.VELOCITY);
            controller.setRollPitchControlMode(RollPitchControlMode.VELOCITY);
            controller.setYawControlMode(YawControlMode.ANGULAR_VELOCITY);
//            controller.setTerrainFollowModeEnabled(false, new CommonCallbacks.CompletionCallback() {
//                @Override
//                public void onResult(DJIError djiError) {
//                    MyLog.d(djiError.getDescription());
//                }
//            });
//            controller.setTripodModeEnabled(false, new CommonCallbacks.CompletionCallback() {
//                @Override
//                public void onResult(DJIError djiError) {
//                    MyLog.d(djiError.getDescription());
//                }
//            });
//            controller.setFlightOrientationMode(FlightOrientationMode.AIRCRAFT_HEADING, new CommonCallbacks.CompletionCallback() {
//                @Override
//                public void onResult(DJIError djiError) {
//                    MyLog.d(djiError.getDescription());
//                    if (djiError==null){
//                        if (controller.isVirtualStickControlModeAvailable()){
//
//                        }else {
//                            MyLog.d("虚拟摇杆模式不可用");
//                        }
//                    }
//                }
//            });

        }
    }

    //电池信息
    private void batteryInformation(BaseProduct mProduct) {
        if (null != mProduct && mProduct.isConnected()) {
            battery = ((Aircraft) mProduct).getBattery();
        }
        if (battery != null) {
            battery.setStateCallback(new BatteryState.Callback() {
                @Override
                public void onUpdate(BatteryState batteryState) {
                    //电池电量
                    power = batteryState.getChargeRemainingInPercent();
                    //电池温度
                    temperature = batteryState.getTemperature();
                }
            });
        }
    }

    //云台信息
    private void cameraInformation(BaseProduct mProduct) {
        if (null != mProduct && mProduct.isConnected()) {
            gimbal = ((Aircraft) mProduct).getGimbal();
        }
        if (gimbal != null) {
            gimbal.setMode(GimbalMode.YAW_FOLLOW, null);
            gimbal.setStateCallback(new GimbalState.Callback() {
                @Override
                public void onUpdate(@NonNull GimbalState gimbalState) {
                    //俯仰角、滚转、偏航值
                    g_attitude = gimbalState.getAttitudeInDegrees();
                    g_pitch = g_attitude.getPitch();
                    g_roll = g_attitude.getRoll();
                    g_yaw = g_attitude.getYaw();
                }
            });
        }
    }

    private void camera(BaseProduct mProduct) {
        if (null != mProduct && mProduct.isConnected()) {
            camera = ((Aircraft) mProduct).getCamera();
        }
        if (camera != null) {
            //            camera.setVideoCaptionEnabled(true, new CommonCallbacks.CompletionCallback() {
            //                @Override
            //                public void onResult(DJIError djiError) {
            //                    MyLog.d("VideoCaptionEnabled"+djiError.toString());
            //                }
            //            });
            //            camera.setMediaFileCustomInformation(projectId +","+trajectoryId, new CommonCallbacks.CompletionCallback() {
            //                @Override
            //                public void onResult(DJIError djiError) {
            //                    MyLog.d("自定义信息:"+djiError.toString());
            //                }
            //            });
            camera.setSystemStateCallback(new SystemState.Callback() {
                @RequiresApi(api = Build.VERSION_CODES.O)
                @Override
                public void onUpdate(@NonNull SystemState systemState) {
                    if (systemState.getMode().equals(SettingsDefinitions.CameraMode.SHOOT_PHOTO)) {
                        if (systemState.isStoringPhoto()) {
                            dateStr = Long.toString(System.currentTimeMillis());
                            list.add(new DeviceInfo(dateStr, lat, lon, high, pitch, roll, yaw, velocity_X, velocity_Y, velocity_Z, g_yaw, g_roll, g_pitch));
                            CsvWriter.getInstance(",""UTF-8").writeDataToFile(list, FileUtil.checkDirPath(FLY_FILE_PATH + "/照片数据") + "/" + DateUtils.getCurrentDates() + ".csv");
                            list.clear();
                            return;
                        }
                    } else if (systemState.getMode().equals(SettingsDefinitions.CameraMode.RECORD_VIDEO)) {
                        if (systemState.isRecording()) {
                            try {
                                dateStr = Long.toString(System.currentTimeMillis());
                                list.add(new DeviceInfo(dateStr, lat, lon, high, pitch, roll, yaw, velocity_X, velocity_Y, velocity_Z, g_yaw, g_roll, g_pitch));
                                getList.add(dateStr);
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            if (list.size() > 1) {
                                posName = DateUtils.getCurrentDates() + ".csv";
                                CsvWriter.getInstance(",""UTF-8").writeDataToFile(list, FileUtil.checkDirPath(FLY_FILE_PATH + "/视频数据") + "/" + posName);
                                list.clear();
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        getFileList("end");
                                    }
                                });
                            }
                        }
                    }
                }
            });
        }
    }

    //遥控器信息
    private void handheldInforamation(BaseProduct mProduct) {
        if (null != mProduct && mProduct.isConnected()) {
            handheldController = ((HandHeld) mProduct).getHandHeldController();
        }
        if (handheldController != null) {
            handheldController.setPowerModeCallback(new PowerMode.Callback() {
                @Override
                public void onUpdate(PowerMode powerMode) {
                    switch (powerMode) {
                        case ON:
                            Battery battery = ((HandHeld) mProduct).getBattery();
                            battery.setStateCallback(new BatteryState.Callback() {
                                @Override
                                public void onUpdate(BatteryState batteryState) {
                                    h_power = batteryState.getChargeRemainingInPercent();
                                }
                            });
                            break;
                    }
                }
            });
        }
    }
   

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
//                        closeConnect();
            MainActivity.this.finish();
        }
        return super.onKeyDown(keyCode, event);
    }

}

完成后界面如下所示:

上面的工作完成后就可以在无人且宽阔的地方进行无人机飞行了。


4


多媒体资源的操作


多媒体文件操作,主要为多媒体文件的获取、查看、删除、下载的操作 同样创建多媒体功能文件FileManagementActivity及activity_file_management.xml

activity_file_management.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    tools:context=".ui.FileManagementActivity"
    android:orientation="vertical"
    android:background="@drawable/shape_corner_eight">

    <include layout="@layout/activity_toolbar"
        android:id="@+id/layout_file">include
>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp">

            <RadioGroup
                android:id="@+id/rg_file_management"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:orientation="horizontal"
                android:background="#2B3141"
                android:gravity="center">


                <RadioButton
                    android:id="@+id/rb_file_all"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:button="@null"
                    android:checked="true"
                    android:gravity="center"
                    android:text="全部"
                    android:textColor="@drawable/nav_item_color_selector"
                    android:textSize="18sp"
                    tools:ignore="TouchTargetSizeCheck">RadioButton
>

                <RadioButton
                    android:id="@+id/rb_file_photo"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center"
                    android:text="照片"
                    android:textColor="@drawable/nav_item_color_selector"
                    android:textSize="18sp"
                    tools:ignore="TouchTargetSizeCheck">RadioButton
>

                <RadioButton
                    android:id="@+id/rb_file_video"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center"
                    android:text="视频"
                    android:textColor="@drawable/nav_item_color_selector"
                    android:textSize="18sp"
                    tools:ignore="TouchTargetSizeCheck">RadioButton
>
            RadioGroup>
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_file_management"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:layout_marginTop="10dp">androidx.recyclerview.widget.RecyclerView
>
        LinearLayout>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="match_parent">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">


                <dji.ux.widget.FPVWidget
                    android:id="@+id/FPVWidget"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_centerInParent="true"
                    custom:sourceCameraNameVisibility="false" />

            RelativeLayout>
            <ImageView
                android:id="@+id/img_show"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:visibility="invisible">ImageView
>
            <LinearLayout
                android:id="@+id/ll_video_btn"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:orientation="horizontal"
                android:gravity="center"
                android:layout_marginBottom="15dp"
                android:layout_alignParentBottom="true"
                android:visibility="gone">


                <ImageView
                    android:id="@+id/img_video_pause"
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:src="@drawable/background_stop_selector">ImageView
>

                <ImageView
                    android:id="@+id/img_video_play"
                    android:layout_width="45dp"
                    android:layout_height="45dp"
                    android:layout_marginLeft="20dp"
                    android:src="@drawable/background_palyer_selector">ImageView
>

                <ImageView
                    android:id="@+id/img_video_stop"
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:layout_marginLeft="20dp"
                    android:src="@mipmap/ic_reset_36dp">ImageView
>
            LinearLayout>
        RelativeLayout>

    LinearLayout>
LinearLayout>

FileManagementActivity

@Layout(R.layout.activity_file_management)
public class FileManagementActivity extends BaseActivity implements View.OnClickListener {

    private static final String TAG = FileManagementActivity.class.getName();

    @BindView(R.id.layout_file)
    View mViewLayoutToolbar;
    @BindView(R.id.tv_toolbar_title)
    TextView mTextViewToolbarTitle;
    @BindView(R.id.ll_file)
    LinearLayout mLinearLayout;
    @BindView(R.id.rg_file_management)
    RadioGroup mRadioGroup;
    @BindView(R.id.rv_file_management)
    RecyclerView mRecyclerView;
    @BindView(R.id.img_show)
    ImageView mImageView;
    @BindView(R.id.ll_video_btn)
    LinearLayout mLinearLayoutVideo;
    @BindView(R.id.img_video_play)
    ImageView mImageViewVideoPlay;
    @BindView(R.id.img_video_pause)
    ImageView mImageViewVideoPause;

    private FileListAdapter mListAdapter;
    private List List = new ArrayList();
    private List mediaFileList = new ArrayList();
    private MediaManager mMediaManager;
    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;
    private MediaManager.VideoPlaybackState state;
    private ProgressDialog mLoadingDialog;
    private ProgressDialog mDownloadDialog;
    private FetchMediaTaskScheduler scheduler;
    private int lastClickViewIndex = -1;
    private int currentProgress = -1;
    private String SavePath = "";
    private View lastClickView;
    private boolean isResume = false;
    private SFTPUtils sftp;
    private SettingsDefinitions.StorageLocation storageLocation;

    @Override
    public void initViews() {
        mLinearLayout.setVisibility(View.VISIBLE);
        mTextViewToolbarTitle.setText("文件管理");
        mImageViewVideoPlay.setEnabled(true);
        mImageViewVideoPause.setEnabled(false);
        mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                List.clear();
                mediaFileList.clear();
                switch (checkedId) {
                    case R.id.rb_file_all:
                        getFileList(0);
                        mListAdapter.notifyDataSetChanged();
                        break;
                    case R.id.rb_file_photo:
                        getFileList(1);
                        mListAdapter.notifyDataSetChanged();
                        break;
                    case R.id.rb_file_video:
                        getFileList(2);
                        mListAdapter.notifyDataSetChanged();
                        break;
                }
            }
        });

        LinearLayoutManager layoutManager = new LinearLayoutManager(FileManagementActivity.this, RecyclerView.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);

        //Init FileListAdapter
        mListAdapter = new FileListAdapter();
        mRecyclerView.setAdapter(mListAdapter);

        //Init Loading Dialog
        mLoadingDialog = new ProgressDialog(FileManagementActivity.this);
        mLoadingDialog.setMessage("请等待...");
        mLoadingDialog.setCanceledOnTouchOutside(false);
        mLoadingDialog.setCancelable(false);

        //Init Download Dialog
        mDownloadDialog = new ProgressDialog(FileManagementActivity.this);
        mDownloadDialog.setTitle("下载中...");
        mDownloadDialog.setIcon(android.R.drawable.ic_dialog_info);
        mDownloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mDownloadDialog.setCanceledOnTouchOutside(false);
        mDownloadDialog.setCancelable(true);
        mDownloadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                if (mMediaManager != null) {
                    mMediaManager.exitMediaDownloading();
                }
            }
        });
        sftp = new SFTPUtils("49.4.79.249","uav","uavHHch@YREC.cn");
        ReceiverApplication.getAircraftInstance().getCamera().setStorageStateCallBack(new StorageState.Callback() {
            @Override
            public void onUpdate(@NonNull @NotNull StorageState storageState) {
                if(storageState.isInserted()) {
                    storageLocation = SettingsDefinitions.StorageLocation.SDCARD;
                    ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, new CommonCallbacks.CompletionCallback() {
                        @Override
                        public void onResult(DJIError djiError) {
                        }
                    });
                } else {
                    storageLocation = SettingsDefinitions.StorageLocation.INTERNAL_STORAGE;
                    ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.INTERNAL_STORAGE, new CommonCallbacks.CompletionCallback() {
                        @Override
                        public void onResult(DJIError djiError) {
                        }
                    });
                }
            }
        });
    }

    @Override
    public void initDatas() {

    }

    @Override
    protected void requestData() {

    }

    @Override
    public void onComplete(String url, String jsonStr) {
        super.onComplete(url, jsonStr);
        switch (url){
            case POST_VIDEO_INFO:
                break;
            default:
                getVideoJson(jsonStr);
                break;
        }
    }

    private void getVideoJson(String jsonStr) {
        VideoModule module = GsonUtil.GsonToBean(jsonStr,VideoModule.class);
        if (module.getCode() == 200 && module.getRows().size() == 1){
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    UpdateFileModule fileModule = new UpdateFileModule(module.getRows().get(0).getId(),"/mnt/uavFtpFolder/"+module.getRows().get(0).getFileName());
                    http.getHttp(POST_VIDEO_INFO,"PUT",GsonUtil.GsonString(fileModule));
                }
            });
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        initMediaManager();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }


    @Override
    protected void onDestroy() {
        lastClickView = null;
        if (mMediaManager != null) {
            mMediaManager.stop(null);
            mMediaManager.removeFileListStateCallback(this.updateFileListStateListener);
            mMediaManager.exitMediaDownloading();
            if (scheduler != null) {
                scheduler.removeAllTasks();
            }
        }

        if (isMavicAir2() || isM300()) {
            if (ReceiverApplication.getCameraInstance() != null) {
                ReceiverApplication.getCameraInstance().exitPlayback(djiError -> {
                    if (djiError != null) {
                        ReceiverApplication.getCameraInstance().setFlatMode(SettingsDefinitions.FlatCameraMode.PHOTO_SINGLE, djiError1 -> {
                            if (djiError1 != null) {
                                showToasts("设置单张拍照模式失败. " + djiError1.getDescription());
                            }
                        });
                    }
                });
            } else {
                ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, djiError -> {
                    if (djiError != null) {
                        showToasts("设置拍照模式失败. " + djiError.getDescription());
                    }
                });
            }
        }

        if (mediaFileList != null) {
            //            List.clear();
            mediaFileList.clear();
        }
        super.onDestroy();
    }

    private void showProgressDialogs() {
        runOnUiThread(new Runnable() {
            public void run() {
                if (mLoadingDialog != null) {
                    mLoadingDialog.show();
                }
            }
        });
    }

    private void hideProgressDialog() {
        runOnUiThread(new Runnable() {
            public void run() {
                if (null != mLoadingDialog && mLoadingDialog.isShowing()) {
                    mLoadingDialog.dismiss();
                }
            }
        });
    }

    private void ShowDownloadProgressDialog() {
        if (mDownloadDialog != null) {
            runOnUiThread(new Runnable() {
                public void run() {
                    mDownloadDialog.incrementProgressBy(-mDownloadDialog.getProgress());
                    mDownloadDialog.show();
                }
            });
        }
    }

    private void HideDownloadProgressDialog() {
        if (null != mDownloadDialog && mDownloadDialog.isShowing()) {
            runOnUiThread(new Runnable() {
                public void run() {
                    mDownloadDialog.dismiss();
                }
            });
        }
    }

    private void initMediaManager() {
        if (ReceiverApplication.getProductInstance() == null) {
            mediaFileList.clear();
            mListAdapter.notifyDataSetChanged();
            DJILog.e(TAG, "设备已断开");
            return;
        } else {
            if (null != ReceiverApplication.getCameraInstance() && ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {
                mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();
                if (null != mMediaManager) {
                    mMediaManager.addUpdateFileListStateListener(this.updateFileListStateListener);
                    mMediaManager.addMediaUpdatedVideoPlaybackStateListener(new MediaManager.VideoPlaybackStateListener() {
                        @Override
                        public void onUpdate(MediaManager.VideoPlaybackState videoPlaybackState) {
                            state = videoPlaybackState;
                            if (videoPlaybackState.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
//                                        mImageViewVideoPlay.setEnabled(true);
//                                        mImageViewVideoPause.setEnabled(false);
                                    }
                                });
                            }
                        }
                    });
                    if (isMavicAir2() || isM300()) {
                        ReceiverApplication.getCameraInstance().enterPlayback(djiError -> {
                            if (djiError == null) {
                                DJILog.e(TAG, "设置cameraMode成功");
                                showProgressDialogs();
                                getFileList(0);
                            } else {
                                showToasts("设置cameraMode失败");
                            }
                        });
                    } else {
                        ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, error -> {
                            if (error == null) {
                                DJILog.e(TAG, "设置cameraMode成功");
                                showProgressDialogs();
                                getFileList(0);
                            } else {
                                showToasts("设置cameraMode失败");
                            }
                        });
                    }
                    if (mMediaManager.isVideoPlaybackSupported()) {
                        DJILog.e(TAG, "摄像头支持视频播放!");
                    } else {
                        showToasts("摄像头不支持视频播放!");
                    }
                    scheduler = mMediaManager.getScheduler();
                }

            } else if (null != ReceiverApplication.getCameraInstance()
                    && !ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {
                showToasts("不支持媒体下载模式");
            }
        }
        return;
    }

    private void getFileList(int index) {
        mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();
        if (mMediaManager != null) {
            if ((currentFileListState == MediaManager.FileListState.SYNCING) || (currentFileListState == MediaManager.FileListState.DELETING)) {
                DJILog.e(TAG, "媒体管理器正忙.");
            } else {
                mMediaManager.refreshFileListOfStorageLocation(storageLocation, djiError -> {
//                mMediaManager.refreshFileListOfStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, djiError -> {
                    if (null == djiError) {
                        hideProgressDialog();
                        //Reset data
                        if (currentFileListState != MediaManager.FileListState.INCOMPLETE) {
                            List.clear();
                            mediaFileList.clear();
                            lastClickViewIndex = -1;
                        }
//                        List = mMediaManager.getSDCardFileListSnapshot();
//                        List = mMediaManager.getInternalStorageFileListSnapshot();
                        if (storageLocation == SettingsDefinitions.StorageLocation.SDCARD) {
                            List = mMediaManager.getSDCardFileListSnapshot();
                        } else {
                            List = mMediaManager.getInternalStorageFileListSnapshot();
                        }
                        switch (index) {
                            case 0:
                                for (int i = 0; i < List.size(); i++) {
                                    mediaFileList.add(List.get(i));
                                }
                                break;
                            case 1:
                                for (int i = 0; i < List.size(); i++) {
                                    if (List.get(i).getMediaType() == MediaFile.MediaType.JPEG) {
                                        mediaFileList.add(List.get(i));
                                        MyLog.d("图片名称:"+List.get(i).getFileName());
                                    }
                                }
                                break;
                            case 2:
                                for (int i = 0; i < List.size(); i++) {
                                    if ((List.get(i).getMediaType() == MediaFile.MediaType.MOV) || (List.get(i).getMediaType() == MediaFile.MediaType.MP4)) {
                                        mediaFileList.add(List.get(i));
                                        MyLog.d("视频名称:"+List.get(i).getFileName());
                                    }
                                }
                                break;
                        }
                        if (mediaFileList != null) {
                            Collections.sort(mediaFileList, (lhs, rhs) -> {
                                if (lhs.getTimeCreated() < rhs.getTimeCreated()) {
                                    return 1;
                                } else if (lhs.getTimeCreated() > rhs.getTimeCreated()) {
                                    return -1;
                                }
                                return 0;
                            });
                        }
                        scheduler.resume(error -> {
                            if (error == null) {
                                getThumbnails();
                            }
                        });
                    } else {
                        hideProgressDialog();
                        showToasts("获取媒体文件列表失败:" + djiError.getDescription());
                    }
                });
            }
        }
    }

    private void getThumbnails() {
        if (mediaFileList.size() <= 0) {
            showToasts("没有用于下载缩略图的文件信息");
            return;
        }
        for (int i = 0; i < mediaFileList.size(); i++) {
            getThumbnailByIndex(i);
        }
    }

    private FetchMediaTask.Callback taskCallback = new FetchMediaTask.Callback() {
        @Override
        public void onUpdate(MediaFile file, FetchMediaTaskContent option, DJIError error) {
            if (null == error) {
                if (option == FetchMediaTaskContent.PREVIEW) {
                    runOnUiThread(new Runnable() {
                        public void run() {
                            mListAdapter.notifyDataSetChanged();
                        }
                    });
                }
                if (option == FetchMediaTaskContent.THUMBNAIL) {
                    runOnUiThread(new Runnable() {
                        public void run() {
                            mListAdapter.notifyDataSetChanged();
                        }
                    });
                }
            } else {
                DJILog.e(TAG, "获取媒体任务失败" + error.getDescription());
            }
        }
    };

    private void getThumbnailByIndex(final int index) {
        FetchMediaTask task = new FetchMediaTask(mediaFileList.get(index), FetchMediaTaskContent.THUMBNAIL, taskCallback);
        scheduler.moveTaskToEnd(task);
    }

    class ItemHolder extends RecyclerView.ViewHolder {
        ImageView thumbnail_img;
        TextView file_name;
        TextView file_type;
        TextView file_size;
        TextView file_time;

        public ItemHolder(View itemView) {
            super(itemView);
            this.thumbnail_img = (ImageView) itemView.findViewById(R.id.filethumbnail);
            this.file_name = (TextView) itemView.findViewById(R.id.filename);
            this.file_type = (TextView) itemView.findViewById(R.id.filetype);
            this.file_size = (TextView) itemView.findViewById(R.id.fileSize);
            this.file_time = (TextView) itemView.findViewById(R.id.filetime);
        }
    }

    private class FileListAdapter extends RecyclerView.Adapter<ItemHolder{
        @Override
        public int getItemCount() {
            if (mediaFileList != null) {
                return mediaFileList.size();
            }
            return 0;
        }

        @Override
        public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_info_item, parent, false);
            return new ItemHolder(view);
        }

        @Override
        public void onBindViewHolder(ItemHolder mItemHolder, final int index) {

            final MediaFile mediaFile = mediaFileList.get(index);
            if (mediaFile != null) {
                if (mediaFile.getMediaType() != MediaFile.MediaType.MOV && mediaFile.getMediaType() != MediaFile.MediaType.MP4) {
                    mItemHolder.file_time.setVisibility(View.GONE);
                } else {
                    mItemHolder.file_time.setVisibility(View.VISIBLE);
                    mItemHolder.file_time.setText(mediaFile.getDurationInSeconds() + " s");
                }
                mItemHolder.file_name.setText(mediaFile.getFileName());
                mItemHolder.file_type.setText(mediaFile.getMediaType().name());
                mItemHolder.file_size.setText(String.format("%.2f", (double) (mediaFile.getFileSize() / 1048576d)) + " MB");
                mItemHolder.thumbnail_img.setImageBitmap(mediaFile.getThumbnail());
                mItemHolder.thumbnail_img.setTag(mediaFile);
                mItemHolder.itemView.setTag(index);

                if (lastClickViewIndex == index) {
                    mItemHolder.itemView.setSelected(true);
                } else {
                    mItemHolder.itemView.setSelected(false);
                }
                mItemHolder.itemView.setOnClickListener(itemViewOnClickListener);

            }
        }
    }

    private View.OnClickListener itemViewOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            lastClickViewIndex = (int) (v.getTag());
            if (lastClickView != null && lastClickView != v) {
                lastClickView.setSelected(false);
            }
            v.setSelected(true);
            lastClickView = v;
            MediaFile selectedMedia = mediaFileList.get(lastClickViewIndex);
            if (selectedMedia != null && mMediaManager != null) {
                addMediaTask(selectedMedia);
            }
        }
    };

    private void addMediaTask(final MediaFile mediaFile) {
        final FetchMediaTaskScheduler scheduler = mMediaManager.getScheduler();
        final FetchMediaTask task =
                new FetchMediaTask(mediaFile, FetchMediaTaskContent.PREVIEW, new FetchMediaTask.Callback() {
                    @Override
                    public void onUpdate(final MediaFile mediaFile, FetchMediaTaskContent fetchMediaTaskContent, DJIError error) {
                        if (null == error) {
                            if (mediaFile.getPreview() != null) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        final Bitmap previewBitmap = mediaFile.getPreview();
                                        mImageView.setVisibility(View.VISIBLE);
                                        mImageView.setImageBitmap(previewBitmap);
                                        if (mediaFile.getMediaType() == MediaFile.MediaType.MP4){
                                            mLinearLayoutVideo.setVisibility(View.VISIBLE);
                                        }else {
                                            mLinearLayoutVideo.setVisibility(View.GONE);
                                        }
                                    }
                                });
                            } else {
                                showToasts("没有图像bitmap!");
                            }
                        } else {
                            showToasts("查找图像内容失败: " + error.getDescription());
                        }
                    }
                });

        scheduler.resume(error -> {
            if (error == null) {
                scheduler.moveTaskToNext(task);
            } else {
                showToasts("恢复计划程序失败: " + error.getDescription());
            }
        });
    }

    //Listeners
    private MediaManager.FileListStateListener updateFileListStateListener = state -> currentFileListState = state;


    private void deleteFileByIndex(final int index) {
        ArrayList fileToDelete = new ArrayList();
        if (mediaFileList.size() > index) {
            fileToDelete.add(mediaFileList.get(index));
            mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam, DJICameraError>() {
                @Override
                public void onSuccess(List x, DJICameraError y) {
                    DJILog.e(TAG, "Delete file success");
                    runOnUiThread(new Runnable() {
                        public void run() {
                            mediaFileList.remove(index);
                            //Reset select view
                            lastClickViewIndex = -1;
                            lastClickView = null;
                            //Update recyclerView
                            mListAdapter.notifyDataSetChanged();
                        }
                    });
                }

                @Override
                public void onFailure(DJIError error) {
                    showToasts("删除失败");
                }
            });
        }
    }

    private void downloadFileByIndex(final int index) {

        if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.PANORAMA)
                || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.SHALLOW_FOCUS)) {
            return;
        }
        if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {
            SavePath = MyStatic.FLY_FILE_VIDEO;
        } else if (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.JPEG) {
            SavePath = MyStatic.FLY_FILE_PHOTO;
        }
        File destDir = new File(FileUtil.checkDirPath(SavePath));
        mediaFileList.get(index).fetchFileData(destDir,nullnew DownloadListener() {
            @Override
            public void onFailure(DJIError error) {
                HideDownloadProgressDialog();
                showToasts("下载失败" + error.getDescription());
                currentProgress = -1;
            }

            @Override
            public void onProgress(long total, long current) {
            }

            @Override
            public void onRateUpdate(long total, long current, long persize) {
                int tmpProgress = (int) (1.0 * current / total * 100);
                if (tmpProgress != currentProgress) {
                    mDownloadDialog.setProgress(tmpProgress);
                    currentProgress = tmpProgress;
                }
            }

            @Override
            public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {

            }

            @Override
            public void onStart() {
                currentProgress = -1;
                ShowDownloadProgressDialog();
            }

            @Override
            public void onSuccess(String filePath) {
                HideDownloadProgressDialog();
                showToasts("下载成功" + ":" + filePath);
                currentProgress = -1;
            }
        });
//        mediaFileList.get(index).fetchFileByteData(0, new DownloadListener() {
//            @Override
//            public void onStart() {
//                currentProgress = -1;
//                ShowDownloadProgressDialog();
//            }
//
//            @Override
//            public void onRateUpdate(long total, long current, long persize) {
//                int tmpProgress = (int) (1.0 * current / total * 100);
//                if (tmpProgress != currentProgress) {
//                    mDownloadDialog.setProgress(tmpProgress);
//                    currentProgress = tmpProgress;
//                }
//            }
//
//            @Override
//            public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {
//                byteToFile(bytes, FileUtil.checkDirPath(SavePath)+mediaFileList.get(index).getFileName());
//            }
//
//            @Override
//            public void onProgress(long l, long l1) {
//
//            }
//
//            @Override
//            public void onSuccess(String s) {
//                HideDownloadProgressDialog();
//                showToasts("下载成功" + ":" + s);
//                currentProgress = -1;
//            }
//
//            @Override
//            public void onFailure(DJIError djiError) {
//
//            }
//        });
    }

    public static void byteToFile(byte[] bytes, String path)
    
{
        try
        {
            // 根据绝对路径初始化文件
            File localFile = new File(path);
            if (!localFile.exists())
            {
                localFile.createNewFile();
            }
            // 输出流
            OutputStream os = new FileOutputStream(localFile);
            os.write(bytes);
            os.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private void playVideo() {
        mImageView.setVisibility(View.INVISIBLE);
        MediaFile selectedMediaFile = mediaFileList.get(lastClickViewIndex);
        if ((selectedMediaFile.getMediaType() == MediaFile.MediaType.MOV) || (selectedMediaFile.getMediaType() == MediaFile.MediaType.MP4)) {
            mMediaManager.playVideoMediaFile(selectedMediaFile, error -> {
                if (null != error) {
                    showToasts("播放失败 " + error.getDescription());
                } else {
                    DJILog.e(TAG, "播放成功");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mImageViewVideoPlay.setEnabled(false);
                            mImageViewVideoPause.setEnabled(true);
                        }
                    });
                }
            });
        }
    }

    @OnClick({R.id.img_back, R.id.img_delete, R.id.img_download, R.id.img_upload, R.id.img_video_play,
            R.id.img_video_pause, R.id.img_video_stop})
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.img_back:
                FileManagementActivity.this.finish();
                break;
            case R.id.img_delete:
                if (lastClickViewIndex >= 0) {
                    deleteFileByIndex(lastClickViewIndex);
                } else {
                    showToasts("请先选择文件。");
                }
                break;
            case R.id.img_download:
                if (lastClickViewIndex >= 0) {
                    downloadFileByIndex(lastClickViewIndex);
                } else {
                    showToasts("请先选择文件。");
                }
                break;
            case R.id.img_upload:
                if (lastClickViewIndex >= 0) {
                    uploadFileByIndex(lastClickViewIndex);
                } else {
                    showToasts("请先选择文件。");
                }
                break;
            case R.id.img_video_play:

                if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){
                    playVideo();
                }else if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.PAUSED){
                    mMediaManager.resume(error -> {
                        if (null != error) {
                            showToasts("继续播放失败:" + error.getDescription());
                        } else {
                            DJILog.e(TAG, "继续播放成功");
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mImageViewVideoPlay.setEnabled(false);
                                    mImageViewVideoPause.setEnabled(true);
                                }
                            });
                        }
                    });
                }
                break;
            case R.id.img_video_pause:
                mMediaManager.pause(error -> {
                    if (null != error) {
                        showToasts("暂停播放失败:" + error.getDescription());
                    } else {
                        DJILog.e(TAG, "暂停播放成功");
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mImageViewVideoPlay.setEnabled(true);
                                mImageViewVideoPause.setEnabled(false);
                            }
                        });
                    }
                });

                break;
            case R.id.img_video_stop:
                mMediaManager.stop(error -> {
                    if (null != error) {
                        showToasts("停止播放失败:" + error.getDescription());
                    } else {
                        DJILog.e(TAG, "停止播放成功");
                    }
                });
                break;
        }
    }

    private void uploadFileByIndex(int index) {

        if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {
            showProgressDialog("正在上传");
            new Thread(new Runnable() {
                        @Override
                        public void run() {
                            boolean isConnect = sftp.connect().isConnected();
                            if (isConnect){
                                boolean isUpdate = sftp.uploadFile("/mnt/uavFtpFolder/",mediaFileList.get(index).getFileName(), FLY_FILE_VIDEO, mediaFileList.get(index).getFileName());
                                if (isUpdate){
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            removeProgressDialog();
                                            http.getHttp(GET_VIDEO_INFO+"?fileName="+mediaFileList.get(index).getFileName(),"GET");
                                        }
                                    });
                                    sftp.disconnect();
                                }else {
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            showErrorTip("上传失败");
                                            removeProgressDialog();
                                        }
                                    });

                                }
                            }else {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        showErrorTip("服务器连接失败");
                                        removeProgressDialog();
                                    }
                                });
                            }
                        }
                    }).start();
        }else {
            showToasts("当前仅支持视频上传,请选择视频文件!");
        }
    }

    private boolean isMavicAir2() {
        BaseProduct baseProduct = ReceiverApplication.getProductInstance();
        if (baseProduct != null) {
            return baseProduct.getModel() == Model.MAVIC_AIR_2;
        }
        return false;
    }

    private boolean isM300() {
        BaseProduct baseProduct = ReceiverApplication.getProductInstance();
        if (baseProduct != null) {
            return baseProduct.getModel() == Model.MATRICE_300_RTK;
        }
        return false;
    }
}

运行后界面如下:

往期推荐
  • LabVIEW OCR 实现车牌识别

  • 和12岁小同志搞创客开发:有意思的激光切割技术

  • JavaScript+TensorFlow.js让你在视频中瞬间消失

  • 使用OpenCV测量图像中物体之间的距离

  • 全网仅此一篇:工业级压力传感器设计及实现

点击阅读原文,更精彩~

美男子玩编程 多领域、有深度的开发者交流平台
评论
  • Matter 协议,原名 CHIP(Connected Home over IP),是由苹果、谷歌、亚马逊和三星等科技巨头联合ZigBee联盟(现连接标准联盟CSA)共同推出的一套基于IP协议的智能家居连接标准,旨在打破智能家居设备之间的 “语言障碍”,实现真正的互联互通。然而,目标与现实之间总有落差,前期阶段的Matter 协议由于设备支持类型有限、设备生态协同滞后以及设备通信协议割裂等原因,并未能彻底消除智能家居中的“设备孤岛”现象,但随着2025年的到来,这些现象都将得到完美的解决。近期,
    华普微HOPERF 2025-02-27 10:32 212浏览
  • 美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?‌美国加州CEC能效认证与美国DOE能效认证在多个方面存在显著差异‌。认证范围和适用地区‌CEC能效认证‌:仅适用于在加利福尼亚州销售的电器产品。CEC认证的范围包括制冷设备、房间空调、中央空调、便携式空调、加热器、热水器、游泳池加热器、卫浴配件、光源、应急灯具、交通信号模块、灯具、洗碗机、洗衣机、干衣机、烹饪器具、电机和压缩机、变压器、外置电源、消费类电子设备
    张工nx808593 2025-02-27 18:04 120浏览
  • RGB灯光无法同步?细致的动态光效设定反而成为产品客诉来源!随着科技的进步和消费者需求变化,电脑接口设备单一功能性已无法满足市场需求,因此在产品上增加「动态光效」的形式便应运而生,藉此吸引消费者目光。这种RGB灯光效果,不仅能增强电脑周边产品的视觉吸引力,还能为用户提供个性化的体验,展现独特自我风格。如今,笔记本电脑、键盘、鼠标、鼠标垫、耳机、显示器等多种电脑接口设备多数已配备动态光效。这些设备的灯光效果会随着音乐节奏、游戏情节或使用者的设置而变化。想象一个画面,当一名游戏玩家,按下电源开关,整
    百佳泰测试实验室 2025-02-27 14:15 137浏览
  • 在物联网领域中,无线射频技术作为设备间通信的核心手段,已深度渗透工业自动化、智慧城市及智能家居等多元场景。然而,随着物联网设备接入规模的不断扩大,如何降低运维成本,提升通信数据的传输速度和响应时间,实现更广泛、更稳定的覆盖已成为当前亟待解决的系统性难题。SoC无线收发模块-RFM25A12在此背景下,华普微创新推出了一款高性能、远距离与高性价比的Sub-GHz无线SoC收发模块RFM25A12,旨在提升射频性能以满足行业中日益增长与复杂的设备互联需求。值得一提的是,RFM25A12还支持Wi-S
    华普微HOPERF 2025-02-28 09:06 143浏览
  • 应用趋势与客户需求,AI PC的未来展望随着人工智能(AI)技术的日益成熟,AI PC(人工智能个人电脑)逐渐成为消费者和企业工作中的重要工具。这类产品集成了最新的AI处理器,如NPU、CPU和GPU,并具备许多智能化功能,为用户带来更高效且直观的操作体验。AI PC的目标是提升工作和日常生活的效率,通过深度学习与自然语言处理等技术,实现更流畅的多任务处理、实时翻译、语音助手、图像生成等功能,满足现代用户对生产力和娱乐的双重需求。随着各行各业对数字转型需求的增长,AI PC也开始在各个领域中显示
    百佳泰测试实验室 2025-02-27 14:08 252浏览
  • 振动样品磁强计是一种用于测量材料磁性的精密仪器,广泛应用于科研、工业检测等领域。然而,其测量准确度会受到多种因素的影响,下面我们将逐一分析这些因素。一、温度因素温度是影响振动样品磁强计测量准确度的重要因素之一。随着温度的变化,材料的磁性也会发生变化,从而影响测量结果的准确性。因此,在进行磁性测量时,应确保恒温环境,以减少温度波动对测量结果的影响。二、样品制备样品的制备过程同样会影响振动样品磁强计的测量准确度。样品的形状、尺寸和表面处理等因素都会对测量结果产生影响。为了确保测量准确度,应严格按照规
    锦正茂科技 2025-02-28 14:05 134浏览
  •         近日,广电计量在聚焦离子束(FIB)领域编写的专业著作《聚焦离子束:失效分析》正式出版,填补了国内聚焦离子束领域实践性专业书籍的空白,为该领域的技术发展与知识传播提供了重要助力。         随着芯片技术不断发展,芯片的集成度越来越高,结构也日益复杂。这使得传统的失效分析方法面临巨大挑战。FIB技术的出现,为芯片失效分析带来了新的解决方案。它能够在纳米尺度上对芯片进行精确加工和分析。当芯
    广电计量 2025-02-28 09:15 116浏览
  • 1,微软下载免费Visual Studio Code2,安装C/C++插件,如果无法直接点击下载, 可以选择手动install from VSIX:ms-vscode.cpptools-1.23.6@win32-x64.vsix3,安装C/C++编译器MniGW (MinGW在 Windows 环境下提供类似于 Unix/Linux 环境下的开发工具,使开发者能够轻松地在 Windows 上编写和编译 C、C++ 等程序.)4,C/C++插件扩展设置中添加Include Path 5,
    黎查 2025-02-28 14:39 140浏览
  •           近日受某专业机构邀请,参加了官方举办的《广东省科技创新条例》宣讲会。在与会之前,作为一名技术工作者一直认为技术的法例都是保密和侵权方面的,而潜意识中感觉法律有束缚创新工作的进行可能。通过一个上午学习新法,对广东省的科技创新有了新的认识。广东是改革的前沿阵地,是科技创新的沃土,企业是创新的主要个体。《广东省科技创新条例》是广东省为促进科技创新、推动高质量发展而制定的地方性法规,主要内容包括: 总则:明确立法目
    广州铁金刚 2025-02-28 10:14 103浏览
  • 一、VSM的基本原理震动样品磁强计(Vibrating Sample Magnetometer,简称VSM)是一种灵敏且高效的磁性测量仪器。其基本工作原理是利用震动样品在探测线圈中引起的变化磁场来产生感应电压,这个感应电压与样品的磁矩成正比。因此,通过测量这个感应电压,我们就能够精确地确定样品的磁矩。在VSM中,被测量的样品通常被固定在一个震动头上,并以一定的频率和振幅震动。这种震动在探测线圈中引起了变化的磁通量,从而产生了一个交流电信号。这个信号的幅度和样品的磁矩有着直接的关系。因此,通过仔细
    锦正茂科技 2025-02-28 13:30 100浏览
  • 在2024年的科技征程中,具身智能的发展已成为全球关注的焦点。从实验室到现实应用,这一领域正以前所未有的速度推进,改写着人类与机器的互动边界。这一年,我们见证了具身智能技术的突破与变革,它不仅落地各行各业,带来新的机遇,更在深刻影响着我们的生活方式和思维方式。随着相关技术的飞速发展,具身智能不再仅仅是一个技术概念,更像是一把神奇的钥匙。身后的众多行业,无论愿意与否,都像是被卷入一场伟大变革浪潮中的船只,注定要被这股汹涌的力量重塑航向。01为什么是具身智能?为什么在中国?最近,中国具身智能行业的进
    艾迈斯欧司朗 2025-02-28 15:45 221浏览
  • 更多生命体征指标风靡的背后都只有一个原因:更多人将健康排在人生第一顺位!“AGEs,也就是晚期糖基化终末产物,英文名Advanced Glycation End-products,是存在于我们体内的一种代谢产物” 艾迈斯欧司朗亚太区健康监测高级市场经理王亚琴说道,“相信业内的朋友都会有关注,最近该指标的热度很高,它可以用来评估人的生活方式是否健康。”据悉,AGEs是可穿戴健康监测领域的一个“萌新”指标,近来备受关注。如果站在学术角度来理解它,那么AGEs是在非酶促条件下,蛋白质、氨基酸
    艾迈斯欧司朗 2025-02-27 14:50 400浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦