电子产业一站式赋能平台

PCB联盟网

搜索
查看: 216|回复: 0
收起左侧

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

[复制链接]

853

主题

853

帖子

8351

积分

高级会员

Rank: 5Rank: 5

积分
8351
发表于 2023-6-8 12:00:00 | 显示全部楼层 |阅读模式

n1njpvfuqfl64023083205.gif

n1njpvfuqfl64023083205.gif

( `/ q+ L' ^& k* s8 E) |: o' o点击上方蓝色字体,关注我们, I/ ?6 g& N5 B) b
: w; i" J6 I* p; y5 y  G( U
上一篇文章(基于Mobile SDK V4版固件开发大疆无人机手机端遥控器(1))因为时间原因介绍了一部分内容,如果已经完成上一篇内容的操作就可以进行下面功能方面的制作了。自己开发的APP功能不是很多,但是已经将大疆无人机的常用功能进行了结合,同大家一起进行学习~
/ Y* F1 O6 ?1 @0 q9 [1
0 c, s1 [5 T0 ^应用程序激活与绑定
1 B8 b3 {5 c5 c: B; `& V如果在中国使用DJI飞行器固件,则需要使用该用户的DJI帐户激活控制DJI飞行器的移动应用程序。这将确保大疆能根据飞行器的地理位置和用户个人资料,为飞行器配置正确的地理空间信息和飞行功能集。激活系统的主要是:
! p' S! l. E" f+ D# C. [0 b6 {
  • 中国用户必须在每三个月至少登录一次DJI帐户以遍激活应用程序。
  • 激活信息将存储在应用程序中,直到用户注销为止。
  • 登录DJI帐号需要连接互联网。
  • 在中国境外,SDK会自动激活应用程序,无需用户登录。
  • 另外,中国用户必须将飞机绑定到DJI官方app中的用户帐户。这仅需要一次。如果未激活应用程序,未绑定飞机(如果需要)或使用旧版SDK(, k. i0 L1 d" R

    7 y" u& J& A" K2
    / Y5 I0 I/ ]% X; F- O' O3 S3 Z为应用程序创建UI编写MApplication、ReceiverApplication和RegistrationActivity文件(此处粘贴部分代码)。$ W1 A! L+ H8 q# W: ~
    public class MApplication extends MultiDexApplication {
    # b+ D6 L2 O% d    private ReceiverApplication receiverApplication;
    - S% M" s5 }, U' Q' |$ c    @Override3 j# D2 f2 }" j4 u' Z& n( X
        protected void attachBaseContext(Context paramContext) {
    & o* ]! m, F8 F& [        super.attachBaseContext(paramContext);
    & {! k3 i. I, n: E' h0 C        CrashHandler.getInstance().init(this);
    $ Y9 K  [; f' E& F, y, b        Helper.install(MApplication.this);$ E0 y7 |# C- y. s8 o
            if (receiverApplication == null) {
    8 q7 D6 ?( I% O. D( K            receiverApplication = new ReceiverApplication();2 C9 I' V" ]1 e/ j" o7 V% [$ F0 w
                receiverApplication.setContext(this);' [, R$ Q3 o: c
            }
    & x0 o6 C  x6 Y# A    }- M( Z/ S6 P4 D5 p& h: k+ R2 u) H
        @Override
    . z* O* N7 T- J* @4 x' o    public void onCreate() {
    - \  b* v* ]8 X: k: x6 G! N3 `6 o        super.onCreate();$ D  @. s( v9 l% F. u' T3 x$ s
            receiverApplication.onCreate();
    5 d* T0 x# w, `# E    }
    2 c6 k1 ?2 G1 G}  B1 T7 f/ q! w7 _
    上面的代码实现了绑定当前APP,将后续需要用到的类函数封装到ReceiverApplication 中,在ReceiverApplication 中也能够进行账户登录的操作。
    9 e! ?1 V" q5 Ypublic class ReceiverApplication extends MultiDexApplication {
    : u' X5 h% z& t6 i$ @& E$ O: x    public static final String FLAG_CONNECTION_CHANGE = "activation_connection_change";) i! v! W* `* e, ]3 X4 {6 M9 _, H
        private static BaseProduct mProduct;( ~& X6 ~2 z# h7 x$ {3 h( l
        public Handler mHandler;+ ^. u4 Z# z5 B  K' F# Z! x7 Y
        private Application instance;
    ( d1 a; Q6 _' i; y+ o$ F6 A    public void setContext(Application application) {+ E& e  t  f3 [% G
            instance = application;  K% N3 W: m4 V7 g% E" o1 ]
        }
    / b& J, @8 D, u* b& Z    @Override6 v$ D9 a5 y5 Z* ~; E7 R, K
        protected void attachBaseContext(Context base) {
    ! n& s' h9 }8 \        super.attachBaseContext(base);
    4 E. q  N4 X4 c9 I! Q        Helper.install(this);2 |+ i3 V2 ~) K& z$ c
        }
    7 n, t2 e! j  P9 i, U, ]- z# a    @Override
    6 M5 G# R. |! }1 J0 {- V    public Context getApplicationContext() {: g( e) d+ z, |  ^
            return instance;
      ?1 [3 A8 c9 @+ v2 k8 ^    }" |( s* L7 Q  b( A# ^* s
        public ReceiverApplication() {6 x# q: m1 B. Q% T0 _
        }
    + p2 _1 J" x2 O$ I& Y: ^1 R    /**# I  S, b. L3 [2 A
         * This function is used to get the instance of DJIBaseProduct.
      c# J7 n$ Q+ j/ C. O; a: o- [: M) X3 f. i     * If no product is connected, it returns null.
      X8 \/ D' Y, H* G8 V     */2 L+ N) k7 \  g+ u$ u$ b3 ?
        public static synchronized BaseProduct getProductInstance() {
    % ^& w& ~# y8 K8 A3 J        if (null == mProduct) {/ \. G4 [0 `6 ^% D' w' l' R- r; H
                mProduct = DJISDKManager.getInstance().getProduct();
    ' H5 N4 ~; }, O        }* V, K! S8 M% ~. ~' |- Z. R
            return mProduct;
    / K4 K0 g1 Q" m$ c) K, |    }! a* Y/ E7 P, W# {+ K
        public static synchronized Aircraft getAircraftInstance() {
    6 V" R% Q1 Y! u( w7 \        if (!isAircraftConnected()) return null;3 u- z" b) q$ E7 x
            return (Aircraft) getProductInstance();; U; c  T; q; [% u
        }
    - L, a! P; @0 X4 Z; M/ i  J    public static synchronized Camera getCameraInstance() {) F; S: B6 n8 {  g* ], m9 p4 g
            if (getProductInstance() == null) return null;: _( ]' l+ S8 k9 D
            Camera camera = null;" m8 f2 l  L+ k( |" _, ^1 m
            if (getProductInstance() instanceof Aircraft){6 o0 m) S  ]/ \. g8 t3 T  d2 o
                camera = ((Aircraft) getProductInstance()).getCamera();
    1 ^$ |2 i9 i6 s& [. D2 R        } else if (getProductInstance() instanceof HandHeld) {, |( f+ @0 h. o+ \( }' _
                camera = ((HandHeld) getProductInstance()).getCamera();
    & K" O! O0 z- q. @        }
    # U, B8 T, y1 I1 C7 A6 W+ O" ~& t        return camera;
    8 R" t1 c( j6 i! C* k    }
    * g& D; Z% e9 V7 y; l    public static boolean isAircraftConnected() {" y1 P$ r0 X4 |* ]' W8 }
            return getProductInstance() != null && getProductInstance() instanceof Aircraft;
    . a8 R2 ?" e1 D' K& q3 [    }/ d3 b8 ?4 G, U2 C! a
        public static boolean isHandHeldConnected() {) K1 w) E, E  K4 `4 k
            return getProductInstance() != null && getProductInstance() instanceof HandHeld;, e% p7 O& [: ^# X( O, ?8 @, U
        }) [7 H, |8 y5 S
        public static boolean isProductModuleAvailable() {
    + @( }# f; A3 J; E' ~1 C        return (null != ReceiverApplication.getProductInstance());
    " r! ^5 k5 [9 a4 V! ?    }
    % g) s0 w% _. \3 b    public static boolean isCameraModuleAvailable() {9 e! a$ H  o; a! Q& U& o
            return isProductModuleAvailable() &&
    # _9 e/ B3 L1 i6 m  }) `                (null != ReceiverApplication.getProductInstance().getCamera());
    ( |; B, i; J( a! H0 L8 v7 ~    }% u5 K2 X2 S/ J6 m3 i5 r
        public static boolean isPlaybackAvailable() {
    / ^/ t, j$ n; |8 W; Q. J        return isCameraModuleAvailable() &&
    2 B6 C% K  m2 N6 L( ?0 n2 @                (null != ReceiverApplication.getProductInstance().getCamera().getPlaybackManager());3 w; I* D% j) ]* ?& x
        }
    ; `4 l$ R, V+ r" R    @Override
    # G5 _2 J" r/ s$ N$ v' S8 S    public void onCreate() {7 I$ q; U# P$ F# M0 S+ r
            super.onCreate();9 G. d$ g; Y9 K. [% H
            mHandler = new Handler(Looper.getMainLooper());
    % t( H- j/ |3 k, z# `% W! q$ K        /**
    2 t' f7 G; ^: x) ^         * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to
    % N/ v  @, s/ ]0 Z% s. e5 G         * the SDK Registration result and the product changing.& `' W6 ~. f: B
             */
    $ \8 ]% U! C- u" x        //Listens to the SDK registration result
    5 L/ q$ w1 I% U* P        DJISDKManager.SDKManagerCallback mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() {
    3 k8 ?6 i5 S# W% ?+ S            //Listens to the SDK registration result
      Z; o- l! @8 L( s# ^! I# H            @Override6 z5 W0 B: S' \. V: z2 s
                public void onRegister(DJIError error) {9 c3 w4 u2 p) m4 D
                    if (error == DJISDKError.REGISTRATION_SUCCESS) {8 K) n( y+ K: p" v. d" l' ?. X
                        Handler handler = new Handler(Looper.getMainLooper());* i. X, g' e9 Z, }' t, ~2 s
                        handler.post(new Runnable() {9 C/ _& Y# w/ Q
                            @Override
    4 O( f5 t8 Q' u- z1 k' r                        public void run() {; `0 z; I; E( Y% t9 \# C
    //                            ToastUtils.showToast(getApplicationContext(), "注册成功");" L' q: B) k; z" t8 y1 j) I
    //                            Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_LONG).show();
    9 r0 g2 A  F1 \1 R. A  g3 c" z* h//                            loginAccount();& t. U, l& P! D+ M+ l% @0 a
                            }
    / R& N, d  u$ G0 e2 `% l                    });0 r$ U1 F6 i2 h; z+ E" _% W+ L
                        DJISDKManager.getInstance().startConnectionToProduct();- i3 A/ U& r- }! P- Q
                    } else {- ~  e, N4 j0 y5 t
                        Handler handler = new Handler(Looper.getMainLooper());
    % b) {1 K3 S; M! ^2 a                    handler.post(new Runnable() {$ |# S: k0 v& X/ f' v6 ]
                            @Override
    + E1 D6 a  X2 L0 ]7 G7 f) V                        public void run() {
    7 ^/ _. x5 b- A( ^" c//                            ToastUtils.showToast(getApplicationContext(), "注册sdk失败,请检查网络是否可用");4 D, u, W2 E( h1 z1 u
    //                            Toast.makeText(getApplicationContext(), "注册sdk失败,请检查网络是否可用", Toast.LENGTH_LONG).show();- b6 `* d* L, |# p5 _6 `
                            }* r; J# w" J+ t! P: U
                        });
    6 b3 y4 Z5 }! q* U/ d6 h                }
    ; ~9 _% C/ U0 m5 ~7 m  d                Log.e("TAG", error.toString());1 l% M! b7 y2 u7 h( t
                }
    % F- n- l+ I5 X; ^( I: o            @Override  r" d, x' j& g! p# t  e. v' v
                public void onProductDisconnect() {
    ' ^* Y( `/ g, |. l" s                Log.d("TAG", "设备连接");
    0 M' Y7 C# x( T4 u2 p                notifyStatusChange();2 \3 a. {) @8 N% {
                }  ^$ q/ }4 m5 s4 p
                @Override, F1 T! ^) w% E6 S
                public void onProductConnect(BaseProduct baseProduct) {
    4 p7 p! Q& c, j# K' a. d! }2 D0 u: e                Log.d("TAG", String.format("新设备连接:%s", baseProduct));
    ; \& U  v6 H/ C, Z/ H0 S                notifyStatusChange();
    / J2 A1 O- M, x4 i5 |1 T            }
    - J* c3 E- u( T! n0 D; \: f            @Override; V( v/ J2 K8 k. |7 h( T8 }$ Q: K
                public void onProductChanged(BaseProduct baseProduct) {
    / n! f5 v1 P3 H4 v/ Z            }
    6 n  _9 R/ w! S1 ^2 \, N& x3 p            @Override! z* q" n  x$ w9 C% G, e
                public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,) x# e, {* O5 M$ L, t6 W+ I
                                              BaseComponent newComponent) {" H4 L' L0 M4 p* x0 C. _  j
                    if (newComponent != null) {
    6 n( m# \( p3 `7 U6 j3 h9 m0 C3 L4 I                    newComponent.setComponentListener(new BaseComponent.ComponentListener() {: W3 \1 T5 e6 b1 a# P
                            @Override
    / P: [+ F1 d% O" j+ Z% m: W                        public void onConnectivityChange(boolean isConnected) {" t9 s- T  \/ V, r1 |
                                Log.d("TAG", "设备连接已更改: " + isConnected);
    * x) \! P9 t- z* i6 z) j                            notifyStatusChange();4 {3 N3 g4 A7 w, |9 g( o0 u! e4 x. V
                            }& H0 A1 b5 F1 n
                        });; u6 ^% L/ w  X( \. ]  P; K
                    }7 S! d" ^) Q/ f( ^6 }. n
                    Log.d("TAG",
    9 U' _% P/ N1 U* n; r8 A, a5 w                        String.format("设备改变 key:%s, 旧设备:%s, 新设备:%s",/ B  m1 R6 j  v  D7 o& s$ Q
                                    componentKey,
    " Z6 ^5 i0 d9 w. I6 g                                oldComponent,
    # d9 ~" G0 J9 l( A) Y                                newComponent));. C% s" Z7 V) G5 e& X6 C
                }
    9 ~0 G2 ]7 g9 R0 W3 Q0 k2 C# J: q            @Override
    , o3 n2 n* `0 l$ Z            public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {
    # }$ ^+ w' d0 [            }
    ' L" h+ V# I) U            @Override
    4 a0 p% }0 d7 G4 |: f9 l3 r            public void onDatabaseDownloadProgress(long l, long l1) {
    ; I1 B  F# y; {4 @2 [& x0 h            }3 L& e3 z$ F8 ?3 Q* G6 a3 C$ N
            };
    $ H- J) m( e2 ]0 t9 V& H, }        //Check the permissions before registering the application for android system 6.0 above.5 ~) y* h4 W2 ~  Z  j* T
            int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE);' q8 a; o$ ?8 j( K& R
            int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE);
    / p! r; Y+ d8 i" f        if (Build.VERSION.SDK_INT 0 && permissionCheck2 == 0)) {6 w; k2 L2 ]+ f/ }- W
                //This is used to start SDK services and initiate SDK.4 h+ K4 j( @1 |4 h: m; B7 x$ u
                DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback);* q1 k9 v8 R4 d8 v7 P; F$ f3 `" ^
    //            ToastUtils.showToast(getApplicationContext(), "正在注册,请等待...");: k; l. ]  B. M4 ?
    //            Toast.makeText(getApplicationContext(), "正在注册,请等待...", Toast.LENGTH_LONG).show();+ `3 k0 t# Y- a/ L7 M5 [
            } else {) Q9 y7 b4 L0 ]* R5 x
    //            ToastUtils.showToast(getApplicationContext(), "请检查是否授予了权限");( S% i! Q6 i* B4 I# B. `1 h
    //            Toast.makeText(getApplicationContext(), "请检查是否授予了权限。", Toast.LENGTH_LONG).show();) [8 ~$ s1 F" V+ O) c& z% y
            }
    7 v) h! n8 Y! S! i0 F" {# {" _    }
    5 m. J- o; h' Q7 _    private void notifyStatusChange() {
    * z! n5 b0 w  @7 e4 m7 k7 N        mHandler.removeCallbacks(updateRunnable);8 L) r. s3 r9 R0 y9 Y
            mHandler.postDelayed(updateRunnable, 500);: P% ~: h& V5 [  R
        }5 u. t$ y5 m% n" s& }
        private Runnable updateRunnable = new Runnable() {
    : G( [/ f( q! ^. e3 h        @Override
    ; a. c9 ~+ S; E$ U7 D& J        public void run() {
    ; L% m0 [  T! \; O! I5 h0 i2 |            Intent intent = new Intent(FLAG_CONNECTION_CHANGE);, j: v  E* _/ G0 i
                getApplicationContext().sendBroadcast(intent);
    1 s0 r2 ^1 `+ M0 ^        }% m* X# r/ u  s0 Z: T0 ]
        };
    : f( v6 X' |% b3 K3 ^8 d}
    $ o6 R5 A9 J, @& {$ O上面的代码是对BaseProduct、Aircraft和Camera类进行实例化,在后续使用中不用再去进行重复的实例化工作,减少内存的消耗。+ V: J+ S1 d  v/ t6 o8 \0 \
    @layout(R.layout.activity_registration). x; p0 t$ s1 y$ x. Z
    public class RegistrationActivity extends BaseActivity implements View.OnClickListener{& x* A+ E% F* @9 Z% }( I: N
        private static final String TAG = RegistrationActivity.class.getName();7 S; U2 @; b" E5 I
        private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false);% Z# ~2 Z  q; f5 Y( x2 q7 C+ `! {
        private static final String[] permissions = new String[]{
    ( p- G( B) [2 l            Manifest.permission.BLUETOOTH,/ W! D9 Z& |7 `) i9 `# _$ r
                Manifest.permission.BLUETOOTH_ADMIN,
    . ~/ ?6 M! x/ x# h4 g            Manifest.permission.VIBRATE,8 @/ q' w5 \5 u6 O
                Manifest.permission.INTERNET,
    ( z- U5 P: J' I# C! q% z( `# ~            Manifest.permission.ACCESS_WIFI_STATE,, p! S! f: J7 I/ l
                Manifest.permission.ACCESS_COARSE_LOCATION,
    9 L; W+ [7 d* V7 s$ F            Manifest.permission.ACCESS_NETWORK_STATE,
    5 r4 R# `( R- W& U            Manifest.permission.ACCESS_FINE_LOCATION,, y5 A5 y7 |9 D, j8 D
                Manifest.permission.CHANGE_WIFI_STATE,
    7 g! J# ~6 {9 C            Manifest.permission.RECORD_AUDIO,
    & @* o9 E8 [0 F+ K* B- S: k            Manifest.permission.WRITE_EXTERNAL_STORAGE,! N! R+ u% V  i' d0 E
                Manifest.permission.READ_EXTERNAL_STORAGE,' N' O% F' j! O3 g, [" o" ^
                Manifest.permission.READ_PHONE_STATE,
    0 K& h+ e7 N8 }    };9 V9 O( l4 [+ t4 S- y. G
    - H4 ]  j7 k) \/ H) q2 i
        @Override6 a: G0 p6 J+ X: m9 S
        public void initViews() {
    ! I3 B, b# g/ h0 A; Z, [* P  O, X        isPermission();. ~; A5 f! o2 G  b7 o8 x
            IntentFilter filter = new IntentFilter();
    # i( u9 \2 E" |+ G' R, `        filter.addAction(ReceiverApplication.FLAG_CONNECTION_CHANGE);
    + U3 N+ @* \* k, a! a) _        registerReceiver(mReceiver, filter);
    : u/ q* j6 a+ x/ e    }+ t3 a& B$ |0 p9 w% b9 e$ N
        @Override( g' Y6 p5 y+ |  |; z3 j
        public void initDatas() {
    % g2 r2 u9 K8 S  z+ V) c- ?        startSDKRegistration();
    , E; o- c# K9 t  v    }+ O" p& B! b+ l) d# f
        @Override
    0 h4 t2 R9 T9 s# F& D2 E  K! k. i8 E    protected void requestData() {
    1 s+ Y2 ~) q1 M, T7 O4 n        
    8 ]6 M! ^2 ?8 `! ]    }
    , `+ F# c: O* d8 M
    - y0 ?7 u/ r! o9 U; |+ R    @Override7 X: ]* _1 Y( U
        protected void onResume() {
    9 L. L( K1 M/ a# H/ `" P        super.onResume();
    ; _3 y/ S' z" {( O6 F    }) l' M' r8 Y0 s. {8 v

    8 O! F$ k% {( i6 J2 o    private void isPermission() {- C% X6 \- x4 T5 p  n" o( m: \4 J) a
            requestRunTimePermission(permissions, new IPermission() {. z& B+ u/ _$ _% h
                @Override
    ; e% ~6 O1 M/ Z! ]$ a            public void onGranted() {. [  _( u! A* o' G8 }
                }
      n% F' I& V& f! J: |2 \            @Override
      K. _( p2 ~' q" ]7 @/ j' |, S            public void onDenied(List deniedPermissions) {' d* Q' w! I0 {! g% Q  y6 Q
                }! S6 ?& \- g- g5 ]; [8 Y
            });1 @2 W0 \) f2 J1 o- q
        }
    8 v4 w3 Q" W9 l( d/ ]1 V  , S) y, a) v) z3 z* B5 O5 O; T
        //无人机首次注册
    % x( V  ]- A* V4 C$ }9 ?        private void startSDKRegistration() {
    - L7 U# V$ @( |1 E3 T! V            if (isRegistrationInProgress.compareAndSet(false, true)) {
    5 g& z* g. _6 W8 b                AsyncTask.execute(new Runnable() {
    6 ~) F  r$ i2 E6 S0 \  }2 q                    @Override' n5 k) i6 o8 c% |! W8 p3 e: x
                        public void run() {: U( J* J! X+ x
    //                      showToasts("注册中,请等待...");
    8 F7 H3 q" x3 W; P                        DJISDKManager.getInstance().registerApp(getApplicationContext(), new DJISDKManager.SDKManagerCallback() {
    & o+ Y' X# }2 |2 k                            @Override
    % b! X( E; B8 ?3 n: y5 O                            public void onRegister(DJIError djiError) {
    - g! q  @. K% P; ^& b                                if (djiError == DJISDKError.REGISTRATION_SUCCESS) {4 x3 @' j6 _7 G$ c$ i
                                        DJILog.e("App 注册", DJISDKError.REGISTRATION_SUCCESS.getDescription());0 _- |- A8 J/ t2 j! ~5 D; T7 L
                                        DJISDKManager.getInstance().startConnectionToProduct();
    " s0 J- N" [; y0 h7 K9 H! H    //                                showToasts("注册成功");- x# z0 h3 m! ?! S
                                        loginAccount();; v" E3 ?4 C" |0 ?. b( J6 q
                                    } else {
    0 }; C# v% V% d3 @1 g5 a                                    showToasts("注册sdk失败,请检查网络是否可用");
    $ ?' ^) n$ o" W" U) ?                                }
    ; H+ C& K; U  G1 u, b9 N                                Log.v(TAG, djiError.getDescription());( D; R* k( R/ o8 K) @9 k
                                }
    6 D  @: |* d( r' L& F# Z5 k) S                            @Override$ n  R: S4 H6 W+ w
                                public void onProductDisconnect() {
    ) ?2 a  X9 ~9 _( x( u$ V$ K. h1 L                                Log.d(TAG, "产品断开连接");8 j# l& Y( B9 T. q% U$ z
        //                            showToasts("产品断开连接");, \+ T1 n3 P4 ?1 f4 w5 n
                                }
    & `% ~+ q3 C' \& i! l5 l8 [6 _                            @Override0 K1 G7 ?3 j3 x$ [0 J; Z1 O; V; C
                                public void onProductConnect(BaseProduct baseProduct) {& R) R) e& P. \! y+ P$ f5 f6 q
                                    Log.d(TAG, String.format("新产品连接:%s", baseProduct));
      V6 S; j- H  g/ \9 u, C: W    //                            showToasts("产品连接");
    5 i+ `, J) v3 V  b4 t                            }
    . y( y$ L4 m% C. c. S7 i                            @Override9 n0 r& ]. ]6 x) c$ Y
                                public void onProductChanged(BaseProduct baseProduct) {# ?0 a) B3 {5 c$ k$ G
                                }+ b" R$ ?  Y5 q3 y2 N6 x
                                @Override
    5 J9 P# k/ h: ~. n                            public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
    ; `0 ]1 x" z# D& V9 u                                                          BaseComponent newComponent) {' r' w) }6 ?+ I* u( l2 k- b
                                    if (newComponent != null) {
    6 S8 {8 W: M& _: ~' K                                    newComponent.setComponentListener(new BaseComponent.ComponentListener() {; Z1 S4 Y3 \* q2 x6 C7 ~8 A' l
                                            @Override
    0 W( M& N. q5 K8 |                                        public void onConnectivityChange(boolean isConnected) {
      g+ }: O* d4 v3 D2 I                                            Log.d(TAG, "组件连接已更改: " + isConnected);
    8 h! Y4 w, @) U/ w                                        }+ e! R. G- `1 l- Y, G2 `3 B5 @
                                        });
    + |: l( T' ~2 {( h+ o                                }
    3 H8 a# R/ G- S  f% k                                Log.d(TAG, String.format("改变设备Key:%s, " + "旧设备:%s, " + "新设备:%s",
    6 }$ x" c1 J- g                                        componentKey, oldComponent, newComponent));: \3 d$ b9 \  i5 A9 [1 }
                                }
    3 }# e) z2 `) V1 d                            @Override
    - E7 ?$ E8 z. N1 y9 T2 ~9 [) l                            public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {
    & h6 g' s2 P9 _. i0 Y                            }1 M* B$ M9 U+ e% o4 f+ B' f3 _
                                @Override
    1 |9 V! H7 S( [( Y2 @: r& K0 R2 L                            public void onDatabaseDownloadProgress(long l, long l1) {
    ' ?, i7 x' I5 z5 ]                            }
    7 Y# K5 q) q  m9 J                        });
    # T  \& z6 ~/ [: ^" {                    }1 `( O& [- p8 }3 q* j
                    });8 K: R4 ^: G4 H* b# D- k7 j) b
                }
    6 I7 i/ @( v% r        }
    " j) U9 U7 t3 t: f9 F    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
      @& ^0 k5 k6 s2 c        @Override
    7 p9 c  q  l% U' A1 A; M" c! F9 `        public void onReceive(Context context, Intent intent) {/ m9 h. ]0 T! n( w  a4 L
                refreshSDKRelativeUI();7 B! O& s' K% t- }  ]/ ]. `( K/ I
            }6 i7 @! Q) m" K9 @" Y" C# c  x) R- e
        };
    . x1 q  Z3 w) E* u( c* _    private void refreshSDKRelativeUI() {
    7 E; F0 W7 a1 |& ]        BaseProduct mProduct = ReceiverApplication.getProductInstance();; r* n: k3 P6 p! ~5 j. i( M% B, G' m$ ~4 E: p
            if (null != mProduct && mProduct.isConnected()) {
    ! y1 ?; Y4 m# x3 b: t7 j4 j+ J  r            Log.v(TAG, "刷新SDK: True");: d# x: B( O3 G- t6 g
                mButtonFlightTask.setEnabled(true);1 @9 F$ R7 M, D( R/ A' ^3 @; ]* ]
                mButtonSettingRoute.setEnabled(true);. _) R, p% ~% w* M0 Z5 B+ o
                mButtonFileManagement.setEnabled(true);9 E% Z( N: z3 a
            } else {
    , M/ x1 |1 o. u% U! R3 Y            Log.v(TAG, "刷新SDK: False");/ H2 ]& S7 w" b& J8 _
    //            mButtonOpen.setEnabled(false);- D4 E5 V$ q. i' k
    //            mButtonSettingRoute.setEnabled(false);9 }( E; V' g4 K, Q0 W
    //            mButtonFileManagement.setEnabled(false);8 z' _: Y% u6 a7 X! F! e
    //            startSDKRegistration();8 j% Y2 Z( ]& p
            }+ z2 N, x) q) u
        }
    " q, v" w7 _/ f& @! O  G    protected long exitTime;   //记录第一次点击时的时间6 }, u/ n" v5 _7 P6 Y" m5 ?
        @Override! M# W( M9 ]9 W& G# {  W( z: S/ p
        public boolean onKeyDown(int keyCode, KeyEvent event) {1 C6 d9 ^8 z  p  X
            if (keyCode == KeyEvent.KEYCODE_BACK0 \) e8 F  Z; l0 e: o) K) D9 A
                    && event.getAction() == KeyEvent.ACTION_DOWN) {: m% U7 x- ^) N1 }8 s# P
                if ((System.currentTimeMillis() - exitTime) > 2000) {
    : F( {" Y; f$ _+ }                showToast("再按一次退出程序");/ [' a" z0 x% {" s# X- W
                    exitTime = System.currentTimeMillis();5 I5 x7 i, p% r5 N; B
                } else {% r9 r9 q2 T+ `" z
                    RegistrationActivity.this.finish();8 ^/ a3 c1 O/ {4 n9 {$ z
                    System.exit(0);, V7 Y0 r+ }% S9 a
                }
    6 W1 g! `% }: e  O            return true;
    * b5 H& `2 c& H" j: f4 l7 h3 {        }1 s3 C5 d% }9 I1 H2 R
            return super.onKeyDown(keyCode, event);
    ; Z- G( Y3 g+ |1 z6 l( [    }
    " A8 M7 I# V, H' g  g- W, M3 U' A1 J9 \9 I: X3 F  m$ Z& S
            private void loginAccount() {
    . I0 Z+ I/ f) }9 M$ p7 y- T/ W            UserAccountManager.getInstance().logIntoDJIUserAccount(this, new CommonCallbacks.CompletionCallbackWith[U]() {8 A" I7 @6 i! Q, ^" L
                    @Override
    3 ]. q' m- z* l0 z6 X5 {& R5 G8 T                public void onSuccess(UserAccountState userAccountState) {
    : L. B9 M. b. P) L                    runOnUiThread(new Runnable() {2 K( ^# y- e8 S! A2 j: A
                            @Override
    % Q6 Y$ e2 N/ g- i' l. t4 y5 |0 g                        public void run() {
    ! A% @) K) k4 X" `                            mButtonFlightTask.setEnabled(true);
    4 k, n) s; P8 U5 B# c) ~" c                            mButtonSettingRoute.setEnabled(true);0 j+ u" _' j  u5 C
                                mButtonFileManagement.setEnabled(true);
    0 Y6 x3 U0 m* K                        }
    - r* a# R/ F% p7 _+ w5 t! v                    });
    - C6 }0 z4 i; e) s1 C5 W- _7 z: }                }3 J8 @$ z: N: r
                    @Override- U* @0 F# E- ?( r+ {
                    public void onFailure(DJIError djiError) {) N, C& `  V' W$ _; M. |; p
                    }" g. l! z% m4 k& C& S
                });
    3 y+ H5 Q1 r- Y" S) l2 o% }        }: d9 }. M3 ?3 J9 U; N
    }! T6 K# h2 P% C; F- f
    上面的代码就要进行第一次注册登录了,当然你不需要自己去设计登录注册页面,大疆会调取自己的登录注册页面供你使用。! }' g0 I& a& a; t1 q% D4 R

    5vvpks3hoqw64023083305.png

    5vvpks3hoqw64023083305.png
    4 S7 @! u  P. P# s
    安装提示注册登录即可。
    ) F- ~2 M0 H! {1 ?上面的这些做完后,恭喜你!现在,您的移动应用程序和飞机可以在中国使用而没有任何问题。换句话说,您的应用程序现在可以看到飞机的视频流,并且飞行将不仅限于直径为100m和高度为30m的圆柱体区域。* `, Z2 F2 w( p. h  \& U$ E& S5 f
    34 `7 h. ~1 K3 p* k2 {# ~% V, c+ o6 Q
    飞行界面使用2 w- z1 ^: b& w! E
    虽然说可以正常飞行了,但是飞行需要设计飞行界面。那么创建一下飞行界面的UI及逻辑处理文件。逻辑处理文件中包含了获取飞机的实时姿态信息,代码中有注释内容,描述的内容就不多说了。, m* |7 l; J  ^

    ; z9 O2 N! D0 u+ e/ j, K( p) r, k导入UX SDK依赖' q: E8 J; j/ @/ X- g  x
    上一节有说过集成部分,其中内容有导入UxSDk 的操作,这里再顺便提一下。再build.gradle文件中加入implementation "com.dji:dji-uxsdk:4.16"依赖,等待安装即可。
    4 @6 {" e% a$ N9 Z" c$ h7 o9 m5 o. l" p2 y7 I; ]) R
    设计界面UI
    5 o/ V5 A- m- W5 K$ M% o8 m. `创建MainActivity文件及activity_main.xml。  G3 {3 a2 [- ~
    RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"' u) R- E2 N$ w3 L
        xmlns:tools="http://schemas.android.com/tools"
    2 G6 Z7 q: l0 N. m( u( }    xmlns:custom="http://schemas.android.com/apk/res-auto"
    ' h/ p; O# P( ]" m    android:layout_width="match_parent"
    & u) W; @- F, `" d, b, a- R' y    android:layout_height="match_parent"' n( R1 @* w( A5 {
        android:background="@color/background_blue"
    & v- ^( e8 e( q$ {' u0 a5 y    android:id="@+id/root_view"
    5 F( p9 M6 K% s" o. Z$ {    tools:context=".ui.MainActivity">
    ( y0 I6 X3 j* ?7 F   
    9 B' \; `/ c0 H3 m3 I; v0 U    RelativeLayout" g2 x9 Z# O* I- m4 T1 o5 n
            android:id="@+id/fpv_container"
    6 ]& {, @* q7 [3 ]        android:layout_width="match_parent"0 ~' W2 x( }) q8 h7 ?. b
            android:layout_height="match_parent">
    $ _1 [) c% h/ a3 a        dji.ux.widget.FPVWidget0 b& j$ r# N$ E, c
                android:id="@+id/fpv_widget"' U8 V: J- }+ }% M3 ^; j* L; e# W" g# q
                android:layout_width="match_parent"
    8 I# P) {) ^: R# _# ?8 F8 l8 ]            android:layout_height="match_parent"$ A: k7 h& n1 h8 t4 F0 L
                android:layout_centerInParent="true". x. R: S8 Q2 L! s+ V2 i
                custom:sourceCameraNameVisibility="false" />- H1 N7 v  h  M# y8 q4 W" \1 {
        RelativeLayout>' A$ k5 H7 r1 Q* F$ @& p2 k
        dji.ux.widget.FPVOverlayWidget8 `: w" x) L/ E* e  m
            android:id="@+id/fpv_overlay_widget"3 n/ Y0 @$ [8 g! D" a9 ~: K- c* B
            android:layout_width="match_parent"- z0 `6 x5 X% ~% F
            android:layout_height="match_parent"/>- f1 P2 m/ w' I0 W
        RelativeLayout
    4 x% T' c; i6 I4 B5 E        android:layout_width="match_parent"! j  {" V6 v9 y& R" J7 @9 k
            android:layout_height="match_parent"
    : I! G# s3 i4 s; q# w  e" R        android:layout_marginBottom="40dp"3 t/ n  K9 k6 y6 M9 T
            android:layout_toRightOf="@+id/TakeOffReturnPanel"
    # b$ C& S  O! g( w% T" C        android:layout_toLeftOf="@+id/CameraCapturePanel"- q3 r* m  E0 V$ r) R4 k1 [# B
            android:layout_below="@+id/camera"
    3 Z4 l# y( C1 W/ t$ T        tools:ignore="RtlHardcoded">* y: R4 Q; _( E" _- b4 ^; v
            dji.ux.widget.RadarWidget( ^5 M9 o6 S1 S& h/ u
                android:layout_width="wrap_content"2 H$ w1 Z8 p  @$ F/ {
                android:layout_height="wrap_content"
    7 J& Q, x. m( r6 b            android:layout_centerInParent="true"/>
    ! O, @& ?3 v1 c- R    RelativeLayout>+ Q; v3 Y) d7 f* K( C: y
       
    - c- {4 U3 S  F2 r    LinearLayout
    $ ^! u+ w- Y$ H7 r* P4 U        android:id="@+id/TakeOffReturnPanel") K; e5 X, \: i0 z; L6 h$ U
            android:layout_width="40dp"
    8 g1 {6 B  S1 |( [        android:layout_height="wrap_content"( P3 i) l& B  p2 B) Y0 d+ `
            android:layout_marginLeft="12dp"
    : m; ?3 h+ D4 t/ y        android:layout_marginBottom="4dp"2 d& W: A: ?& ?2 P0 P) }0 K
            android:layout_marginTop="50dp"; t! ]+ Y+ g' I1 `! }/ s, H, C
            android:orientation="vertical", b' D7 C9 @  z/ C% ~( y
            android:gravity="center">( m( H- \8 b9 c1 M$ A/ A2 y
            ImageView
    ) [0 j0 U8 w$ U& h% X' \            android:id="@+id/img_show_back"- c5 t" l  D; e4 G
                android:layout_width="match_parent"5 O. C& i2 W$ R! h. P  w; |  C
                android:layout_height="38dp"
    ; N3 q( [/ C1 _3 [- ^            android:src="@mipmap/ic_back_36dp". P9 ?! U5 y2 ^5 A$ U7 o& O& M
                android:layout_marginBottom="10dp">ImageView>
    9 h/ t! A- B7 N; N        dji.ux.widget.TakeOffWidget
    1 {" [+ s3 r& A) x7 [            android:layout_width="40dp"
    ; I2 P3 Y4 I5 x; B) P% X7 L7 z9 T- @            android:layout_height="40dp"
    + y* l) Q! h: F: Q. y            android:layout_marginBottom="5dp" />
    , x; J  W/ V3 s" Q3 _" y9 i        dji.ux.widget.ReturnHomeWidget4 }2 E" u. U& V( O
                android:layout_width="40dp"
    1 n0 Z$ J! }  `, R% v# u            android:layout_height="40dp": f  r7 Y  t" x; v
                android:layout_marginTop="5dp". n% w3 v$ p& w4 v8 [1 i0 ^6 u
                android:layout_marginBottom="5dp"/>0 u/ ]. `5 d  W9 V" v* x9 R
            ImageView
    ! N8 |! @. i1 |& D; ?2 g            android:id="@+id/img_live", `! Z" Z8 j, Z/ z
                android:layout_width="35dp"0 g% o  x: W4 A5 y* W3 ?, P- U
                android:layout_height="35dp"4 \8 d0 S$ U7 T, V% h( u
                android:layout_marginTop="5dp"8 L* t$ [& e0 C, O2 a- |7 r' C
                android:layout_marginBottom="5dp"
    0 @  x0 n) ~/ j9 S% v. \9 k            android:src="@mipmap/ic_live_write_36dp">ImageView>) c  I1 v* Z% B- o. s4 @- H  Q
        LinearLayout>
    " {% g, O$ w+ p& T    FrameLayout$ z' \3 O/ n% I, D! Y, |0 h7 s# C
            android:layout_width="150dp"
    : m% g6 D: v3 i+ |        android:layout_height="100dp": u0 T/ p* t% J/ w; @7 {
            android:id="@+id/secondary_video_view"
    ( Z) D; S- J: [8 z& W4 w        android:layout_marginLeft="12dp"
    ( b9 C1 j' ^( B8 ^# n2 ~$ q' w        android:layout_marginBottom="7dp"6 o+ D: u' O) d8 [6 c( L1 F
            android:layout_marginTop="50dp"3 ]  i/ K9 u* L
            android:layout_alignParentLeft="true"
    # N& X  c" r4 V  v: P        android:layout_below="@+id/TakeOffReturnPanel"
    % V0 `) k7 S# U; |        android:background="@color/black">. j5 v; N/ C& D) D8 s4 j
            dji.ux.widget.FPVWidget
    & ?2 R+ q! `/ t' G7 ]' B) p" f            android:id="@+id/secondary_fpv_widget"
    7 }: L% b9 q; ]            android:layout_width="match_parent"5 P8 k) x3 }6 M; ?( ~0 g
                android:layout_height="match_parent"
    - r+ O* N9 p$ I! E; Y, t* M; @            custom:sourceCameraNameVisibility="false"
    $ R. C* [5 x$ u$ g1 K            custom:videoSource="secondary"/>
    - [0 X, l6 Z3 K4 w$ y" ^    FrameLayout>
    - a3 _% k+ Z) x1 Y  n' A    dji.ux.workflow.CompassCalibratingWorkFlow- _( ]1 y7 B9 k! H6 F! t5 M8 P
            android:layout_width="match_parent"
    # Z: x( d; d. ]        android:layout_height="match_parent"/>
    ' S' _" I" K6 N7 s8 ?    dji.ux.workflow.CameraSensorCleaningWorkFlow+ f! e, ?0 D8 q1 E* F
            android:layout_width="match_parent"
    6 z" ~) J5 ]5 O        android:layout_height="match_parent"/>3 `9 \0 C( _+ s. z  m* N( N
        dji.ux.widget.RemainingFlightTimeWidget
    . P7 n( O+ U* [        android:layout_alignParentTop="true"
    ; R7 \2 y+ ]: P. Q; c9 M$ \        android:layout_marginTop="18dp"
    ( d. P0 ~' {0 ?7 k2 y        android:layout_width="match_parent"
    4 b9 a9 A6 t* `! j) J8 g        android:id="@+id/remaining_flight_time"8 v5 f. r9 k7 O( `
            android:background="@color/transparent"
    " f, [( H6 v0 S2 S; m) K        android:layout_height="20dp"/># C' Y* x9 x, {7 X! x* [
        LinearLayout; w" o( _( V; R5 e/ j8 P0 H
            android:id="@+id/camera"
    $ ^5 w7 H, ^# k: b6 d) j. H3 s, ^        android:layout_alignParentRight="true"
    ) a3 i, q( q$ C  Y+ F4 S9 z9 b* z" l        android:layout_width="wrap_content"
    ) Z5 s5 {  x9 v7 `) D        android:layout_height="wrap_content"4 f* s7 r- X5 }0 X
            android:layout_below="@+id/signal"3 f& `# Q& q5 U4 G
            android:layout_marginTop="15dp"
    : p$ K  y/ S/ P        android:background="@color/dark_gray"4 O4 }/ E, L& d7 J9 F9 |, ~
            android:orientation="horizontal">
    + t# _5 _5 S0 S; O( W7 |4 q        dji.ux.widget.config.CameraConfigISOAndEIWidget% T/ h! [$ M4 C" Q
                android:layout_width="50dp"/ c$ O8 n  k, e5 c% F
                android:layout_height="25dp"/>( i% i+ j8 m4 z6 I7 e
            dji.ux.widget.config.CameraConfigShutterWidget
    3 ^0 @8 L' r! G- _0 [2 U8 {# W" W            android:layout_width="50dp"
    - \6 H1 a" @7 t. r+ d* O            android:layout_height="25dp"/>/ M, f" w' R5 \. b
            dji.ux.widget.config.CameraConfigApertureWidget
    6 K5 O# R3 L* I, K7 I            android:layout_width="50dp"
    " s1 v3 |- y6 q" U            android:layout_height="25dp"/>
      y* y* z* V2 }2 ]* ]# E: O        dji.ux.widget.config.CameraConfigEVWidget$ j, R  A/ f+ i: x
                android:layout_width="50dp"
    ) F( n$ Q5 I+ c& w# v            android:layout_height="25dp"/>
    3 O' V0 b8 e" F; O  L& y        dji.ux.widget.config.CameraConfigWBWidget3 ^8 t$ k0 o# u& S5 _! J
                android:layout_width="60dp"
    9 s& s( o3 J, M, n0 U            android:layout_height="25dp"/>
    . ]6 c1 y7 \5 k6 I        dji.ux.widget.config.CameraConfigStorageWidget
    % V# w! e$ l- u' l' g/ ~            android:layout_width="108dp"
    / W9 W( h' E; Q) h# H" G" |. q            android:layout_height="25dp"/>
    ( i4 C  j. w& g% k% O4 A        dji.ux.widget.config.CameraConfigSSDWidget& M$ g8 T% K' d: w# H: X
                android:layout_width="125dp"
    2 l4 h- t# D* U1 g8 g) O            android:layout_height="25dp"/>
    5 p: C: K) ?4 H    LinearLayout>) b: d1 Y  U' D% C+ r! D
        LinearLayout4 i5 g' A& c1 t' R. q
            android:id="@+id/camera2"5 b( o$ q4 i1 M9 Y0 h; ~
            android:layout_width="wrap_content"$ T$ p8 s" U3 T# M! G0 V) Z1 m
            android:layout_height="wrap_content"+ a! ~( m$ F) ^" z# C% d6 ]/ i
            android:layout_marginTop="5dp"
    # L2 \; f, e. G8 }; W' C5 F9 [( |        android:layout_below="@id/camera"; S4 `; ]( f: d$ m7 \. @' ^
            android:layout_toLeftOf="@+id/CameraCapturePanel"% {- ^  \+ _: }$ b# j! W2 y
            android:background="@color/dark_gray"& k: Q. n( c, I5 y, S
            android:orientation="horizontal">% R6 w2 w, G# T7 C5 ~* s
            dji.ux.widget.SpeakerWidget* Q1 h2 q0 Z+ _3 t4 K% m8 P$ y$ p
                android:layout_width="35dp". x( S4 j. G, I0 i" x( c8 K& j
                android:layout_height="35dp"/>( _$ F, h' B2 g! J. p. x* K8 L
            dji.ux.widget.AutoExposureLockWidget0 A/ e1 w+ I+ ?7 [8 ?7 U5 x
                android:layout_width="35dp"
    9 @* X$ n( g) z( c- Z            android:layout_height="35dp"/>5 O9 @) P4 N' U  [: w' e
            dji.ux.widget.FocusModeWidget) G* R# g5 w& \- G, @+ Z
                android:layout_width="35dp"/ m8 A) i' n2 _% n7 J5 u
                android:layout_height="35dp"/>2 k/ W5 _! \3 }9 J: v
            dji.ux.widget.FocusExposureSwitchWidget
    # h% B7 v4 S) |. S- I            android:layout_width="35dp"
    / A- [5 y. i3 p, n; e7 W            android:layout_height="35dp"/>' g- r# C% k% \9 r; S( P9 j: `
            dji.ux.widget.BeaconWidget
    8 |& z! B' b1 I+ q! B* Q            android:layout_width="35dp"! z; M3 ?: a' @, L
                android:layout_height="35dp"/>& e9 a" {2 W$ f1 ~/ N& ?
            dji.ux.widget.SpotlightWidget
    , Z  |: p- r* a0 F. m            android:layout_width="35dp"
    / J  C2 o% N7 ?5 S5 [* M9 z            android:layout_height="35dp"/>8 n; R2 B# S$ q% T# T
            dji.ux.widget.AccessLockerWidget
    5 U; `, \5 [8 W9 }+ Z' H' T9 e& k            android:layout_width="35dp"
    4 Z% L, k) @8 K6 h; x: g            android:layout_height="35dp"/>
    ! i/ Q5 f3 D8 C, a    LinearLayout>. y- _  \6 _' p% o& S* q, S# \
        dji.ux.widget.ManualFocusWidget! I* F) A1 f+ u2 C
            android:layout_alignTop="@+id/camera2") i  m5 \+ W) I, B6 k( Q
            android:layout_toLeftOf="@+id/camera2"
    5 i1 X1 c* ^; F+ F- V: s6 P# C: r        android:layout_width="50dp"
    , g9 A4 z3 \% o        android:layout_height="210dp"
    * ]8 a, h; U' F& x; r, q. h        tools:ignore="RtlHardcoded"/>
    & l7 G/ d) E6 `; I) V( f( K    dji.ux.widget.MapWidget
    " V; c% |8 ]! n" x7 G# x( M) ^, q        android:id="@+id/map_widget"9 K9 t2 w1 F/ S% V7 F
            android:layout_width="150dp"
    1 v1 m( R+ r' K        android:layout_height="100dp"
    " B9 Y' `# D- d) t        android:layout_marginRight="12dp"7 {! V7 v- ]& X, b# c! ]3 g" {
            android:layout_marginBottom="12dp"
    * ]! q6 z3 \, z: B0 `. H5 O        android:layout_alignParentRight="true"
    . x8 U# p1 m8 o7 k        android:layout_alignParentBottom="true"/>
    0 A2 w/ H  I7 e* _    . F2 y( S4 }  A. o# l
        dji.ux.widget.controls.CameraControlsWidget& o6 I# Z0 s- s& o# D. j
            android:id="@+id/CameraCapturePanel"
    7 V$ [4 k  O+ O. o8 ~# a5 K3 _1 {" n        android:layout_alignParentRight="true"2 E" [. D$ o9 |' s& c* L; x( V. F
            android:layout_below="@id/camera"
      Y+ Q$ f1 }9 }        android:layout_width="50dp"
    + t$ u: b, j% Y6 E  P& d$ Z, L5 c        android:layout_height="213dp": F' J, X0 m$ i0 s8 P8 Z
            android:layout_marginTop="5dp"
    $ M) R+ L/ B) M* T! F        tools:ignore="RtlHardcoded"/>
    # W5 P8 W2 @7 D# B   
    : t: V9 ]: W; P& `& G, H$ [    LinearLayout
    " I$ y4 E2 n) S9 c        android:id="@+id/signal": y% p9 ^* c4 S5 V$ W* }" ^
            android:layout_width="match_parent"# C. c9 r; y1 D4 v# q" @7 Z3 g
            android:layout_height="25dp"2 t3 S! ?: t0 B2 r
            android:background="@color/dark_gray": j% Q* o1 j9 ^% f0 W/ J! N6 [/ W, e
            android:orientation="horizontal">
    & ]6 N% p  Z# u/ j; Z: n3 W        dji.ux.widget.PreFlightStatusWidget  b, c( l, W! M9 u8 k
                android:layout_width="180dp"
    1 L6 A$ y2 ]8 d3 f            android:layout_height="25dp"/>% h$ m. Q% ]0 Q" n
            dji.ux.widget.FlightModeWidget; b9 m4 Q, |! v4 M) ~% W
                android:layout_width="103dp"
    . w8 ^1 p% j) N- T( K% f7 }4 A            android:layout_height="22dp"/>" X5 b1 n* K- I9 A/ U$ U, {  L
            dji.ux.widget.GPSSignalWidget
    ; q+ @$ I5 |' D) H: g: F            android:layout_width="44dp"
    9 B0 u/ A  p5 j/ U6 T, l% J            android:layout_height="22dp"/>
    ( E* ^3 u9 z. n$ L9 |- H; z, Z        dji.ux.widget.VisionWidget
    7 }  X2 Y. y" t9 l  D* a6 n: r            android:layout_width="22dp"% X" ^- ]" }+ B; K0 S( L; {- v' t" }$ a( S
                android:layout_height="22dp"/>7 }# U& ?' ]+ [8 f! {; B* p
            dji.ux.widget.RemoteControlSignalWidget
    ' W5 v9 c- ]7 z/ T" K7 d            android:layout_width="38dp"' U$ w3 ^/ n1 l4 L. j7 M, e
                android:layout_height="22dp"/>; _1 [# h: I+ r  Y6 K7 A
            dji.ux.widget.VideoSignalWidget
    & G# q" E' y+ l, w5 h            android:layout_width="38dp"
    ( `( n% v5 s5 q/ H2 W' h' X            android:layout_height="22dp"/>
    8 g) E: V- O8 [; e        dji.ux.widget.WiFiSignalWidget
    8 J$ L6 J' Q1 M+ ?  {            android:layout_width="32dp"3 j+ S1 t: U7 _9 b4 Y
                android:layout_height="25dp"/>
    8 i7 q, M4 ~# A, s7 H1 V7 A% \& c4 ^        dji.ux.widget.BatteryWidget3 h6 W+ ]( I2 ^
                android:layout_width="96dp"
    3 |7 u5 g% A# J( n! y4 A) O3 \* r# b            android:layout_height="22dp"
    9 z4 r- l8 O0 O9 u8 \            custom:excludeView="singleVoltage"/>
    / H# P4 y) D. X        dji.ux.widget.ConnectionWidget
    0 }; I# {2 d. s- v1 w( e0 ~            android:layout_marginTop="3dp"
      k2 x  J6 I- B* \7 R/ G9 V7 Y: O% G            android:layout_width="18dp"
    / @; I7 _, {& d# B            android:layout_height="18dp"/>
    - }5 X; k! Y: I7 {/ ?  [& I    LinearLayout>( z0 B0 L- w6 F/ g- S$ w4 m
        LinearLayout/ `! _+ S: v0 k4 i6 a/ y; v" n) z
            android:id="@+id/dashboard_widget"
    ( s* F+ j& S( [* x        android:layout_width="match_parent"3 z' e3 T9 N# t! m7 {9 W) C
            android:layout_height="wrap_content"1 ?  @9 t, Z7 `; }& P9 r9 Z! P
            android:layout_alignParentBottom="true"
    % g1 p# Z8 W+ ], e  q* Q4 ^/ F        android:orientation="horizontal"5 z$ P+ c+ n9 t) r. W/ I9 n$ q
            android:padding="12dp">9 X1 O9 F9 M! Z1 s; T0 {% Y8 w  \
            dji.ux.widget.dashboard.DashboardWidget
    9 A3 J1 L% K" e- f# }6 T+ p6 O            android:id="@+id/Compass"0 A3 w2 x6 A/ G. E1 t  B  Z# ~" E
                android:layout_width="405dp"! n- e. E1 i7 Z
                android:layout_height="91dp"
    5 J/ n* v) |  M2 l) X            android:layout_marginRight="12dp"
    & I; K* Y. M  Y: s$ R* s            tools:ignore="RtlHardcoded" />
    : x/ @* L& [# j6 u! P    LinearLayout>$ F6 S' t' k- Q8 L. e# j+ l  O7 n
    , F" ?0 n7 e1 O0 q% N, Q) ?2 P* d

    " _9 G  s* R) `; C+ h& H0 A, {   
    ' n( t- z4 b8 I0 A5 J: U) N4 ?6 c  l    dji.ux.widget.HistogramWidget; B) _5 N% ^" A7 w( v- o# a/ Q
            android:layout_width="150dp"! N* _  `% q, W- {5 ^
            android:layout_height="75dp"
    9 k9 J6 X' |. L+ @! B2 ]5 W5 b        android:layout_centerVertical="true"
    8 G7 K/ |# h! o/ {: u2 M4 R9 \        android:layout_toRightOf="@+id/TakeOffReturnPanel"! A4 z* I$ d5 J$ Q5 @
            tools:ignore="RtlHardcoded" />
    6 V! [8 ^! |  m% z: y' ]    dji.ux.panel.CameraSettingExposurePanel
    - W& g* z+ T: O! |, Q4 l        android:layout_width="180dp"6 R3 x" H7 D! J. p4 X
            android:layout_below="@id/camera"
    $ ^8 @8 N, Q6 b% ]/ b        android:layout_toLeftOf="@+id/CameraCapturePanel"5 P0 E6 U# v' ^0 V  k! ]
            android:gravity="center"
    . x2 |7 W1 k) t1 c        android:layout_height="263dp"" Y$ p1 m9 q5 F/ g* x7 o2 o6 m
            android:visibility="gone"
    " I2 K( C: a2 `: a* A4 M        tools:ignore="RtlHardcoded"/>
    0 O  x; o# I( B! c    dji.ux.panel.CameraSettingAdvancedPanel
    % o3 s  O6 v' p2 L0 s; p        android:layout_width="180dp"2 S3 q1 U/ i/ f; Y
            android:layout_height="263dp"
    ) f1 V' N6 C+ M  j- L" H9 I        android:layout_below="@id/camera"
    6 N7 e0 x% f0 u0 v$ i        android:layout_toLeftOf="@+id/CameraCapturePanel"
    2 d. v$ a0 x5 O. f% w1 l        android:gravity="center"
    ) A1 h" z( V( q8 k        android:visibility="gone"9 l; y! I8 H1 \) f3 q
            tools:ignore="RtlHardcoded"/>
    # T# D  P8 g) E' T/ m( {, K    dji.ux.panel.RTKStatusPanel
    8 @6 Z$ |0 K6 {        android:id="@+id/rtk_panel"
    " ]) G: G& D/ n. M0 _8 ]  Q, U        android:layout_width="500dp"5 ]; X. M) u; G. d
            android:layout_height="350dp"
    : a% c8 I; V2 _. o8 f4 R        android:layout_below="@id/signal": D/ z- Y) ]: N( g7 |5 [
            android:gravity="center"
    ! m: t! l7 i. r% h5 h  r0 a7 C8 a        android:layout_centerInParent="true"; C+ f# I& f4 H( O# J7 @1 W
            android:visibility="gone"/>
      d2 h- X( R; D) b; @- ~/ X8 U    dji.ux.widget.ColorWaveformWidget
    9 f+ f6 ~7 H2 d$ y        android:layout_width="394dp"' Q3 y  ^$ g$ r9 Y& q3 h
            android:layout_height="300dp"
      Z3 h' y9 e! l& u        android:layout_below="@+id/camera". K& p0 i  i- D5 q- j3 |" V+ c
            android:gravity="center"
    ( t( n% R7 A7 a5 F2 d, K        android:layout_centerInParent="true"
    - R1 e- a/ Y8 U3 P        android:visibility="gone"/>
    4 H7 O  _, U# f4 W% \' x  K; v3 W    4 i$ E, g  d5 I5 }- \3 c6 V
        dji.ux.panel.PreFlightCheckListPanel
    ) ?, m* d) R# ]8 D+ X        android:id="@+id/pre_flight_check_list"1 g0 F7 l/ O9 ~* b
            android:layout_width="400dp"; x3 T6 [/ F! s2 o. Q' {
            android:layout_height="wrap_content"
    $ Y/ h9 `7 z" v" n8 S        android:layout_below="@id/signal") I8 m" y) r2 o& l+ N  W# G( S
            custom:excludeItem="ESCStatus"
    , J) Z2 h2 h0 A3 p- Y        android:visibility="gone"/>
    7 P& A  W( B0 [' S    dji.ux.panel.SpotlightPanel
      E. D% U9 o) r        android:id="@+id/spotlight_panel"
    . c6 }6 T0 B, Y4 p" `. Z7 |4 s        android:layout_width="300dp"6 d4 I& r- h3 e) z3 L
            android:layout_height="wrap_content": P% j5 o; g2 R6 n- l. d
            android:layout_below="@id/camera2"4 ^+ O: k5 x! D1 @
            android:layout_alignRight="@+id/camera2"
    6 N3 l4 ^# f; r  c: K: S/ r        android:visibility="gone"
    ! @( x! C7 d% x0 {: a        android:gravity="center" />( S6 R* M' n7 s" B
        dji.ux.panel.SpeakerPanel
    # C  K$ H' p/ y  i        android:id="@+id/speaker_panel"
    : P$ Z! `9 y1 \: j8 ?% D        android:layout_width="300dp"( V! q! q* X, O! q% C7 x6 g+ \
            android:layout_height="match_parent"
    : @' z7 w7 t% p6 p" c        android:layout_alignParentLeft="true"* Y4 |+ ?  B, d1 J* `
            android:layout_below="@+id/signal"0 p; j% S, K* w8 u& h' H
            android:visibility="gone"/ a  r1 U4 N$ i/ f, m
            android:gravity="center" />! f$ R) a. H" O( ~4 |9 T
    RelativeLayout>
    ( e% a$ Q. v$ R4 d9 |@Layout(R.layout.activity_main)1 T' X/ \4 Q5 q+ M4 P* A
    public class MainActivity extends BaseActivity implements View.OnClickListener {
    1 [/ d$ g: D' A- B    @BindView(R.id.img_live)
    0 X+ f- k4 [! x4 ]6 L    ImageView mImageViewLive;
    4 l6 T0 {3 |; P  |& L7 b    private MapWidget mapWidget;3 Q2 @- R$ v5 r7 I% [
        private DJIMap aMap;! Q! N) A6 Q, M! M. y9 f/ l
        private ViewGroup parentView;
    ( \) [3 W0 [! D" k    private FPVWidget fpvWidget;5 C0 L" ~: f/ G3 O0 C; T
        private FPVWidget secondaryFPVWidget;% [# F3 N' J( y
        private RelativeLayout primaryVideoView;
    ' i! t/ \7 q. e" m3 B; Q( i- v    private FrameLayout secondaryVideoView;
    . r- T7 v# Q: B3 ]1 v. V    private boolean isMapMini = true;
    3 X2 j& T0 O, g1 }  @    private String liveShowUrl = "";: h9 w; T0 @- V$ {( ]  y1 @
        private int height;
    ) K0 r$ F8 @& z/ r5 h3 @; p5 r5 S    private int width;' {% J' g1 B/ s2 y1 p
        private int margin;
    / ]- a% L' S) g: ~+ i4 O    private int deviceWidth;# Z" c" E1 T8 k% R; Z7 ^/ ^4 t
        private int deviceHeight;
    2 D9 R9 P) h1 H8 {    private SharedPreUtils mSharedPreUtils;
    5 t$ [" D1 D8 Q- r' t- N    //unix时间戳
    ! o# O! F1 e2 E/ ~1 b8 m+ J    private String dateStr = "";1 R; o5 Y8 L) r( I
        //飞行器管理器5 w& `! u! w( w0 T
        private FlightController controller;  s  z% R9 `! G  |/ @
        //经纬度
    : Y* o# O& o4 e9 q8 _    private double lat = 0, lon = 0;
    " j4 K+ U1 J) M" G- |    //高度
    5 @, @1 Z+ H* T+ A    private float high = 0;0 T/ k! z+ e( [/ k0 K$ f& f
        //飞机的姿态4 U, ~8 {3 F8 M( r
        private Attitude attitude;
      a  z2 I: X$ S1 V" r% Z7 G) D. s    //俯仰角、滚转、偏航值
    ( i1 ^3 s- @5 s! b6 e) Z& Z    private double pitch = 0, roll = 0, yaw = 0;2 t( n5 b2 }( y1 y# X: D6 Q
        //飞机的速度
    , @' A! g, ^/ ]- R  F6 X    private float velocity_X = 0, velocity_Y = 0, velocity_Z = 0;
    9 x8 _# d8 V5 W) F0 p    //飞机/控制器电池管理器# g% ~. E5 u6 L7 U
        private Battery battery;
    6 L( ~1 s" k" U( f" T) b. H9 `. r* T7 `    //电池电量、温度
    0 z: p+ `( q1 }7 a  }; f! t    private int power = 0;6 [( L3 p# V% P6 }  R( T5 X) O
        private float temperature = 0;
    9 _& G% g1 d1 b7 C& e: {    //云台管理器
    8 m, T4 S3 x' M% q- L* S( T    private Gimbal gimbal;
    . e5 M- n7 p$ `    //云台的姿态
    & U1 U- d9 g& h) ~9 a    private dji.common.gimbal.Attitude g_attitude;  x+ c& U# X/ l$ T! @. e
        //俯仰角、滚转、偏航值/ B7 ~" \- v# o8 `9 C6 R. f! t
        private double g_pitch = 0, g_roll = 0, g_yaw = 0;' w" w3 o- f2 X
        private Camera camera;7 \1 J( n( {6 P
        private List lens = new ArrayList();
    / t0 o- O+ j1 s2 x9 {6 B% m  N    private List djiList = new ArrayList();( ^/ J- L" n0 t8 G/ E" I0 t
        //手柄控制器
    2 J, z8 S5 I: l% `' h5 A7 ~/ Q    private HandheldController handheldController;; \$ E% G6 F1 s
        //手柄电量5 \) Y( ]- {1 r5 G) z5 I4 l0 B
        private int h_power = 0;
    * z" K% U6 u! m, ~3 P! q    private static List list = new ArrayList();/ }2 T9 k9 H1 n0 C- I# E
        private static List getList = new ArrayList();
    7 P& |0 s  a. h5 T# R* e/ j+ N; X    private MediaManager mMediaManager;
    ; o! `- h( M; m0 w( H    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;* l; L$ |8 M' O2 C  F! ^2 @
        private List arrayList = new ArrayList();
    6 p2 ?. {7 }6 l  F) e, Q4 D2 w    private List startList = new ArrayList();) p; @. a8 U3 I* z6 M  j3 @) g
        private List endList = new ArrayList();% `- }1 f5 A( X9 E2 |% S$ o% n
        private boolean isStartLive = false;: ~% o! s! j! s: r- F' a, a
        private boolean isFlying = false;
    2 A0 Z6 R2 t5 p9 W! Z0 b- E+ E, U    private boolean start = false;
    . l7 t, H2 I2 n    private BaseProduct mProduct;& H8 D8 i: E) L, G
        private String posName = "";
    & S% f. A! b6 W0 h8 j/ h  y    //webSocket
    2 `* k7 E9 e/ P4 L. d$ }    private JWebSocketClient client;
    & ~( O+ A0 T7 R$ _% ?/ ]    private Map params = new HashMap();- B1 a& {. `9 p" ]; a9 I2 n
        Map mapData = new HashMap();, D) L/ \: Z/ E7 G% n6 m& [
        @Override  i; }; r( e7 f* w# J9 r6 t
        protected void onCreate(Bundle savedInstanceState) {
    8 }0 Q9 D! I2 C& `5 h: P        super.onCreate(savedInstanceState);) q6 A& r- D' J* i% ?0 Y
            height = ToolKit.dip2px(this, 100);9 I$ f8 U- o7 j: V2 T( f
            width = ToolKit.dip2px(this, 150);
    % G: n% ?3 @! t& N* p  z( _        margin = ToolKit.dip2px(this, 12);8 \# M% W' w/ {
            WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
      W" V& v1 B2 Z! C4 I( _        final Display display = windowManager.getDefaultDisplay();
    5 q% F, a' h' q5 u        Point outPoint = new Point();
    / U7 f( D) ?+ {/ l  X) n$ I) p        display.getRealSize(outPoint);  M6 Q, v2 l) T$ R
            deviceHeight = outPoint.y;
    ! }3 o% G2 u+ Y- F. q8 ~        deviceWidth = outPoint.x;4 r. ?! U  w+ k3 X  n
            parentView = (ViewGroup) findViewById(R.id.root_view);
    + n" U% ^+ s3 i: b1 {# |( D# X        fpvWidget = findViewById(R.id.fpv_widget);0 U7 \# w0 Z3 ?- e
            fpvWidget.setOnClickListener(new View.OnClickListener() {* {4 G  `% a1 ]$ v
                @Override8 v6 y: R$ J$ ?; h8 n
                public void onClick(View view) {
    ; B% G9 [, T# Z% I                onViewClick(fpvWidget);0 C$ ^4 r0 U' Y. y; @+ D- e# `
                }
    ( u9 `- O# d/ o( ?, p        });( _6 \; {( ]6 u* Y% C2 Y
            primaryVideoView = (RelativeLayout) findViewById(R.id.fpv_container);
      x8 M' \) D5 W; t4 v+ R( w* r6 l! y        secondaryVideoView = (FrameLayout) findViewById(R.id.secondary_video_view);
    % f% f9 `' I0 p0 X3 p' [5 Z        secondaryFPVWidget = findViewById(R.id.secondary_fpv_widget);
    * j& F" T1 S; ~! d  m        secondaryFPVWidget.setOnClickListener(new View.OnClickListener() {& j9 V* ^# Q& D- L& J
                @Override6 h0 ]. K: j* T
                public void onClick(View view) {( W' E* B9 ], a7 Q8 v* c) Y
                    swapVideoSource();
    . O6 ~+ {  {/ `& ~            }
    4 {  y0 d0 E; r" R' v        });
    7 l1 V' L" s9 d% k        if (VideoFeeder.getInstance() != null) {4 o8 ^; a3 r% G* ~8 h% `! a
                //If secondary video feed is already initialized, get video source
    7 \' p. e  o2 j, v, u9 \% r6 B            updateSecondaryVideoVisibility(VideoFeeder.getInstance().getSecondaryVideoFeed().getVideoSource() != PhysicalSource.UNKNOWN);' x/ t, x& u, `( K7 T# e# L
                //If secondary video feed is not yet initialized, wait for active status3 @% k; ^! f2 M4 E; X5 _! B% l
                VideoFeeder.getInstance().getSecondaryVideoFeed()
    + B( X- `. y1 ?4 ^! W- q                    .addVideoActiveStatusListener(isActive ->5 B6 b! a1 T  R( f0 p
                                runOnUiThread(() -> updateSecondaryVideoVisibility(isActive)));
    " k  d5 \' M9 H8 z; h( v* F6 {        }- n( v8 ]) c0 E/ w! \
            mSharedPreUtils = SharedPreUtils.getInStance(this);
    . l  ^  d4 F5 o+ W3 _' b! }9 }        this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    0 Z9 w1 v6 s8 M) T        mapWidget = findViewById(R.id.map_widget);" i2 U# I" w. ~* d' Z% o
            mapWidget.setFlightPathColor(Color.parseColor("#2fa8e7"));: q9 h% q' G- \4 a7 l0 ^/ ~; X- X
            mapWidget.setFlightPathWidth(15);
    5 {" v: K9 ?2 O        mapWidget.setDirectionToHomeVisible(false);; N2 E$ ^9 h2 H1 f
            mapWidget.initAMap(new MapWidget.OnMapReadyListener() {0 F1 E6 ~% H% `0 n4 l' u+ V
                @Override" Z- a2 \% M* C
                public void onMapReady(@NonNull DJIMap djiMap) {% Q6 D1 C* g3 W; A9 ~) B+ A, o3 \
                    djiMap.setOnMapClickListener(new DJIMap.OnMapClickListener() {  w: L! @& {- V" H
                        @Override5 J- G& D9 Z: q
                        public void onMapClick(DJILatLng latLng) {
    ( c( I1 n; F! t& N, j$ e1 E                        onViewClick(mapWidget);4 W( U# a0 P6 c% C4 M, ?
                        }
    # H) n& q, W2 _( i; a9 l                });
    , _& _0 s. V6 n7 R. A7 {. d' q                djiMap.getUiSettings().setZoomControlsEnabled(false);
    2 k$ ~8 N+ Y7 [# S: L1 B6 `& j/ j            }
    $ u, Z$ c1 ]& c, D        });$ [2 g5 }: @& `7 k) p4 M# i- ]
            if (aMap == null) {4 A3 R" {6 l% ^& t0 Y
                aMap = mapWidget.getMap();
    ! F( _! ~0 B$ i. x# o; e        }
    ) _4 g- W9 Q/ a% k1 x        mapWidget.onCreate(savedInstanceState);
    5 Q: ?$ H( ]+ O, N- M0 v' ?        mProduct = ReceiverApplication.getProductInstance();
    & n1 h8 N8 Y, v% ^* |) C        if (null != mProduct && mProduct.isConnected()) {+ t! Q) ?( E* {9 J( r( {
                flyInformation(mProduct);' d5 s; {2 m0 @1 x3 j6 }
                batteryInformation(mProduct);
    2 G$ W2 x! a9 j$ Y) A            cameraInformation(mProduct);" g, a- T, |5 T. d
                camera(mProduct);( @, `* a5 t& W& h/ I" D4 R
            }) Z$ q0 N( N5 |- ]- m6 a
            Timer timer = new Timer();4 t6 {7 L' C4 {! r- c+ q& W
            timer.schedule(new TimerTask() {
    . H; b, r- W4 v, M9 s3 {            @Override# V. c; a' {7 y$ L( A  k: {
                public void run() {
    : t( h7 T6 }( t4 G" m+ o                Message msg = new Message();+ r$ D& f7 d9 V5 I# u* m+ A: S
                    if (isFlying && !start) {1 a& `& q' E1 y3 s7 P7 _% a; s
                        start = true;
    & d- H6 L6 c/ B- m0 H/ l                    
    ! C8 D3 ]& B  `9 Q            5 c6 L& a. [9 g& W
                    }6 }; ?: o% c6 k: b
                    if (!isFlying && start) {# \9 ?7 F* `! {
                        start = false;6 m- S1 V  \( W6 h/ a- {# b
                  ! J! c. x# n5 e; `; [! t
                    }
    0 ?( Y2 @5 P% q) |/ J/ d9 \4 ^                if (isFlying && high >= 0) {0 b8 l! |  U8 c# F1 H
                        msg.what = 1;! h$ ^6 `1 P5 Y# J! O
                    }7 \4 m( Q/ F; }$ j, S5 I, e+ n
                    mHandler.sendMessage(msg);  [! Z' R# ?! o, n: S# @
                }
    9 n7 S7 e  G9 [. C6 \- h        }, 200, 200);3 ?' _' s  v3 I7 K) I" r/ G
        }, A( v, D1 S  X0 f: p4 d+ s
        Handler mHandler = new Handler() {
    . P" O+ U, ]& Q1 |3 E        @RequiresApi(api = Build.VERSION_CODES.O)4 H6 e( F. H* F. A; d2 j
            @Override
    ( ]$ Y' r" J" h9 S8 i/ [        public void handleMessage(@NonNull Message msg) {7 e' Y( @% B( }$ j* Y
                switch (msg.what) {8 y) k8 l0 V/ [0 E- M5 s2 l
                    case 1:
    & m8 p! R' i; K                    Long time = System.currentTimeMillis();
    ! w' n5 @6 O7 B, v//                    MyLog.d("时间:"+time);. v/ v; h- @8 d+ L4 A
                        RecordModule module = new RecordModule(String.valueOf(projectId), String.valueOf(planeId),' G2 b0 {& I3 b, B
                                trajectoryId, time, String.valueOf(lon), String.valueOf(lat),. a# x. C3 [& M9 N1 w
                                String.valueOf(high), String.valueOf(yaw), String.valueOf(pitch), String.valueOf(roll),
    2 s4 E+ X# `1 y0 n; e( v                            String.valueOf(""), String.valueOf(velocity_X), String.valueOf(velocity_Y),3 o, i, B* G; J# l5 s. ~. `% I
                                String.valueOf(velocity_Z), String.valueOf(g_yaw), String.valueOf(g_roll), String.valueOf(g_pitch));
    ( t0 Q/ g: N9 F% R2 Z                    http.getHttp(INSERT_DATA, GsonUtil.GsonString(module));+ F- i' `; W# z# p) v% ~2 q: z
                        break;
    % R! {- G6 n3 P4 K9 ?7 R& D                case 2:
    ' Q5 I+ S! I" P: {  M! J* M. _                    MyLog.d("飞机移动的数据:"+msg.obj.toString());$ F) ~- J6 [& [: T, W) `( f
                        ControlModule control = GsonUtil.GsonToBean(msg.obj.toString(),ControlModule.class);
    , Y( o4 K4 o5 Y                    if (controller!=null&&isFlying){
    5 e% ~, d( W0 _                        if (control.getContent().isBack()){
    6 E  f. m! a+ `" L/ `                            controller.sendVirtualStickFlightControlData(new FlightControlData(-10,0,0,0),null);
    5 A% i) I8 h( Q/ O                        }
    7 v% H* X. w. o6 ]- A4 `$ _                        if (control.getContent().isFront()){6 u! \5 s2 Y- _' V$ l& d' P
                                controller.sendVirtualStickFlightControlData(new FlightControlData(10,0,0,0),null);2 F7 Z2 ~+ u" q, p1 g4 Z2 J
                            }
    ! t$ W; P2 G% R  \, {$ i, p- z                        if (control.getContent().isDown()){/ v" e! r% m9 I5 c, H
                                controller.sendVirtualStickFlightControlData(new FlightControlData(0,0,0,-4),null);
    6 s) x: Y2 ]" s2 N                        }$ ^9 ~: A) o0 z3 D8 P, r; a  J+ D
                            if (control.getContent().isUp()){, N% V  p2 W. T+ K! Y
                                controller.sendVirtualStickFlightControlData(new FlightControlData(0,0,0,4),null);7 K1 {3 J7 l' H' K3 |% f- Q
                            }
    6 O: f* E! I6 a9 i& L6 x1 [8 r                        if (control.getContent().isLeft()){3 {* ?$ ^: Z1 d9 ^& ~) K" x: K
                                controller.sendVirtualStickFlightControlData(new FlightControlData(0,-10,0,0),null);
    ; W) n. K8 [( ]9 M- E                        }- R' Z; `: w  H2 B9 z2 b1 O5 Z- g+ `
                            if (control.getContent().isRight()){" u6 J# p! H. t  f# f; _+ h. ]
                                controller.sendVirtualStickFlightControlData(new FlightControlData(0,10,0,0),null);
    5 |  j, q& }$ R: h$ s& J. i                        }/ |/ G0 _5 ^& i, F# J' s
                        }else {; h5 k3 `0 g" O; z
                            MyLog.d("controller控制器为空");
    9 z5 X/ s) U0 B$ ^                    }
    , L0 H/ ^8 l# s! y2 R                    break;, S/ j. P5 J+ m4 M
                }9 t+ Y$ l+ X2 `) |- j0 Z2 N: Q
            }
    0 K$ z- b; a, X1 t( [    };
    0 Y4 g2 `( l2 z' I    @Override# k: U3 B5 c+ ~5 o' p) o& ~
        public void initViews() {
    & c8 f$ U, C6 _' Q        mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();) }) L* l! E4 M: y1 I* ?
            getFileList("start");
    ' M, o7 Q3 H* e) ^( R+ U+ p/ F    }8 I9 j6 ~8 m$ D6 [9 y9 `
        @Override
    : \% n* T4 q& ^( v! |; ~  W3 p    public void onComplete(String url, String jsonStr) {" O, q) r+ Y0 T' T& @
            super.onComplete(url, jsonStr);+ A0 e  A+ W2 M8 e" s, j: @
         
      _% E! J; x+ }) _  n; Q    }) l4 j( ~) H- P/ |1 V, p6 c
        @Override& o0 L: l* t- ]3 Q, n* d; g- s% Z
        public void initDatas() {
    7 p4 s  T2 M* |: h3 q; w; d* C    }
    . f7 y  @' W1 {2 x" Q  W    private void onViewClick(View view) {) ]3 q1 y! t. z; N
            if (view == fpvWidget && !isMapMini) {0 [' [& v8 t, G4 i, u
                resizeFPVWidget(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT, 0, 0);+ ?) \2 s0 f' k
                reorderCameraCapturePanel();' V" K' y% X. }& T  v0 U3 M  U7 x- L
                ResizeAnimation mapViewAnimation = new ResizeAnimation(mapWidget, deviceWidth, deviceHeight, width, height, margin);
    5 Q  M' k2 \: W! t            mapWidget.startAnimation(mapViewAnimation);5 K  U/ z3 K/ Q
                isMapMini = true;( P% o  u! {2 V2 E$ K5 A2 `) p
            } else if (view == mapWidget && isMapMini) {
    2 b" B! w3 ?- e2 R! W  y- w" X            hidePanels();
    $ W; M# N2 w  W2 P6 A6 }            resizeFPVWidget(width, height, margin, 12);
    / G4 K  E& q) c3 B! h0 G6 R: {! K            reorderCameraCapturePanel();% [/ e, m# x0 n; V  {
                ResizeAnimation mapViewAnimation = new ResizeAnimation(mapWidget, width, height, deviceWidth, deviceHeight, 0);- y1 `* l; q* `, b
                mapWidget.startAnimation(mapViewAnimation);
    $ ]% y$ j/ E5 u; A            isMapMini = false;! U0 w+ [7 L9 w# G! R
            }
    6 a0 g! i5 t" M3 S$ ^1 D) V' q$ f    }' [9 a! x0 y: g1 H
        private void resizeFPVWidget(int width, int height, int margin, int fpvInsertPosition) {( i3 n8 O9 c5 c9 D) d6 }9 m) D
            RelativeLayout.LayoutParams fpvParams = (RelativeLayout.LayoutParams) primaryVideoView.getLayoutParams();
    * ?+ q0 B6 B  o1 r        fpvParams.height = height;
    $ ^' M' d: u+ T! c& G! s5 P        fpvParams.width = width;
    7 V6 N* j9 ^7 \+ X3 g        fpvParams.rightMargin = margin;! V$ l9 J; j. Y1 i
            fpvParams.bottomMargin = margin;
    6 W$ p( h+ z3 f  g, {! I- G. G8 O        if (isMapMini) {# B6 S/ `  T/ R2 a
                fpvParams.addRule(RelativeLayout.CENTER_IN_PARENT, 0);
    ( }( d* b& P8 p3 Z# z. a! y* d9 Q            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);' K( [+ r6 t# Y5 _: m# `1 `4 ]( p1 I
                fpvParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
    ( `! @! G- ^1 H6 \" C. W        } else {( b, O0 a1 B) W0 _# J/ a3 F( L! y4 `
                fpvParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
    ' v: B/ Y3 _+ w2 |2 S5 a1 P            fpvParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0);( ^" e. ]1 }; A; {
                fpvParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);" e4 e# H1 B( [7 t1 @
            }  {$ u; x  T' Q! R2 m: h& D- m
            primaryVideoView.setLayoutParams(fpvParams);$ F$ f- ^2 m+ `0 Y/ s& S0 }
            parentView.removeView(primaryVideoView);! L( @% i+ l1 l+ Q
            parentView.addView(primaryVideoView, fpvInsertPosition);7 y1 A2 X: j9 t4 ~0 o, Y& V
        }
    0 l- e. b. l0 `- d' q    private void reorderCameraCapturePanel() {
    6 r& S% W! y' I5 `' C  q0 B( {        View cameraCapturePanel = findViewById(R.id.CameraCapturePanel);
    & R( b! [5 B) n' [6 c        parentView.removeView(cameraCapturePanel);
    9 z8 B5 }( f* V( L% R* ~        parentView.addView(cameraCapturePanel, isMapMini ? 9 : 13);% D" h7 D, [( {+ m& Q5 i: H0 _( n$ M' _  m
        }
    , v; m* j/ [! V3 T0 }, P    private void swapVideoSource() {
    - G/ t+ q- M; h* M! y! s8 I        if (secondaryFPVWidget.getVideoSource() == FPVWidget.VideoSource.SECONDARY) {+ V+ }/ n$ o  ?3 O1 d4 C
                fpvWidget.setVideoSource(FPVWidget.VideoSource.SECONDARY);; _2 R" `7 Q3 x+ k0 e0 {
                secondaryFPVWidget.setVideoSource(FPVWidget.VideoSource.PRIMARY);
    / x. d; f0 c' ?! v; ?8 o        } else {9 L! E1 u0 r( H/ R# n# W& v% P
                fpvWidget.setVideoSource(FPVWidget.VideoSource.PRIMARY);  d' r, [$ j% X! F+ R
                secondaryFPVWidget.setVideoSource(FPVWidget.VideoSource.SECONDARY);* v' b* ]; O3 V& S: P2 `
            }
    ' s( F& j8 l# @0 g5 j% ?    }0 }* o4 H  P$ o, J" M0 I6 i4 C& b
        private void updateSecondaryVideoVisibility(boolean isActive) {
    5 z  j4 N- B6 v8 K- V+ g        if (isActive) {
    : x7 R1 p7 \# e6 d            secondaryVideoView.setVisibility(View.VISIBLE);/ S  W* p( _& R  k4 a- a" z
            } else {7 k& ~$ Z/ y+ Z2 }
                secondaryVideoView.setVisibility(View.GONE);
      L9 W! c) b1 B+ f/ I        }3 K2 j# f# L1 w) }# x8 U' K' L* l
        }
    * P  b$ f! f' ^  }* D; w    private void hidePanels() {
    3 K! k! t$ u; ^( {- m% @% E# Q$ Q  K        //These panels appear based on keys from the drone itself.
    6 u- c: i5 I/ @/ i, y; ?        if (KeyManager.getInstance() != null) {# f; N; y9 h# N: R9 q4 [; Q
                KeyManager.getInstance().setValue(CameraKey.create(CameraKey.HISTOGRAM_ENABLED), false, null);
    / Y. {$ k8 O0 x            KeyManager.getInstance().setValue(CameraKey.create(CameraKey.COLOR_WAVEFORM_ENABLED), false, null);
    3 E5 o3 N8 X% a9 f5 y1 V6 x' \' b+ i        }
    0 r# p/ e  x' I8 o        //These panels have buttons that toggle them, so call the methods to make sure the button state is correct.
    0 x+ T! n& N* Y, F4 p        CameraControlsWidget controlsWidget = findViewById(R.id.CameraCapturePanel);2 d$ u, x. u  S' _3 a! N0 K, q! W
            controlsWidget.setAdvancedPanelVisibility(false);7 `* C  O) ]9 V- v5 v& N, x: O4 g4 P
            controlsWidget.setExposurePanelVisibility(false);( b" Z0 f' u* o* R; v" U8 w
            //These panels don't have a button state, so we can just hide them.
    . h1 T+ h3 E8 C5 }2 [        findViewById(R.id.pre_flight_check_list).setVisibility(View.GONE);% h2 k* q3 X  n1 y6 u  t# d
            findViewById(R.id.rtk_panel).setVisibility(View.GONE);
    ' n% r5 g* I" F/ A# O! q        findViewById(R.id.spotlight_panel).setVisibility(View.GONE);
    6 D$ F3 Q' `) @, @, ~, G% @6 d# d- r        findViewById(R.id.speaker_panel).setVisibility(View.GONE);
    : O" V! Z1 ?5 b5 K    }. ^6 c) z3 P) a0 N# ?/ {
        @Override* h" i2 V* I3 I+ J7 ~
        protected void onResume() {
    / O/ j# F/ l4 o7 }9 T8 `& b3 Q  A        super.onResume();% C" N% w( ^% r
            // Hide both the navigation bar and the status bar.  S  e! w1 y& \# P3 R
            View decorView = getWindow().getDecorView();
    . Z. L: o# i, U2 T        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE# W3 r' c$ @  R3 c1 P% b
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION" A+ O3 k- s/ H4 K; l, k8 ~
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN" `& V/ E/ j: I% _" q
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION, c3 x% b6 [# c8 p7 c# R
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
    4 a: x' R* c/ d$ P/ _                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    ! I/ C9 O) D; t6 A% F3 y        mapWidget.onResume();' k, W+ F* }2 Q+ a: ~8 P
            if (client == null) {( |1 |, g3 o2 @% W
                MyLog.e("``````````````````````onResume");2 B+ U) r% [* t, @
    //            initWebSocket();
    ! B* {! T/ Y, ?) c% o! d- A' g        } else if (!client.isOpen()) {
    3 _+ S& A& z6 b' d; J            reconnectWs();//进入页面发现断开开启重连: N$ V( r* t) f& ?2 q8 ~
            }: i- I5 ~% `1 x7 f
        }) L) X+ f( E1 p1 |: C
        @Override9 D7 K5 M$ `" J0 |: r/ j1 H
        protected void onStop() {
    " A$ h" j4 h5 |3 H) ?. t        super.onStop();
    & m4 m% P. Z+ O- [$ h        MyLog.e("``````````````````````````````onStop");6 U8 P1 j, j0 _" l) R& V
        }
    3 E, C* e$ y$ x5 Z0 r1 F4 g    @Override
    $ b7 u- p9 @, B; h    protected void onPause() {
    2 l% p) Y0 i7 O7 `/ U8 ~' r        mapWidget.onPause();. o* w. X6 s/ X' y
            super.onPause();' n* G" B* T% R) H7 V$ ~
        }+ _& e& {. {; F+ B
        @Override6 ~, T+ ~. j1 u6 y: ?6 M+ B2 I
        protected void onDestroy() {
    2 N# C4 ]$ _' E: M; ]        mapWidget.onDestroy();
    - s) B" K" t; }+ X2 w9 [) H        super.onDestroy();
      J3 \& p7 P# s* m" I        MyLog.e( "`````````````````````````onDestroy");
    0 }; f( C) B9 \) T3 t: Y        closeConnect();
    : i, F  \9 U! B- q    }9 L# X1 j9 ^0 b5 B
        @Override! s4 M" g! x$ b1 I9 `. h& F! @- q+ w
        protected void requestData() {
    0 P) d2 ?- e* \6 C% _) D" S* R1 {    }8 G; Z8 T1 q" h( q) T
        @Override* }; t$ G6 D) [& t# z7 R" ~5 i4 K
        protected void onSaveInstanceState(Bundle outState) {0 y# h; T, K9 C+ W) e
            super.onSaveInstanceState(outState);
    0 Y5 w4 p3 p: x        mapWidget.onSaveInstanceState(outState);
    ; k1 l7 y3 l, Q1 S1 d8 @7 R  x    }/ w% o$ g7 K  s. b2 P- G& P& {/ l' j
        @Override& _+ }" K- D! o
        public void onLowMemory() {* Q% \+ I: _- m& I, N; W3 M1 n
            super.onLowMemory();
    2 x9 v! a* r; o        mapWidget.onLowMemory();
    0 A  a) v2 b0 v4 }5 N1 ?% n    }
    5 N" Y* L, N  r2 m2 C$ M    private class ResizeAnimation extends Animation {
    3 \4 S2 a; ^) p% j9 Y        private View mView;
    8 X! x. K, M+ \- J9 L4 d        private int mToHeight;2 ]- C7 t7 q% |; J: x  N6 T
            private int mFromHeight;
    ( z; ^& C0 O  k2 J        private int mToWidth;- y! g0 _; y( ~$ b
            private int mFromWidth;  g) v# Q. G: ~
            private int mMargin;
    ' ^$ k7 L3 k4 ~  |0 v! R8 [        private ResizeAnimation(View v, int fromWidth, int fromHeight, int toWidth, int toHeight, int margin) {
    - W( u* b+ t2 u1 `/ n            mToHeight = toHeight;
    5 v' V) X7 W3 L            mToWidth = toWidth;  `* ~2 ]3 g% V0 O! q( A
                mFromHeight = fromHeight;
    9 H/ V8 h7 U# z- I            mFromWidth = fromWidth;5 ]' N7 F. Y) }* }' y3 n
                mView = v;
    / j7 P/ r! _- H0 J            mMargin = margin;. _8 y/ Y+ E& `, w* F
                setDuration(300);; w+ ]7 ?2 P9 |  Q5 b
            }
    ' V0 R6 t$ h% ?/ a2 F1 m; `2 V9 e        @Override7 V( q. w& u( S5 D
            protected void applyTransformation(float interpolatedTime, Transformation t) {/ o/ y# x. G3 E! c0 N6 k+ E
                float height = (mToHeight - mFromHeight) * interpolatedTime + mFromHeight;
    3 b- C% ^) j; {. Z& L            float width = (mToWidth - mFromWidth) * interpolatedTime + mFromWidth;
    2 @: J- W0 s2 y. j1 ]# h9 c            RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) mView.getLayoutParams();0 ^+ c3 K+ O- y5 l' s  G$ _8 E+ {, \
                p.height = (int) height;4 h) W; \9 u6 k7 V
                p.width = (int) width;
      [+ g% R& |% o: l            p.rightMargin = mMargin;( u4 _' c' k/ w; [. Y% @% s, b  P
                p.bottomMargin = mMargin;" t  V9 c1 t. h9 Y
                mView.requestLayout();
    - T/ M# z# u5 S/ L2 o* n; u        }. D: J: I1 {* F% K' {: C
        }
    & q- x$ Q8 l  Q5 d2 M( B' S1 s7 v8 G- y" l
        //直播流推送- O4 e: t: _. \% E# u% p
        @RequiresApi(api = Build.VERSION_CODES.O)
    ! W6 }! q( Z* y9 N  _; A& h  \. B5 M* U    @OnClick({R.id.img_live, R.id.img_show_back})& c% I7 s: v; I( H0 Q1 }; C6 L" @$ @
        @Override1 p% D3 I; V( x; B5 W
        public void onClick(View v) {% W  z, ?1 C, b! W
            switch (v.getId()) {/ q* z0 f! {0 q9 T' Y
                case R.id.img_live:
    1 I% R3 }" N! F0 ~' f6 Q. H% e                params.clear();
    ! L4 R5 U6 g7 x) \- b9 ~! o. u                mapData.clear();
    , u2 r; @4 G9 r                if (!isStartLive) {: Y* C; W' W" w8 A$ j' Q2 G7 i! ^
                        if (!TextUtils.isEmpty(mSharedPreUtils.getStringSharePre("rtmp_url"))) {
    8 r% T; b- m, s/ H" R0 s                        liveShowUrl = mSharedPreUtils.getStringSharePre("rtmp_url") + trajectoryId;
    # o0 e' N; M0 z) d//                        LiveModule module = new LiveModule("liveStreamStateChanged","plane",planeId,true,trajectoryId+"");1 Z5 B8 q$ r$ c6 R2 b
                            MyLog.d("地址:"+liveShowUrl);
    : ?( Z7 y, R. c                        startLiveShow();) @6 T7 U) S2 r; h; `: \4 Z6 O( \
                            isStartLive = true;7 j" d1 K0 i# ^8 |) u5 m6 I& n
                            showToast("开始推流");$ ]3 R4 r& t( x4 x3 ^
                        } else {
    4 N6 o% a3 }' e0 O, g5 d% |                        showToast("请先进行系统设置(RTMP)。");1 L! s7 M9 o: M0 H  o
                        }
    ; r; M% S0 J; u: J/ A$ j7 w                } else {
    2 @# A, s  D6 u9 r/ m4 K                    stopLiveShow();3 R* t4 m& Q& z1 V# m/ l) h) _
                        isStartLive = false;
    ) Z! p. q% ?  R) S4 b2 }/ P$ x; {                }
    1 Q3 `- z. O0 m7 B% O3 n' L0 \                break;
    $ ^0 P6 G# M$ z/ }! I, B            case R.id.img_show_back:; e! M- ~' {' K3 a1 m. w' D5 o
    //                controller = null;
    2 j" K3 U: Q5 G; J# M# j# l                closeConnect();) P  @' F# l' z9 E, G
                    MainActivity.this.finish();
    " k' @/ f, P5 a                break;# {# j$ j  {0 E0 `) b6 {7 x  q
            }0 W2 s: H: f0 |3 g! U
        }
    9 a/ T& U8 R* c5 h    private boolean isLiveStreamManagerOn() {# d, k5 N  [# W% }1 F: R
            if (DJISDKManager.getInstance().getLiveStreamManager() == null) {7 {7 w6 {3 C7 |# S) Y
                return false;
    ( f1 h4 `; S; M7 L2 }" m        }
    6 C3 ]) a. F8 r# M5 E. m        return true;; v# L; ?0 J' m! \; L+ K
        }% T; O+ m* v4 C
        private void startLiveShow() {* Q; m% [( y8 F5 p) H
            if (!isLiveStreamManagerOn()) {$ T0 W9 a' W, l. s0 X
                return;' ?6 b0 I* ?. r0 C" k
            }
    ; C- {0 G2 h( v; I: D        if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {& f7 ]3 F) g9 \) V
                return;+ l0 P" g  {4 O$ f
            }' ]1 \! B: u+ R: n! ~/ g) ?
            new Thread() {' N* n6 O: L& ?2 A1 K+ p
                @Override
    0 l2 F3 l/ K! `; I6 r+ U            public void run() {
    : o8 v$ W# A8 V$ ]5 W                DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl(liveShowUrl);9 L& D! S- ?( \. y2 F' `( D
                    DJISDKManager.getInstance().getLiveStreamManager().setAudioStreamingEnabled(true);
    * D! I5 ^" ]4 X+ Z" l# }, y                int result = DJISDKManager.getInstance().getLiveStreamManager().startStream();1 n! ?" M% p, H. J; o% ~+ G
                    DJISDKManager.getInstance().getLiveStreamManager().setStartTime();; d5 x0 Y2 a8 ^6 s
                }
    ! y; _1 E* [) \  j1 v4 Z; ?        }.start();
    6 g* V# t+ l& K" {) K8 f4 S% h7 W. O# o    }
    ( z2 N, w) T) r! s    private void stopLiveShow() {
    2 O9 e" J8 z$ _, S" `$ |; _; m        AlertDialog.Builder Builder = new AlertDialog.Builder(MainActivity.this);- j# w$ S7 H3 d5 |0 T; h
            Builder.setTitle("提示");  ~; X( }* a/ @7 Y, g% p
            Builder.setMessage("是否结束推流?");; {0 @$ ?! I- k  [+ z
            Builder.setIcon(android.R.drawable.ic_dialog_alert);
    * N6 x! G& O2 \& C0 O# K        Builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
    ; Y$ T% m, h* z$ `/ r4 G: |4 [            @Override
    ' g0 t& M' J; q            public void onClick(DialogInterface dialog, int which) {
    7 O% f; T( P1 b% X0 f                if (!isLiveStreamManagerOn()) {7 A5 N0 q9 v6 f
                        return;
    5 Y2 ^. r$ F; ~1 M! w" P. e                }9 b9 E8 C2 \9 z. V9 G3 V$ [4 t5 t
                    DJISDKManager.getInstance().getLiveStreamManager().stopStream();
    - ^/ e8 I2 B- J1 p                showToast("结束推流");( N" z7 K0 a' ^4 S' ]
                }6 W1 r8 S# T, n: w6 B, P( G( d
            });* H5 {- `3 l4 X7 g! N
            Builder.setNegativeButton("取消", null);$ q( {9 @* w7 a4 c1 o% l, l8 c  a
            Builder.show();, ~- y9 m) s, l0 E6 \- G* U
        }7 H! [( w5 n# v" `) C0 s

    - t0 E- b% {; e- Q. P    //获取飞机信息、云台信息
    * K9 m9 g1 \: h2 y* @4 ]% R/ P    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
    & B! L1 Q/ e# x+ X6 h        @Override
    1 u& O$ E) B2 Y        public void onReceive(Context context, Intent intent) {
    + r4 @1 b6 k  d/ z  u- g            BaseProduct mProduct = ReceiverApplication.getProductInstance();
    6 ^3 `) `: s6 W( H            if (null != mProduct && mProduct.isConnected()) {9 g! H8 k) D% A# w# H! ^! B
                    flyInformation(mProduct);
    9 Y: M) \( R) v$ H6 z3 k- d* \8 g' E                batteryInformation(mProduct);: l8 R( {" t  a& z2 G
                    cameraInformation(mProduct);
    ; B7 [7 Z0 s" h# M* ~                camera(mProduct);. b" Y; u8 j5 N, M
    //                MobileRemote(mProduct);
    " U$ r, m- j/ C" ~' G' x7 ]# l# O            }/ F8 f  Y8 B* h7 _
            }
    * {8 C2 q" O8 e3 K- ]    };
    2 e/ ~  a0 D% @; c; K. Q( h) X( ^1 V//    private void MobileRemote(BaseProduct mProduct) {$ O3 A) M6 Q1 u, k( \
    //        if (null != mProduct && mProduct.isConnected()) {
    / c9 W) h/ l% n* z8 E7 n//            mobileController = ((Aircraft) mProduct).getMobileRemoteController();4 x& i7 X6 j* w4 f
    //        }
    8 n5 G. w; D7 K, W' E# W$ Y% |//    }/ s1 i# c" v( s" J+ v
        //获取飞机信息6 Q! U3 H' |5 [
        private void flyInformation(BaseProduct mProduct) {" n' e3 t& g4 T0 M# t
            if (null != mProduct && mProduct.isConnected()) {3 o0 {/ x& H* j/ g
                controller = ((Aircraft) mProduct).getFlightController();
    ! D9 h4 W+ q: G7 J        }
    # |2 h) s1 y' X6 c+ v2 [        if (controller != null) {
    2 Y) F9 s1 `. `1 X! `            controller.setStateCallback(new FlightControllerState.Callback() {
    1 O/ ]: S$ }* o7 E$ r                @RequiresApi(api = Build.VERSION_CODES.O)- T+ f; Q* y0 [! ^  |) I
                    @Override
    ) B( w5 f( `- K                public void onUpdate(@NonNull FlightControllerState flightControllerState) {
    ) j/ n) q' {. _. u8 c- S                    //纬度、经度、高度、俯仰角、滚转、偏航值、速度  n- n% ~! o) T% R5 m$ }
                        lat = flightControllerState.getAircraftLocation().getLatitude();5 c6 h! K, n' b5 r5 g7 u0 W
                        lon = flightControllerState.getAircraftLocation().getLongitude();
    1 q) N. h4 I9 n8 `) j& U+ D                    high = flightControllerState.getAircraftLocation().getAltitude();( J+ l1 ]% g7 C
                        attitude = flightControllerState.getAttitude();2 Y* k. A1 f# v: `$ E( I4 {% N
                        pitch = attitude.pitch;  k- }. S* g  r- F+ k2 @3 r" I0 v
                        roll = attitude.roll;$ ~* u( w0 q" {. H3 b4 X! [
                        yaw = attitude.yaw;
    # F- ]6 z  ]$ L7 f9 g5 A                    velocity_X = flightControllerState.getVelocityX();
    1 D! E. R0 V. j+ h7 g& I                    velocity_Y = flightControllerState.getVelocityY();$ h1 K* O- r+ c2 U; H9 M, e, D+ g/ r
                        velocity_Z = flightControllerState.getVelocityZ();3 q6 b% W# L' Q
                        isFlying = flightControllerState.isFlying();& M' U7 s! L$ p: l( \6 ^
                        //                    MyLog.d("经度:" + lat + ",纬度:" + lon + ",高度:" + high + ",角度:" + pitch + ",速度:" + velocity_X + "," + velocity_Y + "," + velocity_Z);7 R/ `( F4 L% t/ K5 ^3 j
                    }
    ! J& e% e/ h8 v/ ?5 l/ D; R; i( o            });2 b$ y3 w5 B+ E8 l; n/ |! I4 `% D0 Y  [
                controller.setVirtualStickAdvancedModeEnabled(true);
    + C0 h# M8 G$ h            controller.setRollPitchCoordinateSystem(FlightCoordinateSystem.BODY);
    + [& N4 e3 T7 r            controller.setVerticalControlMode(VerticalControlMode.VELOCITY);) k% d: @& i. i) e
                controller.setRollPitchControlMode(RollPitchControlMode.VELOCITY);
    ' t* [: g0 [, g  M" `: i+ m) M# R# X            controller.setYawControlMode(YawControlMode.ANGULAR_VELOCITY);, T" J1 b% _* _, x$ n; |! e' f$ k) D- y
    //            controller.setTerrainFollowModeEnabled(false, new CommonCallbacks.CompletionCallback() {4 a; l, x' ?! \4 t$ u/ l$ E! Q3 x
    //                @Override
    ! y8 l5 [9 W- n% F//                public void onResult(DJIError djiError) {
    - C( O8 ~6 U6 o* o3 a, r& _0 @( F//                    MyLog.d(djiError.getDescription());
    & S- m4 r" F- d5 N//                }9 a. U) m6 Z3 Z6 Q9 D
    //            });- S( z  y) h  R- b& m$ X
    //            controller.setTripodModeEnabled(false, new CommonCallbacks.CompletionCallback() {$ ~" W1 z# \/ [6 q+ C0 R" V# o
    //                @Override, P: t3 \( a5 f8 o
    //                public void onResult(DJIError djiError) {
    & I, B! K' t  E$ W! h7 H//                    MyLog.d(djiError.getDescription());
    6 i& W6 @! I2 @% b+ r" F: P1 i//                }
    " M& w& [+ s% J7 V3 ~: _- x//            });
    : i1 ~8 \: J9 ?//            controller.setFlightOrientationMode(FlightOrientationMode.AIRCRAFT_HEADING, new CommonCallbacks.CompletionCallback() {
    2 x- E( P6 X" _3 B( n. ?//                @Override
    5 Y2 D# Z% o' `8 U, h8 \//                public void onResult(DJIError djiError) {; o, _' e  j& ?( C" W* Q/ z  }% G
    //                    MyLog.d(djiError.getDescription());
    3 n# P1 f. x5 |3 X7 x! D" R//                    if (djiError==null){
    0 M! Y( _6 P$ N//                        if (controller.isVirtualStickControlModeAvailable()){
      O) @" M( v2 v* [0 c. K//
    . k# d3 H* D6 A$ a# H1 S//                        }else {
    " s" ]3 O# p  c+ R/ ?. Q- F9 |8 k% h//                            MyLog.d("虚拟摇杆模式不可用");" _- d6 w; O6 ?. N' A9 K
    //                        }
    ) h) ~  _  L& c9 w//                    }
    2 I- `. W: O- j5 ?- J//                }
      x+ \( S/ Z) ^, J' \8 S//            });
    ' U& F: f- ], C# J: R1 H        }
    4 D1 U5 D& z2 ]+ e0 `    }# I$ N3 Q# Q4 x/ |/ Q
        //电池信息
    4 U2 t- {: m2 Z# @+ T% j    private void batteryInformation(BaseProduct mProduct) {
    & S! k9 c8 C+ B2 u9 a        if (null != mProduct && mProduct.isConnected()) {
    7 C1 f9 m5 G- S2 i# m5 x: l: p            battery = ((Aircraft) mProduct).getBattery();
    + t5 s- I+ v/ j, P' g        }3 w% G; h# A! P/ s# D" o  L# _- `
            if (battery != null) {
    / J6 O4 V8 n/ N3 T+ F            battery.setStateCallback(new BatteryState.Callback() {- y* q8 }  ]2 X7 O6 I" F
                    @Override
    * D/ {( w- g: w/ J9 n3 u$ a; Y* G                public void onUpdate(BatteryState batteryState) {9 y+ Z* R5 H. j2 X9 ^9 D$ {2 v
                        //电池电量
    & L8 _4 R" `' q, H  K; Z3 V! q                    power = batteryState.getChargeRemainingInPercent();
    ! }+ f  @& O& U                    //电池温度
    + N+ b. D* Y6 ~8 c                    temperature = batteryState.getTemperature();
    9 r9 K: w! I1 a# J3 X* X* e                }1 g$ E4 {" D& y  l+ V
                });
    3 n7 E+ T1 h4 X1 g7 S        }% @7 y1 C4 C% v* _# D9 ^* x+ O! M! i
        }! Q) P( b, j8 O
        //云台信息$ [3 B  J# @' U0 y+ ~5 A) d3 i6 ?9 ^
        private void cameraInformation(BaseProduct mProduct) {, A# i& _0 S' a# R, Y2 h- A
            if (null != mProduct && mProduct.isConnected()) {' u0 S. k6 y# A% u2 X+ j- p
                gimbal = ((Aircraft) mProduct).getGimbal();9 V8 @( Q5 {$ Y2 }9 \
            }
    ' L7 Y" r/ W8 B        if (gimbal != null) {
    * I' H4 l( i, n! @2 x            gimbal.setMode(GimbalMode.YAW_FOLLOW, null);2 t2 P9 J" G- Q
                gimbal.setStateCallback(new GimbalState.Callback() {+ r& w7 O9 q$ P8 i* V) N: {
                    @Override$ h; q# ~' I4 {- t
                    public void onUpdate(@NonNull GimbalState gimbalState) {" W" a/ J* B, L
                        //俯仰角、滚转、偏航值6 [% u# @( ]" w0 \% ~1 S) P3 z+ f
                        g_attitude = gimbalState.getAttitudeInDegrees();
    6 @* A' `" s$ P+ h                    g_pitch = g_attitude.getPitch();0 q& Z. ^2 J$ a1 x/ I6 V
                        g_roll = g_attitude.getRoll();
    9 z' ~1 u9 }) X. I5 w0 {! e2 A/ ]                    g_yaw = g_attitude.getYaw();
    + [1 a; J8 d/ P6 F' L' v                }( T9 q% G" a4 ]
                });
    0 K, N& @: P5 L" F        }+ U& P2 i; P' a) m# E3 V
        }
    1 w+ }: }1 a7 w+ d    private void camera(BaseProduct mProduct) {8 ~- o7 B7 b8 D1 v; y0 {
            if (null != mProduct && mProduct.isConnected()) {
    7 J8 G8 e! @0 H# w            camera = ((Aircraft) mProduct).getCamera();& o! ~- Q. a/ `3 h; J1 g: {* x$ m
            }
    & a; s* m) J- n  Y- S' u        if (camera != null) {4 Y2 t/ y  L4 d( V6 t
                //            camera.setVideoCaptionEnabled(true, new CommonCallbacks.CompletionCallback() {. R5 Y7 ^( \8 U4 u, M, u- F( S
                //                @Override
    9 [. j) I. H( |( Y7 L( \            //                public void onResult(DJIError djiError) {
    0 [' z; `- ~/ m            //                    MyLog.d("VideoCaptionEnabled"+djiError.toString());* ?) `' u& H# h  T3 E
                //                }/ j% f+ f* W' C" z  ?
                //            });0 d6 ^) M" G- J/ R7 Y2 ^
                //            camera.setMediaFileCustomInformation(projectId +","+trajectoryId, new CommonCallbacks.CompletionCallback() {
    9 s% `+ @% Q* i9 ?' n6 ?8 L            //                @Override; A& Y1 M* i/ m9 j" {- K
                //                public void onResult(DJIError djiError) {- P1 {- c0 \) p, R  c4 U
                //                    MyLog.d("自定义信息:"+djiError.toString());) e3 {3 N- w4 Y
                //                }3 a& t. D6 K' z6 w$ v1 y0 @, O
                //            });
    % a, G4 P6 k9 _0 a. M            camera.setSystemStateCallback(new SystemState.Callback() {" K# O: v5 i0 {' T* k" w
                    @RequiresApi(api = Build.VERSION_CODES.O)
    5 H6 R' Z4 B( e& G# A                @Override
    . [2 Y' i# k' d9 \                public void onUpdate(@NonNull SystemState systemState) {1 a# W  H# I1 ^% K' I
                        if (systemState.getMode().equals(SettingsDefinitions.CameraMode.SHOOT_PHOTO)) {
    1 f& I! n. C& b+ N8 `                        if (systemState.isStoringPhoto()) {( _+ }( o7 m  G7 Q2 r
                                dateStr = Long.toString(System.currentTimeMillis());
    ) L* m, q, I# F0 V                            list.add(new DeviceInfo(dateStr, lat, lon, high, pitch, roll, yaw, velocity_X, velocity_Y, velocity_Z, g_yaw, g_roll, g_pitch));, V* W! l* [$ a' D3 c2 n8 v! ]
                                CsvWriter.getInstance(",", "UTF-8").writeDataToFile(list, FileUtil.checkDirPath(FLY_FILE_PATH + "/照片数据") + "/" + DateUtils.getCurrentDates() + ".csv");2 H7 G2 c: ~3 Y/ l) {
                                list.clear();$ W) G: i5 P1 U8 i1 y
                                return;
    8 u! s8 P! z* z# ]( p                        }
    ' T' r* N0 W/ {: N- ~2 i# r5 S                    } else if (systemState.getMode().equals(SettingsDefinitions.CameraMode.RECORD_VIDEO)) {$ |& _$ c% ?, x( k/ }# |! r
                            if (systemState.isRecording()) {* R/ o5 Z5 v$ u$ a/ S
                                try {  t5 u9 |! k1 ]
                                    dateStr = Long.toString(System.currentTimeMillis());( u9 g9 @+ l, p$ Z" P
                                    list.add(new DeviceInfo(dateStr, lat, lon, high, pitch, roll, yaw, velocity_X, velocity_Y, velocity_Z, g_yaw, g_roll, g_pitch));5 T3 G$ d( N$ Q8 q
                                    getList.add(dateStr);" [4 F( _+ r. C) y) x( M
                                    Thread.sleep(100);
    8 C. m5 c6 c% _( l! F                            } catch (InterruptedException e) {
    7 @7 C: u7 K0 m+ W; O                                e.printStackTrace();
    6 q/ C, l; W, k5 h/ [3 M2 j                            }
    . A0 h! G  S" m% h3 w6 D* b                        } else {
    0 `+ q' X" }; ]+ ]# }6 U                            if (list.size() > 1) {+ w. M) Y( _9 J+ ?, m/ E
                                    posName = DateUtils.getCurrentDates() + ".csv";
    $ g3 }6 E, c- S- X! p; D& T8 q  v                                CsvWriter.getInstance(",", "UTF-8").writeDataToFile(list, FileUtil.checkDirPath(FLY_FILE_PATH + "/视频数据") + "/" + posName);, A& U+ [" K' J3 z$ X8 @
                                    list.clear();( l* D* l# b, z6 V9 u
                                    runOnUiThread(new Runnable() {
    2 D  T! D' H& ^, D% O' E                                    @Override3 `0 v. Q* ]/ d3 [
                                        public void run() {
    % i$ t( g) n) D" \' M                                        getFileList("end");
    4 ^; y* @, ^7 |/ _7 g& B                                    }
    2 x! v7 S) y' t' e                                });9 l, d* q5 Q# ~# q$ U3 E
                                }
    ' |, D0 m$ L0 N7 a' ?* M# s1 o                        }9 A9 W  x2 ], f# p1 I
                        }# R1 S# |4 ~2 q; p3 k% d' Y) t6 i* P
                    }
    5 `: B2 T# `# W/ b" E+ Y            });4 _+ P4 Y3 @  c4 I5 j2 H
            }0 a# V! H; S* b  w1 {
        }
    . S$ M7 Z% S  O$ R0 x  ]    //遥控器信息
    , u" [* }& o+ I7 u    private void handheldInforamation(BaseProduct mProduct) {" Z6 k) D7 S# @, h9 F3 Y4 h/ W
            if (null != mProduct && mProduct.isConnected()) {
    ! z! C; q# z) C% w* G6 V            handheldController = ((HandHeld) mProduct).getHandHeldController();9 ]2 }! k8 {' e5 G; z
            }
    ( d( G2 P' ^/ X/ q, G+ r        if (handheldController != null) {
    1 ]+ N0 X; X. F/ w, P            handheldController.setPowerModeCallback(new PowerMode.Callback() {
    ' n1 v- _) t5 l/ ?8 O; R" C                @Override
    3 g0 |: Q1 h% Y/ x1 Q+ ~" Y                public void onUpdate(PowerMode powerMode) {
    % n$ M) P1 R' X+ R) `5 K$ V. I/ u                    switch (powerMode) {
    ! q* g( v/ u2 Q2 q9 G                        case ON:  q5 y# ^8 T6 y3 y, B
                                Battery battery = ((HandHeld) mProduct).getBattery();+ n4 ?8 }$ ]1 ?9 ]; d9 F
                                battery.setStateCallback(new BatteryState.Callback() {
    5 \- v  X. P3 ]- U  ?! s4 n" U: M" o  E                                @Override1 o' R2 X. M; L! ^' |; Y; H5 `8 v# Y
                                    public void onUpdate(BatteryState batteryState) {: u2 _0 v! ]1 }- X  A3 y
                                        h_power = batteryState.getChargeRemainingInPercent();
    6 ?. \3 Y/ J# k& l5 r- U9 v/ l                                }1 h* J: }9 W) j8 }
                                });: D* ?! k" K) t% s
                                break;
    9 s$ [1 L; ~& h2 E% o* p9 E                    }3 a/ R6 ^9 h4 h3 N
                    }' \: r+ {' ?5 Z+ N7 j5 d. b
                });
    / N  M$ o8 @6 t3 }2 _        }: l  Z# a% j+ x& o) c' ?
        }
    # O  O- _! N* N. g  {& |  B% f+ A; o   : e- D4 R) ?! ?2 \
        @Override% B: h1 u3 Y& D5 F$ k+ H: f$ L( h
        public boolean onKeyDown(int keyCode, KeyEvent event) {8 j2 n: G4 G$ \% ]  G) w  D; z3 m
            if (keyCode == KeyEvent.KEYCODE_BACK8 x+ _! a+ _, y5 I- z% I7 ^! G! |1 x7 ?
                    && event.getAction() == KeyEvent.ACTION_DOWN) {( H! J7 h9 P/ q5 ?
    //                        closeConnect();
    & E% ?9 |) U) t6 U3 @( ~$ b; r) Z( n8 \            MainActivity.this.finish();6 b5 @1 M" K% J7 {- q- P
            }
    * Z7 K- v5 P5 I( z8 o6 [; ~        return super.onKeyDown(keyCode, event);7 e. E2 \1 h! G& t5 R* _" N5 J
        }/ {" y% O& l& q
    }
    ! U9 X$ Z4 r* [3 G; _' l: g3 J4 M完成后界面如下所示:$ Q6 o& o$ C$ X/ n% E

    rndxjmine2a64023083406.jpg

    rndxjmine2a64023083406.jpg
    : E) A, h! \0 V6 R9 z
    上面的工作完成后就可以在无人且宽阔的地方进行无人机飞行了。
    , t- R8 J4 D/ q4 H, r. i4  x* v8 b" b% I( |5 J5 N& y) I  n
    多媒体资源的操作
      K* r# g/ Q$ y' w* l  P多媒体文件操作,主要为多媒体文件的获取、查看、删除、下载的操作1 p. W4 i2 W! f" Y, x
    同样创建多媒体功能文件FileManagementActivity及activity_file_management.xml
    . d, [2 ?: y* X& P8 iactivity_file_management.xml
    3 U* j+ q: C. \# kLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ( G% m% A, r4 q  x    xmlns:tools="http://schemas.android.com/tools"
    9 `( b' ]* e) I9 [; l    android:layout_width="match_parent"
    & K4 d, Y# l! Y; A/ U    android:layout_height="match_parent"9 E, f% l+ x. |* w0 q
        xmlns:custom="http://schemas.android.com/apk/res-auto"/ j' X  G( u1 Y5 ^& u
        tools:context=".ui.FileManagementActivity"
    . `3 h' _. |3 {+ _6 ^    android:orientation="vertical"& ~  m* F$ T9 `& d% F: E3 t* j# Q
        android:background="@drawable/shape_corner_eight">
    / O& @. y( T9 }% [9 Z    include layout="@layout/activity_toolbar"$ T" D2 X, J5 S! F
            android:id="@+id/layout_file">include>0 m* @" _' x# [1 q  K* ?4 Z+ z
        LinearLayout5 a4 r' i: _0 K
            android:layout_width="match_parent"1 G( j0 [& U1 N( y6 W+ k! d$ S' z. ^
            android:layout_height="match_parent", X2 L/ L$ n! P# x1 [3 ~; Y
            android:orientation="horizontal">. w' n. V* m. b' d- d$ b2 ?5 M. Z+ U
            LinearLayout
    / ^9 n2 K4 Q" _            android:layout_width="250dp"
      `% _7 {' R2 ]- Q8 E! i$ h) _; I            android:layout_height="match_parent"
    4 _3 T9 i$ u! |( i6 M2 s: p            android:orientation="vertical"  `4 z% x1 e1 [
                android:layout_marginLeft="15dp"# t0 `  n8 C) t
                android:layout_marginRight="15dp">
    1 N* f* P1 u; ?* E% R. s' T! ]            RadioGroup
    - W* o6 f  f5 @                android:id="@+id/rg_file_management"
    % I9 N' v& K% z9 j* \                android:layout_width="match_parent"$ N; z* G2 N* N- W1 n
                    android:layout_height="40dp"4 l0 b/ U2 E0 S; {# w! R# ?8 @& ?
                    android:orientation="horizontal"
    1 L  f# }( k' o/ _3 K  z                android:background="#2B3141"" x! o' i* g" ~! J* c- c2 `
                    android:gravity="center">* X! J7 R/ K( c$ ~. u
                    RadioButton) E; C1 [. |$ V) N8 `6 ^
                        android:id="@+id/rb_file_all"
    ' ], m3 G% \% h6 l0 k# G/ n                    android:layout_width="0dp": L" ^7 O: ~5 V$ p' `# ~  ?
                        android:layout_height="match_parent"* m- B# z8 \" l$ N' h4 }& C
                        android:layout_weight="1"" D4 J7 C$ ?$ @  E( C
                        android:button="@null"
    * p+ m$ P5 V! ]                    android:checked="true"; H, v: r6 o6 ?
                        android:gravity="center"
    : N7 r3 G% F/ S. m1 y                    android:text="全部"' `# J' {' n: w* Q4 E2 ?0 V
                        android:textColor="@drawable/nav_item_color_selector", T/ s9 ^# |/ v6 ?! ~$ |: g
                        android:textSize="18sp"5 S1 @3 j0 _4 c7 D! t7 x7 n- f
                        tools:ignore="TouchTargetSizeCheck">RadioButton>* o  a( G9 |3 ]1 ?5 f' H
                    RadioButton
    # U, u- o" J2 R3 ?2 |                    android:id="@+id/rb_file_photo"8 j0 t4 t4 c" R# T3 j/ Z; o
                        android:layout_width="0dp": G! a9 r+ g6 X$ G
                        android:layout_height="match_parent"& q  ~, X) [  Y, L; l" l9 C" V* J
                        android:layout_weight="1"0 Z& s" ~4 S  W/ j
                        android:button="@null"7 S; C7 P, D; a6 j$ Z
                        android:gravity="center"
    , T9 ^4 y* }, I& b- E                    android:text="照片"0 j% Z: }  i0 w6 @0 s( W% s
                        android:textColor="@drawable/nav_item_color_selector"* [# T; Q( q4 R% Y- K
                        android:textSize="18sp"
      a" A! l! Z* v: N- l( L* ^  P                    tools:ignore="TouchTargetSizeCheck">RadioButton>/ Q7 a# h& H: d4 ^* ~! t. R% w
                    RadioButton
    4 H0 z7 s& m8 X                    android:id="@+id/rb_file_video"2 l( l% w2 {2 o8 H# v  z5 E. w) j" s
                        android:layout_width="0dp"
    9 m0 H- {7 t- f) R                    android:layout_height="match_parent"
    ! y4 x2 o2 U) ~) h                    android:layout_weight="1"$ u( ^7 S9 f, l; S+ f5 I
                        android:button="@null"; i3 C; @& X- W
                        android:gravity="center"
      \* _, `$ B% I  P, m: v                    android:text="视频") D7 \! z8 I; D! B. F# U
                        android:textColor="@drawable/nav_item_color_selector"3 {0 Y( @; A7 s0 y
                        android:textSize="18sp"
    9 `; t  F: J$ k4 Q1 ~' E3 |% U                    tools:ignore="TouchTargetSizeCheck">RadioButton>
    3 E( |2 ~# ~3 U' L* e3 l: p3 _            RadioGroup>0 v  y% E: Q: ?6 V
                androidx.recyclerview.widget.RecyclerView
    ; m) Q$ ~2 e. }6 x" |+ V                android:id="@+id/rv_file_management"
    / C$ h. X. r  ?8 k, A  F                android:layout_width="match_parent"
    & [6 z/ [3 k) k' I2 n                android:layout_height="0dp"
    ! o( @# P7 r! t                android:layout_weight="1"9 Z* w) g3 s2 R  x# n
                    android:layout_marginTop="10dp">androidx.recyclerview.widget.RecyclerView>, a. s( {$ R* l) \  `
            LinearLayout>
    : r% f: O7 O) u4 z1 L- o        RelativeLayout: I" O- {) w, u( \' G% t
                android:layout_width="0dp"
    2 V: y% N$ a8 Y5 x9 [' {" L. M6 _            android:layout_weight="2"$ z, c/ {0 M. ?4 ~" I) j( w
                android:layout_height="match_parent">0 h0 w! L" a. ~: a6 U3 c0 y
                RelativeLayout6 S9 P" s# g1 I; R" {* |1 d
                    android:layout_width="match_parent"
    5 _. }# {( d/ k3 N                android:layout_height="match_parent">( l; c, j6 B% Z8 M& R' N& T2 l3 ]+ l( h
                    dji.ux.widget.FPVWidget+ D" x/ m( I* O, G  j1 h
                        android:id="@+id/FPVWidget". {( p' m6 N- b5 t' ?( T9 t. d
                        android:layout_width="match_parent"
    ; z3 @7 M, S7 Q$ o9 {; R                    android:layout_height="match_parent"
    ' Z5 ]; o( g% H2 i3 z; {( B* ]                    android:layout_centerInParent="true"- \: F) M$ c! _7 L
                        custom:sourceCameraNameVisibility="false" />( @; P. ]& W+ Q; o& P+ z7 k4 c) a
                RelativeLayout>
    # G/ h+ T9 ^6 z6 T            ImageView
    3 B1 t0 O8 i7 T, c6 D                android:id="@+id/img_show"' F* p/ J  o7 u& x) y: `! g8 l( e
                    android:layout_width="match_parent"' E# m7 {, U: q2 Z
                    android:layout_height="match_parent"
    + o1 P+ W  O" r% ]                android:scaleType="fitXY"8 J1 f$ s5 Y8 s5 m  A9 t; f, \6 O
                    android:visibility="invisible">ImageView>
    ! G/ K# G# m7 M4 `& L- w$ Q            LinearLayout: y  y2 p8 l* U  u( B2 y% j5 H
                    android:id="@+id/ll_video_btn"' [; E$ L9 \( Y
                    android:layout_width="match_parent"
    % V" W- f$ m4 s: K                android:layout_height="50dp"$ k0 a' [) u3 o, I) i
                    android:orientation="horizontal"* k0 n" B+ U- h0 d* o* T( K3 l
                    android:gravity="center"3 H. m2 c) N1 X8 b/ x* E, L
                    android:layout_marginBottom="15dp"
    # B9 z3 |: N6 G6 u& c" \+ R                android:layout_alignParentBottom="true"8 w3 u2 B: J7 O* I) f! y3 c
                    android:visibility="gone">, s3 a( P' h/ G' r  p
                    ImageView) v0 ]* B3 O- m5 }1 Y$ a
                        android:id="@+id/img_video_pause"
    2 C5 Y4 T* D6 K% }5 G9 _                    android:layout_width="35dp"
    % K3 O+ \* w4 x# ?# F9 J. p4 l                    android:layout_height="35dp"
    1 `8 s4 |7 n0 r8 z9 C* Y/ D                    android:src="@drawable/background_stop_selector">ImageView>* o) n( Q- o! P
                    ImageView: a) J% R+ j. ~* W/ F( e
                        android:id="@+id/img_video_play"
    8 v- G2 q) I  l, V" q9 |4 S& f                    android:layout_width="45dp"7 d1 ]" k& ?- e) M  _$ c/ h9 z! n
                        android:layout_height="45dp"
    8 N( y7 f6 F8 ]3 a* K                    android:layout_marginLeft="20dp". o  w+ e3 v6 C
                        android:src="@drawable/background_palyer_selector">ImageView>
    ( T- q) N9 F. H" y1 ]# _& @                ImageView2 C1 y  b! J- J+ j. e8 L
                        android:id="@+id/img_video_stop"
    ) t$ g8 q5 K, S8 \) M1 z, V                    android:layout_width="35dp"& B) u) _4 _2 [- u& D' p' l
                        android:layout_height="35dp"
    " d* s6 F3 {# c( d7 g2 _( z2 A/ Z                    android:layout_marginLeft="20dp"; Z/ i$ C  K+ U; T' f( Y; S5 t0 E; n0 w
                        android:src="@mipmap/ic_reset_36dp">ImageView>
    # n1 K; |3 k; R; m' I/ I  |: R            LinearLayout>7 h0 Y$ u6 @; e/ H  B% V
            RelativeLayout>
    . ~3 Z! R4 w) i- _, ~, F" u' p9 }    LinearLayout>- z& Z$ w5 Z8 f* E# U4 f
    LinearLayout>
    1 D. x/ H/ \0 ~" {FileManagementActivity9 Q. W% o. E) K0 P) Y$ P
    @Layout(R.layout.activity_file_management)
    0 m' x/ v( W4 h7 w% p- _public class FileManagementActivity extends BaseActivity implements View.OnClickListener {
    ; [" W8 P/ o5 R    private static final String TAG = FileManagementActivity.class.getName();
    , K: d5 c: |7 F5 W- j  [    @BindView(R.id.layout_file)' a+ Q* `) J( e1 u( h
        View mViewLayoutToolbar;
    # z- R; F* n3 [    @BindView(R.id.tv_toolbar_title)9 J* i" P7 L5 k. g$ p# S6 D" S7 S
        TextView mTextViewToolbarTitle;  W& T+ [' Y: a( P2 A6 j7 w
        @BindView(R.id.ll_file)) X$ e; `- d, k1 ^
        LinearLayout mLinearLayout;
    ; f+ ?* W  m1 m8 H    @BindView(R.id.rg_file_management)
    ; m+ p1 t3 n+ G% F0 |1 q* Z# d2 h    RadioGroup mRadioGroup;+ g7 X4 {. K8 j' d5 f8 R8 ~
        @BindView(R.id.rv_file_management)
      h7 \! A' I, E    RecyclerView mRecyclerView;3 J* B" r: b% E+ J3 Z
        @BindView(R.id.img_show)
    3 ?) W3 x, G' y    ImageView mImageView;2 J1 h+ T5 L8 D& @' {
        @BindView(R.id.ll_video_btn)
    8 d/ D' e  h# U# r3 e! O    LinearLayout mLinearLayoutVideo;1 `' V% l: H: ~, p: `4 Q* i9 w
        @BindView(R.id.img_video_play)* b- L4 \: h: N; O+ q5 Y$ J
        ImageView mImageViewVideoPlay;
    " o; M0 c8 R6 S0 }+ N1 W- Z' @2 n    @BindView(R.id.img_video_pause)
    ! j  k6 ~3 Z- V- N5 W8 e* z1 x    ImageView mImageViewVideoPause;
    - ~+ _+ q0 e7 A3 ^  J! H    private FileListAdapter mListAdapter;+ m( E( Z, z5 w: a1 Z9 ?+ }; S3 h
        private List List = new ArrayList();
    7 a+ Q  S* F  |& w    private List mediaFileList = new ArrayList();
    . r0 I8 R: O, o3 l& m7 y& C6 }    private MediaManager mMediaManager;
    . W3 {& q' d5 h    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;4 d& t9 Q7 K  D* B8 A8 @
        private MediaManager.VideoPlaybackState state;2 N' N& R1 ^9 E1 k
        private ProgressDialog mLoadingDialog;& k3 n  E1 @# \0 p! Z
        private ProgressDialog mDownloadDialog;
    & N9 |4 y1 }5 Z    private FetchMediaTaskScheduler scheduler;' `1 L3 Z2 @: T, O! `
        private int lastClickViewIndex = -1;
    6 D2 W8 c0 S! n! e- m    private int currentProgress = -1;
    6 ~1 q9 }" Z6 O! z" ^    private String SavePath = "";- K% g7 b; c( l, |/ s) A
        private View lastClickView;
    * H5 F( _" j6 A1 W    private boolean isResume = false;
    9 e; W) a1 r% x0 O) u) f    private SFTPUtils sftp;
    % r# b3 T/ _3 w& c1 X7 c& [* Z  R$ x    private SettingsDefinitions.StorageLocation storageLocation;3 }% i2 v9 Q: |8 d4 L: x
        @Override) I/ c+ J5 Y6 V# g/ b8 W9 p
        public void initViews() {6 G+ L9 Z% G/ p  O7 J2 E* }
            mLinearLayout.setVisibility(View.VISIBLE);& {, x' v# H) ^3 U1 t
            mTextViewToolbarTitle.setText("文件管理");
    " Q, N3 E% }7 q5 R0 a        mImageViewVideoPlay.setEnabled(true);; f& P! s. R9 R# i. D
            mImageViewVideoPause.setEnabled(false);/ F+ n6 T, g2 e% [
            mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {  r+ F  V" _* i/ S/ U2 Q
                @Override
    " Y0 _7 h) J5 {. B- c            public void onCheckedChanged(RadioGroup group, int checkedId) {
    ' r5 S! H+ n: l( [# b) U7 j                List.clear();
    4 E+ ^/ G& e( {$ \$ R0 y9 ?+ L5 s                mediaFileList.clear();
    7 n( V& n9 B$ Q                switch (checkedId) {/ O3 c8 d* {& d$ ]. f. g2 v* ~
                        case R.id.rb_file_all:) @  L, }+ K' ^
                            getFileList(0);1 I4 r& w* _" W& i
                            mListAdapter.notifyDataSetChanged();1 t  [3 W; Y3 }, U9 g! d8 ^: e
                            break;) z2 O% c: c0 V# a8 X+ w( p
                        case R.id.rb_file_photo:- Y  K5 |& R7 v% D& b2 y$ S
                            getFileList(1);# q5 L# H. t$ c8 B4 l! J* u
                            mListAdapter.notifyDataSetChanged();: Q/ o5 W8 ^9 P4 x- Z# q- z: h
                            break;
    # l+ O+ _9 A* Q. M& Z$ p, l; A2 C                    case R.id.rb_file_video:4 r2 N  \# e! i5 V
                            getFileList(2);
    & K. \2 g! L* g, ?                        mListAdapter.notifyDataSetChanged();# w2 X, C* C" B0 A" z
                            break;- N' h5 S+ @/ U9 W% X; B7 a
                    }
    / e" ]9 ^, }' I5 o, l& a            }7 v% K3 i) ?- U2 Q/ o% @
            });8 A! g, f0 e; c& D
            LinearLayoutManager layoutManager = new LinearLayoutManager(FileManagementActivity.this, RecyclerView.VERTICAL, false);
    ( c' [' u; K2 E0 l' _0 @4 L3 v1 U; |        mRecyclerView.setLayoutManager(layoutManager);3 U6 H0 `2 b, C5 u) Q3 m' N! q
            //Init FileListAdapter9 I  b7 Z8 }+ e% g. k+ W: {3 B
            mListAdapter = new FileListAdapter();, j5 E! R5 ?+ U" r& o$ Q
            mRecyclerView.setAdapter(mListAdapter);3 K4 U# u3 h' N! h8 p8 w9 |+ j
            //Init Loading Dialog
    / ?$ V7 i8 }+ n! k  C* _! }$ O9 d/ u        mLoadingDialog = new ProgressDialog(FileManagementActivity.this);5 L9 p- e  v" Z) r
            mLoadingDialog.setMessage("请等待...");6 L6 K/ s, X: g
            mLoadingDialog.setCanceledOnTouchOutside(false);; @, T6 E$ F8 z' m
            mLoadingDialog.setCancelable(false);
    ; c. U$ j4 E( }. @) B        //Init Download Dialog# E) J, |! o& u6 p/ P+ {4 ^. E5 G
            mDownloadDialog = new ProgressDialog(FileManagementActivity.this);' M3 y( g3 k( B5 w0 b" ?
            mDownloadDialog.setTitle("下载中...");
    ) ?: C! q' P! l, K8 g" I        mDownloadDialog.setIcon(android.R.drawable.ic_dialog_info);3 k5 S8 r. p# m/ s  G3 S, J
            mDownloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);3 s0 m0 X1 b2 s8 _' i
            mDownloadDialog.setCanceledOnTouchOutside(false);. X& o5 X0 b3 c" z
            mDownloadDialog.setCancelable(true);
    2 r( S3 ]: F5 V( w4 M4 e" f# h        mDownloadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {2 A* L: O' Q  ^* d
                @Override
    ) x; b& o/ H9 [' V& J1 _            public void onCancel(DialogInterface dialog) {# s% X& F$ Z5 U2 S0 U9 f3 ?! c
                    if (mMediaManager != null) {4 M" z4 \1 x2 E
                        mMediaManager.exitMediaDownloading();
    : Z% d5 l$ a6 J$ T$ _* w9 F                }- T% f( g6 Y* e6 s
                }( w1 f$ p$ q# W7 r
            });& v8 O- ]5 E8 H
            sftp = new SFTPUtils("49.4.79.249","uav","uavHHch@YREC.cn");" @7 U4 N6 [: d: d6 Q
            ReceiverApplication.getAircraftInstance().getCamera().setStorageStateCallBack(new StorageState.Callback() {
    # r2 z8 S, D' U3 w            @Override
    ( `9 w1 T7 X; m1 G! ]6 v8 d% y* E/ O: t            public void onUpdate(@NonNull @NotNull StorageState storageState) {
    " o* b) @5 D1 h: C                if(storageState.isInserted()) {
    0 Q8 H* ~, a7 A0 q+ S' T( Q# _                    storageLocation = SettingsDefinitions.StorageLocation.SDCARD;
    : Y1 b: j( m) r                    ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, new CommonCallbacks.CompletionCallback() {8 Y4 P' _" p8 M) ^( L' }/ V
                            @Override
    ' z# _+ A' Y6 g/ G) L- @- ^: Q                        public void onResult(DJIError djiError) {
    % l8 c% h3 `9 d. D5 N+ L3 w                        }
    ) v" M& T& ~% l* B4 Y4 ^" L                    });: a3 M3 i& j. C: z; o
                    } else {
    % L' ?' L& D. Z& S1 `                    storageLocation = SettingsDefinitions.StorageLocation.INTERNAL_STORAGE;
    % o% p# j0 h* c                    ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.INTERNAL_STORAGE, new CommonCallbacks.CompletionCallback() {- n( w3 K. j- e7 ?
                            @Override
    : Y% H1 @/ g3 ^; S, m+ g/ G/ _                        public void onResult(DJIError djiError) {1 p8 ]7 R' [( Y9 B* ?
                            }* c! d. d( w( a; _6 Q+ W
                        });
    8 g3 ~5 k, x, ?4 r                }
      d$ [- |0 I; }, v! f" v5 L            }
    8 G: }3 j/ ~/ x- ~# c0 m' `- L        });! t5 J4 @4 `3 o( M% \
        }2 P( V4 }0 Q& z  D: x  l2 ?
        @Override  X% N+ `7 L3 L' y
        public void initDatas() {
    * L4 B  Q3 H: {& ]    }) r; c4 T9 y: f3 {; o6 y
        @Override
    ' r# f) L, ?0 g/ n3 R' f+ S/ i4 X# Q    protected void requestData() {1 p, |! ]7 `' H1 u
        }
    4 }$ u1 U% Q  U- i    @Override
    + X3 Q( E4 {8 Y" x/ E    public void onComplete(String url, String jsonStr) {
    " {& S4 q% H3 w( D# [) c7 E        super.onComplete(url, jsonStr);+ [$ T- I3 h8 A( I
            switch (url){6 X  S1 x5 O: K  y+ t
                case POST_VIDEO_INFO:) f4 ~' s& o' s* r9 A1 A, s+ R( y
                    break;' a5 R, ^; F  S  [( n3 @
                default:
    . f' s5 j; b/ \, q: ]& s                getVideoJson(jsonStr);2 l% S3 ~/ m) E. g5 k2 a% W+ w
                    break;) Y+ q# N0 F2 D1 w% M
            }; {  \5 M: D; P# Z% V& Z& r
        }
    7 z5 a$ Y! w$ ]6 c! t6 D    private void getVideoJson(String jsonStr) {3 T8 }" B# p; t) ]0 v2 Y
            VideoModule module = GsonUtil.GsonToBean(jsonStr,VideoModule.class);
    7 Z0 v; A0 A2 U. I/ c: K        if (module.getCode() == 200 && module.getRows().size() == 1){+ M. k, F* n% y5 d8 [5 G
                runOnUiThread(new Runnable() {9 e* G& m. F/ t5 E. e, |
                    @Override
    6 t6 \& P4 G7 J2 K9 E+ {                public void run() {
    % t! _2 P, E6 b- t, l5 Y                    UpdateFileModule fileModule = new UpdateFileModule(module.getRows().get(0).getId(),"/mnt/uavFtpFolder/"+module.getRows().get(0).getFileName());1 X4 l/ S5 w# _
                        http.getHttp(POST_VIDEO_INFO,"PUT",GsonUtil.GsonString(fileModule));  B  c& d3 u5 C  ~" N
                    }# J5 W0 q0 X4 s. F
                });
    . N/ C, q! k3 v/ p  h        }
      m/ N% u# n; ~) B. w    }
    ( j3 |0 k' y: U# ]# z5 J5 I    @Override
    ; a( ~- I- f; W' t    protected void onResume() {( O6 w& }- O& Z: @$ E$ j# Z
            super.onResume();4 `1 K% \! T- h2 H; N% s
            initMediaManager();
    : {, k! ]# `4 s, x$ U7 |- S: _    }4 ^) t! v/ V* a: D4 I, z
        @Override
    6 H, T1 V. u7 x5 _4 S3 b+ H    protected void onPause() {
    : x* ?& C5 e: i: ^. l' ]: q3 W" n        super.onPause();
    . ^5 s  g  K2 C+ ^7 w8 j, T    }
    ) `$ Y5 y4 u- P$ R1 _, N    @Override
    : o2 \2 l+ Z% X7 Q) }    protected void onStop() {" @8 k3 k4 G2 Y! A7 J( V% l
            super.onStop();0 E; @$ B! j, y0 P
        }
    : g4 j# y0 i, B9 W' @( v
    & k( ]5 H  P5 O* S    @Override
    , w0 W* v6 p, C( V' l/ t    protected void onDestroy() {$ X; q' {2 Z8 p8 V6 h6 [7 D/ x" U
            lastClickView = null;
    / A  R$ T- ^/ a0 W' R        if (mMediaManager != null) {
    ( h& O7 e% A6 @  _5 l            mMediaManager.stop(null);& i# ^5 Y8 g# X
                mMediaManager.removeFileListStateCallback(this.updateFileListStateListener);1 C- N3 \! O8 Y9 u& z8 Z* W
                mMediaManager.exitMediaDownloading();
    * p3 L( f! [3 S% h3 x            if (scheduler != null) {6 f" F. T8 S5 a* `2 ], m0 \  h
                    scheduler.removeAllTasks();; s3 Y+ h8 A. g7 ^6 c* |0 b3 w" U
                }
    8 v- l" x+ r9 N; [        }4 e/ N7 X  ~7 T# S! m3 F# S
            if (isMavicAir2() || isM300()) {. V$ k% X( l: T9 D) k7 ?
                if (ReceiverApplication.getCameraInstance() != null) {1 v* Q5 t. {* |# W
                    ReceiverApplication.getCameraInstance().exitPlayback(djiError -> {6 j/ P; q  O' X
                        if (djiError != null) {
    6 v( d3 |" v8 A                        ReceiverApplication.getCameraInstance().setFlatMode(SettingsDefinitions.FlatCameraMode.PHOTO_SINGLE, djiError1 -> {
    9 O! E: }5 A9 K: S- e                            if (djiError1 != null) {% ^. `* b' e* {+ L' D$ p
                                    showToasts("设置单张拍照模式失败. " + djiError1.getDescription());6 G( q2 @$ H- V& y' F# X8 H7 L
                                }. I" z5 L# A" z( ?8 v: m2 D! G- a
                            });5 Q4 `" i6 J  k4 r
                        }
    9 V) m7 Q: p5 k' n- {# E$ n: n! R                });1 K3 R6 s# M; a/ L% W: K- I
                } else {1 M- T( {: R0 T- \1 I  R  _4 g8 u, O
                    ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, djiError -> {
    2 G5 V" @8 E- ^& P" X$ L2 B                    if (djiError != null) {
    8 x2 `  G) w8 u! k                        showToasts("设置拍照模式失败. " + djiError.getDescription());1 X9 F  h9 D/ H" C. n
                        }
    / r$ Q/ O* r1 a0 |8 e1 V                });9 n2 `% x$ w; M. ^1 R0 J5 A* w# }
                }4 w% ?$ \: g! P: m
            }& q) G" r5 A% @1 I1 M
            if (mediaFileList != null) {& x) k& D3 k1 a( K9 V* A
                //            List.clear();$ i9 v- W0 Y7 }
                mediaFileList.clear();; N. ]2 L6 X" R$ w; {) N, }
            }. M) G8 p1 O0 L" P0 b# G/ y% T( |
            super.onDestroy();. a" D$ L3 [7 K9 t- ]% r
        }
    + Q: Z7 [, Q& h  \1 B5 H    private void showProgressDialogs() {1 i& d8 h2 H2 `
            runOnUiThread(new Runnable() {
    9 x4 V' F& Q3 U# U4 L" b0 W  ?            public void run() {/ W1 Y/ B1 v1 E
                    if (mLoadingDialog != null) {
    # z! x( y  m$ p) v9 F( c1 j                    mLoadingDialog.show();; w4 o9 |4 ^' i% E. }& A
                    }  a( C" M7 S/ E* Q4 ~) F: f1 O  x
                }3 N1 [$ B( d0 B- O3 {
            });1 @8 Z- C! g1 \, z8 Z/ k4 T, \: q
        }
    + f' H8 }1 w* \    private void hideProgressDialog() {
    . D2 E  |3 v/ T+ b        runOnUiThread(new Runnable() {
    $ Z3 U3 F! w8 k; r# O7 D            public void run() {5 _; P; @( ?$ B5 W$ N, t4 h9 e* C
                    if (null != mLoadingDialog && mLoadingDialog.isShowing()) {" T+ `4 ^+ c$ o8 C- H
                        mLoadingDialog.dismiss();
      ^" i4 l: S' l8 D) Q5 G                }- p" L2 x7 U" ~: a: L- `
                }
    & p+ t1 U" z4 \* o/ B        });, ~# a( y4 i" |8 M  O( N
        }6 [. j9 p* u* f2 u; n0 Z
        private void ShowDownloadProgressDialog() {
    4 L* ^1 V7 Q) q+ `6 u& Q        if (mDownloadDialog != null) {
    # Z# |  H4 x* K% g, o# R" M            runOnUiThread(new Runnable() {
    & |* O- `9 {0 @                public void run() {
    3 Z  k$ N6 N; s2 v9 @( o                    mDownloadDialog.incrementProgressBy(-mDownloadDialog.getProgress());% V* ~" S2 e% l8 p; u+ X& {
                        mDownloadDialog.show();+ c' a9 e" K+ `3 ]0 {: F1 m/ S, |
                    }
    3 M$ U" l: z2 j0 |            });! g9 R7 s! D: p; q
            }, e$ h- t1 ^( w' W9 k" W0 y) n
        }$ S- d8 V3 I; X5 {
        private void HideDownloadProgressDialog() {6 |- b3 d; _& D* ?0 k9 y
            if (null != mDownloadDialog && mDownloadDialog.isShowing()) {! B. e4 z; f; D- W. o- q
                runOnUiThread(new Runnable() {
    $ z2 h9 p" \& M$ S                public void run() {; n/ g( q" W7 [
                        mDownloadDialog.dismiss();/ X0 V: i" m- e1 j; v# z
                    }$ L5 b% ]0 X9 @, A1 Q+ ?/ w
                });
    $ |5 V- Q0 o  m3 B* X        }, ^8 M* ~9 V' v, v
        }0 a3 i5 i. _  O/ u& A9 C: a8 d
        private void initMediaManager() {
    - ^0 s8 P  Z! b: Q; R, }        if (ReceiverApplication.getProductInstance() == null) {
    % }2 p. G) B! }2 \1 |2 E2 ]* p4 x            mediaFileList.clear();. m* W. |" {) N/ |
                mListAdapter.notifyDataSetChanged();
    2 |/ ~1 W  O5 y, _& l  q9 ?& `            DJILog.e(TAG, "设备已断开");
    : D+ y/ {' H- w0 P            return;
    3 d* I5 Y( _; r1 _        } else {! r" w4 Y- h4 G+ u0 V3 {' ?* p' Q
                if (null != ReceiverApplication.getCameraInstance() && ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {
      H" X  x1 D! G5 d5 b                mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();5 y4 ]' E4 K8 \) s# g
                    if (null != mMediaManager) {& V$ l9 A3 f* Y9 [2 Q
                        mMediaManager.addUpdateFileListStateListener(this.updateFileListStateListener);
    " M: c6 K1 l9 w5 \1 d                    mMediaManager.addMediaUpdatedVideoPlaybackStateListener(new MediaManager.VideoPlaybackStateListener() {
    & P5 }# [6 b1 q8 R- G  D                        @Override: _+ [" J" e( L! [1 U# Z
                            public void onUpdate(MediaManager.VideoPlaybackState videoPlaybackState) {& e( o# I' m. S& S( \% n- M) d
                                state = videoPlaybackState;
    $ q! z4 M% D- `% J- [2 Q9 {                            if (videoPlaybackState.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){2 C! [( F$ j) c% i
                                    runOnUiThread(new Runnable() {2 v8 Z: I0 c: u! \& i% [) K' t; F4 B
                                        @Override
    # `  j8 [+ x& P. ~9 Y7 q: Z* v" a                                    public void run() {
    / J7 p0 c: Y% O2 @//                                        mImageViewVideoPlay.setEnabled(true);
    % p0 @0 y; ~7 N- i+ p9 G$ y% B//                                        mImageViewVideoPause.setEnabled(false);* C: }" d) B+ s" r  N5 {6 |
                                        }0 ]) \# h- G  F0 S) w2 j$ A4 [
                                    });! h- D4 q, S' t; @; ]
                                }  p: d4 u( O* B& c
                            }
    * J7 Z) E$ q6 P7 {                    });
    - f, F% M% R" V1 B* a+ O                    if (isMavicAir2() || isM300()) {
    0 Z" |# Y0 a5 {) \' z* C                        ReceiverApplication.getCameraInstance().enterPlayback(djiError -> {
    + s0 ^7 \4 f* o9 O8 O/ O                            if (djiError == null) {
    2 `/ O8 H- G6 }9 F5 J: U                                DJILog.e(TAG, "设置cameraMode成功");
    ( F3 M- n* Q$ r                                showProgressDialogs();4 R. ]* x4 i* a! U# A5 k4 U; {
                                    getFileList(0);
    % d- U5 A6 m4 P% Q$ L                            } else {+ A+ n5 p- {- V! i% c4 M
                                    showToasts("设置cameraMode失败");; a& Q2 C1 I# Z: U; _5 g$ o2 m
                                }2 Z5 f, [2 c9 t+ C9 [$ @
                            });# v- \' s# i. j* I: ]
                        } else {! t+ Y6 T( D( O: _3 C+ B
                            ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, error -> {
    9 N, d' T# P5 @9 ^; y" L                            if (error == null) {
    8 e; a: k2 S- p6 S: ?                                DJILog.e(TAG, "设置cameraMode成功");2 C" N, h4 }- z
                                    showProgressDialogs();; g" `! {' Z3 |
                                    getFileList(0);3 N" F1 O. b) a/ f$ B9 T  B* i7 w( @$ L
                                } else {& L4 N$ D! x4 b3 X' J, g
                                    showToasts("设置cameraMode失败");
    ' L5 u' M  I: r1 S6 t* D4 e+ Y& ?                            }
    ! X- J( _* M2 g: h                        });
    5 Q& a# k# d+ u2 a! T3 g                    }. X7 T3 v/ e4 l4 E5 Z
                        if (mMediaManager.isVideoPlaybackSupported()) {
    - E( z) r% f: ^8 O- H. ]: f                        DJILog.e(TAG, "摄像头支持视频播放!");
    # f/ `+ S, t- U- N/ Y7 ?$ z                    } else {* e$ T- E5 D3 U! P/ @2 d5 g/ A& Y  _  S
                            showToasts("摄像头不支持视频播放!");
    1 e( S2 K* @6 c5 W# y                    }
    $ T# Y" h  b8 h6 Z' a8 i+ ?3 ^                    scheduler = mMediaManager.getScheduler();
    $ M8 b: H5 |$ t+ C                }: H9 u' @$ I5 }' v. V! {/ ^1 i
                } else if (null != ReceiverApplication.getCameraInstance()
    ! V. ]5 }7 K; Z                    && !ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {$ a+ j2 S- B# I+ z) M
                    showToasts("不支持媒体下载模式");. C' Z- a  [. O& w# H
                }/ s4 S+ w; m+ \
            }
    " J- z& C' Y! z3 Y        return;
    - r) T% m" ^. u8 o; p. V( ^    }
    " r/ N$ q9 Q: g# A/ \6 \    private void getFileList(int index) {
    3 j, Q* k9 t! H. ]5 S0 t        mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();
    ( p! J/ W6 C. ?7 k# y8 q5 f        if (mMediaManager != null) {4 }3 A) n1 C5 L: I; a, R% |- p# M5 o
                if ((currentFileListState == MediaManager.FileListState.SYNCING) || (currentFileListState == MediaManager.FileListState.DELETING)) {" x- A) d! s8 ]/ x
                    DJILog.e(TAG, "媒体管理器正忙.");
    ) e; Q1 N; {1 e1 d  D+ {4 w: k            } else {  y7 d7 z3 N+ X8 w. Y$ v
                    mMediaManager.refreshFileListOfStorageLocation(storageLocation, djiError -> {
    ! \+ u; k6 ?8 X$ \, h" \//                mMediaManager.refreshFileListOfStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, djiError -> {# k* v0 w" M$ A" `3 L; V
                        if (null == djiError) {# A0 w$ ]' h# c- G
                            hideProgressDialog();
    $ F: f) x# D( e0 V0 _; x                        //Reset data! r! G; _/ l8 L8 p
                            if (currentFileListState != MediaManager.FileListState.INCOMPLETE) {6 E* i3 Z9 N; j  ]
                                List.clear();
    % U, `' l: P. j4 T, y7 s                            mediaFileList.clear();
      ~! ?  v+ M. L6 h2 X# o                            lastClickViewIndex = -1;2 ?1 }; t# O7 j$ G
                            }
    " H  ?, V7 B2 k" i//                        List = mMediaManager.getSDCardFileListSnapshot();" R; Q- _  F9 \" Y
    //                        List = mMediaManager.getInternalStorageFileListSnapshot();4 v7 ?" N; H8 o' f% m
                            if (storageLocation == SettingsDefinitions.StorageLocation.SDCARD) {: h9 K& X* A% V; X' J
                                List = mMediaManager.getSDCardFileListSnapshot();8 M1 h: {2 ]& j/ a9 I
                            } else {# C! ~; K) D' V& J& a+ ?
                                List = mMediaManager.getInternalStorageFileListSnapshot();
    + L: s6 @0 \! T2 q                        }) G8 n& ]' R  J( l
                            switch (index) {
    8 |0 Z- L: M& E                            case 0:
    6 S, R, G3 l; v                                for (int i = 0; i break;
    # F; p' A/ _; q4 C, }( j                            case 1:
    - k; R8 s- R3 L5 Q/ Z8 e* f                                for (int i = 0; i if (List.get(i).getMediaType() == MediaFile.MediaType.JPEG) {' }5 G8 x* l0 S% K/ q, _$ ]; n  Z) k
                                            mediaFileList.add(List.get(i));
    1 C; H; A/ K# e) ~                                        MyLog.d("图片名称:"+List.get(i).getFileName());  U" q5 j( h! n0 F8 @7 z
                                        }
    ! u  p/ P# K0 a                                }  F. [# _7 b0 P" @" f  _7 T- H% `- y
                                    break;9 O7 Y8 d/ F1 \: v+ e
                                case 2:
    6 u- l( A+ q2 \. W" j                                for (int i = 0; i if ((List.get(i).getMediaType() == MediaFile.MediaType.MOV) || (List.get(i).getMediaType() == MediaFile.MediaType.MP4)) {4 f& P4 C8 O, a1 Y4 J% R4 K7 X
                                            mediaFileList.add(List.get(i));
    ! X5 j0 t5 Z/ E- P" x0 }3 H4 h                                        MyLog.d("视频名称:"+List.get(i).getFileName());' g. ~" m3 @0 g+ A3 p! T
                                        }
    7 T, M) K2 Z6 b, K; J1 u7 y                                }
    2 g% \/ C1 M& y5 |                                break;
    8 J) _: O" j% k( V  h' V" K                        }0 ^% P  m9 i% R& z
                            if (mediaFileList != null) {. u, E" a7 n- z+ p- x
                                Collections.sort(mediaFileList, (lhs, rhs) -> {) x8 L+ ~9 M: L
                                    if (lhs.getTimeCreated() return 1;
    6 H% c8 t7 A" _# ]; {: _  X                                } else if (lhs.getTimeCreated() > rhs.getTimeCreated()) {- N& z  f8 F9 Z/ G
                                        return -1;  E! ~, B* m& [7 L" P
                                    }
    & \' y" Q" l/ ], ]                                return 0;
    / \, _4 B' D7 p5 v) U. S                            });
    ' Q) o8 t% F5 u                        }
    5 j3 R2 K4 `! ~2 K. G; {1 Z9 C                        scheduler.resume(error -> {
    ; \. W% }. u; `                            if (error == null) {
    5 z' y  z2 f+ ~. v                                getThumbnails();* \% Y2 m  x- K( R. G
                                }
    " {3 R+ r& b3 u                        });
    ! U5 v* a( @9 ?% E( T                    } else {
    $ T9 f* b! |8 Z/ d+ o) a; l                        hideProgressDialog();* C" A) N; i  p! g% v& A
                            showToasts("获取媒体文件列表失败:" + djiError.getDescription());% Y; ?7 `3 l" f  |
                        }
    7 l5 o; b/ {0 F/ y: L                });- O& f( ?1 C$ p& J' D# T
                }
    : ?+ P3 [8 i$ ~( A/ |; b        }& m+ E8 b0 ~  M' ~9 d' f6 A
        }- i% `8 d2 T2 @, X1 p, |
        private void getThumbnails() {+ u0 l; D9 M- p+ Q# ~. S( T
            if (mediaFileList.size() 0) {5 w' R1 }$ A3 y' r  d
                showToasts("没有用于下载缩略图的文件信息");
    ( t0 J1 L3 e$ L            return;
    + v' r* \4 d7 `" j  G$ H        }
    0 b  F7 J; P+ y5 g8 d0 B+ f/ p        for (int i = 0; i private FetchMediaTask.Callback taskCallback = new FetchMediaTask.Callback() {
    8 l0 K. H9 \9 \8 y9 F) b        @Override2 K0 ~, k8 `% e4 g$ C0 T
            public void onUpdate(MediaFile file, FetchMediaTaskContent option, DJIError error) {
    4 m# s' i" {) F# S            if (null == error) {
    2 D! n6 g8 M& ?! D                if (option == FetchMediaTaskContent.PREVIEW) {
    0 u. X& a/ g2 \* e2 z                    runOnUiThread(new Runnable() {
    + L* J" C9 g- S3 K# d& i. X6 m                        public void run() {1 z# [7 W8 G: m/ Y0 z; B
                                mListAdapter.notifyDataSetChanged();" @$ o1 M  r% G
                            }
    : d6 Y- S6 q4 N6 {) c                    });
    ' A& L( {* c0 `) K) i                }
    / y2 t* {: C. ]# S                if (option == FetchMediaTaskContent.THUMBNAIL) {
    : }- Y3 \, N6 Z: U# h. ^                    runOnUiThread(new Runnable() {2 q- \  L2 F  w2 Q- [
                            public void run() {: _* J: l6 J5 ?% C& \. N8 ^% p
                                mListAdapter.notifyDataSetChanged();0 d" {+ m: M( f. Q% y  p: H* ~
                            }" q# V% C: T! Q: D/ o
                        });
    2 M# `' G9 U% h6 S6 _                }' @7 |, h: L) h7 ~# N. V
                } else {- G9 B. U) o5 h) E
                    DJILog.e(TAG, "获取媒体任务失败" + error.getDescription());- h8 v' k- R" n( \
                }
    6 e; H4 z4 a* Z# f        }
    8 K# p1 D) ]( f4 q9 P5 \    };
    6 {, V  x2 W% `- q% M) z    private void getThumbnailByIndex(final int index) {1 [* P* V' x& N2 e3 Q5 f8 V! @
            FetchMediaTask task = new FetchMediaTask(mediaFileList.get(index), FetchMediaTaskContent.THUMBNAIL, taskCallback);
    7 H, [- D4 _; y  M( I5 g        scheduler.moveTaskToEnd(task);
    $ c! E" b8 D! ~    }0 A4 B0 C, W5 V5 a! i/ W9 l
        class ItemHolder extends RecyclerView.ViewHolder {
    3 W3 G4 k2 \+ m        ImageView thumbnail_img;; n- F  j' z; ]/ T. W/ k: [
            TextView file_name;
    : c( q+ h2 C" G8 r; l4 H/ q        TextView file_type;/ P/ e- I' @4 u# a# b
            TextView file_size;
    + K9 W  h$ R3 J( O        TextView file_time;  f+ |+ S( {) t$ u# m# j2 P8 O
            public ItemHolder(View itemView) {
    ( j& p2 G3 r# M3 `1 b$ N$ e5 S4 k            super(itemView);
      z4 i0 j7 Q: L) U            this.thumbnail_img = (ImageView) itemView.findViewById(R.id.filethumbnail);
    ; i8 l: Q0 D$ K( O% k7 Q/ r            this.file_name = (TextView) itemView.findViewById(R.id.filename);
    9 `/ G8 S. C4 C- C* o  |! L            this.file_type = (TextView) itemView.findViewById(R.id.filetype);
    - A( |0 k+ A$ U8 {            this.file_size = (TextView) itemView.findViewById(R.id.fileSize);% z1 N! M3 U: S  [) |9 j" I4 R3 S
                this.file_time = (TextView) itemView.findViewById(R.id.filetime);
    8 J6 `$ e  A( Y4 e' y        }0 \2 y( _+ E2 m+ q5 q9 N
        }
    : `. \+ M0 ~* u8 J6 H- ]    private class FileListAdapter extends RecyclerView.AdapterItemHolder> {: [7 X9 p, `' I
            @Override) c! l* @9 v+ p6 |; D7 b3 g2 L
            public int getItemcount() {
    : t% q+ C/ |+ \# ]# R            if (mediaFileList != null) {
    8 Y% b5 }1 ]/ _: b# c                return mediaFileList.size();
    3 \. N4 L. C. W            }% l. K7 u7 j5 [" k
                return 0;
    + Z8 S0 t3 F0 P6 T0 T2 Z% l        }
    2 W* s: W# t4 ?+ U) `        @Override
      k% c( z5 x9 C; L        public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {# B* a- `: I1 N* ]0 {8 g
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_info_item, parent, false);
    3 a6 w. U* T0 H( Y" H" h            return new ItemHolder(view);+ ^( ~' I/ B# F. I5 ^
            }  y% `; t8 D- ^# ?6 ]( A
            @Override, `( V8 B4 S/ M  z# `) K3 Y6 U! C8 h
            public void onBindViewHolder(ItemHolder mItemHolder, final int index) {
    7 R/ r( n- e2 j* Y5 x$ F3 r            final MediaFile mediaFile = mediaFileList.get(index);7 u/ G; f6 x$ J$ U" Z5 `7 S( S/ l
                if (mediaFile != null) {
    9 H! F6 g1 E3 F                if (mediaFile.getMediaType() != MediaFile.MediaType.MOV && mediaFile.getMediaType() != MediaFile.MediaType.MP4) {- Y; `6 T* A0 g9 f  r. S/ V
                        mItemHolder.file_time.setVisibility(View.GONE);
    + l$ `- X! U' M                } else {
    : k: ~9 X' h( v                    mItemHolder.file_time.setVisibility(View.VISIBLE);
    . y1 w$ a8 P. u9 J% v8 v! K                    mItemHolder.file_time.setText(mediaFile.getDurationInSeconds() + " s");4 Z# e) K3 A( A( ^
                    }4 I* x0 m5 B! R+ Y& A
                    mItemHolder.file_name.setText(mediaFile.getFileName());
    . j& }% e+ a  U! Z6 [/ [                mItemHolder.file_type.setText(mediaFile.getMediaType().name());
    " g, t- r# L, Y  ]! D  d% i. u                mItemHolder.file_size.setText(String.format("%.2f", (double) (mediaFile.getFileSize() / 1048576d)) + " MB");: a. x6 o8 }: B
                    mItemHolder.thumbnail_img.setImageBitmap(mediaFile.getThumbnail());6 H6 G$ @( ]* H8 w
                    mItemHolder.thumbnail_img.setTag(mediaFile);  O4 V" x; V$ t+ d0 D
                    mItemHolder.itemView.setTag(index);
    2 u4 _: Q, o% H+ W& l$ f( ^% z                if (lastClickViewIndex == index) {
    ) J) T1 m* @0 q                    mItemHolder.itemView.setSelected(true);# b' y1 Q( ?4 H& F
                    } else {
    " H$ ^4 \9 ?5 S7 ^. E( L                    mItemHolder.itemView.setSelected(false);
    * k% g! _. J& A( _. i0 W) |                }
    " ~* J  \2 l+ s" p5 [                mItemHolder.itemView.setOnClickListener(itemViewOnClickListener);
    . G  _8 ~/ x1 d. x) E! Z1 S            }
    * h4 i8 q) s* p        }; |& |( i' b! _  K$ N+ C' g+ n" r
        }4 {: l! r0 ~4 ^1 E" i
        private View.OnClickListener itemViewOnClickListener = new View.OnClickListener() {  g( k0 j. r! a) M, Y
            @Override! `# F3 O8 ^: W) U* O4 j2 d
            public void onClick(View v) {# r1 b1 L5 p- ?% [3 Y0 B
                lastClickViewIndex = (int) (v.getTag());0 A3 h" b4 x; w1 L: z7 z. R
                if (lastClickView != null && lastClickView != v) {: C! \5 E' d/ R% v! ~) x9 o
                    lastClickView.setSelected(false);( A! B' D3 T; q0 s. ^1 ~: A! u
                }
    2 d- B- }+ T8 L" Z4 u9 d' p6 _; ^            v.setSelected(true);" e& ^. k; x! i- V3 u
                lastClickView = v;$ U! a  H* m! ?' K( g# ?
                MediaFile selectedMedia = mediaFileList.get(lastClickViewIndex);! G0 [) ?' |8 b& _
                if (selectedMedia != null && mMediaManager != null) {1 z9 \5 Y1 o6 ], {$ y8 l; F+ l
                    addMediaTask(selectedMedia);
      _2 r* [/ [+ S1 s( @6 {2 L            }
    ' f+ I* u  N( v$ B+ P7 p        }6 M9 I! Y7 M# P3 |$ f* I  Q
        };/ }) T7 W$ [  T( h5 s
        private void addMediaTask(final MediaFile mediaFile) {" p) s" U( c4 J
            final FetchMediaTaskScheduler scheduler = mMediaManager.getScheduler();
    ) Y2 {7 E, y( c8 r6 A        final FetchMediaTask task =
    , B) ?3 b2 L" H+ t                new FetchMediaTask(mediaFile, FetchMediaTaskContent.PREVIEW, new FetchMediaTask.Callback() {
    3 \+ X, b3 W! L, ?% ~0 b# Y4 g$ f                    @Override
    # Q8 H5 F8 ]4 k6 Q, D                    public void onUpdate(final MediaFile mediaFile, FetchMediaTaskContent fetchMediaTaskContent, DJIError error) {
    - K4 T, `" s$ b( l& D/ w                        if (null == error) {% `* q% u. \, q  g/ P
                                if (mediaFile.getPreview() != null) {5 }" Q" Z1 G; _5 W3 p
                                    runOnUiThread(new Runnable() {
    0 n" U6 R8 c  V- g                                    @Override, d/ S* o1 E8 Z) T& [0 M7 w- W
                                        public void run() {
    ( \+ c1 m5 M% {9 b0 \" C* y4 }2 F                                        final Bitmap previewBitmap = mediaFile.getPreview();/ e6 P3 G4 X0 p# \; L8 P
                                            mImageView.setVisibility(View.VISIBLE);
    ' F& i5 r2 |* ^9 ^# L# w- Q                                        mImageView.setImageBitmap(previewBitmap);( v  c) Q( z' k9 p6 S
                                            if (mediaFile.getMediaType() == MediaFile.MediaType.MP4){
    9 r3 a! H+ T) i% t                                            mLinearLayoutVideo.setVisibility(View.VISIBLE);; Y4 _' I; X; B' U. E
                                            }else {
    $ v8 V- u9 z2 c3 ]                                            mLinearLayoutVideo.setVisibility(View.GONE);
    3 {# B$ R1 D. f" D6 j1 s                                        }- ]" z3 r1 \2 e+ g+ n
                                        }3 ~7 |) F" A( v- Y
                                    });
    1 k1 g- F5 s$ x+ ^0 ~: y                            } else {
    ) ~) N& ~: Y" [* X) e                                showToasts("没有图像bitmap!");0 P0 r: e8 z0 s+ Q
                                }
    & n' l! E' N% E# B7 Y                        } else {7 t% _% W, D' Z# Y: p
                                showToasts("查找图像内容失败: " + error.getDescription());4 W3 U% a: R  b
                            }/ [0 E5 A& ]- W) a) ^  p/ {9 G, T
                        }6 W, u6 I4 J; N* Z" z' `
                    });
    0 Q6 l/ _0 _1 n! c2 f1 p' X, I        scheduler.resume(error -> {0 C2 I4 r# y1 y  q( u5 U8 g
                if (error == null) {
    7 A' \; O2 |, W                scheduler.moveTaskToNext(task);
    " c0 S8 E% R1 H+ Z3 }7 Q$ c            } else {
    , [3 H- S2 l2 E6 }" `                showToasts("恢复计划程序失败: " + error.getDescription());
    ; c2 X3 u# c& @) P7 m" G            }# k7 A% T2 w, ]" |) c8 U
            });
    " B0 I4 _  b; I! h  {    }4 U6 H- X- \# w4 x' R
        //Listeners
    " P! i( K; n. Z9 o% }+ O. ?" y    private MediaManager.FileListStateListener updateFileListStateListener = state -> currentFileListState = state;( F/ v6 D! ?; l' h; a4 A5 D7 u1 _

    6 }0 _' Y. \, O& T2 Q7 `& t    private void deleteFileByIndex(final int index) {* l* o5 v5 s( f. {! \( m& `) A
            ArrayList fileToDelete = new ArrayList();$ m( L/ V/ N  J) w+ W; r! [
            if (mediaFileList.size() > index) {2 j9 Q/ b; u2 ~5 v0 s; g3 y
                fileToDelete.add(mediaFileList.get(index));" E8 r% _! b+ v! |/ s
                mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam, DJICameraError>() {
    & [3 J% }" I2 N2 [# x' M' F! R                @Override3 A, P% @5 C5 ]; c
                    public void onSuccess(List x, DJICameraError y) {; w5 c! N8 E# m: S5 M& t) z2 K+ o
                        DJILog.e(TAG, "Delete file success");
    ; C. e7 W. F  h: S' N% V2 `" X) E                    runOnUiThread(new Runnable() {% Z) t. x3 @: y( H' W
                            public void run() {5 g3 H" f6 n9 \6 d& w5 h# X0 o
                                mediaFileList.remove(index);
    $ h3 L; q$ v: h" O                            //Reset select view
    " e3 y/ P$ O# I) L9 f, i' o& _                            lastClickViewIndex = -1;$ s  j: z1 [! S2 \# c# T$ H, ^- b
                                lastClickView = null;
    " z6 `( u# ~; j7 B                            //Update recyclerView
    6 A; c# v$ d9 Z" m$ x                            mListAdapter.notifyDataSetChanged();
    , X9 _" M4 F- |$ I# Y6 a1 g$ T  V                        }1 m" p, G9 T4 P5 d! a. v7 x) z# \
                        });; a3 R# z5 \" m/ s+ x' X: J$ {" d
                    }
      J$ ?% h5 Y8 z                @Override' L8 J7 ~8 i7 F9 @* u
                    public void onFailure(DJIError error) {: ]+ t/ J% Y5 \. D; Z: m
                        showToasts("删除失败");5 b- M, \, g" |- B3 k8 i
                    }
    0 A; b0 R) `) e( \            });" v0 H# W, @- l! t1 A+ k7 M, E
            }
    + q' x0 h: ]% \" t    }
    # E5 I# d0 `/ @+ _/ G    private void downloadFileByIndex(final int index) {3 [+ C* c1 q. @  W( d/ H
            if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.PANORAMA); Q+ y: U! X  i
                    || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.SHALLOW_FOCUS)) {, w- f9 k* S9 O+ T+ H3 L6 K! [/ W; Z
                return;0 I% Y$ t8 s# @- @: b
            }" T- ^* u& P7 f* A. @$ Z
            if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {) Q" d' o7 Z; t' e, [2 @
                SavePath = MyStatic.FLY_FILE_VIDEO;/ z" N* G4 U- M- b* E
            } else if (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.JPEG) {* b7 l, ]/ m+ o+ x+ G4 n3 ]8 _
                SavePath = MyStatic.FLY_FILE_PHOTO;
    ! j+ t3 o1 V0 F1 ^, |: d- |- k        }
    0 H/ t6 p( U; v) i9 _        File destDir = new File(FileUtil.checkDirPath(SavePath));7 y9 O; g4 x( C% m+ B' L9 k. d1 Q
            mediaFileList.get(index).fetchFileData(destDir,null, new DownloadListener() {
    , B; s) ]& Z, l* G; U3 V. q            @Override
    3 ?$ s& S" {9 B. a7 Y- R; l            public void onFailure(DJIError error) {8 K0 u. _2 m9 Y# u/ D# J0 C( W
                    HideDownloadProgressDialog();! _4 d* ~4 J% [# C
                    showToasts("下载失败" + error.getDescription());2 \% I* f9 m! [: _, R/ @; U
                    currentProgress = -1;
    6 |; r) j" `0 M1 X( Q( R            }
      W" j- R+ w. B- O/ u0 j; D            @Override# t" z3 T- v9 }% s- w
                public void onProgress(long total, long current) {
    0 R* R: b" {6 N" V% ?3 ]% u            }
    4 H: ^+ M' k4 w0 @* b, o            @Override" E  z4 x& Y2 R, d
                public void onRateUpdate(long total, long current, long persize) {/ K; R1 w- |4 ]8 d
                    int tmpProgress = (int) (1.0 * current / total * 100);
    - A* T4 l' ^& ?: _4 ~9 M* `                if (tmpProgress != currentProgress) {( }& }/ X* L* r
                        mDownloadDialog.setProgress(tmpProgress);
      k% u8 P# n4 S% z" r7 B                    currentProgress = tmpProgress;: q# Q) {/ E. o3 x. O- e1 t
                    }5 n* q  X7 t- j6 I, i
                }
    ( m0 \- @* {, l% Z            @Override
    5 {/ h; {0 F* i) {5 r/ Y3 j            public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {
    8 n- W* Z2 n: z- D3 b            }. V( ~' u7 S, R) ~7 `
                @Override
    6 O( l! I& K, Q' B1 E7 e$ m            public void onStart() {
    . `! }7 m9 ~" ^- p" y$ N0 r' Q                currentProgress = -1;
    % A4 C" T7 A3 d8 t                ShowDownloadProgressDialog();
    * F: f- d/ G8 H, @6 l* f            }
    ' |6 I2 Q! w7 P6 ^) _0 y            @Override$ x' Q) h7 B' B, Z* c8 f  E
                public void onSuccess(String filePath) {
    3 Q* _3 |5 ?  f) d9 W; Q                HideDownloadProgressDialog();
    / o9 F) f+ L3 ?/ a1 Y                showToasts("下载成功" + ":" + filePath);1 V4 M8 [' k9 j2 o$ V1 w: v0 r9 v
                    currentProgress = -1;4 C" w3 t6 i( P! Q; n& E
                }
    ) T" `, Q4 Q  B% t8 u        });$ O; S8 ^& V) k( Q! @3 l
    //        mediaFileList.get(index).fetchFileByteData(0, new DownloadListener() {3 O% ~& b& d! [
    //            @Override3 D& M& \- o/ S$ d; t
    //            public void onStart() {& J; O5 H0 Y# d* }, r
    //                currentProgress = -1;" p& E/ v& ~7 Q9 i8 c7 N
    //                ShowDownloadProgressDialog();3 Q3 i4 B( Z- N' ^, t; D$ b
    //            }- N; u! g- \5 ]2 ?/ A6 n) L
    //
    : o- V6 K/ }1 K. T* l. y//            @Override% Q( l- z" z. `; y7 d
    //            public void onRateUpdate(long total, long current, long persize) {  E* l  _8 b7 C9 b  A+ [
    //                int tmpProgress = (int) (1.0 * current / total * 100);" T3 B( S% L3 ~8 A
    //                if (tmpProgress != currentProgress) {
    * a3 Q# k; ^6 D% {. A: q) O# H- P//                    mDownloadDialog.setProgress(tmpProgress);
    5 S7 p+ T7 Y3 ?$ d6 ?//                    currentProgress = tmpProgress;# K( M6 l  u8 `" `, }& }' W; f
    //                }) k6 N: o6 d/ ]
    //            }# m+ c5 X: D+ V- A6 {
    //
    $ Y: V8 ~# K- h) w; |4 ^//            @Override
    4 L: K8 L8 W1 T6 T' O" Z9 K//            public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {
    & g: h9 ^6 a0 ~//                byteToFile(bytes, FileUtil.checkDirPath(SavePath)+mediaFileList.get(index).getFileName());
    1 ]& y. m1 O& X* ]! `0 @" X7 l. x//            }
    . O+ z; I4 D8 [& O! {//
    5 W4 t1 i9 f) G% }# q# V  ^% Y, K9 ~//            @Override
    6 X& Z. l3 f; z  F: y9 ~//            public void onProgress(long l, long l1) {
    6 X" x& Q# q% B$ M0 A& d//
    0 Z( J: x; M7 I8 l//            }
    , m% A' H  g9 @//
    , b. u: h) y5 j' ?$ R- ^  b. ^//            @Override4 @! m# B& d9 j% H+ v6 ?
    //            public void onSuccess(String s) {& \" Q7 [' Q2 o' g) ^
    //                HideDownloadProgressDialog();+ t% M* T" n7 k
    //                showToasts("下载成功" + ":" + s);
    ) [& P# a' j/ \5 [, }1 I//                currentProgress = -1;$ L, T6 ^- @0 w  N6 Z$ A
    //            }
    / d+ X/ J7 J' e+ Y: a//
    , ]4 @# b. Q! a( Y* F" a$ d//            @Override
    5 F. h5 Q) O: P! Z2 V* b. n9 N//            public void onFailure(DJIError djiError) {: D  x: x7 V* t) f
    //
    . k9 Y: h3 B! F; m//            }
    " X& F4 _" B3 A* Y- ~5 Z, h% C//        });: o6 j, q: C# e  c) K4 X! B* O
        }
    * j/ a# X2 ?8 g    public static void byteToFile(byte[] bytes, String path)
    0 T6 s, k$ J- ]9 Z1 A    {0 G( n* s" j  ~2 e0 [0 Y' J! |
            try
    " z; P. C# C; t  C1 E        {
    + `! p9 v4 Q! j! w6 Y            // 根据绝对路径初始化文件$ }! S3 @2 ]  I+ [8 }- i
                File localFile = new File(path);& c% I% T7 k. p$ l
                if (!localFile.exists()). r" ?' R( X1 |# L
                {
    + D% s/ n1 |0 I! b                localFile.createNewFile();& T$ n/ O% E; j4 w- S7 }- A
                }& i/ a% O" \8 s% b
                // 输出流
    9 Z! U: K6 T1 f+ }! b2 I+ k  r' p0 [            OutputStream os = new FileOutputStream(localFile);
    ; M1 @. a4 R# R. g8 j! X1 p' g' P4 i            os.write(bytes);
    , x) p- t- w1 j            os.close();
    2 y( G$ F: X" g9 H3 Q; s        }) [3 M% Q1 ^& ]6 b( f& r8 `9 x
            catch (Exception e)
    % K4 B6 Y( @9 v* m& o, f        {
    9 G! o/ i" u# G& U            e.printStackTrace();- P) Q' t+ P7 J# ]" Z$ n5 M& z2 h; d
            }
    7 U1 }" f7 K" a    }' q* r8 w5 C# u$ P
        private void playVideo() {
    0 h; p6 {4 O5 v% s        mImageView.setVisibility(View.INVISIBLE);
    $ w3 W7 R; @; E" y        MediaFile selectedMediaFile = mediaFileList.get(lastClickViewIndex);" o/ A7 k3 d* F& S/ G6 f" g/ [6 R, Z
            if ((selectedMediaFile.getMediaType() == MediaFile.MediaType.MOV) || (selectedMediaFile.getMediaType() == MediaFile.MediaType.MP4)) {; @# s  p2 W, F4 `
                mMediaManager.playVideoMediaFile(selectedMediaFile, error -> {& w, M$ n, [/ R+ A
                    if (null != error) {6 N$ G$ R) N; }
                        showToasts("播放失败 " + error.getDescription());+ i: M$ Q1 x, K: e; s/ Z# \
                    } else {  c* ]* e* r- x! u# O9 f7 P+ K
                        DJILog.e(TAG, "播放成功");: }8 E$ \0 S9 s  H$ p
                        runOnUiThread(new Runnable() {" Q/ `2 I4 e% v; K2 E: y: k
                            @Override
    & E+ d. e' B$ G4 }) E, f" {                        public void run() {' c, O# X( a: s7 X; E+ b* n) H
                                mImageViewVideoPlay.setEnabled(false);
    9 p& @+ N  ~/ w6 X                            mImageViewVideoPause.setEnabled(true);
    . B/ X; n) e& `7 k1 P( P( N) d                        }3 r7 V  W! l1 C. P& c( D
                        });: B2 p0 M! l, l  E' D
                    }
    ! O- u! R$ k) Y; I0 u4 t6 |            });
    4 u1 @  A5 p- `/ V6 Z0 t% z        }
    + ~& S6 d& o, G8 U    }/ _2 b/ W( T4 m, c1 G) ^
        @OnClick({R.id.img_back, R.id.img_delete, R.id.img_download, R.id.img_upload, R.id.img_video_play,3 ]) Z( U# w# a, I5 M, Z
                R.id.img_video_pause, R.id.img_video_stop})
    2 P7 H* X; o! B3 D4 }8 Q* q$ n    @Override
    . ?2 r- V" y3 i- _2 E    public void onClick(View v) {
    ) F9 ~4 s; W4 s        switch (v.getId()) {
    7 l' r) T2 i. o  \& h  W' V2 o            case R.id.img_back:/ i) K* q) O3 Z6 k7 q
                    FileManagementActivity.this.finish();! _& V+ q4 j3 C* a
                    break;
    ! x- g" \1 X' z" Z8 F            case R.id.img_delete:/ g- _. c, U) Y# v4 x& V
                    if (lastClickViewIndex >= 0) {
    1 G/ ^' V) N; M& [) z. H! Q, c# r& V. U                    deleteFileByIndex(lastClickViewIndex);/ v& Y' q  L& B7 S; ~: i2 B
                    } else {
    9 A6 C- U. W) ]+ w% L* n% a4 A                    showToasts("请先选择文件。");
    % w  \; [. g" b                }
    + c6 H& F6 D- e* `' U- I                break;
    , F/ s1 D: R" [8 d8 q            case R.id.img_download:
    2 y+ W. e# Z* C* d' D( g                if (lastClickViewIndex >= 0) {: f9 |( l/ z7 Z4 v3 V* ?$ Z
                        downloadFileByIndex(lastClickViewIndex);
    , X% g4 |4 J6 }" C/ M# a2 @                } else {
    " `7 R1 G3 p. W+ }6 t/ H. L0 `                    showToasts("请先选择文件。");
    ( d* ]- F2 c& O$ R2 q' d' h0 _* ^& W7 s( G                }: f* Q8 ?/ r& t5 J
                    break;
    ( [/ f  F3 R, p' ^. t5 Z" R, o            case R.id.img_upload:
    $ d2 K" u9 ~* E, V) X( z$ U) m                if (lastClickViewIndex >= 0) {
    * `# J' J1 I+ d3 q                    uploadFileByIndex(lastClickViewIndex);' d/ y9 J9 _$ i/ f
                    } else {
    $ }: }  Z! g3 w# S& V) B* }1 d                    showToasts("请先选择文件。");
    5 E2 j% M- z( B2 u                }1 b! W/ w5 I- W9 r& u; q) {5 Y
                    break;
    * K( C, D0 `/ C# ]' r            case R.id.img_video_play:
    : A- d$ |. G( g% |                if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){
    : M+ h, t3 v3 j: l, o- i+ g                    playVideo();
    ) q5 z+ F' l  C. o: U* j                }else if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.PAUSED){9 i! R, p* i) u$ G5 [2 I
                        mMediaManager.resume(error -> {$ [  `1 L5 D8 G' j, e9 t3 u5 T
                            if (null != error) {8 B1 n0 ^) H) j/ `0 u" ~* z; t, k
                                showToasts("继续播放失败:" + error.getDescription());' ~! `! u+ M# p, n" v# ~. w
                            } else {
    . \4 }' v, z6 D. o% Y5 V                            DJILog.e(TAG, "继续播放成功");
    , y# m  o' A  I( |" g                            runOnUiThread(new Runnable() {
    / a0 ^3 B( I' i/ o: }                                @Override
    ! O# M7 ~" k1 Z' r5 U                                public void run() {2 J$ O- T5 [  r- l$ K5 ]
                                        mImageViewVideoPlay.setEnabled(false);! S1 t6 |5 x( m, @" L5 y0 h
                                        mImageViewVideoPause.setEnabled(true);$ A: i% W- ~9 O  _, R9 _1 f. ~
                                    }
    1 @- Q0 |9 ^8 ^5 ]                            });
    ' x2 m9 C5 |+ v9 z; m3 y3 c/ Q                        }
    ( n$ `6 C  ]* t2 E7 O0 _  r                    });
    ) z: e: l( {; z- C6 f                }
    - l; _/ t7 K0 Z                break;
    0 h# a9 M1 J5 H( R/ @            case R.id.img_video_pause:" N/ k% ^" F5 U) o
                    mMediaManager.pause(error -> {! W" ^5 k$ W- g1 s; z
                        if (null != error) {
    % ~$ R4 F3 V4 a7 n                        showToasts("暂停播放失败:" + error.getDescription());
    7 S- R& ^' o6 E                    } else {
    ! e, F$ p# S' h. K8 @% t5 F                        DJILog.e(TAG, "暂停播放成功");
    4 S: M2 F# U, j; b2 x0 ~! B+ T                        runOnUiThread(new Runnable() {2 X8 |2 G& b* T$ D* z6 N% @
                                @Override0 V0 z; [1 {% q) S& R
                                public void run() {
    # w6 w( n* U7 R. m1 U$ R' c                                mImageViewVideoPlay.setEnabled(true);4 e  }+ k% z; Y1 X9 Q8 s, _* a
                                    mImageViewVideoPause.setEnabled(false);
    ' R% ?" o  t1 k8 u9 u7 V: j% _                            }( e; v3 e. c0 }/ n- G1 U! A+ O* L2 `
                            });
    * l( |' S# b, Q: c- R+ [& F. \+ Q! C                    }
    8 M# A4 k( _3 \2 _/ ~& ?! `                });" R! `5 \6 s; j* J$ H! M  R7 I9 `7 w
                    break;
    - q7 f; R* u$ @7 L. n: m$ l            case R.id.img_video_stop:) ^2 ^2 f) k5 U1 O: M$ {
                    mMediaManager.stop(error -> {
    0 A' z) F) N; \  `9 E$ ?% t0 b" w                    if (null != error) {
    5 a, z! i3 a% V6 {9 M# p- V                        showToasts("停止播放失败:" + error.getDescription());
    % W- i( v0 e& H2 q$ T7 ?                    } else {1 S/ t5 P2 S+ B1 }
                            DJILog.e(TAG, "停止播放成功");
    # J- s+ Z5 r) z                    }
    + {. [/ T  W5 {$ s4 x  A% z                });3 {9 T0 W+ ]# y- P2 O  X0 c
                    break;2 c" }, F  n5 ?8 T' U7 A  t
            }
    4 b. B6 ~+ M8 [    }5 F! D+ i8 M4 H2 ^! W
        private void uploadFileByIndex(int index) {4 b- B# e' n3 C8 i" ]6 A2 ^+ ^
            if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {9 m% }7 y8 b! s& q( _1 ]6 E
                showProgressDialog("正在上传");
    5 T( E/ a4 d& \            new Thread(new Runnable() {
    / ?* W0 S' j" X8 k3 d# S                        @Override
    9 H# ]+ |+ Z# X  E                        public void run() {
    8 @0 V/ x. ]/ {# C5 A% n' e+ ^                            boolean isConnect = sftp.connect().isConnected();6 {9 }. G( P) `  v% Q/ }
                                if (isConnect){
    2 I0 }/ _% p+ Z7 x8 D2 }5 _- h                                boolean isUpdate = sftp.uploadFile("/mnt/uavFtpFolder/",mediaFileList.get(index).getFileName(), FLY_FILE_VIDEO, mediaFileList.get(index).getFileName());
    0 O* u3 A3 \+ `# |/ F                                if (isUpdate){; S* r# ]  I$ z. N' S/ |
                                        runOnUiThread(new Runnable() {
    ( F5 {) r8 ~, W6 b0 j  B, |                                        @Override
    & K; t2 L7 x3 [% d, d/ Q/ v                                        public void run() {
      }# j, b( H; U% P3 K- B                                            removeProgressDialog();
    ) D: ~* @  ^* a0 \3 {! O                                            http.getHttp(GET_VIDEO_INFO+"?fileName="+mediaFileList.get(index).getFileName(),"GET");* ]5 P  O7 s5 D
                                            }( [, b8 T9 Y8 P  F# o1 b) i5 C
                                        });
    3 d. O6 [, q4 p# t) Z- A& E                                    sftp.disconnect();6 k1 s* `- I7 z" ]
                                    }else {
    8 R5 D( h' d( `2 G                                    runOnUiThread(new Runnable() {) N/ P0 f4 W& H( Z+ e* i4 j% d
                                            @Override9 @1 q3 n- |3 B" y* l9 ?
                                            public void run() {
    ' U" F, G( }+ s                                            showErrorTip("上传失败");
    0 O  R9 s' n' E4 i$ P                                            removeProgressDialog();+ C3 U1 N; U) E' J
                                            }2 r# o7 ]' G; Y$ _/ Y8 i3 e* I! V
                                        });& G, Y+ W; z& x: k' T$ K
                                    }
    ; _% t+ a9 m5 e0 \2 G$ t: J                            }else {/ @) ]+ x" K' Z3 W4 d
                                    runOnUiThread(new Runnable() {
    & }0 {5 V; Q  `& H                                    @Override
    1 S7 ^! T3 c- S- y: e9 ]* g& u                                    public void run() {: p; a7 z3 w" F. i
                                            showErrorTip("服务器连接失败");
    4 ?& ^7 Z1 f  Y' p: d" ^                                        removeProgressDialog();
    ! i8 P$ ~; C+ c3 T                                    }& c7 l- H4 l/ P2 ^5 e. I- a
                                    });4 Q7 n% r, _4 Y& W. }' `3 C9 H
                                }
    - r" l2 d0 _8 {: l7 O                        }
    ) \6 R3 V9 x- D  n3 [! o  Q3 a                    }).start();
    7 W- V3 I+ H0 E! m9 s. F3 Q3 ?        }else {
    3 H. \) g. @1 D; G, V# N            showToasts("当前仅支持视频上传,请选择视频文件!");
    ( W; T7 K' S% t# G1 Y        }' E$ q1 c9 n) D6 h4 H5 _
        }/ v$ B% z& Q9 M8 R
        private boolean isMavicAir2() {
    + p: p3 V$ g2 L/ x3 m  N% [9 l        BaseProduct baseProduct = ReceiverApplication.getProductInstance();
    4 m4 ?, k( c( q6 m' T        if (baseProduct != null) {+ ]- B, V, t8 k' i
                return baseProduct.getModel() == Model.MAVIC_AIR_2;6 B3 X0 v$ }1 ]4 L1 f$ n- L
            }
    / L" x; j. ?- _, |        return false;; j% u3 i' |' L) b& {7 L
        }
    ; r' j& R* V  q5 V    private boolean isM300() {
    6 G# d( l2 L, p& ^+ W# w        BaseProduct baseProduct = ReceiverApplication.getProductInstance();
    0 U* V- I2 l* w* U3 p' o        if (baseProduct != null) {
    , p" }: l: `8 K- u- H" O            return baseProduct.getModel() == Model.MATRICE_300_RTK;
    # F1 \" D1 X6 Z$ r; N. P: G' V        }
    ( y. b8 ^9 ^+ {- h0 x        return false;
      d/ R4 V: H6 b' l5 U    }
    2 g3 _5 \& d3 ]" A, D* Q5 H! Y}( c$ G& ?4 H. R' E8 x, w! p
    运行后界面如下:4 g. z7 l5 {% W. j; h

    dwx4hpo5o5k64023083506.jpg

    dwx4hpo5o5k64023083506.jpg

    # {& ^8 p4 Q& f+ T  F/ M: e6 y4 P$ W7 u5 X" O. C# o# R5 ~: Q8 [

    uiwobraut0x64023083606.png

    uiwobraut0x64023083606.png

    0 W( |6 Q7 Q  l" {4 K往期推荐LabVIEW OCR 实现车牌识别$ C/ j7 a+ k: {/ f/ D3 D! U( ?
    和12岁小同志搞创客开发:有意思的激光切割技术0 o3 k2 O9 y* \0 N; N4 g
    JavaScript+TensorFlow.js让你在视频中瞬间消失
    8 i3 N6 U$ U# v' N  Q* B& M3 O8 Y1 a使用OpenCV测量图像中物体之间的距离4 q6 u* M7 I& U
    全网仅此一篇:工业级压力传感器设计及实现- J9 n; K- S/ f$ P+ A" k7 O% T' e, d

    ; _0 {5 \% E3 o

    qye2bh0mhdb64023083706.jpg

    qye2bh0mhdb64023083706.jpg
    - v1 m, p4 m/ s5 V/ a6 l

    cnnb1olyf5d64023083806.gif

    cnnb1olyf5d64023083806.gif

    5 g$ s4 s9 P# [. ~4 s+ \点击阅读原文,更精彩~
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表