电子产业一站式赋能平台

PCB联盟网

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

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

[复制链接]

1001

主题

1001

帖子

8807

积分

高级会员

Rank: 5Rank: 5

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

omqaxwaojye64015955823.gif

omqaxwaojye64015955823.gif
) d4 l( K  C8 W( x, o
点击上方蓝色字体,关注我们
6 B9 z& U# G+ r1 D* m6 L4 U/ C9 S) M" J- `2 v# Z' K2 ]
上一篇文章(基于Mobile SDK V4版固件开发大疆无人机手机端遥控器(1))因为时间原因介绍了一部分内容,如果已经完成上一篇内容的操作就可以进行下面功能方面的制作了。自己开发的APP功能不是很多,但是已经将大疆无人机的常用功能进行了结合,同大家一起进行学习~
, c3 s0 ~8 C& P& I1+ W/ Q. k8 b6 [2 R3 C" i' U: Y# h
应用程序激活与绑定
! |: a; `7 e  d' _" s" _2 b$ h如果在中国使用DJI飞行器固件,则需要使用该用户的DJI帐户激活控制DJI飞行器的移动应用程序。这将确保大疆能根据飞行器的地理位置和用户个人资料,为飞行器配置正确的地理空间信息和飞行功能集。激活系统的主要是:, `2 ^2 [7 S7 a) B
  • 中国用户必须在每三个月至少登录一次DJI帐户以遍激活应用程序。
  • 激活信息将存储在应用程序中,直到用户注销为止。
  • 登录DJI帐号需要连接互联网。
  • 在中国境外,SDK会自动激活应用程序,无需用户登录。
  • 另外,中国用户必须将飞机绑定到DJI官方app中的用户帐户。这仅需要一次。如果未激活应用程序,未绑定飞机(如果需要)或使用旧版SDK(
    6 f4 P" X- u  c+ o$ g
    / Y( U  g) |2 f; `: H+ o1 ]( U5 t
    24 Y$ f% ?  a4 X! M4 y/ A; N
    为应用程序创建UI编写MApplication、ReceiverApplication和RegistrationActivity文件(此处粘贴部分代码)。
    ( ~# N0 f, f3 w* T9 ^6 _: spublic class MApplication extends MultiDexApplication {
    ) f2 X- V" |8 x; f" W    private ReceiverApplication receiverApplication;
    4 r- G2 @7 v6 o2 x: ^9 [$ T    @Override# E* P9 p0 i4 Y5 v" h7 U* a
        protected void attachBaseContext(Context paramContext) {
    , V9 M6 q: L/ K8 T) K% r7 j        super.attachBaseContext(paramContext);" l. u6 \* Q" c+ ^
            CrashHandler.getInstance().init(this);' Z/ `& f  x6 X3 ^
            Helper.install(MApplication.this);
    . _8 j# q8 o2 y7 Q        if (receiverApplication == null) {; `) ?4 y* K3 x+ `9 Q& m2 e/ W
                receiverApplication = new ReceiverApplication();; `! y2 n/ F4 g6 T& |7 y% i
                receiverApplication.setContext(this);
    5 m* r, Y" S4 m7 a# n4 Y        }! Q7 [1 ~6 k3 ~1 o8 S/ W/ v
        }, g$ S" E6 c# B
        @Override
    ! o2 \1 s, h; w# U( B7 U: z  u" P    public void onCreate() {
    3 |3 O: v8 }+ x        super.onCreate();
    0 W% s. H: I" P% J$ W6 }        receiverApplication.onCreate();
    * i9 \7 C% C- G1 f* U0 ~) h, C7 L    }: ?- H# [, O1 Y7 `# l, W
    }
    * _0 Y' p2 w* Q9 \上面的代码实现了绑定当前APP,将后续需要用到的类函数封装到ReceiverApplication 中,在ReceiverApplication 中也能够进行账户登录的操作。4 [4 }: g" i$ ?5 X, W1 _
    public class ReceiverApplication extends MultiDexApplication {( r. H. t9 b- a* J
        public static final String FLAG_CONNECTION_CHANGE = "activation_connection_change";1 G9 q7 k. U4 b- ^* h
        private static BaseProduct mProduct;& ~+ W7 W7 x8 x# P0 n5 t+ [
        public Handler mHandler;7 G- R& ~, s4 P7 r( |* }; L
        private Application instance;+ A$ S: L7 h9 I: r
        public void setContext(Application application) {
    , L! `2 d+ s9 S/ J. _        instance = application;
    # ]" N# V/ H9 ]5 V) U( p    }% I3 }7 T4 z1 ~3 k5 G. j# y
        @Override
    6 N! U" q5 o# C4 J2 N    protected void attachBaseContext(Context base) {0 N5 q% H0 N6 m% h5 @: ^
            super.attachBaseContext(base);
    ; u' t! X3 N" V. T        Helper.install(this);# C1 d, f7 S( W+ x
        }
    ( {' }, b1 z) M8 K5 ]( \    @Override
    . h, M4 d% |" p9 u5 S6 ]; V9 G    public Context getApplicationContext() {0 \6 ^5 f% p3 ~4 C! Z7 g
            return instance;
    - E* L1 D2 v% X% v+ `0 b    }. H# ?2 q% u" V3 x) m8 c, ?
        public ReceiverApplication() {- g. b$ _4 j7 v' Z" i- i* L. A: k
        }
    3 ^1 ~; S+ B: n5 A; l  a1 [    /**
    : I5 Z; t6 V7 F2 M- C! Q' A( d     * This function is used to get the instance of DJIBaseProduct.: J7 e, a) F! l  G/ C6 O
         * If no product is connected, it returns null.$ ?( m* X/ e) Q* H! Z+ T
         */
    3 V  W" E+ h5 n4 I; |1 t9 Y    public static synchronized BaseProduct getProductInstance() {( Q3 s9 Y+ }( D3 j# K+ A
            if (null == mProduct) {
    8 s) f$ s: }& K/ I1 ]            mProduct = DJISDKManager.getInstance().getProduct();
    2 Y( L* i/ W; ]% T5 x8 r        }/ R+ |0 D6 m& H8 w
            return mProduct;6 ]/ I9 o4 ]; H# k5 q2 N8 ]. V9 E
        }7 |8 |3 F, {! b5 u3 S/ \
        public static synchronized Aircraft getAircraftInstance() {
    9 a) g9 @6 Y, z. l* c+ v        if (!isAircraftConnected()) return null;* @0 v2 @% l1 C, |1 }
            return (Aircraft) getProductInstance();
    % V3 u, {( j& V/ E' z4 w    }
    1 X( [% u5 w6 D  w    public static synchronized Camera getCameraInstance() {
    . ], ^# X. T6 Q6 ~- M9 F        if (getProductInstance() == null) return null;0 r# j) L1 e+ }
            Camera camera = null;, M7 U2 f* @! L2 a/ }
            if (getProductInstance() instanceof Aircraft){
    1 I! W. \% |2 a0 z  Y& H            camera = ((Aircraft) getProductInstance()).getCamera();; d! c. E# w$ o; G+ E, h* C
            } else if (getProductInstance() instanceof HandHeld) {
    : g2 e3 Q! h2 g9 U  [            camera = ((HandHeld) getProductInstance()).getCamera();
    & Z& n) p7 O  u# ?* R        }- G$ E, D1 O' G3 h
            return camera;
    . o2 f5 a3 O: y6 m3 E    }) P8 s" {* w- `4 F% N6 `9 Y4 e
        public static boolean isAircraftConnected() {
    : Y; r1 V& E( y$ A0 [        return getProductInstance() != null && getProductInstance() instanceof Aircraft;
    . Z' T( w( l3 N  p2 o    }
    . P! G6 f5 ]( f    public static boolean isHandHeldConnected() {
    3 m. c3 f6 `6 O9 t8 V. ~; |        return getProductInstance() != null && getProductInstance() instanceof HandHeld;
    - h& S4 C2 w8 l* i$ |4 u9 H    }3 I7 L! O6 w; z0 Y) W0 N- x+ x, A& S
        public static boolean isProductModuleAvailable() {* u# S7 x8 m- I, H9 B; T1 n
            return (null != ReceiverApplication.getProductInstance());/ L  n+ d7 O3 L! v- ^
        }5 R/ l% `/ p* {. |
        public static boolean isCameraModuleAvailable() {* z$ i: l) r& M; i# _1 Q7 E
            return isProductModuleAvailable() &&: _. m, F# t5 v9 S; h
                    (null != ReceiverApplication.getProductInstance().getCamera());& M  Q7 h  ?) p" K' [9 x* C/ W. A
        }9 O2 B3 f# I2 U
        public static boolean isPlaybackAvailable() {
    ! y; d: r2 p, ?8 C6 Y        return isCameraModuleAvailable() &&) o( o1 L% V- Y
                    (null != ReceiverApplication.getProductInstance().getCamera().getPlaybackManager());0 S$ z% A) s9 o7 B# ?4 N/ T
        }
    1 A  l. @0 E  s: ]    @Override
    4 ?" L8 O8 K( G$ l- v! K7 I8 N    public void onCreate() {
    . u2 v9 `# @# n$ U  q/ ^8 T3 m; H8 \7 `        super.onCreate();( T) w6 p6 C/ K5 L
            mHandler = new Handler(Looper.getMainLooper());
    , M% {! z- r# i8 J) r( E        /**" d; Q4 u* d" p0 ]3 F0 c9 k" W
             * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to% b7 ?* j7 u8 I; z& r# I2 N
             * the SDK Registration result and the product changing.+ l/ z( n0 o. p: N6 i* G) _4 D
             */
    ( R1 h! F4 J2 z9 s        //Listens to the SDK registration result- d9 l8 D! ]) z4 ]3 P
            DJISDKManager.SDKManagerCallback mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() {
    8 b! Z# |6 y+ x* {  u5 w            //Listens to the SDK registration result" h9 {- Y9 F9 x% G
                @Override1 z3 [: x) M" w2 A0 ]  [
                public void onRegister(DJIError error) {
    7 z$ b7 `: w/ e) I5 E9 x3 K                if (error == DJISDKError.REGISTRATION_SUCCESS) {
    & H+ p1 z, q+ T5 K, P% s                    Handler handler = new Handler(Looper.getMainLooper());% S" {5 c8 J: l" Z# I
                        handler.post(new Runnable() {
    * C" n6 U8 ~, A* @  F* C& m                        @Override, J: ?3 O* s2 ~& o, Q) t  s. r
                            public void run() {3 B: `9 V3 i3 Z! j
    //                            ToastUtils.showToast(getApplicationContext(), "注册成功");: ?  [: L: ]4 P
    //                            Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_LONG).show();% Z% I7 ~& G! a; B. S  Z
    //                            loginAccount();
    , i& Z/ v/ m! I# b4 r( n                        }
    6 `$ G8 G# }8 H0 [6 `                    });# m6 W+ s8 G% B: J
                        DJISDKManager.getInstance().startConnectionToProduct();
    , A: M8 C: w; s2 o                } else {& _' v  g' r9 Z) X5 i
                        Handler handler = new Handler(Looper.getMainLooper());# c# i+ Z: F. n
                        handler.post(new Runnable() {
    # T* s# f, B% P3 l3 s" U                        @Override
    - Z. b+ Z. l+ j  T; w6 G                        public void run() {
    ! m" ?2 J. ~: d/ O8 C) M//                            ToastUtils.showToast(getApplicationContext(), "注册sdk失败,请检查网络是否可用");
      l+ P- _1 N, I( S/ S8 L//                            Toast.makeText(getApplicationContext(), "注册sdk失败,请检查网络是否可用", Toast.LENGTH_LONG).show();& R% z# M$ x9 y; C; ^8 ~
                            }
    - |. k7 W# j5 c& l                    });
    5 Q: \6 L1 K6 x, J; I                }
    % y" W2 ^: e) f: o                Log.e("TAG", error.toString());! Y' f% s8 @6 E/ S8 A1 D# L" M
                }
    1 s. I7 v# W" N. `5 ~            @Override
    0 H/ q9 o; ^( v8 r            public void onProductDisconnect() {; j+ H2 ]9 J# o! @$ R& n
                    Log.d("TAG", "设备连接");: q  N2 I5 r5 r- u
                    notifyStatusChange();" a* _! Y# \0 g3 L' Z; Y
                }
    ) k2 \! g, s* v6 y7 g; D            @Override& _- z( K' m, f3 W
                public void onProductConnect(BaseProduct baseProduct) {4 B) S' N8 ?! Z4 g( b" {
                    Log.d("TAG", String.format("新设备连接:%s", baseProduct));/ u2 n: c' |# C0 ]4 e, a
                    notifyStatusChange();
    7 f3 b; ^) Y: b4 a# X) S6 X* ^- z            }, ^/ o: N; o. G
                @Override
    1 _4 P+ {  o" M9 q2 c            public void onProductChanged(BaseProduct baseProduct) {4 d  H* @0 M- X) X0 m# r, I& y
                }
    $ q; R4 p2 o7 s4 q- M            @Override
    4 \6 l3 }  ^/ V8 @& ~            public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,2 D1 A2 `9 |# g, ~6 k- R$ M
                                              BaseComponent newComponent) {
    ' @  t0 M$ Y) M$ ^                if (newComponent != null) {
    4 [- n/ F; }% Z                    newComponent.setComponentListener(new BaseComponent.ComponentListener() {
    4 [8 q" {) i1 S( Z* D/ n: [& B- m                        @Override9 ^$ D* O, v: z+ z" m
                            public void onConnectivityChange(boolean isConnected) {
    * l1 k6 B4 o* f/ I5 G% ?                            Log.d("TAG", "设备连接已更改: " + isConnected);' j3 [  g7 [+ X. H& J
                                notifyStatusChange();
    1 v- `+ ?, V" C8 L- K. w2 ~                        }
    : [! ]4 v  t; ^/ C' Q$ V                    });3 m6 _( z$ t" l, V
                    }
    - g1 |7 S7 x' H                Log.d("TAG",
    - N: ^' b* K2 f3 a  v3 C& Y& j                        String.format("设备改变 key:%s, 旧设备:%s, 新设备:%s",* A3 Q" e6 H3 z- X2 G
                                    componentKey,
    , i0 ^/ E6 b- H+ e) B                                oldComponent,
    4 Z% K; q9 G# w. Z                                newComponent));
    ) p; |# R6 H" F3 }) Y. v            }$ [" {5 D3 X" L* ^
                @Override
    $ G/ ?& F1 s4 l2 V7 O3 F            public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {1 J2 M7 x' Z4 G8 Q$ M
                }/ O( e+ r+ i% J/ m
                @Override
    4 n" b; Q, h+ \2 v, j/ h5 h            public void onDatabaseDownloadProgress(long l, long l1) {- z: f$ l  |+ u7 X
                }+ z: r  S/ s) W0 Y2 p* ?
            };
    7 O3 V2 M6 x- \7 D. F        //Check the permissions before registering the application for android system 6.0 above., I5 p2 e5 }7 ~$ v& `/ H
            int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE);" T- Z7 g4 {+ `
            int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE);8 S4 K& L* j  ^
            if (Build.VERSION.SDK_INT 0 && permissionCheck2 == 0)) {. d* A; a" n. Y% [$ D
                //This is used to start SDK services and initiate SDK./ Q* I; ~. w- l. n, e: Y: K
                DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback);% C/ p( G# m/ ]3 C( a
    //            ToastUtils.showToast(getApplicationContext(), "正在注册,请等待...");4 z1 U. l  v: I3 [9 H7 w: B/ ~
    //            Toast.makeText(getApplicationContext(), "正在注册,请等待...", Toast.LENGTH_LONG).show();
    , G# f) a# L- t( ?& \        } else {8 e/ }! M/ n, o: ?; c  L+ h
    //            ToastUtils.showToast(getApplicationContext(), "请检查是否授予了权限");4 s6 P! }  ~, Y+ h& _# J7 G
    //            Toast.makeText(getApplicationContext(), "请检查是否授予了权限。", Toast.LENGTH_LONG).show();5 E$ H5 a0 v4 F9 q5 e
            }5 a0 q/ [- w# V$ G
        }" t4 V! j5 n3 ^: g
        private void notifyStatusChange() {
    " W3 r9 G6 k" p8 z2 q        mHandler.removeCallbacks(updateRunnable);
    ) C: G$ E" e, o        mHandler.postDelayed(updateRunnable, 500);
    2 ~: G$ R8 v; |( o    }- i7 Z+ q  {, k# U" C# d
        private Runnable updateRunnable = new Runnable() {
    + D* v# C3 m; F( g4 K0 K: k        @Override3 t/ c- j$ s. t" H5 d1 |( d+ t
            public void run() {
    : ^; I# }# a, w4 E; A) r( n            Intent intent = new Intent(FLAG_CONNECTION_CHANGE);& D+ o* @3 L$ @" O; m, J
                getApplicationContext().sendBroadcast(intent);
    0 A  j# B$ N. o+ P; [. `) T        }
    ! n6 H1 U4 H" D* e    };! }/ q2 z3 }6 S$ q" @# s
    }
    9 @( O2 x" K. g+ _. A& |8 s上面的代码是对BaseProduct、Aircraft和Camera类进行实例化,在后续使用中不用再去进行重复的实例化工作,减少内存的消耗。% G" s: o1 j" l& |
    @layout(R.layout.activity_registration)* F, a9 \- e  I" O
    public class RegistrationActivity extends BaseActivity implements View.OnClickListener{% m5 x8 \0 v% G4 b; S/ o
        private static final String TAG = RegistrationActivity.class.getName();8 p( j2 k3 H& [* L
        private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false);2 Z( l9 S2 ?8 {( J
        private static final String[] permissions = new String[]{
    * V+ `) ^0 f" Z8 c2 L6 e            Manifest.permission.BLUETOOTH," [5 _  c) a8 V( B! v) W
                Manifest.permission.BLUETOOTH_ADMIN,
    9 z& G4 N7 }* \- s, z3 o% v: V            Manifest.permission.VIBRATE,5 r9 s: V. m3 U" I  N
                Manifest.permission.INTERNET,0 m: X" A% F* F7 u" y
                Manifest.permission.ACCESS_WIFI_STATE,
    4 L5 Y, t! c" {9 {9 M9 ?+ o& `" n            Manifest.permission.ACCESS_COARSE_LOCATION,/ d: G# f& [3 K" P
                Manifest.permission.ACCESS_NETWORK_STATE,
    1 Z9 j& _5 f  U2 i- C3 R3 \            Manifest.permission.ACCESS_FINE_LOCATION,
    : q$ C" {& t3 l7 P& s* J/ b- m            Manifest.permission.CHANGE_WIFI_STATE,
    + f  w+ Q( F3 P- V2 d% r2 Z; c* ~% Y            Manifest.permission.RECORD_AUDIO,: _0 y& {7 l* o: N& K  f% T
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
    1 y( E! M. g" ?# U) L- }1 C; a# s( r            Manifest.permission.READ_EXTERNAL_STORAGE,
    7 @% K. W" k5 o' ]            Manifest.permission.READ_PHONE_STATE,; t5 Z: _  p$ q( c& N5 P
        };0 C" K1 \# z. ^$ \9 \$ x

    6 J9 K, Y4 [! _8 d4 ^0 p    @Override
    : d) x& t$ x  T+ z    public void initViews() {4 J- I0 O' H( b2 ^
            isPermission();
    ; D3 w" ~: h0 m- E( Y, m        IntentFilter filter = new IntentFilter();
    0 i4 R% Z8 z$ q9 U7 x# U        filter.addAction(ReceiverApplication.FLAG_CONNECTION_CHANGE);; w5 R- B1 h  O& e$ C% e' \: ]5 G
            registerReceiver(mReceiver, filter);
    & p) `# K# \2 H9 c* d! n0 l, p    }
    : i6 _0 R% d( q; s2 o5 d    @Override* y; |9 N( q4 X
        public void initDatas() {* }& z+ F8 G8 E- M5 ~: e- V
            startSDKRegistration();% F- b4 A9 v. E5 H$ N# |
        }
    5 d/ E4 y3 W9 X# b3 x    @Override! i6 K/ C9 V' y# J" N; z
        protected void requestData() {
    ! T/ z. N- g* U. N& e. @9 X* L        
      ~8 X4 i) z) E! l    }
    * Z6 h3 {% L& `) o
    % Y, v' ^3 ?( `1 q6 N- q9 D4 C: q( Z. n. b6 F    @Override# O: ?- ^9 \9 b
        protected void onResume() {
    " \3 W1 E: U4 G        super.onResume();$ _' L6 q* i5 x  [9 N  Y
        }' I/ Z7 E5 v( U( g  h

    % o; |+ i3 M" j4 n2 }1 N$ G/ _" q    private void isPermission() {! [% ]( a2 Z! N! Z2 s: {  K4 ^, S
            requestRunTimePermission(permissions, new IPermission() {
    4 {9 F! S$ _/ G! f3 \            @Override
    5 }/ h9 h4 }) E& }4 P            public void onGranted() {
    ( o2 k$ T+ C# L% Z# k            }6 u: `5 o: v: ]) @6 R4 t
                @Override
    # q" Z1 _2 ?+ d6 J9 Q5 V            public void onDenied(List deniedPermissions) {9 z' Y0 d0 B# ?, Y0 r
                }
    8 e7 I+ {' @- ^8 l# ?4 {& x        });% p+ C9 a: l/ B+ Z2 p) f
        }
    ; K: g0 B; |# I! N. l  0 H4 h1 H9 P' ]) F0 |
        //无人机首次注册  J* A% _0 Z4 C( O# p8 p
            private void startSDKRegistration() {
    . L2 }. O9 A4 F$ n& _            if (isRegistrationInProgress.compareAndSet(false, true)) {
    * |( G: r: s( s% N  i" r. q% ?' S                AsyncTask.execute(new Runnable() {
    6 }3 t: x! ~" C                    @Override
    . p% x- K7 O6 o( O/ M                    public void run() {8 L" u  R, I0 L: G9 x; g1 m
    //                      showToasts("注册中,请等待...");
    3 a) z! _7 a, x  d& K' F( ]                        DJISDKManager.getInstance().registerApp(getApplicationContext(), new DJISDKManager.SDKManagerCallback() {( s! ?5 u* k0 A1 G" v- Z( ~8 @
                                @Override/ }8 `7 l$ E  i3 g8 |: B) Y$ u4 }: m2 C
                                public void onRegister(DJIError djiError) {$ n' f3 |$ o$ y+ L/ ?4 I
                                    if (djiError == DJISDKError.REGISTRATION_SUCCESS) {
    ) i  }: P1 J) J# \: x2 w- e- X                                    DJILog.e("App 注册", DJISDKError.REGISTRATION_SUCCESS.getDescription());6 I+ s" h8 q7 ]& {9 N
                                        DJISDKManager.getInstance().startConnectionToProduct();5 Y7 ?8 _* T4 z# {* H$ k
        //                                showToasts("注册成功");
    ) y6 s, S& r3 |; s* W                                    loginAccount();, }* }) y8 M* l3 x
                                    } else {8 `& w2 U7 Z& _
                                        showToasts("注册sdk失败,请检查网络是否可用");# O/ J0 E5 z8 w7 r, i% ?) N0 r: N
                                    }* j* j; P: x; J4 E
                                    Log.v(TAG, djiError.getDescription());1 M6 c7 a+ c  M
                                }, k4 _4 z7 ~( n+ j0 |
                                @Override8 E3 ^2 f& M7 G. l/ K" \
                                public void onProductDisconnect() {  |* s0 @0 b+ V$ g) R2 T: ~
                                    Log.d(TAG, "产品断开连接");6 _  Q7 g1 b0 W0 a# \+ I
        //                            showToasts("产品断开连接");2 U9 `, t; p1 m+ T
                                }
    & ?& `4 d$ C/ E6 M6 i6 B7 h8 t                            @Override
    ' R) ~0 g' `* Y% \9 C0 _( b6 t                            public void onProductConnect(BaseProduct baseProduct) {& W% ~1 p( g, B( L; p0 h
                                    Log.d(TAG, String.format("新产品连接:%s", baseProduct));
    " i5 N: _. \( f& S7 b    //                            showToasts("产品连接");# c5 c8 }( `4 ~9 y. G: Q7 u
                                }
    7 N0 w0 k) x4 ]8 |% D& f* S. ]& r                            @Override7 v; m8 j+ t6 m2 x( J% N7 d! @  s
                                public void onProductChanged(BaseProduct baseProduct) {. ?' {# d6 W* i0 `, I
                                }
    " ?& i. o. u8 l0 z% j                            @Override: Q0 P" s" k( _5 F$ c) J$ d
                                public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
    4 Z" ?  q5 O7 t% s0 C                                                          BaseComponent newComponent) {
    , |$ P3 A& |% B, ]1 S2 A                                if (newComponent != null) {+ c& c) ^: r/ h3 j( b+ H  g
                                        newComponent.setComponentListener(new BaseComponent.ComponentListener() {
    8 r4 G4 Q& R3 H                                        @Override+ D+ h$ j! a0 f3 n; J4 K4 ^$ l3 v
                                            public void onConnectivityChange(boolean isConnected) {6 i" F# M+ \, ?& o" D( Q
                                                Log.d(TAG, "组件连接已更改: " + isConnected);
    / E- x* J% a$ [, L                                        }0 r. c/ E' P5 w, K) E( ^
                                        });  C: k( H* y2 l) \' n+ U& [* J$ x$ {
                                    }7 t) Z. I$ v1 A
                                    Log.d(TAG, String.format("改变设备Key:%s, " + "旧设备:%s, " + "新设备:%s",7 b, e0 }5 S6 m- g% x
                                            componentKey, oldComponent, newComponent));
    0 H+ R8 r6 |. M                            }% w5 u) ^2 f9 D  _$ U8 B' O
                                @Override5 M+ h3 G4 ~$ m0 ?/ I( }
                                public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {
    3 E" L& }, i. F! b: R" a+ q, w                            }
    5 I8 F- h0 @4 X( D, m                            @Override
    : }5 w! N) F& X; o. l                            public void onDatabaseDownloadProgress(long l, long l1) {
    0 b% K' G9 z% ]! k# O3 U1 {3 J                            }
    5 s' s" J! J  z3 r' P                        });% p/ z# X$ n8 X
                        }
    8 u* d$ V! d. W9 N/ t  @                });
    ' q5 _4 Z1 f" f, g9 `            }
    ) _+ ~2 z- u9 l6 E0 z$ d        }. F  {- \1 J9 A
        protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
    : \4 b3 x4 ?& ]! E+ ~        @Override
    % x- q! ^% W' V        public void onReceive(Context context, Intent intent) {
    % g2 Q* h, ~/ }: y            refreshSDKRelativeUI();( |( T. `  r& H6 `% \) d/ S
            }% M7 p# ]0 X1 ?8 v
        };# C1 E7 u: [7 ]; O0 t0 x1 L- u
        private void refreshSDKRelativeUI() {2 ^5 f9 q. P: e5 y$ D1 K9 j# Y
            BaseProduct mProduct = ReceiverApplication.getProductInstance();% |0 i5 v9 n$ [9 U% o3 p
            if (null != mProduct && mProduct.isConnected()) {
    & `9 V( \8 L% Z2 r0 {" l            Log.v(TAG, "刷新SDK: True");6 r. j7 f' @2 ]
                mButtonFlightTask.setEnabled(true);- {8 u6 R0 W% H
                mButtonSettingRoute.setEnabled(true);
    : H9 Y1 G% f0 I! W  }# |  d+ W            mButtonFileManagement.setEnabled(true);
    6 n+ F; p6 T$ t) y        } else {1 k3 N1 G% q0 I& ^; z8 b+ ~7 `
                Log.v(TAG, "刷新SDK: False");+ J; L8 i% X$ ^5 X1 V
    //            mButtonOpen.setEnabled(false);: M) x7 K4 Q5 C& C7 t* ?8 ~8 M
    //            mButtonSettingRoute.setEnabled(false);
    0 v5 m& {- ]# O: i/ [//            mButtonFileManagement.setEnabled(false);
    + f9 r; k6 M; P" ~5 z//            startSDKRegistration();
    ) [0 n* _- M% p; _) r        }
    2 c5 U/ _0 m* j; W# [    }
    * d* i, ]* D1 r4 I7 N    protected long exitTime;   //记录第一次点击时的时间
    & K0 F( l( ^, [- m/ b    @Override2 B: c0 X! x6 R/ c( A  v
        public boolean onKeyDown(int keyCode, KeyEvent event) {
    6 P7 B7 S/ O' V7 t7 E/ J$ l, l1 X        if (keyCode == KeyEvent.KEYCODE_BACK/ G, S# {2 Q. U: |2 ?# Y, E
                    && event.getAction() == KeyEvent.ACTION_DOWN) {/ w6 [) |7 Y/ [% h- z6 \2 A; L
                if ((System.currentTimeMillis() - exitTime) > 2000) {- R* K6 U& D# O) L
                    showToast("再按一次退出程序");
    7 }, p8 T) d- V6 s                exitTime = System.currentTimeMillis();0 \* T3 U8 C! W) ^7 z$ k( C
                } else {
    3 I! b# e: |- ]- Q1 H1 j                RegistrationActivity.this.finish();
    2 h/ b; }, p6 t# m2 P. U                System.exit(0);9 U5 H# V! ?% X( n9 i/ V! Q1 H0 {
                }
      J: D* x# |. ]5 R% F1 s            return true;
    ' I6 t6 B% i: E2 y        }
    " }% F& T+ g2 F        return super.onKeyDown(keyCode, event);4 K: b# t0 U* R2 w6 N
        }' x5 h9 W8 r' U& F

    2 ]6 s! W0 b  ]4 b        private void loginAccount() {; ?) x  P$ H; \! C5 ^. u! a# r
                UserAccountManager.getInstance().logIntoDJIUserAccount(this, new CommonCallbacks.CompletionCallbackWith[U]() {0 P9 X# u1 [6 I% V
                    @Override, ]) W0 q) `$ g2 o, F0 U. T
                    public void onSuccess(UserAccountState userAccountState) {  c9 q+ o2 C: G4 X) e7 [
                        runOnUiThread(new Runnable() {
    $ p$ l. F0 N% j+ j6 e0 u                        @Override
    % Q" p% g4 h, N) h9 E7 G! E                        public void run() {. ]7 b1 n# O* b1 l( E5 V8 m) }% x
                                mButtonFlightTask.setEnabled(true);
    ; c, @2 N# o* Y" C" R& \6 T                            mButtonSettingRoute.setEnabled(true);3 W, J4 N4 e  Q, W4 U( U4 k2 u
                                mButtonFileManagement.setEnabled(true);1 V1 t2 D# c: B/ x
                            }
    2 L8 K- t. Z2 F                    });
    8 K- W! {3 M  P- X4 D8 D. u                }  M2 i9 n6 x4 a
                    @Override9 @4 A. |( B  A, m5 m0 [
                    public void onFailure(DJIError djiError) {# n9 v& [6 v5 p
                    }3 {: u. Z( G8 g6 y- A
                });% f# H+ b& ^$ S3 |$ a
            }
    5 V. m4 I2 F, w" [}8 ^$ s" m% @/ w
    上面的代码就要进行第一次注册登录了,当然你不需要自己去设计登录注册页面,大疆会调取自己的登录注册页面供你使用。) ]. n9 f9 v' a2 A8 m$ C0 G& u

    mk1fg5zkzzj64015955923.png

    mk1fg5zkzzj64015955923.png

    * m- d1 d6 M8 c$ r( K- o安装提示注册登录即可。
    ; k# h5 v' O( x, U上面的这些做完后,恭喜你!现在,您的移动应用程序和飞机可以在中国使用而没有任何问题。换句话说,您的应用程序现在可以看到飞机的视频流,并且飞行将不仅限于直径为100m和高度为30m的圆柱体区域。
    7 B1 G9 k" f3 x6 s  u/ L. H3
    - |; N  j4 y; T7 E飞行界面使用8 @5 ~& l' ?1 P3 o7 A
    虽然说可以正常飞行了,但是飞行需要设计飞行界面。那么创建一下飞行界面的UI及逻辑处理文件。逻辑处理文件中包含了获取飞机的实时姿态信息,代码中有注释内容,描述的内容就不多说了。
    / i2 v! r4 G* s! e' C  N4 I0 b& i9 y/ ?
    导入UX SDK依赖! U0 S6 P. @  [5 w4 d  ]
    上一节有说过集成部分,其中内容有导入UxSDk 的操作,这里再顺便提一下。再build.gradle文件中加入implementation "com.dji:dji-uxsdk:4.16"依赖,等待安装即可。
    & N+ k8 h' r! r* O) @
    " W% ^' q3 C/ S设计界面UI, |' \8 M+ @" h7 a
    创建MainActivity文件及activity_main.xml。3 f% t! x! Y5 v
    RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    , W- Q9 {& g, ~8 Z/ t3 c    xmlns:tools="http://schemas.android.com/tools"
    % ?1 [5 t6 S3 [( H) T    xmlns:custom="http://schemas.android.com/apk/res-auto"" D* j( i5 |( C  t+ z
        android:layout_width="match_parent"8 X9 w2 n  n5 x# l0 m
        android:layout_height="match_parent"& b7 p( a2 A0 ^8 F- _, Y% u
        android:background="@color/background_blue", T: g) |1 m3 [" O) _" @, Q$ K
        android:id="@+id/root_view"$ T" ?3 S* E* ?! B# `2 Y! g6 }
        tools:context=".ui.MainActivity">
    ) M' l8 q; P' j$ {   
    " A( k+ U/ ]* z, J    RelativeLayout
    ( n5 c; P' }. [        android:id="@+id/fpv_container"4 V2 L' |4 z+ T$ t1 N$ t* y6 @) u; X
            android:layout_width="match_parent"& m& |( G4 g) b6 ?* y
            android:layout_height="match_parent">: d) @/ \; }! ]" a
            dji.ux.widget.FPVWidget
    - |' Y: N* Z  d            android:id="@+id/fpv_widget"
    * q2 W' I" e; R            android:layout_width="match_parent"
    7 ?) F8 d3 _4 G, K  S; G/ `5 ^8 e& S" v            android:layout_height="match_parent"" X: @( b& z& T- T- |
                android:layout_centerInParent="true"
    3 V6 k5 j0 I' y* A; X7 @( C            custom:sourceCameraNameVisibility="false" />
    : v  [* d+ l% u6 `2 y- H- s# ^1 R    RelativeLayout>3 G; l; Y# A1 Y+ G2 }. Z. d) t9 ~
        dji.ux.widget.FPVOverlayWidget
    % D  I8 N. k# E' g        android:id="@+id/fpv_overlay_widget"
    1 s" z8 W! Z: g% ?+ t4 K        android:layout_width="match_parent"" z: Y  d; n/ P1 B/ N( o
            android:layout_height="match_parent"/>5 o. {3 D% }3 K5 h! s
        RelativeLayout. U) V4 G3 j$ K4 z" O' U
            android:layout_width="match_parent"0 ]9 P. Q, h/ l3 U
            android:layout_height="match_parent"
    5 y9 v$ h* W/ {* h& g. c        android:layout_marginBottom="40dp"9 Q- ?* g( k& K# _8 i. Y9 h
            android:layout_toRightOf="@+id/TakeOffReturnPanel"7 S6 y/ H0 L2 t
            android:layout_toLeftOf="@+id/CameraCapturePanel"1 X) A8 J$ {9 [9 Y
            android:layout_below="@+id/camera"1 u, P& G1 G' ^$ Z  J6 \: w
            tools:ignore="RtlHardcoded">
    # v9 o- t( ~' s; w, L: Z# S) s        dji.ux.widget.RadarWidget: l/ e1 Y" {7 D" w/ J# s
                android:layout_width="wrap_content"
    , t( c& \4 {' F8 l2 C            android:layout_height="wrap_content"
    4 i+ g+ f/ t; z+ B& o            android:layout_centerInParent="true"/>
    % J- m. d" B( u0 h! Z7 A: T    RelativeLayout>$ x! D. _! {4 A" U1 x- `% b
        6 I1 N  I) E' @
        LinearLayout
    2 g" t1 {4 H+ i# J: D        android:id="@+id/TakeOffReturnPanel": {. J3 F; O/ b# L. H! u. @& h
            android:layout_width="40dp"
    " M6 R4 U4 i) E! _1 u        android:layout_height="wrap_content". v. u5 H9 o% R9 `1 o# O/ @
            android:layout_marginLeft="12dp"- _' J$ s7 W: i  R
            android:layout_marginBottom="4dp"
    7 p6 B1 ]9 p/ G9 A# ?( A        android:layout_marginTop="50dp"
    4 P3 T; t1 f  p9 i: h, ~* {        android:orientation="vertical"
    % L" }/ ]. L0 O& M4 @        android:gravity="center">
    ! ~! ]. ?! B  F! \+ D: S        ImageView
    3 [- {* M9 F& N            android:id="@+id/img_show_back"1 i: p  B( K/ B0 u2 ]$ E+ O: v
                android:layout_width="match_parent"- V+ \( i4 v7 }  y( N. ~1 r
                android:layout_height="38dp"( I' E8 \4 {8 ^: n- P
                android:src="@mipmap/ic_back_36dp"0 a  h! K, u, u
                android:layout_marginBottom="10dp">ImageView>
    8 T( i: {8 ?. _3 u1 ]        dji.ux.widget.TakeOffWidget, U3 C9 ^$ R& V* L% {" ?( ?4 k3 d) r
                android:layout_width="40dp", ^: p2 @# b; O0 q. E  d* S
                android:layout_height="40dp"
    / k# Z1 j$ f: _0 t            android:layout_marginBottom="5dp" />
    9 r1 \  H+ f3 f        dji.ux.widget.ReturnHomeWidget: a; T- Q) D/ e/ K/ v& D. T' X
                android:layout_width="40dp"
    . H5 T( n/ A1 A7 v* p            android:layout_height="40dp"+ p2 m; I" `7 f# Y- V9 Z4 I1 f
                android:layout_marginTop="5dp"
    . J6 n! s, `% Y- d* w4 ^$ z2 k            android:layout_marginBottom="5dp"/>; O- {/ B- `( {% P
            ImageView8 \: H+ m+ U8 d. p3 q. G
                android:id="@+id/img_live"
    6 f* k3 X: Z# K) `6 Z            android:layout_width="35dp"5 C8 s& u6 t4 L0 U- F( _0 K
                android:layout_height="35dp"
      J: x# J, i0 a* S4 B/ u            android:layout_marginTop="5dp"9 g$ G+ W& P- s% m5 U6 J5 y# v
                android:layout_marginBottom="5dp"6 ?9 N& N  y/ W/ s' _
                android:src="@mipmap/ic_live_write_36dp">ImageView>: L' k8 Z0 b. @2 v; b1 Y
        LinearLayout>
    $ k" T* S1 o/ ~: y  E& D    FrameLayout. u) ]7 B2 G& f# v+ s, _7 ~
            android:layout_width="150dp"5 s1 Q$ g; I3 F
            android:layout_height="100dp"
    ' Y! ~6 M* c3 e8 q        android:id="@+id/secondary_video_view"4 h4 _; M/ Y2 U' h' S" X
            android:layout_marginLeft="12dp"
    : L8 q3 ]% Y# I$ b        android:layout_marginBottom="7dp"
    . I" T) f0 H$ G4 e+ `        android:layout_marginTop="50dp"7 n8 ?1 \/ m( R* u6 Q+ f
            android:layout_alignParentLeft="true"2 H8 D, M3 D5 X. i( @, B
            android:layout_below="@+id/TakeOffReturnPanel"% ~) S. p" s8 m1 m
            android:background="@color/black">
    ( \, T+ P& O8 m( W        dji.ux.widget.FPVWidget
    " y3 M+ {% A9 P; Y            android:id="@+id/secondary_fpv_widget"5 w- o4 i' L  ~4 X
                android:layout_width="match_parent") u2 a. X7 S# f8 E4 V( d3 j
                android:layout_height="match_parent"
    7 o. J  M8 q8 h. A, x4 s% n8 x            custom:sourceCameraNameVisibility="false"
    . d2 ~& R8 w: O9 k8 E1 `5 F, k            custom:videoSource="secondary"/>8 u' r2 K1 l0 Z( |
        FrameLayout>8 g! F# \: T- @6 ]/ f4 a
        dji.ux.workflow.CompassCalibratingWorkFlow
    ( V" [5 a3 B8 g5 `8 P& v$ K        android:layout_width="match_parent"
    - i8 [  W7 i8 N; |& U% u        android:layout_height="match_parent"/>: S3 Y, m. i$ V' D( G
        dji.ux.workflow.CameraSensorCleaningWorkFlow- J$ L4 ]! ~7 ]9 `$ t6 b* o! t+ Z
            android:layout_width="match_parent"' _+ i( H% ~9 s- u1 P" @
            android:layout_height="match_parent"/>
    ! V5 W6 w" p/ z& S    dji.ux.widget.RemainingFlightTimeWidget8 H  f: |+ ^( I/ ~1 Z  z% Z" Y
            android:layout_alignParentTop="true"9 W( Q. H  V+ k# R; e
            android:layout_marginTop="18dp"
    0 U. B2 Z' S) D& i9 u) B+ Q        android:layout_width="match_parent", V; s/ z0 k  [
            android:id="@+id/remaining_flight_time"
    * m" k, u: X& w6 _0 F+ l        android:background="@color/transparent"
    / I; E1 S9 v  ?+ I! G        android:layout_height="20dp"/>
    , D7 z3 X3 I" e) M  m# Z    LinearLayout0 b9 q& q# [+ Q2 z: F# v8 W
            android:id="@+id/camera") n. a2 Y( z: C) `0 r- c
            android:layout_alignParentRight="true"6 b  T7 ^+ |' z" _3 ?
            android:layout_width="wrap_content"
    8 o& Y# F+ n! R/ Q" O1 ?        android:layout_height="wrap_content"
    " j* H! `0 M5 Y" `0 ]  G& l! @- r        android:layout_below="@+id/signal": m1 @) ]- U3 W( e2 R0 R
            android:layout_marginTop="15dp"5 E8 d' H" I' _- I; [  ~3 w3 E% W5 H
            android:background="@color/dark_gray"1 O' q  u$ f1 S7 ]
            android:orientation="horizontal">3 h( M* X5 ?& R6 l, Q' n7 H
            dji.ux.widget.config.CameraConfigISOAndEIWidget7 o. t. `4 p4 x/ P  q  R" ?
                android:layout_width="50dp"* ^- F" [9 H5 r- F
                android:layout_height="25dp"/>; C8 t& W3 X- c1 _
            dji.ux.widget.config.CameraConfigShutterWidget' z* I. d7 h' p) U
                android:layout_width="50dp"2 ^* x1 Y. r% ~; L8 ^# d
                android:layout_height="25dp"/>
    1 B5 y, O. e3 c( v2 s6 b        dji.ux.widget.config.CameraConfigApertureWidget
    8 \5 |$ ~  z; Z! L. k            android:layout_width="50dp". a- S7 k- a  _- W; z6 V: _
                android:layout_height="25dp"/>
    9 b5 J0 z) Q& j' M6 Q4 V5 A2 ?        dji.ux.widget.config.CameraConfigEVWidget
    % e5 q$ C# x/ e) n            android:layout_width="50dp"
    0 x- r9 J! {5 s8 _$ r: }7 S# S            android:layout_height="25dp"/>$ z3 I: d! r8 v/ |( u; R, n+ }6 B
            dji.ux.widget.config.CameraConfigWBWidget
    & d$ [; X' r! d# w. ]1 ]# [8 Y            android:layout_width="60dp"
    8 w( S. h2 @( g( V/ ]) R            android:layout_height="25dp"/>
    - h6 n1 G  {) x! m3 n  s! U        dji.ux.widget.config.CameraConfigStorageWidget
    $ g/ N& |3 n: I. w8 C1 w) V" p. ~, Q            android:layout_width="108dp"
      c& y6 Z4 t- R            android:layout_height="25dp"/>4 d0 e+ Z$ x3 z' j. l0 b0 @7 m
            dji.ux.widget.config.CameraConfigSSDWidget, @7 A, L, l/ h9 {6 `$ o& e0 j) k
                android:layout_width="125dp"
    ' x3 O3 e/ x# Q1 o2 n+ c3 Y4 r            android:layout_height="25dp"/>5 l% Q3 K* |$ Q5 S
        LinearLayout>2 {' L) ~5 S9 L; e7 W8 \: Z
        LinearLayout- L' Q& ]2 w4 f% u! g$ L# T4 u
            android:id="@+id/camera2"* G8 s9 l: \4 Q6 y- v: A+ _
            android:layout_width="wrap_content"2 o4 j0 n: B* Z" O
            android:layout_height="wrap_content"' ?7 H) s5 l/ Z2 z
            android:layout_marginTop="5dp"+ w; a1 @3 p" L( c2 r7 J: h
            android:layout_below="@id/camera"
    1 Y5 l5 F* r3 \6 a3 g        android:layout_toLeftOf="@+id/CameraCapturePanel"7 z& a: ^( {* P, z
            android:background="@color/dark_gray"3 L  ~- R0 J* m" x  f) |0 \
            android:orientation="horizontal">- P% m0 M( s1 M5 y# ^& u
            dji.ux.widget.SpeakerWidget
    4 t3 Y" b8 R6 {' N- p* J3 Z# X            android:layout_width="35dp"( O, p8 f# _, ^/ k* `* p# u6 Z
                android:layout_height="35dp"/>
    9 T% c" W" s7 z% M        dji.ux.widget.AutoExposureLockWidget
    7 [7 M  B. }& V9 W3 l5 S- G0 C            android:layout_width="35dp"
    " y* E' w  {) T! Q. a- w* T            android:layout_height="35dp"/>4 w" v' i7 z7 k  u  W
            dji.ux.widget.FocusModeWidget
    & B0 a+ [3 n# E            android:layout_width="35dp"6 N$ u, W- B3 w; N- Y
                android:layout_height="35dp"/>7 P8 ?+ Y: Q: \  Z6 x/ G
            dji.ux.widget.FocusExposureSwitchWidget$ ~- G& r- p$ R: K' \
                android:layout_width="35dp"
    $ H1 r1 p' ]' I2 A1 n            android:layout_height="35dp"/>' @, o8 i% o' j; Y
            dji.ux.widget.BeaconWidget: U9 x$ W/ w0 C1 u( f
                android:layout_width="35dp"* Q) \' F. v4 s9 T
                android:layout_height="35dp"/>4 l% x# w: a  r( L/ ^4 y4 W
            dji.ux.widget.SpotlightWidget- n3 X% ^- J) r8 B8 b3 w
                android:layout_width="35dp"
    # |3 p2 |9 B0 B$ g2 v: A            android:layout_height="35dp"/>
      f2 `6 }+ V# S. I; [( c3 H" _        dji.ux.widget.AccessLockerWidget
    ) d! r" Z. v: e$ L2 A3 X5 a% S, Y# h            android:layout_width="35dp"3 e+ m# }9 Z$ C* }: a; S  N
                android:layout_height="35dp"/>
    # c- b! _5 b& _% L0 D. G    LinearLayout>
    ; [( g* P" w$ u* b$ @    dji.ux.widget.ManualFocusWidget9 ~; q' t; O1 n% K4 [( C, c
            android:layout_alignTop="@+id/camera2"  g( I' x2 d+ R. d. \/ [- b
            android:layout_toLeftOf="@+id/camera2"3 L* d5 g" N1 D
            android:layout_width="50dp"
    1 a4 q8 F, x1 C3 c. b  y$ Z/ g        android:layout_height="210dp"
    ' ]$ l3 X9 W' W% s# J/ x1 \" N. J        tools:ignore="RtlHardcoded"/>. F0 P' A% X( [/ t! U' Q  w% K
        dji.ux.widget.MapWidget
    8 G' ~( P' B4 U: L9 D* J7 b1 j: e        android:id="@+id/map_widget"
    " u" V& x' M8 O. _        android:layout_width="150dp"5 _( X2 B, f; O3 ?* h
            android:layout_height="100dp"5 K  x  r- h* F+ X
            android:layout_marginRight="12dp"/ }0 y1 `) w1 P) o
            android:layout_marginBottom="12dp"! L. k* v: r5 h8 S8 B+ w  p
            android:layout_alignParentRight="true"+ Z8 \: r3 |& F4 ^
            android:layout_alignParentBottom="true"/>
    + I& l5 [" d" u$ N   
    ( j+ V7 j5 V' y    dji.ux.widget.controls.CameraControlsWidget, @" Y+ t+ K4 X9 d. l2 M) q) n- O
            android:id="@+id/CameraCapturePanel"
    0 j  Y% C; r9 |3 i( p        android:layout_alignParentRight="true". @  Z) r" Q9 V5 [6 n! ~8 K
            android:layout_below="@id/camera"- ^- [9 `! W5 n& z( h
            android:layout_width="50dp"# z) w6 T2 }: s8 ^# N
            android:layout_height="213dp"1 \# R+ L$ Y( Z  R; a
            android:layout_marginTop="5dp", u5 m6 o) w" c$ R- d6 I" k0 z
            tools:ignore="RtlHardcoded"/>
    " }4 @, @8 U! S5 }9 I1 c( K    0 J% W9 q* c, h5 c/ x* c. R- ^
        LinearLayout9 E+ p8 t! D( n* r; Y5 ]% ^
            android:id="@+id/signal"2 H3 `' u, C, Y4 J0 z2 l. ?. z/ y
            android:layout_width="match_parent"" a$ o3 P8 B- b7 g# Y9 v9 W
            android:layout_height="25dp"
    & F/ C6 f& k/ l+ n) J- e        android:background="@color/dark_gray"
    8 }  u& S5 c9 p) |$ D: J        android:orientation="horizontal">
    / L3 |8 J  s! ?' p8 T        dji.ux.widget.PreFlightStatusWidget
    # e/ N4 L/ H) F) a- c  c4 U* J            android:layout_width="180dp"& O/ \, R4 Z0 X1 m+ l. e& v4 Z
                android:layout_height="25dp"/>
    3 H5 a9 T! b  \: P4 w$ z8 }& U        dji.ux.widget.FlightModeWidget
    % j4 m+ S: E! G  Y- d            android:layout_width="103dp"
    . F+ B3 S3 A  ?            android:layout_height="22dp"/>
    # x: h$ j: F) z# a) z        dji.ux.widget.GPSSignalWidget, n; P& l8 q6 N' g- ?9 L. C* a
                android:layout_width="44dp"
    1 s" S0 @3 S% ~' _3 C; _            android:layout_height="22dp"/>2 W7 s1 {) ]3 n" q6 y* p
            dji.ux.widget.VisionWidget
    2 A4 `2 r& G6 \  g# w            android:layout_width="22dp": i, J6 x  g5 F  G
                android:layout_height="22dp"/>( r* q7 D* h) ?% t$ B
            dji.ux.widget.RemoteControlSignalWidget3 B) |: p8 Z/ `* c& b
                android:layout_width="38dp"
    0 m/ P  `2 B$ Z/ z$ U: Z  {  C            android:layout_height="22dp"/>
    2 A! H7 w, L; V3 ~$ P        dji.ux.widget.VideoSignalWidget5 [# o4 ~; J; O% D
                android:layout_width="38dp"
    ) N* }* _% S. ~9 e! Q+ |# K* B7 @            android:layout_height="22dp"/>4 U  P; T0 y9 E; O0 Z" k
            dji.ux.widget.WiFiSignalWidget% m8 [! ^* r# a. d% z# R& w
                android:layout_width="32dp"
    ' W' G( F$ V/ w; Q            android:layout_height="25dp"/>/ @2 l$ O4 e6 c& I( [! E% P
            dji.ux.widget.BatteryWidget+ F: H! h* r6 d: f
                android:layout_width="96dp", Y! A' p8 L6 V
                android:layout_height="22dp"
    $ B2 r  F5 F( x4 i. x) }            custom:excludeView="singleVoltage"/>
    + O# A! r2 |7 C' M        dji.ux.widget.ConnectionWidget
    ! u) y6 n) a' ]/ v: F% n* Z            android:layout_marginTop="3dp"( v9 Q5 c& q- a( J
                android:layout_width="18dp"
    ! ^1 @* l: U  B% A            android:layout_height="18dp"/>
    3 ~& F" t* h8 k4 D8 t' f    LinearLayout>2 O+ j% f' `) r" t$ S
        LinearLayout( m- U; V/ H! g- l; z3 ?
            android:id="@+id/dashboard_widget"& _% N7 Z9 e0 u3 j7 U. U7 W; Z( f; g
            android:layout_width="match_parent"
    0 v: e- {. N! v+ Y: N% e        android:layout_height="wrap_content"
    ; a% {. e' ^" u( L2 q        android:layout_alignParentBottom="true"
    1 f+ D% ]/ T7 }- @* U" q9 E8 d        android:orientation="horizontal"
    ; j/ a* P# V0 N8 h/ k3 y" y        android:padding="12dp">9 ?# D3 v! _& a, ?9 F# [
            dji.ux.widget.dashboard.DashboardWidget& G3 q( N+ X/ t" ^7 p' k
                android:id="@+id/Compass"8 ^3 w/ ?( m* V2 k; p% h
                android:layout_width="405dp"
    ! A* y. y6 M- s5 T) m( Y            android:layout_height="91dp"
    ; j# ]5 \2 W* _4 I            android:layout_marginRight="12dp"6 w. A! h) O& I) H
                tools:ignore="RtlHardcoded" />. V$ n3 f9 R- v/ e! w3 P- h; w; I, l3 V7 [
        LinearLayout>( F7 V7 X( _- j1 L1 [, B
    " |" Y" W: `% e5 b+ I

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

    sz1bbeuylep64015956024.jpg

    sz1bbeuylep64015956024.jpg
    5 k6 B0 r  i+ k+ T
    上面的工作完成后就可以在无人且宽阔的地方进行无人机飞行了。7 r1 I( ^$ Y1 d" ^5 W9 |
    4
    " f9 J$ R. n; K; j; W8 z! X( M多媒体资源的操作, W% W% U. w$ v5 L
    多媒体文件操作,主要为多媒体文件的获取、查看、删除、下载的操作
    5 p5 T) O2 S3 j  k同样创建多媒体功能文件FileManagementActivity及activity_file_management.xml/ c( P' X3 M- X/ A0 p$ w& i
    activity_file_management.xml, [" W0 k1 B7 W5 w* ~) H+ X9 L
    LinearLayout xmlns:android="http://schemas.android.com/apk/res/android", V$ ^1 c" v" N0 g. w) b
        xmlns:tools="http://schemas.android.com/tools"9 i0 n* I/ v" U" d4 `, A& g
        android:layout_width="match_parent"8 J$ X! k4 v8 R' K) n+ B
        android:layout_height="match_parent"
    + s% }8 W. ~2 O. I1 C    xmlns:custom="http://schemas.android.com/apk/res-auto"1 d# b- D$ e6 O/ R# N
        tools:context=".ui.FileManagementActivity"2 z2 d9 Y6 `, p8 S4 j& q7 {
        android:orientation="vertical"
    3 @/ C, t* {# i2 ?2 U1 \( d" @5 C    android:background="@drawable/shape_corner_eight">& Q$ j- T, t% P8 D8 e8 v
        include layout="@layout/activity_toolbar"
    7 \+ h5 n) N5 S! @        android:id="@+id/layout_file">include>( {! m' _: Y4 m- j
        LinearLayout
    1 b5 B. D. S1 ^" ]# Q        android:layout_width="match_parent"
    7 P6 a  ~) x. p1 x/ {% W/ M        android:layout_height="match_parent"/ ~2 P' t: W- n' u  Q; i
            android:orientation="horizontal">
    4 w3 k0 N* f, i& _9 |3 L        LinearLayout4 [: b7 F" |/ L0 }' J
                android:layout_width="250dp"
    1 B" W2 K* q) ^4 ~  D            android:layout_height="match_parent"7 ]. c  E- F8 B6 j" T7 o; f/ B- h/ W
                android:orientation="vertical"
    ; q8 V1 j1 Y5 o" w  z& V            android:layout_marginLeft="15dp"
      b' L  m+ J( m. K6 F! w. e$ ~            android:layout_marginRight="15dp">& g, ]2 Y$ H; p8 a6 H
                RadioGroup
    : j  B" h+ G& w$ `1 P1 x' w8 p                android:id="@+id/rg_file_management"
    2 ]2 S8 V. o2 |9 r7 v                android:layout_width="match_parent"
    % E3 V! o* L" Z9 s2 |0 f8 c( d3 [                android:layout_height="40dp"
    ( ~3 Q" S6 _/ K) x+ M                android:orientation="horizontal"/ J9 s2 J* E. q
                    android:background="#2B3141"/ U/ K" J0 M" y+ H. A6 Q9 k5 q
                    android:gravity="center">! [  I! ^6 ]% _0 v
                    RadioButton" C4 F7 W3 f) v0 c3 E! w1 H
                        android:id="@+id/rb_file_all"
    ! H0 _( J, ~( f) k                    android:layout_width="0dp"' n. O1 J1 u/ d' j- W( ]+ G
                        android:layout_height="match_parent": b9 [) Z5 r  H$ w% u$ ~4 ]2 v
                        android:layout_weight="1"( D* ], A9 @: b( F; F0 |; H' b
                        android:button="@null"# z, G& `; x4 @. S8 U( S2 T
                        android:checked="true"% e' R$ F# W( w7 R9 S
                        android:gravity="center"
    * C7 y' F4 l: d0 Y2 U( ]. N( j                    android:text="全部"
    % a/ S# J5 V( z- N& B* X                    android:textColor="@drawable/nav_item_color_selector"; G8 [; ^# u' G. b# W+ a% v) Q
                        android:textSize="18sp"
    $ k' R1 ~: u% g" G1 r5 Q                    tools:ignore="TouchTargetSizeCheck">RadioButton>
    . i9 {5 o. i3 q! H& j& H, K                RadioButton
    3 ^/ d- E% j9 Y+ z                    android:id="@+id/rb_file_photo"
    - Z+ D) v6 f+ Q' z. o. V                    android:layout_width="0dp"; \# o+ z0 Z8 Y/ n1 B3 q2 H0 E
                        android:layout_height="match_parent"
      ^: ?: E9 i! k, _4 N                    android:layout_weight="1". V3 D0 H( q' l
                        android:button="@null"
    3 H# b  L2 t4 q5 |  C                    android:gravity="center"
    $ Y2 ~" N9 E% E7 m. N. ]% c+ h# @7 I                    android:text="照片"
    ! `# F# }7 \2 `/ e1 S( f                    android:textColor="@drawable/nav_item_color_selector"2 Q4 A0 u4 d- X* @) J
                        android:textSize="18sp"; x& p+ Q2 Y4 L1 K5 S
                        tools:ignore="TouchTargetSizeCheck">RadioButton>, t0 H$ ^* v3 Y* p2 K( W& \/ E* ?
                    RadioButton. y4 F+ R, j; a" N4 J6 Y
                        android:id="@+id/rb_file_video"/ F1 ?7 S+ i0 k( y
                        android:layout_width="0dp"
    2 Z5 U) `  E6 @  B1 k) b' s                    android:layout_height="match_parent"7 [0 t7 d, z& b
                        android:layout_weight="1"1 H; Y0 I" V0 \6 Q8 O3 X: h
                        android:button="@null"
    / @. |* w, ~4 g( a; ^7 O                    android:gravity="center"
    - M; a" H1 C) G9 w4 ~& A* B                    android:text="视频"
    : ^& }; w$ _" {& C: |                    android:textColor="@drawable/nav_item_color_selector"
    ' a4 [" z' q, q/ N                    android:textSize="18sp"
    7 `4 R' y" t7 P5 U7 k                    tools:ignore="TouchTargetSizeCheck">RadioButton>
    ! g2 y8 y7 |9 E' ?: d% ^, B- u            RadioGroup>7 V' F) K& e2 L$ a) v
                androidx.recyclerview.widget.RecyclerView
    8 u4 H$ `) c* t                android:id="@+id/rv_file_management"4 D) |( I. _& e: Z( m
                    android:layout_width="match_parent"
    $ ?2 k4 L. A; v8 O+ M9 I% M                android:layout_height="0dp"7 f/ e* b+ u1 L, K1 @7 c
                    android:layout_weight="1"4 t$ i  U0 z9 Y* C
                    android:layout_marginTop="10dp">androidx.recyclerview.widget.RecyclerView>+ e1 j2 X6 ?0 P+ ~" \
            LinearLayout>
    ' X0 f0 |: A9 F3 J7 C        RelativeLayout* Y: z) j% J8 r. }' I, m
                android:layout_width="0dp"
    , O4 L: {8 M! ^            android:layout_weight="2"
    ' M0 w6 J. W% r. T5 I" |            android:layout_height="match_parent">
    5 |( M8 N" e7 O0 U$ r6 ^4 o' @- O, Y            RelativeLayout6 g0 H+ ?; P+ W7 C$ @
                    android:layout_width="match_parent"$ V4 i# p% x' _) D7 [- t* n' U4 ?( e4 u
                    android:layout_height="match_parent">
    4 S7 y+ L, `' ^6 y& K7 u$ y- `                dji.ux.widget.FPVWidget! i: J  b8 ^7 K$ a( X
                        android:id="@+id/FPVWidget"
    9 z8 m# p' Z$ g9 N+ F6 e                    android:layout_width="match_parent"
    8 X: A5 a7 e* s4 U' f1 D: n$ F                    android:layout_height="match_parent"
    & p7 |1 y" e4 ^5 A                    android:layout_centerInParent="true"8 ~7 ?0 I6 T5 F) Q+ [2 z
                        custom:sourceCameraNameVisibility="false" />2 H: S# z; v5 C& P; F/ t" Y9 Z2 r4 x
                RelativeLayout>. C' W4 d9 Y4 u( k
                ImageView
    1 v8 m- R6 c* a3 K                android:id="@+id/img_show"
    ' [: H- r  M- E) i0 @5 U/ L; n. y( h                android:layout_width="match_parent"
    7 G$ y4 W4 h, [( V6 d! D/ b                android:layout_height="match_parent"
    . z& h! k2 I9 J5 g& r                android:scaleType="fitXY"
    * q8 n2 d, j3 `2 H/ B1 }7 M, ~                android:visibility="invisible">ImageView>
    3 L7 w* _7 `/ v/ C& V, g            LinearLayout
    8 q6 K; k3 M4 x                android:id="@+id/ll_video_btn"  ~$ [9 e2 b9 b2 c3 k$ ~9 T
                    android:layout_width="match_parent"$ a" q+ l! P: i. B& T, [
                    android:layout_height="50dp"
    1 C+ P, ?( y" V. E: ?5 t" V2 |                android:orientation="horizontal"" P% }/ [% }) D  \: Z" v
                    android:gravity="center"
    # @" ?# l( A" p2 ?! q! S                android:layout_marginBottom="15dp"
    - E$ e! a  V6 Z. l5 d                android:layout_alignParentBottom="true"
    # F; Q3 r7 g1 W0 I% H                android:visibility="gone">8 y4 T1 [( }) f! L& t2 H
                    ImageView
    * l# U1 x9 H; E                    android:id="@+id/img_video_pause"* }  c: m; E  @* s) f+ q
                        android:layout_width="35dp"
    / b7 n. N1 l% F( I# F                    android:layout_height="35dp"& J6 F& o3 P- x1 a
                        android:src="@drawable/background_stop_selector">ImageView>7 |& ?6 x" L+ t- ^# k
                    ImageView
    " d4 F9 e8 p6 s7 k+ r. B                    android:id="@+id/img_video_play"
    6 e) o! q5 \! j) ^! H                    android:layout_width="45dp"4 r$ N. W* |  P  t- I( K
                        android:layout_height="45dp"0 C/ y$ S% R# Z. H6 \7 ?
                        android:layout_marginLeft="20dp"6 Z3 B0 X: `6 @' M- Q7 Y9 U
                        android:src="@drawable/background_palyer_selector">ImageView>& `( l  S; m3 \; e) h& c
                    ImageView
    2 _+ U7 D, q" u' ]/ V2 t                    android:id="@+id/img_video_stop"
    ! ~" W! N% U) @6 G                    android:layout_width="35dp"0 r4 Q( k+ d) N& O( s
                        android:layout_height="35dp"
    ! w: r: v' D! q- W+ |                    android:layout_marginLeft="20dp"* }( z+ p0 ?7 ]0 H% W  m
                        android:src="@mipmap/ic_reset_36dp">ImageView>
    , ~) I  R# L' h0 z' ?, X- s: x            LinearLayout>
    0 B- z* i% f/ \5 t: i! V7 y        RelativeLayout>) @4 V. k, ]0 y
        LinearLayout>
      P  x% J) O. W) k+ X+ V6 ~, d$ l3 vLinearLayout>
    6 P3 m0 Q* ]7 f! A0 n8 O9 V8 `FileManagementActivity
    . C; G% F% H3 h@Layout(R.layout.activity_file_management)
    + F/ j6 r# A1 X  K- Mpublic class FileManagementActivity extends BaseActivity implements View.OnClickListener {
    $ g8 v- O% H4 C/ b7 h1 A7 D6 T    private static final String TAG = FileManagementActivity.class.getName();
    * M& c% }; \' h% ?    @BindView(R.id.layout_file)
    % q& b% T3 B* Q    View mViewLayoutToolbar;) M/ ]2 Y; h5 u2 l  P
        @BindView(R.id.tv_toolbar_title)
    + x  X/ l. T- o- ~( W8 @2 b- i5 {    TextView mTextViewToolbarTitle;
    % V2 z0 z8 [4 s    @BindView(R.id.ll_file)4 W2 T8 ]% D6 V2 X( ]
        LinearLayout mLinearLayout;
    ( ^5 @: F3 F" [/ X# t    @BindView(R.id.rg_file_management)) z1 P- [& |+ B' R6 x% G* w
        RadioGroup mRadioGroup;. l- j. r" [% I; k  P) Z
        @BindView(R.id.rv_file_management)
    / Q/ m# K$ Z( B0 h: P# @    RecyclerView mRecyclerView;
    % }( F1 I  W1 ^4 S4 J5 _    @BindView(R.id.img_show)
    * M4 s2 o$ C) @( n, s- `4 A    ImageView mImageView;8 |/ b  ]4 @( C! E/ E* n% o! c; D
        @BindView(R.id.ll_video_btn)
    1 ^! v. g$ E& X" e# @+ I    LinearLayout mLinearLayoutVideo;
    ' s$ c  Y+ G6 b/ R8 t    @BindView(R.id.img_video_play)5 U' f( C+ X5 Q: C/ m2 t5 R
        ImageView mImageViewVideoPlay;$ e$ E4 l% e  E9 H, ^
        @BindView(R.id.img_video_pause)7 r9 O" H' B3 |) C; D' W
        ImageView mImageViewVideoPause;" D  g8 |4 H. _# W) x, n
        private FileListAdapter mListAdapter;% a4 b; K. V2 @% l4 M+ r
        private List List = new ArrayList();
    1 n; P1 p" E4 j# }    private List mediaFileList = new ArrayList();
    . A- a+ s$ _( q; W9 G7 I, ?! t; L    private MediaManager mMediaManager;
    & p3 f! T# G9 m" x, Z1 W    private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;( S% x- _! Q+ x/ O3 Q, y- ^& H
        private MediaManager.VideoPlaybackState state;
    / m4 C. ~5 H8 I; k$ d  a    private ProgressDialog mLoadingDialog;
      j) x! M7 B' W) }9 p5 |* ]5 |    private ProgressDialog mDownloadDialog;
    0 v4 G- d. w0 G' M2 w. K    private FetchMediaTaskScheduler scheduler;
    ' Z1 g7 f! Y+ P1 U  {% ?+ `4 L4 }+ @    private int lastClickViewIndex = -1;
    & J( W/ r3 M9 c$ j6 y9 \5 Y    private int currentProgress = -1;
    ( b& D4 \4 K8 b$ u' j+ U* F/ ~+ X    private String SavePath = "";4 `+ l, i) w  {7 ?0 U# N* E% s
        private View lastClickView;
    ! X: |2 {  O& w9 P    private boolean isResume = false;
    3 u3 A  H9 G/ @2 N6 ]) ?    private SFTPUtils sftp;5 }' F7 m& a/ p* k
        private SettingsDefinitions.StorageLocation storageLocation;
    + F6 X% U) d( n& v7 q$ i    @Override5 m! O' z/ C, r% {# R
        public void initViews() {3 k3 }+ x6 f: a2 |5 w/ `7 S8 ]( t
            mLinearLayout.setVisibility(View.VISIBLE);# g# p# L' e4 e! W! m
            mTextViewToolbarTitle.setText("文件管理");
    - e4 H3 |' v: y4 K        mImageViewVideoPlay.setEnabled(true);
    ; w2 L/ J8 b  @  p        mImageViewVideoPause.setEnabled(false);
    + h( c% G3 h+ m0 P% L        mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {( l7 \  w: B3 T3 y: t7 g- A
                @Override8 x( b% }8 Y% B" P1 e) t
                public void onCheckedChanged(RadioGroup group, int checkedId) {
    ( C3 y2 v9 v$ x9 p/ N: A                List.clear();( u9 g9 B8 I' w2 F  V, V0 h
                    mediaFileList.clear();
    ; p: d4 j# ^0 m' m7 ~! B! N                switch (checkedId) {
    : l4 G( n1 q: a, v8 A                    case R.id.rb_file_all:& ^, v/ O+ Q6 W
                            getFileList(0);& S8 j1 @' A# W( J! O5 S
                            mListAdapter.notifyDataSetChanged();+ B1 b1 B' m' o# d# x% G; ]
                            break;* U; I5 W( b5 K8 r, s
                        case R.id.rb_file_photo:: U: @8 ^) }7 c. D  j
                            getFileList(1);9 S$ k; [6 a) [+ T
                            mListAdapter.notifyDataSetChanged();
    8 I2 l) s5 y) ^7 v/ l6 A/ [                        break;
    ' O: i8 B  ?# G                    case R.id.rb_file_video:( `" @% ^  Q* s" l+ \! k+ c( K" K
                            getFileList(2);
    ! l8 y' L0 N7 Q0 h3 i4 b- X                        mListAdapter.notifyDataSetChanged();
    ) N+ S- S5 I6 X3 O- s7 }6 v! X                        break;
    7 V! W2 o: d1 \  E+ I                }; P8 B5 b. b  D1 o
                }
    # M: U+ A: ?$ n& w, q        });' j# l. a9 u# v
            LinearLayoutManager layoutManager = new LinearLayoutManager(FileManagementActivity.this, RecyclerView.VERTICAL, false);  `  y+ d' v+ b* D& c
            mRecyclerView.setLayoutManager(layoutManager);
    ' w9 i7 B2 S: R6 ]  |( o# ?% B$ }        //Init FileListAdapter4 v% Q2 \* y; f, r" i
            mListAdapter = new FileListAdapter();7 c5 v& J6 j3 `: `8 E6 ~
            mRecyclerView.setAdapter(mListAdapter);. D# m7 X- |- C1 S+ M" f- h/ X
            //Init Loading Dialog( a" t  y* H. U8 J6 V7 `
            mLoadingDialog = new ProgressDialog(FileManagementActivity.this);
    5 v. J2 u- V5 ?: E: i; J% @$ R        mLoadingDialog.setMessage("请等待...");6 Z( _% J) _  a
            mLoadingDialog.setCanceledOnTouchOutside(false);
    # K$ y% x3 v$ y$ n7 i+ \8 J- d4 {        mLoadingDialog.setCancelable(false);5 a7 }; H8 G; N8 V
            //Init Download Dialog9 e5 d8 t$ M9 _5 \2 |2 p% B+ M
            mDownloadDialog = new ProgressDialog(FileManagementActivity.this);
    ; p: s+ a3 b" U. @$ }        mDownloadDialog.setTitle("下载中...");3 X1 v1 r3 D  c" Y1 w. p1 f
            mDownloadDialog.setIcon(android.R.drawable.ic_dialog_info);
    % v( e# Z3 j/ |2 C$ _9 P5 U        mDownloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    9 M, q: C8 L/ y( a' T        mDownloadDialog.setCanceledOnTouchOutside(false);
    " G" h1 H* ?& S' h0 @$ T        mDownloadDialog.setCancelable(true);
    ' r" c' f: |- {1 o  a# E8 ^        mDownloadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    , X; G; D- g  k9 D. `! |# F; y            @Override1 J* y  N6 I$ M% d( Q
                public void onCancel(DialogInterface dialog) {1 {6 @/ O' G* w
                    if (mMediaManager != null) {) ^/ S4 m# H. \3 k( W- x- z) V
                        mMediaManager.exitMediaDownloading();& W' W7 v3 B6 D" h1 Z
                    }& s% t% A$ E/ ?1 \$ D! j2 L
                }
    4 v) Q0 I' m) K5 |! z; x6 Q        });
    1 ~* N' M! f" J        sftp = new SFTPUtils("49.4.79.249","uav","uavHHch@YREC.cn");. ~! w" z' N* z6 n, V, K* }& d
            ReceiverApplication.getAircraftInstance().getCamera().setStorageStateCallBack(new StorageState.Callback() {
    ! l. v8 a( p% O# r' s            @Override" q- i3 q9 l$ f8 x9 F! r2 A" n8 w$ l) G- w2 \
                public void onUpdate(@NonNull @NotNull StorageState storageState) {
    1 Y( O* y) W9 k& S, m8 Q/ C                if(storageState.isInserted()) {: E( Y+ ?8 e3 m5 G/ R. s
                        storageLocation = SettingsDefinitions.StorageLocation.SDCARD;
    : x$ Z* [- }% N2 N                    ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, new CommonCallbacks.CompletionCallback() {
    3 P0 o! R& }. t5 j                        @Override
    / k' D+ n) r) _' ?* \* `! y5 k& H                        public void onResult(DJIError djiError) {8 n& @* Z8 Z+ v0 a
                            }% q' O# g% Q+ g( C
                        });* Y  J+ v" f% f) A; K
                    } else {
    # {" n  O  H1 R. v3 S1 I                    storageLocation = SettingsDefinitions.StorageLocation.INTERNAL_STORAGE;8 M5 w! o$ k  e5 Q
                        ReceiverApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.INTERNAL_STORAGE, new CommonCallbacks.CompletionCallback() {9 |! d* J$ \# S* O- @2 A
                            @Override1 S" E5 q: C8 U/ C
                            public void onResult(DJIError djiError) {% b% C" Q  ^7 f0 C7 v$ i- d* v
                            }
    ; O" p/ G1 z3 M2 ^7 D4 M! r3 J                    });
    / c# C' L6 `9 @4 V                }
    ' C) S; m$ X+ M            }
    - c, P7 M* V- [9 @        });2 D* R4 g  o$ J; ]- A# x- [, K
        }6 {& |, e9 J& Q/ w. I* k% N$ l
        @Override8 g6 K1 J  I  a. {1 V
        public void initDatas() {
    + S, B% d5 d# }7 _4 u2 A    }
    + I, J: ]% g$ k- o: c    @Override
    5 Z5 t9 L, @; ?6 d/ e    protected void requestData() {
    1 G- ^4 ~$ o# o. Q    }& n2 R' ?  p% m* b  S
        @Override  C8 d% k# @& n( C% ^) |0 |
        public void onComplete(String url, String jsonStr) {
    * x8 h, z" Z1 F5 a4 j        super.onComplete(url, jsonStr);
    * E1 k9 B8 O$ D        switch (url){
    ) T* }7 j5 \* _            case POST_VIDEO_INFO:
    0 O6 b! U3 h2 v                break;5 F$ Y- ^0 F& V5 c) V7 V: p( B4 O
                default:
    $ r9 W2 z: {; F% h0 _) p                getVideoJson(jsonStr);) J( L% h$ Y5 i, v) U  ]! t% y
                    break;  O7 W9 S! q& a$ t: x
            }8 W& b' }' L. c8 r* T; V
        }& C9 [# z# e7 d1 n- Z1 }7 h  `  t: i. i
        private void getVideoJson(String jsonStr) {
    ) D0 n3 N- t# m( }4 C3 Z! ^        VideoModule module = GsonUtil.GsonToBean(jsonStr,VideoModule.class);
    6 T9 o  _& L( H) w3 `1 ~" H0 i        if (module.getCode() == 200 && module.getRows().size() == 1){9 y: j+ V8 [  `# X  ^: W% K8 t
                runOnUiThread(new Runnable() {
    0 p+ z- H, ~5 |! i0 |1 F" E                @Override
    ; R# ]4 R+ e4 z. E                public void run() {
    $ r3 B) y" K/ M. i( {, M$ q4 _1 L                    UpdateFileModule fileModule = new UpdateFileModule(module.getRows().get(0).getId(),"/mnt/uavFtpFolder/"+module.getRows().get(0).getFileName());6 d2 P# `* ~5 _. }" Z7 t
                        http.getHttp(POST_VIDEO_INFO,"PUT",GsonUtil.GsonString(fileModule));& H5 Y$ ?- W4 W' k3 `, c, L3 F5 ^
                    }
    " X6 n, q% v! N! c; w  r( N            });
    + q7 j& Y4 S5 F( T& G, d        }
    & k4 T, b' W1 J6 ?% t$ a' a; x    }
    7 X5 ?) t) e6 |/ F+ x    @Override
    ! i6 z) F" |6 p" c    protected void onResume() {2 O9 |$ V8 W- }' L0 ]: R+ [) m! c+ T
            super.onResume();
    . [6 g' h# X% z, A        initMediaManager();
    $ _& v6 a8 M( ~    }
    , H& f5 [% G% n    @Override: @6 j8 ]* `4 Q& T4 `, N& [& T9 ^
        protected void onPause() {
    . m  v  `. e( F% z        super.onPause();( K* s9 N7 ~8 _: X3 J
        }- Q9 K/ ^6 M. k/ K1 g
        @Override
      B% k! |; i& X4 B$ i+ L9 U2 K    protected void onStop() {! n8 f2 L* u/ i  K
            super.onStop();. d2 q0 \) E; @1 P0 I
        }  h$ c0 e# o) D2 l. T

    $ k6 L" H, x) T6 @    @Override
    6 H' Q# G6 ?  z0 R6 I    protected void onDestroy() {
    2 p6 x1 |( |# n3 s  w        lastClickView = null;
    8 m, z- M/ B9 p; z) u        if (mMediaManager != null) {  q6 N& y- r" ~, a# k; |& C0 B
                mMediaManager.stop(null);, F' Q  S1 v' D  ~9 v% G1 Q3 }1 O# ~
                mMediaManager.removeFileListStateCallback(this.updateFileListStateListener);
    % h- t2 K% {) F, P  I            mMediaManager.exitMediaDownloading();  @: d3 Y' [3 X% G8 v2 n" I
                if (scheduler != null) {8 s; B6 k; ?1 E, ^
                    scheduler.removeAllTasks();7 c* f4 h, g( A! N* k/ n+ b
                }
    + m" ]- \# c* X6 ]        }
    0 i2 O! N+ p% n  p        if (isMavicAir2() || isM300()) {
    % C5 i1 \: |  ^. c+ J            if (ReceiverApplication.getCameraInstance() != null) {
    / r2 `3 d& F9 S                ReceiverApplication.getCameraInstance().exitPlayback(djiError -> {4 p, Q* t2 j- Z% L. g( D" [5 X
                        if (djiError != null) {
    ' k# M' ]6 V+ ^9 E/ R( W. ]) m' ]                        ReceiverApplication.getCameraInstance().setFlatMode(SettingsDefinitions.FlatCameraMode.PHOTO_SINGLE, djiError1 -> {  i- T+ b/ M' k
                                if (djiError1 != null) {
    / P/ o3 l' }5 }                                showToasts("设置单张拍照模式失败. " + djiError1.getDescription());
    . L" V+ I6 E; m9 t                            }! @( ^9 H1 z2 ?4 a/ i7 a
                            });& n! w$ r% Q/ A+ G4 X
                        }
    4 S1 }! E8 j' \# B8 t* N                });
    5 {) x8 R9 p) i: `# B7 Q/ p# V            } else {
    9 {: }$ K+ L  ?+ {                ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, djiError -> {5 ^- s7 H( R# a
                        if (djiError != null) {
    6 o# I- S5 P, A& g7 H9 a. [* ?                        showToasts("设置拍照模式失败. " + djiError.getDescription());* a2 h5 Q  q$ H# u* D# G+ a9 G9 w
                        }- X5 O# V, }+ u1 D, B
                    });  i7 |. U% n& c' S
                }
    4 _0 V- ?& \9 g* F$ u; m7 m3 g        }
    / T5 }3 ^- F( T. `+ J        if (mediaFileList != null) {
    ( S/ g( g# a+ B  B9 i3 q1 ]- o            //            List.clear();) n2 P+ ~. `! a8 l; ]: }
                mediaFileList.clear();+ z9 F% L5 x8 Y7 [0 {4 ]
            }
    / Y1 W# i7 g4 I! _! e: ?+ w        super.onDestroy();
    6 |+ E* N9 A7 @  P5 U    }
    ( p; w) b) I9 y0 T    private void showProgressDialogs() {# x' F7 B! h2 M; ^2 s( A
            runOnUiThread(new Runnable() {
    % K2 h( K1 M$ O) w2 `  c            public void run() {. U$ w$ R# M. H# `' y: q' E
                    if (mLoadingDialog != null) {
    & a4 u) f: \9 ~                    mLoadingDialog.show();
    0 p% `9 D7 h( ?) d5 M) B7 D2 ~                }
    3 c2 c# P. r# h0 h            }
    3 H& @2 V) e) x5 a  v& d5 [        });" {3 b% S0 Z* Q: [
        }
    " u0 w  z+ I; R$ j- m    private void hideProgressDialog() {+ L3 _9 v& l# K8 @( N/ ^- F) R
            runOnUiThread(new Runnable() {3 A; b6 g/ \& x' `2 o6 z
                public void run() {
    5 X+ w  x# \+ L' x  u4 {7 m                if (null != mLoadingDialog && mLoadingDialog.isShowing()) {
    2 y- A2 r( X& _1 d4 d! P3 q                    mLoadingDialog.dismiss();
    * W$ Y$ i3 w& k, G, n8 c& C                }
    + o/ L6 a. P& O8 \+ K            }
    , e+ @; E/ G  l/ K& n1 Y# a        });
    3 v6 X. P0 @/ v/ ~8 I/ O5 H3 u    }
      D9 }5 _4 I- }1 `4 M% p- t( L    private void ShowDownloadProgressDialog() {# U9 p& v( e% Y2 Q5 u
            if (mDownloadDialog != null) {
    - Y) I) u( _8 k0 y' z0 y            runOnUiThread(new Runnable() {
    " G  ?- H$ Y+ \; A; y' C3 h6 u: i                public void run() {
      S" M; R* l( F4 o                    mDownloadDialog.incrementProgressBy(-mDownloadDialog.getProgress());8 m: e5 \) g0 _4 y7 ^( i0 o" K( M" M/ Q
                        mDownloadDialog.show();) h' d5 o' c  Z$ C; x
                    }
    0 s! d1 {# B7 S' Y& Y" x            });9 J4 m  ~) \/ H8 w
            }
    # }7 B: C5 z3 N" [+ g    }9 `% G1 ^0 v, k2 m
        private void HideDownloadProgressDialog() {- B" p7 t! W& v
            if (null != mDownloadDialog && mDownloadDialog.isShowing()) {3 f; ^* e4 p1 p" I& C" {
                runOnUiThread(new Runnable() {" n1 ^' }6 d- @0 ~' Q2 a* @9 u* A0 f
                    public void run() {
    % W3 p8 [- j: J9 A4 o+ R& O  y                    mDownloadDialog.dismiss();! b5 E0 |, W, E6 ^# Q0 d4 {( H
                    }
    . z' t8 z. |" Z- Y6 N            });$ Z+ |% b" e5 Y# s8 b
            }/ H( |2 @  L' R. J, o' y
        }  D: E- ?, W* u9 u5 o, S& A
        private void initMediaManager() {* l! ]) z" C7 B6 l
            if (ReceiverApplication.getProductInstance() == null) {: z) p) n- _( P5 A
                mediaFileList.clear();
      o; L/ J# d' o, K" D. P( E            mListAdapter.notifyDataSetChanged();5 q* O5 a( b" e8 f8 [3 N3 I' J# I
                DJILog.e(TAG, "设备已断开");
    : A3 P. _8 ~7 ]: _+ e8 o) O# I5 m            return;# M- D( D8 m" r
            } else {
    1 M; V$ M1 v* i# D- K9 \2 s            if (null != ReceiverApplication.getCameraInstance() && ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {
    - \, q, y: \4 _- O# X$ f                mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();* l4 ?0 M/ m+ D. @. v# M0 z
                    if (null != mMediaManager) {
    $ N  }1 P( X, ]( v7 K" ?8 v                    mMediaManager.addUpdateFileListStateListener(this.updateFileListStateListener);
    , l5 h( |, k) `) f: i                    mMediaManager.addMediaUpdatedVideoPlaybackStateListener(new MediaManager.VideoPlaybackStateListener() {! Q, L4 S5 M  K. _6 s. h
                            @Override4 E: f. Y: v# q, |' ^% p
                            public void onUpdate(MediaManager.VideoPlaybackState videoPlaybackState) {
    3 D' B" ^# U% s2 [/ n4 B                            state = videoPlaybackState;) \1 i1 ^. L& w/ m4 a  k
                                if (videoPlaybackState.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){; B5 I0 D7 r, F# E9 [5 M
                                    runOnUiThread(new Runnable() {
    " v3 j* v% J& {3 D: e+ L                                    @Override
    5 M# t% n. Y, S$ J5 F' ?9 x                                    public void run() {
    $ h8 R+ g8 V/ p& ~6 E# P/ x//                                        mImageViewVideoPlay.setEnabled(true);
    9 i# x) w2 F+ ~//                                        mImageViewVideoPause.setEnabled(false);/ k0 o  s3 s, ?# {: z% X
                                        }
    * b3 R6 G! C2 _; N7 Y+ R                                });
    ) K8 ^; r* }- l4 x9 |3 b                            }
    ! w  X4 y  u6 d5 h2 m! f                        }
    6 e) C9 ^* h9 Z- h+ h: J                    });. O$ X& U, p3 {  i- r- a
                        if (isMavicAir2() || isM300()) {
    ) X6 [: l2 }& I3 |7 ]9 }5 L% D                        ReceiverApplication.getCameraInstance().enterPlayback(djiError -> {# x9 n! k! d7 _/ y
                                if (djiError == null) {
    . K( N; M  T0 |6 @# o                                DJILog.e(TAG, "设置cameraMode成功");9 z8 W  t% B6 y( u! T
                                    showProgressDialogs();
    + I- M. B  X1 r/ u  t( N! R                                getFileList(0);
    , J4 ]5 g# ^7 Z1 e" K+ I# l# h5 q                            } else {) s: Q( M. P. b. I
                                    showToasts("设置cameraMode失败");
    / |* v3 v1 C, n9 ^/ ]- ~                            }: [, ~2 `5 S& c! D% X9 i- i: E
                            });
    / F5 ?8 [4 ^( z# d3 m                    } else {
    5 E$ X/ p% F! m8 D( v& I0 J; V                        ReceiverApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, error -> {
    8 ~" n6 n& z% c4 Y/ [5 D2 ]                            if (error == null) {: V& G1 o6 r5 w% J# w1 f+ u
                                    DJILog.e(TAG, "设置cameraMode成功");
    4 ?; @7 O' k4 r) _  ]. W                                showProgressDialogs();
    6 O3 @& V0 @) d( p9 L9 D8 O/ s                                getFileList(0);3 C& f6 h* Q8 @& ~% a4 H
                                } else {, Q8 x0 k! p# I1 f/ K
                                    showToasts("设置cameraMode失败");  A6 _8 x$ |2 \  ~# N% k1 i/ z# I
                                }, w" X, @$ F# b2 F( `% I" x! B
                            });
    ! e% U% i5 A5 z1 x                    }+ }" ]( q- j  m3 t; i* A5 C! _
                        if (mMediaManager.isVideoPlaybackSupported()) {
    , x7 J  [$ w9 p6 I                        DJILog.e(TAG, "摄像头支持视频播放!");- ^- C5 w; q4 p" g/ h% t% q
                        } else {
    ; j  `  b9 E' G, T5 W- _                        showToasts("摄像头不支持视频播放!");. l4 V1 S3 g6 y2 C. b7 t
                        }' o9 b# k" N7 i1 Z4 s
                        scheduler = mMediaManager.getScheduler();
    ; E* w! T6 f8 k! F" r                }
    % d0 w  h; L1 Q  J$ G8 n            } else if (null != ReceiverApplication.getCameraInstance()
    # ^+ z- D' N4 T$ B% z2 ~                    && !ReceiverApplication.getCameraInstance().isMediaDownloadModeSupported()) {
    5 ?* g* Z4 H3 n) n! L; f                showToasts("不支持媒体下载模式");; d2 V3 v+ h' L8 ]- {' F8 [: m0 z
                }
    9 w2 C% y* x$ t- F        }2 t6 ?* G( e4 p0 y% Y
            return;
    ' o+ ^7 p) v$ z1 W    }
    * ?7 E3 p2 l; F8 N" q4 P3 N    private void getFileList(int index) {
    ; W# }% K1 c$ \7 o+ ?        mMediaManager = ReceiverApplication.getCameraInstance().getMediaManager();
    + c/ m' i! |5 W6 [/ X0 @' f        if (mMediaManager != null) {
    7 d+ s" W) d* D            if ((currentFileListState == MediaManager.FileListState.SYNCING) || (currentFileListState == MediaManager.FileListState.DELETING)) {% c5 m& s, j/ u
                    DJILog.e(TAG, "媒体管理器正忙.");7 ]9 `& a+ K5 b$ X5 t2 ~
                } else {0 o! r' v7 @& D" u& P
                    mMediaManager.refreshFileListOfStorageLocation(storageLocation, djiError -> {
    1 k8 t) R1 g1 [% {7 F! z//                mMediaManager.refreshFileListOfStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, djiError -> {" ?& G. }: X4 P) |" I1 o
                        if (null == djiError) {
    1 B) A4 S. H0 T% P( G2 v' s                        hideProgressDialog();  C8 v3 l0 Q. _# n% m1 _  {
                            //Reset data$ _2 A2 P9 |9 D
                            if (currentFileListState != MediaManager.FileListState.INCOMPLETE) {7 S$ P: R9 M6 N9 w4 j
                                List.clear();
    2 V. i8 A% z3 Q# w                            mediaFileList.clear();
    * a$ _# h3 T: G, b; i, j                            lastClickViewIndex = -1;
      I! t- t1 G/ z1 @$ m+ f6 Q# r& v                        }% f- p: Q( Q/ [$ a' d- J
    //                        List = mMediaManager.getSDCardFileListSnapshot();. |0 r- n$ ?0 _: Y
    //                        List = mMediaManager.getInternalStorageFileListSnapshot();; m7 b5 q" `4 Z) \. ~2 w4 ~
                            if (storageLocation == SettingsDefinitions.StorageLocation.SDCARD) {# }6 }/ c. [( J
                                List = mMediaManager.getSDCardFileListSnapshot();5 S9 {7 C, L: l& j  ~
                            } else {2 M' [& l! r& {8 N. Y. G0 G
                                List = mMediaManager.getInternalStorageFileListSnapshot();
    - B; C. G  q2 E6 R  S' M                        }
    # i. @5 ~- s! g4 }2 _, D8 V                        switch (index) {
    0 W9 ?1 K6 K5 J! x7 S' ?0 A% O                            case 0:
    4 ~5 ~( p5 {9 k8 [' @                                for (int i = 0; i break;) H7 W0 P8 j3 r+ V1 o! X4 ?
                                case 1:; i6 _9 W, I% u; N+ l' p/ ~1 O2 Q
                                    for (int i = 0; i if (List.get(i).getMediaType() == MediaFile.MediaType.JPEG) {
    9 i, X  @' E7 S3 Y( U" o: }                                        mediaFileList.add(List.get(i));0 B: c1 y; }7 h- B' ?/ V( z9 e
                                            MyLog.d("图片名称:"+List.get(i).getFileName());
    0 ]/ Z: @( J" \: F                                    }
    + p! c1 j) ^6 @4 y/ n* K                                }4 L1 S5 o: l8 C* f
                                    break;5 y: Z- O+ D5 m* Q: [
                                case 2:
    + H( y. z: [. \- r                                for (int i = 0; i if ((List.get(i).getMediaType() == MediaFile.MediaType.MOV) || (List.get(i).getMediaType() == MediaFile.MediaType.MP4)) {
    5 b) m& z: ?1 h* J) i& |  X                                        mediaFileList.add(List.get(i));
    ( X$ k6 I7 P* M( y4 k7 u                                        MyLog.d("视频名称:"+List.get(i).getFileName());+ E0 c- o5 h- M& ~" o/ `+ i' O5 j
                                        }
    + [9 _) V9 I9 a                                }- N  @+ G9 u# m- g, r
                                    break;& D. g8 I6 S. ?/ X! f9 \) ?
                            }. B7 n1 A2 i) G. A$ ]8 z% D+ _$ _  ]
                            if (mediaFileList != null) {
    2 r- |  W3 g5 M1 f( n( N9 F                            Collections.sort(mediaFileList, (lhs, rhs) -> {( v- \. f* G: Y; d! i+ Y6 S* i8 R
                                    if (lhs.getTimeCreated() return 1;% R* U* S* H2 o5 d$ U6 H8 F5 h! ]
                                    } else if (lhs.getTimeCreated() > rhs.getTimeCreated()) {! j4 X% z( r4 T8 J
                                        return -1;- Z) Q, @! s! F. y, s) ?! ^
                                    }
    6 r9 o5 l& f7 a0 a: {4 I5 c                                return 0;
    ( C, V1 a1 {9 U5 g                            });5 ]; O' t( h+ j  n
                            }( P/ A8 l2 c' N$ D
                            scheduler.resume(error -> {, n' B0 M$ Z* g' ?
                                if (error == null) {
    3 q- G  [( Z  o                                getThumbnails();
    * h+ r! U8 _5 k7 Q                            }# I6 |% O: D5 r  s7 `
                            });
    , f+ b$ H; x! e# R                    } else {" N1 B- A8 O. S) ]$ D* T
                            hideProgressDialog();) e. ]& m& g0 y! X
                            showToasts("获取媒体文件列表失败:" + djiError.getDescription());
    + m1 |( r1 D# K                    }
    # T' b7 `( h  Z                });
    + ?5 U+ t: c8 _5 \" U7 D            }  n6 ?  [3 x: _/ ?, |6 K; m
            }
    ' W: k4 P) [. h5 O, U; Q! s5 @: b9 Y    }
    ' x9 m# C& j2 Y- j    private void getThumbnails() {
    ( B. I4 B  V% s        if (mediaFileList.size() 0) {5 V5 T3 M0 [7 ^. U2 W1 @
                showToasts("没有用于下载缩略图的文件信息");9 [( G1 b; j  F0 R5 ~. I4 Z
                return;
    1 N# U2 w7 h) }& |5 r7 v        }
    , W$ C* m* |/ l7 U& x; t# O( K0 p        for (int i = 0; i private FetchMediaTask.Callback taskCallback = new FetchMediaTask.Callback() {; I- L7 P* ?' V
            @Override9 d/ N, h- I7 [( e0 S7 k
            public void onUpdate(MediaFile file, FetchMediaTaskContent option, DJIError error) {, e$ u- X, r* T! d/ {- S
                if (null == error) {
    5 L/ T3 O9 H/ B0 v0 i+ ?0 `5 Z" i# Z" E                if (option == FetchMediaTaskContent.PREVIEW) {, e  v8 T  V0 n. h' W1 F4 s+ F+ r
                        runOnUiThread(new Runnable() {
    - r4 C0 v4 i, |, t1 W                        public void run() {6 f8 `6 w  c- j3 ]
                                mListAdapter.notifyDataSetChanged();" z' v' f" }2 V* `- n
                            }# t, B7 O5 u6 P+ k/ m: D
                        });3 _" ^& h, W7 |
                    }1 J& |5 d" T' |1 J- T. ?
                    if (option == FetchMediaTaskContent.THUMBNAIL) {
    ) K' m) e) ~4 f8 |                    runOnUiThread(new Runnable() {" k7 @! k& K$ v
                            public void run() {( R, L* A1 _/ C; J: W
                                mListAdapter.notifyDataSetChanged();
    # v4 z% K8 W! M+ [  s9 ^                        }
    ) b: c4 a, g, d8 Q  g% N3 C                    });+ z! M4 Z$ ~% G
                    }
    0 l, ?. B! ]$ X! L# D! N7 i            } else {
    ; O: o1 `. l# s! L% ^                DJILog.e(TAG, "获取媒体任务失败" + error.getDescription());
    6 o# @* v% D% T4 ~5 k) b            }
    . {5 T& V- V9 G& }6 V        }) G8 T- P6 l. r/ l+ ^4 n8 @
        };
    2 q$ _  _- C9 f+ y7 W% L/ _- C    private void getThumbnailByIndex(final int index) {- v: s+ U$ i1 v6 {5 G8 F# d
            FetchMediaTask task = new FetchMediaTask(mediaFileList.get(index), FetchMediaTaskContent.THUMBNAIL, taskCallback);
    " }" |* Z, o2 B1 S. x. b        scheduler.moveTaskToEnd(task);, i, z5 \/ G/ y! d
        }$ I& v  R6 W! w. G6 K
        class ItemHolder extends RecyclerView.ViewHolder {
    4 R) \9 u8 F' X* ~6 G8 G        ImageView thumbnail_img;7 G8 D! R' Z  @* e
            TextView file_name;2 @8 q6 C% C9 U% t0 m. r
            TextView file_type;
    6 {/ y1 S2 i7 }1 S        TextView file_size;+ L; G( z) j$ w- Z) `
            TextView file_time;
    & l+ a  d) b& b6 m  Q9 r' Y, }" ]        public ItemHolder(View itemView) {7 @. B) Y$ {$ n, D6 @
                super(itemView);
      T! v0 U5 u: a1 [8 u1 o. Y            this.thumbnail_img = (ImageView) itemView.findViewById(R.id.filethumbnail);
    % ?  O: t  d, B% z0 Y( ~            this.file_name = (TextView) itemView.findViewById(R.id.filename);. ?7 x% S/ g4 \' N+ Q  _  v
                this.file_type = (TextView) itemView.findViewById(R.id.filetype);
    2 J2 n2 A9 u: N- L0 F5 E" f( M            this.file_size = (TextView) itemView.findViewById(R.id.fileSize);
    ' B+ y) J. K* d& l5 P            this.file_time = (TextView) itemView.findViewById(R.id.filetime);/ ~( p- H" M0 [8 q+ x+ B
            }3 ]4 q! k' i4 P0 n
        }1 ?5 d7 B% m) G  P
        private class FileListAdapter extends RecyclerView.AdapterItemHolder> {1 X/ T( y  r2 t" M) l: i  w
            @Override/ Z. }+ L: U9 o9 c; ~
            public int getItemcount() {& \. l" A: d% u9 n& M# O) V; ^
                if (mediaFileList != null) {
    5 p9 l8 U" H5 B3 x                return mediaFileList.size();
    ; M! L, m+ w  M6 h' O& O            }8 H9 y2 e) {, K9 u$ Y
                return 0;  q4 y: F; F! S$ P. ?
            }6 l9 P  K9 S0 h- h
            @Override: ?0 i! [* k4 A# `3 Y$ b
            public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    $ H# a+ a, ?% o# O            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_info_item, parent, false);
    - h) A  A/ d' O, [  P# n1 b            return new ItemHolder(view);" M  s, a4 j; V8 Q4 w% L
            }1 l; N% s" x# Z; B2 t  Y$ ^/ L
            @Override
    ! u7 g. W9 o! @$ n' I. |        public void onBindViewHolder(ItemHolder mItemHolder, final int index) {
    & {5 s- K- P. {1 l6 h& Q* c# J            final MediaFile mediaFile = mediaFileList.get(index);" F6 t! {. f- q) C$ Z
                if (mediaFile != null) {
    # N0 t- J/ a& D6 |% W3 W( {                if (mediaFile.getMediaType() != MediaFile.MediaType.MOV && mediaFile.getMediaType() != MediaFile.MediaType.MP4) {
    & \/ O  q9 i3 ]. U3 y; X                    mItemHolder.file_time.setVisibility(View.GONE);
    ; K+ ?% X* v( D( F# ^                } else {
    3 }' V( r( Z( E  o" |; `: p+ r& F' j                    mItemHolder.file_time.setVisibility(View.VISIBLE);
    ( t! j# `& R% B/ A' X! @+ X7 `                    mItemHolder.file_time.setText(mediaFile.getDurationInSeconds() + " s");) |9 P4 o, n; O/ o: p: y6 }
                    }/ Y( l4 L- \" {9 c0 V2 `
                    mItemHolder.file_name.setText(mediaFile.getFileName());
    2 ]- n4 y/ w* L; v                mItemHolder.file_type.setText(mediaFile.getMediaType().name());
    8 x( m- {4 n6 @2 P) E9 p) V                mItemHolder.file_size.setText(String.format("%.2f", (double) (mediaFile.getFileSize() / 1048576d)) + " MB");
    * U6 ~" @  ?( @9 S( _7 V* D/ s                mItemHolder.thumbnail_img.setImageBitmap(mediaFile.getThumbnail());
      [+ v+ M+ Q$ C& p                mItemHolder.thumbnail_img.setTag(mediaFile);2 n  }' e( [  f$ `
                    mItemHolder.itemView.setTag(index);4 M4 i  O& w4 E( U  b
                    if (lastClickViewIndex == index) {! U" p9 {9 G# U+ _* W- X" B
                        mItemHolder.itemView.setSelected(true);0 ]$ J6 [, k- g4 W
                    } else {2 I$ L7 |6 y* F7 l
                        mItemHolder.itemView.setSelected(false);9 I! A  [6 t1 ^$ w3 O- C
                    }
    ) a+ x4 Y7 O  l5 h# M% S' u                mItemHolder.itemView.setOnClickListener(itemViewOnClickListener);
    ! W4 @# F- B9 R1 O" e: H1 o# W" ^            }- q3 u6 b) U% w9 a" |- G2 G4 Z
            }
    7 R0 O1 A* u6 {' }! n: j    }
    % p4 ~) r. ~% S$ V    private View.OnClickListener itemViewOnClickListener = new View.OnClickListener() {
    ' ~3 N& m$ j1 v9 L7 P+ }        @Override
    ( D+ J# f& I1 G2 g! ]        public void onClick(View v) {; E) ~6 i/ V7 u% N5 o) V
                lastClickViewIndex = (int) (v.getTag());! _/ Y. g6 g" g; a6 ^
                if (lastClickView != null && lastClickView != v) {# Z! z( B( T& V6 g7 r& O
                    lastClickView.setSelected(false);
    # h. b* W7 [7 a! O2 Y3 l9 [5 L- A            }& t2 ~( O0 ?  O  g0 q: o1 d. H
                v.setSelected(true);
    1 t5 e* M! P7 C3 `& g' g. S            lastClickView = v;1 }% e7 z) P: i- e
                MediaFile selectedMedia = mediaFileList.get(lastClickViewIndex);9 O; k1 {8 R2 f( N/ T9 b
                if (selectedMedia != null && mMediaManager != null) {) |& c0 b# T/ I" C6 K2 m8 ?
                    addMediaTask(selectedMedia);
    / I4 `5 W9 G% m3 l9 Y8 X            }9 b& J: e5 p- A9 \- c; q6 g
            }; C) W& z& s$ R6 @" I  T
        };
    : |  R2 d( c, \' n  k. @$ `, [    private void addMediaTask(final MediaFile mediaFile) {; |: L" S8 z1 I& _. G5 W) v; `  Y5 i
            final FetchMediaTaskScheduler scheduler = mMediaManager.getScheduler();
    : n" e' c" g. I4 C9 N# M% c, Q        final FetchMediaTask task =
    5 |: y+ f# X) P5 F                new FetchMediaTask(mediaFile, FetchMediaTaskContent.PREVIEW, new FetchMediaTask.Callback() {
    2 J- n8 p3 L5 e: D& O; s                    @Override+ f: {2 m' q* W$ R  s  T/ Z
                        public void onUpdate(final MediaFile mediaFile, FetchMediaTaskContent fetchMediaTaskContent, DJIError error) {! z3 S7 g. c3 ^% Z: x4 J, t1 c
                            if (null == error) {
    # o# E; F7 F& D. b7 Q: F                            if (mediaFile.getPreview() != null) {  m! s1 i6 N% V1 P6 Z
                                    runOnUiThread(new Runnable() {( u0 y/ }" U8 g$ j0 `, G
                                        @Override( d- V& s6 A& J1 ~
                                        public void run() {( |: H2 n" p% K0 k3 Y' |% {& c$ R
                                            final Bitmap previewBitmap = mediaFile.getPreview();3 c- S* n) \# o" k  O, U
                                            mImageView.setVisibility(View.VISIBLE);& G5 K0 S9 y8 @( t- m* y& f
                                            mImageView.setImageBitmap(previewBitmap);
    * L# \/ y: H: p8 b                                        if (mediaFile.getMediaType() == MediaFile.MediaType.MP4){- l" R: |$ _! p6 S
                                                mLinearLayoutVideo.setVisibility(View.VISIBLE);
    * m. C) p2 {8 i0 _) w, @                                        }else {- {$ ~. l, ]) X! B8 q9 Q2 ?
                                                mLinearLayoutVideo.setVisibility(View.GONE);0 T9 H7 v: `+ k. |  r* S, U" p
                                            }9 a7 L0 K9 d, O6 h, X
                                        }
    & X; X6 Y  d, G- b, P* n                                });
    ; U& r- a! P- J1 B  A                            } else {
    5 W& f, V) R' s# E9 P. e+ i                                showToasts("没有图像bitmap!");, B" l- R5 L. ?3 K2 f* \
                                }
    ! u1 ~) C3 F" D+ X* L( ~2 b2 s7 d: a: a                        } else {
    * Y: m9 p' n" |5 @0 @' `) d                            showToasts("查找图像内容失败: " + error.getDescription());2 V& g# O! E; S- i
                            }. u* t; A, T* I& Z/ ?
                        }
    1 u* j1 p2 ?% P$ q& T5 ^                });+ O* q7 c7 t. F+ w
            scheduler.resume(error -> {
    6 o/ z" O+ g9 q8 n            if (error == null) {6 O3 h2 L# H& n5 i) E
                    scheduler.moveTaskToNext(task);2 R, o( S5 C' K7 |* y' x* [
                } else {
    / g+ Z; {" F0 o& Q                showToasts("恢复计划程序失败: " + error.getDescription());  L& V. e% N4 f6 {* f
                }, L# [* c, f, w8 ]! [0 h! X- O
            });
    ; V- a" G0 P/ o* \: s  Z    }3 S! }" Q1 e; f" V5 w
        //Listeners
    . F! ~( B( o" h/ c$ D    private MediaManager.FileListStateListener updateFileListStateListener = state -> currentFileListState = state;; o# t( F, _7 K6 J0 o& n3 v) y

    - u9 h! ?1 l4 J3 t# t. X) g    private void deleteFileByIndex(final int index) {9 D' O/ |4 v8 l8 h% N
            ArrayList fileToDelete = new ArrayList();
    ! z" w9 ^; Y7 u' w8 b: f        if (mediaFileList.size() > index) {1 i( P9 v/ j, h9 [9 n5 U* ^
                fileToDelete.add(mediaFileList.get(index));
    - P" A8 P; X2 w. h            mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam, DJICameraError>() {
    7 {! Q; q; N1 z+ t6 a, w                @Override0 x) |% t3 U& A: u* _
                    public void onSuccess(List x, DJICameraError y) {. s( |1 S  g* X* ^9 i. `
                        DJILog.e(TAG, "Delete file success");7 o  G" j) {- ~' M) V+ l
                        runOnUiThread(new Runnable() {
      k3 E/ V& z, u( t) X2 p                        public void run() {# h! \: _. s9 b8 Z* A; Q$ A4 m
                                mediaFileList.remove(index);) w$ t* d: E, T$ D$ b6 H" X& D
                                //Reset select view6 `7 P% _7 r1 h  Q* Z& @" U" l2 X
                                lastClickViewIndex = -1;
    " Q9 r, U* g0 v  v  Z  l( w7 g                            lastClickView = null;
    ! p/ E7 |. a, m) d                            //Update recyclerView
    ! Y- Y  s* c0 l  C+ {                            mListAdapter.notifyDataSetChanged();6 \2 f  k: U4 n  Z
                            }0 F# _, \/ M7 U- E: R, r# v
                        });3 Y# G: A9 w' u( L  T6 h9 C) J! S5 M
                    }
    & C6 J( _- e: {% h: \7 z                @Override
    - o, u; J' }0 u6 E% C5 ?, o                public void onFailure(DJIError error) {. C. V4 d* j" g! L9 ]2 z' e  ?0 R
                        showToasts("删除失败");
    . T6 H% }" L& b) T+ |5 D                }" m6 ?% ^, e$ |( q4 \7 A
                });' w0 A& a$ W) _, O/ r
            }2 [, H8 C  u% [+ K# b/ K2 K& s
        }; m* p3 ?1 g# o8 I$ O& R# \
        private void downloadFileByIndex(final int index) {
    8 @- S+ y  R8 o3 p) f        if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.PANORAMA). b( g1 ~8 j0 t! h  a# E7 c
                    || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.SHALLOW_FOCUS)) {) V% Y& @: k& G( }4 W& W& L
                return;8 |7 U* W# w9 ?% W9 n' U& E
            }! v$ Q5 r- v* F4 \4 Y
            if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {$ U$ X; f; i2 `
                SavePath = MyStatic.FLY_FILE_VIDEO;1 A5 |& d7 a- h
            } else if (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.JPEG) {$ e4 ?' ]: A  Y) G' o+ d& B* D6 s+ s
                SavePath = MyStatic.FLY_FILE_PHOTO;+ D% y$ E7 p8 U' T
            }% z& S% Q. R4 {5 p4 D
            File destDir = new File(FileUtil.checkDirPath(SavePath));# I7 r: s1 P8 M# R' j* x
            mediaFileList.get(index).fetchFileData(destDir,null, new DownloadListener() {- Y6 t' E" R2 U0 U) }* e
                @Override- K& Z2 [5 c; s: K4 D& \
                public void onFailure(DJIError error) {
    7 B8 z, V2 T) r' k                HideDownloadProgressDialog();! n1 o0 R9 Q4 [% B2 G& ^
                    showToasts("下载失败" + error.getDescription());0 j. `0 e2 L4 J: z/ F; G1 }( L: i# S
                    currentProgress = -1;
    # u8 T% v  j+ n. c            }! a" ~+ d* v5 d1 |0 r) l0 j. u
                @Override
    ! _. z6 u4 o: A+ q; X  p5 X            public void onProgress(long total, long current) {0 Z8 h4 W: W( y/ z) u
                }- I( g) c; ~- r+ `
                @Override" J; w: _0 L! S3 m: B/ I/ A
                public void onRateUpdate(long total, long current, long persize) {, I0 m/ U- ^3 a! j* O# V) a. E0 n
                    int tmpProgress = (int) (1.0 * current / total * 100);
    8 f2 X- V1 \/ o/ ~0 }5 Q                if (tmpProgress != currentProgress) {
    . l! I; p9 D5 i: i6 q                    mDownloadDialog.setProgress(tmpProgress);! x1 _* \4 l' ~
                        currentProgress = tmpProgress;/ r6 N3 D+ B$ c
                    }$ T( T: }! ~$ m' r2 M# V
                }
    . v% S2 y0 T$ m7 g; X# q            @Override% C8 S2 ]8 v% L0 x* a
                public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {, m) R+ J  J4 D- r7 S5 a5 T
                }
    ( t5 @/ s3 {9 Z' C- I# u% m; F            @Override
    ) @5 D! H& J& V            public void onStart() {
    - I  \6 [' W* Y                currentProgress = -1;+ i* S# W, N% j8 C
                    ShowDownloadProgressDialog();: ~) Z3 K* Q. b+ c+ ?
                }; d  K2 I/ y, ?5 f3 [
                @Override+ }. J8 e) D" k+ F  h1 w( w
                public void onSuccess(String filePath) {
    ! h* }" c4 N% s9 j. P6 S5 T  Q                HideDownloadProgressDialog();
    ' [- h+ J( l9 _6 e4 h& }                showToasts("下载成功" + ":" + filePath);$ y/ z6 C" B/ K( K* e7 w
                    currentProgress = -1;
    / }# n: ?! S! Y: P* o+ U            }9 o* i2 k3 p& A
            });/ Z1 t5 e7 w  F. s( l
    //        mediaFileList.get(index).fetchFileByteData(0, new DownloadListener() {$ V. ~8 x3 y0 k0 _8 {
    //            @Override
    4 H5 M0 E& D& N0 v/ O0 W//            public void onStart() {
    : H; _$ c+ B- |# A% K+ a# `//                currentProgress = -1;5 p% g0 i0 {3 z5 ~
    //                ShowDownloadProgressDialog();$ y7 e% o0 L  g4 {
    //            }
    2 }4 u& \$ o1 Z* d- R- y5 N//. k4 F1 P% K& h4 Q
    //            @Override
    + n8 L& |9 f# T9 R; h4 ?/ H4 g//            public void onRateUpdate(long total, long current, long persize) {
    - D' V# w* O+ k& s0 \1 C//                int tmpProgress = (int) (1.0 * current / total * 100);! |1 r; O- J" t: X8 k
    //                if (tmpProgress != currentProgress) {, w. I; b! B; R0 r. ^4 y
    //                    mDownloadDialog.setProgress(tmpProgress);
    & U9 {) m9 Q" G! b9 U7 W" F+ ~* u+ d//                    currentProgress = tmpProgress;/ f% t, `, _. S9 F# u: M4 I
    //                }
    6 V4 F8 S' T7 T" L# W//            }
    4 D5 _5 l- a/ w6 v2 M- }% W//. Y6 D1 \5 d2 w* C) ~
    //            @Override
    ' k2 b: s0 q  B* @# E7 I3 j% B//            public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {$ I7 V2 E; w$ r5 R5 g
    //                byteToFile(bytes, FileUtil.checkDirPath(SavePath)+mediaFileList.get(index).getFileName());
    * v0 h# `  O7 ~2 }//            }$ Y+ [- q1 [4 A
    //: }# O# a) n" h" S: V
    //            @Override
    - [# ]) R+ q5 D; O! ~//            public void onProgress(long l, long l1) {4 r6 }5 w9 v+ A3 E3 c: s3 [
    //
    : R5 z. \0 b* A5 K) m+ O//            }
    $ x% M4 G# ]1 w$ p# ~2 u! G//% y4 i7 j6 K# v: x* @
    //            @Override
    : }$ l- H' `# k' p( E) ~//            public void onSuccess(String s) {$ v( {$ p/ N  Y8 J" e% J
    //                HideDownloadProgressDialog();& [3 g5 g+ w4 _: V: i5 z; K
    //                showToasts("下载成功" + ":" + s);! S0 _: ~9 q# ]8 W
    //                currentProgress = -1;% y8 C" z$ d4 @+ \% S6 O
    //            }
    , O$ @8 {  X8 ?; O6 F//' |5 L0 f0 p# \: u
    //            @Override7 a* `8 C' i. I6 l4 d
    //            public void onFailure(DJIError djiError) {  J' r4 z- w! d7 m9 ~+ o2 s
    //
    1 [. z' C( K7 b( j" U//            }8 m2 R' G1 a, _2 I5 @
    //        });; z9 f; m& g! ?1 @
        }9 Q2 X- @  F' k. @9 r& D+ Q
        public static void byteToFile(byte[] bytes, String path)
    # g+ `6 E* g/ p* H5 l# m    {0 o6 G* V5 l* d  m" t3 F
            try& h) A* |0 k( w: G
            {( [& W9 W! Z  d3 m6 u
                // 根据绝对路径初始化文件
    4 c2 s# a1 [: I  {, q$ m' k- Y            File localFile = new File(path);
      p8 Q9 }% A8 E; v& g2 x9 E5 `            if (!localFile.exists()): q$ y+ n/ f# P2 m. M7 m$ @
                {
    , _; N- O4 D$ C! [1 X                localFile.createNewFile();  |5 c3 {1 @$ f0 d
                }
    4 O- y# _. B2 O            // 输出流
    % V" C( X' r9 ^5 y$ q2 Q) N  N            OutputStream os = new FileOutputStream(localFile);
    9 U+ B" d2 U% N4 T3 U9 I0 A9 b            os.write(bytes);
    - t5 ?( |6 W& }6 z" h( H            os.close();
    0 j* @, }( N! M% v+ T# @- Q' w, x        }
    5 n# w& R8 P# U        catch (Exception e)- U7 X+ ~- a3 x' h2 H- U
            {
    3 f) |/ N& a, A& J7 \9 `* i7 ?- ]            e.printStackTrace();
    . G0 D7 R! |+ ^  e        }3 V' R% s6 m  {
        }5 f" R! ^& B1 f$ ~6 _! S4 Z! v
        private void playVideo() {
    - S/ g: b1 L7 k  \& t% F$ W; S2 O0 ^        mImageView.setVisibility(View.INVISIBLE);
    " ]1 z" y7 g6 M1 L  Z- z6 F        MediaFile selectedMediaFile = mediaFileList.get(lastClickViewIndex);7 o! M: a6 A1 a3 P: z5 ~, R
            if ((selectedMediaFile.getMediaType() == MediaFile.MediaType.MOV) || (selectedMediaFile.getMediaType() == MediaFile.MediaType.MP4)) {
    5 U3 Q3 m, F. H4 c9 e8 x8 c) E            mMediaManager.playVideoMediaFile(selectedMediaFile, error -> {, h& J, K, R  I* s) V
                    if (null != error) {* F+ O# i: @8 F1 s  L
                        showToasts("播放失败 " + error.getDescription());1 p5 \8 }8 }4 g  X
                    } else {( Y$ i" l0 j6 w- U3 e
                        DJILog.e(TAG, "播放成功");' u$ n6 j5 Y8 N- x' V2 F
                        runOnUiThread(new Runnable() {
    0 S/ h) p9 c) }1 ?- V: k5 |                        @Override
    1 Z0 k; X7 ~* g7 X                        public void run() {
    " c, [* W$ k7 ~: O6 z                            mImageViewVideoPlay.setEnabled(false);
    ( K& T5 u8 E+ R2 |0 i3 I9 j                            mImageViewVideoPause.setEnabled(true);  H: R8 v' |7 u  d2 y9 ~6 g; i
                            }
    7 j% N# |6 U% Y5 A4 s                    });
    ! d$ `3 k# }1 C# r, a+ }( L                }
    % P5 j! Z0 ]3 j            });
    , z9 K3 j9 Q$ i* d4 n, i        }
    - d3 t$ D3 G1 Z) }8 ~' T    }6 |: b5 n8 H; u8 T; n7 v$ K3 h' r7 Z7 y) u
        @OnClick({R.id.img_back, R.id.img_delete, R.id.img_download, R.id.img_upload, R.id.img_video_play,5 P8 O; d7 m  O* ]; ~1 H
                R.id.img_video_pause, R.id.img_video_stop})
    1 p5 I' ]/ I2 v6 q1 ]' e/ \. p$ Y    @Override
    7 v& Z3 e' R% z) ~  R5 X# W& ]    public void onClick(View v) {1 ~- G! I8 g) Y6 Z
            switch (v.getId()) {$ f5 B$ A% g- C" c, _* }2 p$ v
                case R.id.img_back:
    2 Y7 d6 m: p7 n* i- B9 ~. @; h0 E8 j7 m                FileManagementActivity.this.finish();; ^. O4 c$ f. l5 H6 e5 a! ]
                    break;  ?3 ^1 X! @. k6 c* c
                case R.id.img_delete:
    / @) M5 E4 p$ Q7 y+ c! j! @$ z                if (lastClickViewIndex >= 0) {
    9 P* ?% y# a3 W$ O0 k" Z& j& Z                    deleteFileByIndex(lastClickViewIndex);: p! A( P0 m! c3 Y" S
                    } else {
    - I6 L( u# W0 i2 r0 y                    showToasts("请先选择文件。");1 N9 C* Z8 l( @% L$ e# R0 I
                    }3 @5 \2 N# R1 E
                    break;, R, M8 k5 A' M; U
                case R.id.img_download:
    4 ]7 i4 G6 g4 J' z3 Y3 K6 c                if (lastClickViewIndex >= 0) {
    2 J3 P4 x4 @7 M                    downloadFileByIndex(lastClickViewIndex);
    # u% H1 w+ Y$ u- G. t                } else {6 W( ~- j8 D+ K" i: L
                        showToasts("请先选择文件。");
    - L# E, E! N" T                }% P8 A: ^- I  E) t
                    break;
    0 |5 Q' I7 A( Z9 O3 I9 U2 n            case R.id.img_upload:
    " y! u' f3 _) \. A9 W                if (lastClickViewIndex >= 0) {# Q6 r: P8 ~1 E7 {1 _
                        uploadFileByIndex(lastClickViewIndex);
    * Q; Z, E2 A* S  I                } else {
    4 Q/ T' H) S8 N8 |2 _                    showToasts("请先选择文件。");
    7 a. y* x- j0 ?% C                }9 x7 h* j) T) B8 K1 Q
                    break;+ V' O6 @, [* F1 d2 r5 _; f
                case R.id.img_video_play:
    # Y6 Q8 [8 D* e$ n! ~                if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.STOPPED){- j3 G" P+ }. ^1 h, @
                        playVideo();7 t5 x! L7 O1 s0 \5 ?* m
                    }else if (state.getPlaybackStatus() == MediaFile.VideoPlaybackStatus.PAUSED){
    " x$ q" h0 o" [# w9 Y9 e                    mMediaManager.resume(error -> {3 a$ |4 \1 x+ ^6 m; u
                            if (null != error) {% G$ N- Y# J' l3 I' Q' N5 ]
                                showToasts("继续播放失败:" + error.getDescription());
    7 T9 b( M  ^# @# l6 i/ e6 @                        } else {& f1 t* L  o) ?9 }
                                DJILog.e(TAG, "继续播放成功");. Y: }8 M0 i  c% J% @
                                runOnUiThread(new Runnable() {
    ! l" f8 S2 f! |: j5 B; q                                @Override8 J) c1 _' w# B8 s3 U
                                    public void run() {( o% L! P1 n% C" e: D- ^; k
                                        mImageViewVideoPlay.setEnabled(false);
    # r; ]. o0 L) v8 _9 p3 r" @                                    mImageViewVideoPause.setEnabled(true);4 B, @" Q4 X4 {5 d, T- {
                                    }
    + ]+ G2 f& N8 s! h$ M% y' \                            });2 w$ k* V) ~* W  D. M. g- t
                            }
    7 P- W4 Y" t" D' G+ ^' G                    });* T: Q3 Q& s4 x4 B
                    }/ V( F  |) C. o- J- v. E
                    break;( t' O8 V& `7 v( Q$ _4 X0 _
                case R.id.img_video_pause:
    2 x4 P- ^/ [" I0 w                mMediaManager.pause(error -> {& ^1 U# G4 a! y4 y& M
                        if (null != error) {; m0 i3 F; P  f' j1 }
                            showToasts("暂停播放失败:" + error.getDescription());
    7 x1 j- r, S* M( b                    } else {
    ' ^: A+ \. W  `8 P                        DJILog.e(TAG, "暂停播放成功");7 t7 I; s9 f! x; k& r% @! C
                            runOnUiThread(new Runnable() {5 q. z3 M' D* Z' E$ [" b
                                @Override% {- v3 K* f* L  u8 C. C1 A
                                public void run() {% m& v5 B* T4 L, L. k/ [" H
                                    mImageViewVideoPlay.setEnabled(true);) v( t, u( F7 p% E4 |2 L  y
                                    mImageViewVideoPause.setEnabled(false);1 S! ], t8 B" L
                                }) a1 Q/ R9 |1 u; I1 Q* c/ Z
                            });) s+ `, J6 E9 J" f9 ^
                        }0 [, E* J2 }7 ^' K( R7 x% \
                    });
    : r$ X" v0 h, f9 e  O                break;5 O! o0 k. x8 x: |  _1 g
                case R.id.img_video_stop:
    ) m* H. O/ ~$ V3 l2 Q                mMediaManager.stop(error -> {
    , b1 A5 N5 ]/ u                    if (null != error) {
    & v2 _' T# o' {; B5 Q+ T                        showToasts("停止播放失败:" + error.getDescription());3 g% u+ G' H1 ]7 c4 y1 S/ ]; \
                        } else {! B' i; g; d) Q" a& O5 j2 z
                            DJILog.e(TAG, "停止播放成功");/ V& L2 Q3 l- d3 d) o
                        }0 D3 m+ p, y( W
                    });
    & H. _) s; N* j# H1 G4 f                break;
    5 O/ m$ p1 y  U1 @6 w' x& }0 S( H, p        }
    2 ^% t- }4 H5 r  m4 c6 H7 }+ g2 e    }
    1 v+ B! K: t0 x# S! m+ z: f    private void uploadFileByIndex(int index) {
    ; h5 e1 A9 {# \4 p* {$ [        if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MOV) || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.MP4)) {
    ; a5 }" F3 R) Q            showProgressDialog("正在上传");  P! V! U4 L  Z3 j9 p5 u
                new Thread(new Runnable() {' r- P- V$ P% Z) f
                            @Override; ]& K5 s5 r6 f
                            public void run() {
    : J7 v% I( A2 Q. L4 X                            boolean isConnect = sftp.connect().isConnected();
    " e- U. k* B7 _$ M, ]( l                            if (isConnect){: i- y6 }( u+ k0 B9 c+ }
                                    boolean isUpdate = sftp.uploadFile("/mnt/uavFtpFolder/",mediaFileList.get(index).getFileName(), FLY_FILE_VIDEO, mediaFileList.get(index).getFileName());
    - a" `/ p  j$ R. J$ G                                if (isUpdate){
      \, S$ ~1 B: J1 ~' u. C6 ^& E1 \/ `                                    runOnUiThread(new Runnable() {. }/ G/ }% P! {8 U. o
                                            @Override
    1 h8 I& C3 ^, m( T                                        public void run() {
    # d9 {! m( m# S4 i$ ]                                            removeProgressDialog();
    & n( y$ M  ]* \  [8 b                                            http.getHttp(GET_VIDEO_INFO+"?fileName="+mediaFileList.get(index).getFileName(),"GET");! e( @, ^3 p3 c+ b6 K- n) p
                                            }! b! K  |7 r! V8 O1 k# d  G7 e
                                        });8 y6 {* H2 C" D% \
                                        sftp.disconnect();
    $ P; J( B+ N' E# L- i# e2 N0 v                                }else {
    9 Q/ ]4 `/ U* f& o2 k& y( W' Y' R  e8 t                                    runOnUiThread(new Runnable() {
    + _  Q3 P1 h7 l2 q* a# \                                        @Override+ a1 r& ^/ N' U+ |% H+ O0 j
                                            public void run() {
    . }7 @7 Y0 i( \                                            showErrorTip("上传失败");
    0 X9 p) h7 J4 S5 X7 o( W- P5 M                                            removeProgressDialog();6 Q* v* p/ _# b. s2 o" V% \7 q( ]
                                            }
    ; }8 X* P2 v. g4 k6 ~6 Z* ]! n! ^6 _                                    });; q: l1 C& a# j3 D- ^; e
                                    }, o( ^+ V. s/ `: @* B! G
                                }else {
    0 \) s# X2 X; Z* B8 u                                runOnUiThread(new Runnable() {) p3 {5 F9 G7 X
                                        @Override
      V, j# B6 w( `9 W% t2 m. D                                    public void run() {* p8 [/ f, f0 t0 R
                                            showErrorTip("服务器连接失败");
    5 h0 x# ?& t8 g; [) P; Y8 b                                        removeProgressDialog();, M6 ?% U+ \+ ?0 s; H6 Q2 F
                                        }) T6 J% h% _0 W  N) O. c
                                    });
    5 z$ n4 j* P  d% j& a                            }
    7 ]. H7 f8 P) E8 J, f                        }: Y1 l1 c: V6 K# E& z3 l
                        }).start();
    . v, U' V+ q; i* G        }else {/ s( H* M. s1 R, ?! x9 e6 e% V- \; ?
                showToasts("当前仅支持视频上传,请选择视频文件!");
    7 O+ `5 c! y4 U4 j# e        }( H% m+ Q; B+ Q8 Z/ p/ m7 p
        }. }, u" B) J( `) V, h
        private boolean isMavicAir2() {
    3 c1 n. c: Q" F8 u4 G0 w9 A        BaseProduct baseProduct = ReceiverApplication.getProductInstance();7 W- b5 }8 |: m; J% X- K& |
            if (baseProduct != null) {6 Q4 l; H. H9 J6 A1 h' v- Q
                return baseProduct.getModel() == Model.MAVIC_AIR_2;
    : q8 V# I  w1 ~' y8 f        }
    5 g- R! ]7 U2 j( h+ y7 M        return false;
    $ ^' Q9 f! \7 @0 W    }& N9 j; @* K. @, a4 {
        private boolean isM300() {3 {( e0 ]0 O7 V* A! n) ~
            BaseProduct baseProduct = ReceiverApplication.getProductInstance();
    2 C6 v; p# h8 T' u0 c        if (baseProduct != null) {3 S+ o' ^1 Z# A6 w
                return baseProduct.getModel() == Model.MATRICE_300_RTK;3 v. N' K" Y9 D+ v
            }
    2 l4 b7 W1 o) v        return false;  J* L$ x! M6 ~
        }
    3 K, ~" I0 N+ v& C$ K* t8 K5 y}
    ( B, q2 ~1 u: k1 q6 U: K运行后界面如下:8 n' h2 H  |& n7 e3 w

    splrzdloa3i64015956124.jpg

    splrzdloa3i64015956124.jpg

    : ?3 N" E! q; c
    , _2 l# M$ ]0 q2 Q: |% }

    szmxbq0ilqc64015956224.png

    szmxbq0ilqc64015956224.png

    - y! O/ h7 {6 P- ]: u# S0 k往期推荐LabVIEW OCR 实现车牌识别- J% i0 P# ^0 W6 M- h- K
    和12岁小同志搞创客开发:有意思的激光切割技术! q8 T" V3 q. `5 [$ s$ c8 q
    JavaScript+TensorFlow.js让你在视频中瞬间消失- t5 K2 B8 W0 k: S2 ]$ T$ E
    使用OpenCV测量图像中物体之间的距离/ ?' k8 _# v* ~/ j0 o
    全网仅此一篇:工业级压力传感器设计及实现
    5 {! p: F- q( T
    - x0 L5 @  W5 P  N

    libqpzwnv4k64015956324.jpg

    libqpzwnv4k64015956324.jpg

    ) }/ g: v9 I3 M& j0 }

    eaw5giox2vj64015956424.gif

    eaw5giox2vj64015956424.gif
    ; Y( }9 R- z+ K0 d7 e4 W
    点击阅读原文,更精彩~
  • 回复

    使用道具 举报

    发表回复

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

    本版积分规则


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