博客專欄

EEPW首頁 > 博客 > 基于Mobile SDK V4版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(2)

基于Mobile SDK V4版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(2)

發(fā)布人:美男子玩編程 時(shí)間:2023-06-09 來源:工程師 發(fā)布文章

上一篇文章(基于Mobile SDK V4版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(1))因?yàn)闀r(shí)間原因介紹了一部分內(nèi)容,如果已經(jīng)完成上一篇內(nèi)容的操作就可以進(jìn)行下面功能方面的制作了。自己開發(fā)的APP功能不是很多,但是已經(jīng)將大疆無人機(jī)的常用功能進(jìn)行了結(jié)合,同大家一起進(jìn)行學(xué)習(xí)~

1

應(yīng)用程序激活與綁定

如果在中國使用DJI飛行器固件,則需要使用該用戶的DJI帳戶激活控制DJI飛行器的移動應(yīng)用程序。這將確保大疆能根據(jù)飛行器的地理位置和用戶個(gè)人資料,為飛行器配置正確的地理空間信息和飛行功能集。激活系統(tǒng)的主要是:

  • 中國用戶必須在每三個(gè)月至少登錄一次DJI帳戶以遍激活應(yīng)用程序。

  • 激活信息將存儲在應(yīng)用程序中,直到用戶注銷為止。

  • 登錄DJI帳號需要連接互聯(lián)網(wǎng)。

  • 在中國境外,SDK會自動激活應(yīng)用程序,無需用戶登錄。

  • 另外,中國用戶必須將飛機(jī)綁定到DJI官方app中的用戶帳戶。這僅需要一次。如果未激活應(yīng)用程序,未綁定飛機(jī)(如果需要)或使用舊版SDK(<4.1),則會禁用相機(jī)視頻流,并且飛行限制在直徑100m和高度30m的區(qū)域中,以確保飛機(jī)停留在視線范圍內(nèi)。

2

為應(yīng)用程序創(chuàng)建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();
    }
}

上面的代碼實(shí)現(xiàn)了綁定當(dāng)前APP,將后續(xù)需要用到的類函數(shù)封裝到ReceiverApplication 中,在ReceiverApplication 中也能夠進(jìn)行賬戶登錄的操作。

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失敗,請檢查網(wǎng)絡(luò)是否可用");
//                            Toast.makeText(getApplicationContext(), "注冊sdk失敗,請檢查網(wǎng)絡(luò)是否可用", Toast.LENGTH_LONG).show();
                        }
                    });
                }
                Log.e("TAG", error.toString());
            }
            @Override
            public void onProductDisconnect() {
                Log.d("TAG""設(shè)備連接");
                notifyStatusChange();
            }
            @Override
            public void onProductConnect(BaseProduct baseProduct) {
                Log.d("TAG", String.format("新設(shè)備連接:%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""設(shè)備連接已更改: " + isConnected);
                            notifyStatusChange();
                        }
                    });
                }
                Log.d("TAG",
                        String.format("設(shè)備改變 key:%s, 舊設(shè)備:%s, 新設(shè)備:%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(), "請檢查是否授予了權(quán)限");
//            Toast.makeText(getApplicationContext(), "請檢查是否授予了權(quán)限。", 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類進(jìn)行實(shí)例化,在后續(xù)使用中不用再去進(jìn)行重復(fù)的實(shí)例化工作,減少內(nèi)存的消耗。

@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<String> deniedPermissions) {
            }
        });
    }
  
    //無人機(jī)首次注冊
        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失敗,請檢查網(wǎng)絡(luò)是否可用");
                                }
                                Log.v(TAG, djiError.getDescription());
                            }
                            @Override
                            public void onProductDisconnect() {
                                Log.d(TAG, "產(chǎn)品斷開連接");
    //                            showToasts("產(chǎn)品斷開連接");
                            }
                            @Override
                            public void onProductConnect(BaseProduct baseProduct) {
                                Log.d(TAG, String.format("新產(chǎn)品連接:%s", baseProduct));
    //                            showToasts("產(chǎn)品連接");
                            }
                            @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("改變設(shè)備Key:%s, " + "舊設(shè)備:%s, " + "新設(shè)備:%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;   //記錄第一次點(diǎn)擊時(shí)的時(shí)間
    @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<UserAccountState>() {
                @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) {
                }
            });
        }
}

上面的代碼就要進(jìn)行第一次注冊登錄了,當(dāng)然你不需要自己去設(shè)計(jì)登錄注冊頁面,大疆會調(diào)取自己的登錄注冊頁面供你使用。


圖片

安裝提示注冊登錄即可。


上面的這些做完后,恭喜你!現(xiàn)在,您的移動應(yīng)用程序和飛機(jī)可以在中國使用而沒有任何問題。換句話說,您的應(yīng)用程序現(xiàn)在可以看到飛機(jī)的視頻流,并且飛行將不僅限于直徑為100m和高度為30m的圓柱體區(qū)域。

3

飛行界面使用

雖然說可以正常飛行了,但是飛行需要設(shè)計(jì)飛行界面。那么創(chuàng)建一下飛行界面的UI及邏輯處理文件。邏輯處理文件中包含了獲取飛機(jī)的實(shí)時(shí)姿態(tài)信息,代碼中有注釋內(nèi)容,描述的內(nèi)容就不多說了。

導(dǎo)入U(xiǎn)X SDK依賴

上一節(jié)有說過集成部分,其中內(nèi)容有導(dǎo)入U(xiǎn)xSDk 的操作,這里再順便提一下。再build.gradle文件中加入implementation "com.dji:dji-uxsdk:4.16"依賴,等待安裝即可。

設(shè)計(jì)界面UI

創(chuàng)建MainActivity文件及activity_main.xml。

<?xml version="1.0" encoding="utf-8"?>
<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">

    <!-- Widget to see first person view (FPV) -->
    <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>
    <!--Take off and return home buttons on left -->
    <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"/>

    <!-- Everything below this line will appear on top of the full-screen map widget -->
    <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"/>

    <!-- Widgets in top status bar -->
    <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>
    <!-- Panels -->
    <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"/>

    <!-- Pre-flight checklist panel -->
    <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時(shí)間戳
    private String dateStr = "";
    //飛行器管理器
    private FlightController controller;
    //經(jīng)緯度
    private double lat = 0, lon = 0;
    //高度
    private float high = 0;
    //飛機(jī)的姿態(tài)
    private Attitude attitude;
    //俯仰角、滾轉(zhuǎn)、偏航值
    private double pitch = 0, roll = 0, yaw = 0;
    //飛機(jī)的速度
    private float velocity_X = 0, velocity_Y = 0, velocity_Z = 0;
    //飛機(jī)/控制器電池管理器
    private Battery battery;
    //電池電量、溫度
    private int power = 0;
    private float temperature = 0;
    //云臺管理器
    private Gimbal gimbal;
    //云臺的姿態(tài)
    private dji.common.gimbal.Attitude g_attitude;
    //俯仰角、滾轉(zhuǎn)、偏航值
    private double g_pitch = 0, g_roll = 0, g_yaw = 0;
    private Camera camera;
    private List<Lens> lens = new ArrayList<>();
    private List<DJILatLng> djiList = new ArrayList<>();
    //手柄控制器
    private HandheldController handheldController;
    //手柄電量
    private int h_power = 0;
    private static List<DeviceInfo> list = new ArrayList<>();
    private static List<String> getList = new ArrayList<>();
    private MediaManager mMediaManager;
    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;
    private List<MediaFile> arrayList = new ArrayList<>();
    private List<String> startList = new ArrayList<>();
    private List<String> 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<String,String> params = new HashMap<>();
    Map<String,String> 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("時(shí)間:"+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("飛機(jī)移動的數(shù)據(jù):"+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();//進(jìn)入頁面發(fā)現(xiàn)斷開開啟重連
        }
    }
    @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("請先進(jìn)行系統(tǒng)設(shè)置(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("是否結(jié)束推流?");
        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("結(jié)束推流");
            }
        });
        Builder.setNegativeButton("取消"null);
        Builder.show();
    }
    //獲取飛機(jī)信息、云臺信息
    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();
//        }
//    }
    //獲取飛機(jī)信息
    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) {
                    //緯度、經(jīng)度、高度、俯仰角、滾轉(zhuǎn)、偏航值、速度
                    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("經(jīng)度:" + 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) {
                    //俯仰角、滾轉(zhuǎn)、偏航值
                    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 + "/照片數(shù)據(jù)") + "/" + 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 + "/視頻數(shù)據(jù)") + "/" + 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);
    }
}

完成后界面如下所示:

圖片


上面的工作完成后就可以在無人且寬闊的地方進(jìn)行無人機(jī)飛行了。

4

多媒體資源的操作

多媒體文件操作,主要為多媒體文件的獲取、查看、刪除、下載的操作 同樣創(chuàng)建多媒體功能文件FileManagementActivity及activity_file_management.xml

activity_file_management.xml

<?xml version="1.0" encoding="utf-8"?>
<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<MediaFile> List = new ArrayList<MediaFile>();
    private List<MediaFile> mediaFileList = new ArrayList<MediaFile>();
    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("設(shè)置單張拍照模式失敗. " + djiError1.getDescription());
                            }
                        });
                    }
                });
            } else {
                ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, djiError -> {
                    if (djiError != null) {
                        showToasts("設(shè)置拍照模式失敗. " + 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, "設(shè)備已斷開");
            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, "設(shè)置cameraMode成功");
                                showProgressDialogs();
                                getFileList(0);
                            } else {
                                showToasts("設(shè)置cameraMode失敗");
                            }
                        });
                    } else {
                        ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, error -> {
                            if (error == null) {
                                DJILog.e(TAG, "設(shè)置cameraMode成功");
                                showProgressDialogs();
                                getFileList(0);
                            } else {
                                showToasts("設(shè)置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, "獲取媒體任務(wù)失敗" + 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("查找圖像內(nèi)容失敗: " + error.getDescription());
                        }
                    }
                });
        scheduler.resume(error -> {
            if (error == null) {
                scheduler.moveTaskToNext(task);
            } else {
                showToasts("恢復(fù)計(jì)劃程序失敗: " + error.getDescription());
            }
        });
    }
    //Listeners
    private MediaManager.FileListStateListener updateFileListStateListener = state -> currentFileListState = state;
    private void deleteFileByIndex(final int index) {
        ArrayList<MediaFile> fileToDelete = new ArrayList<MediaFile>();
        if (mediaFileList.size() > index) {
            fileToDelete.add(mediaFileList.get(index));
            mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam<List<MediaFile>, DJICameraError>() {
                @Override
                public void onSuccess(List<MediaFile> 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<String>() {
            @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<String>() {
//            @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
        {
            // 根據(jù)絕對路徑初始化文件
            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("繼續(xù)播放失敗:" + error.getDescription());
                        } else {
                            DJILog.e(TAG, "繼續(xù)播放成功");
                            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("暫停播放失?。?quot; + 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("服務(wù)器連接失敗");
                                        removeProgressDialog();
                                    }
                                });
                            }
                        }
                    }).start();
        }else {
            showToasts("當(dāng)前僅支持視頻上傳,請選擇視頻文件!");
        }
    }
    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;
    }
}

運(yùn)行后界面如下:

圖片



*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請聯(lián)系工作人員刪除。



關(guān)鍵詞: 大疆 遙控器

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉