├── MediaManagerDemo
├── settings.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── raw
│ │ │ │ │ └── keep.xml
│ │ │ │ ├── drawable
│ │ │ │ │ ├── back_button_press.png
│ │ │ │ │ ├── back_button_disable.png
│ │ │ │ │ ├── back_button_normal.png
│ │ │ │ │ ├── background_selector.xml
│ │ │ │ │ ├── round_btn_normal.xml
│ │ │ │ │ ├── round_btn_disable.xml
│ │ │ │ │ ├── round_btn_pressed.xml
│ │ │ │ │ ├── selector_back_button.xml
│ │ │ │ │ └── round_btn.xml
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── prompt_input_position.xml
│ │ │ │ │ ├── media_info_item.xml
│ │ │ │ │ ├── activity_connection.xml
│ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ └── activity_default_layout.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── dji
│ │ │ │ │ └── mediaManagerDemo
│ │ │ │ │ ├── MApplication.java
│ │ │ │ │ ├── DefaultLayoutActivity.java
│ │ │ │ │ ├── DemoApplication.java
│ │ │ │ │ ├── ConnectionActivity.java
│ │ │ │ │ └── MainActivity.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── dji
│ │ │ │ └── mediaManagerDemo
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── dji
│ │ │ └── mediaManagerDemo
│ │ │ └── ExampleInstrumentedTest.java
│ ├── .gitignore
│ ├── build.gradle
│ └── proguard-rules.pro
├── build.gradle
├── gradlew.bat
└── gradlew
├── LICENSE.txt
├── .gitignore
└── README.md
/MediaManagerDemo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/MediaManagerDemo/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4608M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
--------------------------------------------------------------------------------
/MediaManagerDemo/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/raw/keep.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/back_button_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/drawable/back_button_press.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/back_button_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/drawable/back_button_disable.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/back_button_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/drawable/back_button_normal.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DJI-Mobile-SDK-Tutorials/Android-MediaManagerDemo/HEAD/MediaManagerDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MediaManagerDemo/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Sep 29 16:38:55 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip
7 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/background_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/round_btn_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/round_btn_disable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/round_btn_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/selector_back_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #000000
7 | #FFFFFF
8 | #242d34
9 | #00000000
10 | #80000000
11 |
12 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/test/java/com/dji/mediaManagerDemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MediaManagerDemo
3 | Settings
4 | Disconnected
5 | Product Information
6 | Status: No Product Connected
7 | Model Not Available
8 | Push Info
9 | DJI SDK Version: %1$s
10 |
11 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/drawable/round_btn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/MediaManagerDemo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.2.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | mavenCentral()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | gradle/
19 | build/
20 | gradlew
21 | gradlew.bat
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # Intellij
39 | *.iml
40 | .idea/
41 | .idea/*
42 | .idea/libraries
43 |
44 | # Keystore files
45 | *.jks
46 |
47 | .DS_Store
48 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/java/com/dji/mediaManagerDemo/MApplication.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.secneo.sdk.Helper;
7 |
8 | public class MApplication extends Application {
9 |
10 | private DemoApplication demoApplication;
11 | @Override
12 | protected void attachBaseContext(Context paramContext) {
13 | super.attachBaseContext(paramContext);
14 | Helper.install(MApplication.this);
15 | if (demoApplication == null) {
16 | demoApplication = new DemoApplication();
17 | demoApplication.setContext(this);
18 | }
19 | }
20 |
21 | @Override
22 | public void onCreate() {
23 | super.onCreate();
24 | demoApplication.onCreate();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/androidTest/java/com/dji/mediaManagerDemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.dji.mediaManagerDemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/layout/prompt_input_position.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 | Copyright (c) 2019 DJI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 | obj/
15 | DJI-SDK-LIB_3.1/build/
16 | build/
17 |
18 | # generated file
19 | lint.xml
20 |
21 | # Local configuration file (sdk/lib path, etc)
22 | local.properties
23 | project.properties
24 |
25 | # Eclipse project files
26 | .classpath
27 | .settings/
28 |
29 | # Proguard folder generated by Eclipse
30 | proguard/
31 |
32 | # Intellij project files
33 | *.iml
34 | *.ipr
35 | *.iws
36 | .idea/
37 |
38 | # Mac files
39 | .DS_Store
40 |
41 | # Gradle generated files
42 | .gradle/
43 |
44 | # Signing files
45 | .signing/
46 |
47 | # User-specific configurations
48 | .idea/libraries/
49 | .idea/workspace.xml
50 | .idea/tasks.xml
51 | .idea/.name
52 | .idea/compiler.xml
53 | .idea/copyright/profiles_settings.xml
54 | .idea/encodings.xml
55 | .idea/misc.xml
56 | .idea/modules.xml
57 | .idea/scopes/scope_settings.xml
58 | .idea/vcs.xml
59 | *.iml
60 |
61 | # OS-specific files
62 | .DS_Store
63 | .DS_Store?
64 | ._*
65 | .Spotlight-V100
66 | .Trashes
67 | ehthumbs.db
68 | Thumbs.db
69 |
70 | # Import summary file
71 | import-summary.txt
72 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/java/com/dji/mediaManagerDemo/DefaultLayoutActivity.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import dji.keysdk.ProductKey;
11 | import dji.ux.widget.FPVWidget;
12 |
13 | public class DefaultLayoutActivity extends AppCompatActivity implements View.OnClickListener{
14 |
15 | private Button mMediaManagerBtn;
16 | private FPVWidget fpvWidget;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_default_layout);
22 | mMediaManagerBtn = (Button)findViewById(R.id.btn_mediaManager);
23 | fpvWidget = findViewById(R.id.fpv_widget);
24 | mMediaManagerBtn.setOnClickListener(this);
25 | }
26 |
27 | @Override
28 | public void onClick(View v) {
29 | if (v.getId() == R.id.btn_mediaManager) {
30 | Intent intent = new Intent(this, MainActivity.class);
31 | startActivity(intent);
32 | }
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | fpvWidget.updateWidget(ProductKey.create(ProductKey.MODEL_NAME));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-MediaManagerDemo
2 |
3 | ## Introduction
4 |
5 | This demo is designed for you to learn how to use `MediaManager` to interact with the file system on the SD card of the aircraft's camera. You can use it to preview photos, play videos, download or delete files and so on.
6 |
7 | ## Requirements
8 |
9 | - Android Studio 4.2.1
10 | - Android System 5.0.0+
11 | - DJI Android SDK 4.16.1
12 | - DJI Android UXSDK 4.16
13 |
14 | ## Supported DJI Products
15 |
16 | - Mavic 2 Series
17 | - Mavic Air
18 | - Mavic Pro
19 | - Spark
20 | - Phantom 4 Pro
21 | - Phantom 4 Advanced
22 | - Inspire 2
23 |
24 | ## Tutorial
25 |
26 | For this demo's tutorial: **Creating a Media Manager Application**, please refer to .
27 |
28 | ## Feedback
29 |
30 | We’d love to hear your feedback on this demo and tutorial.
31 |
32 | Please use [DJI Support] (https://djisdksupport.zendesk.com/hc/requests/new) when you meet any problems of using this demo. At a minimum please let us know:
33 |
34 | * Which DJI Product you are using?
35 | * Which Android Device and Android system version you are using?
36 | * Which Android Studio version you are using?
37 | * A short description of your problem includes debugging logs or screenshots.
38 | * Any bugs or typos you come across.
39 |
40 | ## License
41 |
42 | Android-MediaManagerDemo is available under the MIT license. Please see the LICENSE file for more info.
43 |
44 | ## Join Us
45 |
46 | DJI is looking for all kinds of Software Engineers to continue building the Future of Possible. Available positions in Shenzhen, China and around the world. If you are interested, please send your resume to . For more details, and list of all our global offices, please check .
47 |
48 | DJI 招软件工程师啦,based在深圳,如果你想和我们一起把DJI产品做得更好,请发送简历到 . 详情请浏览 .
49 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/layout/media_info_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
27 |
28 |
36 |
37 |
45 |
46 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/MediaManagerDemo/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/layout/activity_connection.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
33 |
34 |
43 |
44 |
55 |
56 |
64 |
65 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
29 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
67 |
68 |
72 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | repositories {
4 | mavenLocal()
5 | mavenCentral()
6 | maven { url 'https://mapbox.bintray.com/mapbox' }
7 | }
8 |
9 | android {
10 | compileSdkVersion 30
11 | buildToolsVersion '30.0.2'
12 |
13 | defaultConfig {
14 | minSdkVersion 21
15 | targetSdkVersion 30
16 | multiDexEnabled true
17 | ndk {
18 | abiFilters 'armeabi-v7a', 'arm64-v8a'
19 | }
20 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
21 |
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | }
29 | debug {
30 | shrinkResources true
31 | minifyEnabled true
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 |
36 | dexOptions {
37 | javaMaxHeapSize "4g"
38 | }
39 |
40 | packagingOptions {
41 | doNotStrip "*/*/libdjivideo.so"
42 | doNotStrip "*/*/libSDKRelativeJNI.so"
43 | doNotStrip "*/*/libFlyForbid.so"
44 | doNotStrip "*/*/libduml_vision_bokeh.so"
45 | doNotStrip "*/*/libyuv2.so"
46 | doNotStrip "*/*/libGroudStation.so"
47 | doNotStrip "*/*/libFRCorkscrew.so"
48 | doNotStrip "*/*/libUpgradeVerify.so"
49 | doNotStrip "*/*/libFR.so"
50 | doNotStrip "*/*/libDJIFlySafeCore.so"
51 | doNotStrip "*/*/libdjifs_jni.so"
52 | doNotStrip "*/*/libsfjni.so"
53 | doNotStrip "*/*/libDJICommonJNI.so"
54 | doNotStrip "*/*/libDJICSDKCommon.so"
55 | doNotStrip "*/*/libDJIUpgradeCore.so"
56 | doNotStrip "*/*/libDJIUpgradeJNI.so"
57 | exclude 'META-INF/rxjava.properties'
58 | }
59 |
60 | compileOptions {
61 | sourceCompatibility JavaVersion.VERSION_1_8
62 | targetCompatibility JavaVersion.VERSION_1_8
63 | }
64 | }
65 |
66 |
67 | dependencies {
68 | implementation 'androidx.multidex:multidex:2.0.1'
69 | implementation 'com.squareup:otto:1.3.8'
70 | implementation('com.dji:dji-sdk:4.16', {
71 | /**
72 | * Uncomment the "library-anti-distortion" if your app does not need Anti Distortion for Mavic 2 Pro and Mavic 2 Zoom.
73 | * Uncomment the "fly-safe-database" if you need database for release, or we will download it when DJISDKManager.getInstance().registerApp
74 | * is called.
75 | * Both will greatly reducing the size of the APK.
76 | */
77 | exclude module: 'library-anti-distortion'
78 | //exclude module: 'fly-safe-database'
79 | })
80 |
81 | androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
82 | exclude group: 'com.android.support', module: 'support-annotations'
83 | })
84 |
85 | compileOnly 'com.dji:dji-sdk-provided:4.16'
86 | implementation ('com.dji:dji-uxsdk:4.16', {
87 | /**
88 | * Uncomment the following line to exclude amap from the app.
89 | * Note that Google Play Store does not allow APKs that include this library.
90 | */
91 | // exclude group: 'com.amap.api'
92 | exclude module: 'dji-sdk'
93 | })
94 |
95 | implementation 'androidx.appcompat:appcompat:1.2.0'
96 | implementation 'androidx.core:core:1.3.2'
97 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
98 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
99 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
100 | implementation 'androidx.annotation:annotation:1.2.0'
101 | }
102 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keepattributes Exceptions,InnerClasses,*Annotation*,Signature,EnclosingMethod
2 |
3 | -dontoptimize
4 | -dontpreverify
5 | -dontwarn okio.**
6 | -dontwarn org.bouncycastle.**
7 | -dontwarn dji.**
8 | -dontwarn com.dji.**
9 | -dontwarn sun.**
10 | -dontwarn java.**
11 | -dontwarn com.amap.api.**
12 | -dontwarn com.here.**
13 | -dontwarn com.mapbox.**
14 | -dontwarn okhttp3.**
15 | -dontwarn retrofit2.**
16 |
17 | -keepclassmembers enum * {
18 | public static ;
19 | }
20 |
21 | -keepnames class * implements java.io.Serializable
22 | -keepclassmembers class * implements java.io.Serializable {
23 | static final long serialVersionUID;
24 | private static final java.io.ObjectStreamField[] serialPersistentFields;
25 | !static !transient ;
26 | private void writeObject(java.io.ObjectOutputStream);
27 | private void readObject(java.io.ObjectInputStream);
28 | java.lang.Object writeReplace();
29 | java.lang.Object readResolve();
30 | }
31 | -keep class * extends android.os.Parcelable {
32 | public static final android.os.Parcelable$Creator *;
33 | }
34 |
35 | -keep,allowshrinking class * extends dji.publics.DJIUI.** {
36 | public ;
37 | }
38 |
39 | -keep class net.sqlcipher.** { *; }
40 |
41 | -keep class net.sqlcipher.database.* { *; }
42 |
43 | -keep class dji.** { *; }
44 |
45 | -keep class com.dji.** { *; }
46 |
47 | -keep class com.google.** { *; }
48 |
49 | -keep class org.bouncycastle.** { *; }
50 |
51 | -keep,allowshrinking class org.** { *; }
52 |
53 | -keep class com.squareup.wire.** { *; }
54 |
55 | -keep class sun.misc.Unsafe { *; }
56 |
57 | -keep class com.secneo.** { *; }
58 |
59 | -keep class org.greenrobot.eventbus.**{*;}
60 |
61 | -keep class it.sauronsoftware.ftp4j.**{*;}
62 |
63 | -keepclasseswithmembers,allowshrinking class * {
64 | native ;
65 | }
66 |
67 | -keep class * implements com.google.gson.TypeAdapterFactory
68 | -keep class * implements com.google.gson.JsonSerializer
69 | -keep class * implements com.google.gson.JsonDeserializer
70 |
71 | -keep class androidx.appcompat.widget.SearchView { *; }
72 |
73 | -keepclassmembers class * extends android.app.Service
74 | -keepclassmembers public class * extends android.view.View {
75 | void set*(***);
76 | *** get*();
77 | }
78 | -keepclassmembers class * extends android.app.Activity {
79 | public void *(android.view.View);
80 | }
81 | -keep class androidx.** { *; }
82 | -keep class android.media.** { *; }
83 | -keep class okio.** { *; }
84 | -keep class com.lmax.disruptor.** { *; }
85 | -keep class com.qx.wz.dj.rtcm.* { *; }
86 |
87 | -dontwarn com.mapbox.services.android.location.LostLocationEngine
88 | -dontwarn com.mapbox.services.android.location.MockLocationEngine
89 | -keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver {
90 | (...);
91 | }
92 | # ViewModel's empty constructor is considered to be unused by proguard
93 | -keepclassmembers class * extends android.arch.lifecycle.ViewModel {
94 | (...);
95 | }
96 | # keep Lifecycle State and Event enums values
97 | -keepclassmembers class android.arch.lifecycle.Lifecycle$State { *; }
98 | -keepclassmembers class android.arch.lifecycle.Lifecycle$Event { *; }
99 | # keep methods annotated with @OnLifecycleEvent even if they seem to be unused
100 | # (Mostly for LiveData.LifecycleBoundObserver.onStateChange(), but who knows)
101 | -keepclassmembers class * {
102 | @android.arch.lifecycle.OnLifecycleEvent *;
103 | }
104 |
105 | -keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver {
106 | (...);
107 | }
108 |
109 | -keep class * implements android.arch.lifecycle.LifecycleObserver {
110 | (...);
111 | }
112 | -keepclassmembers class android.arch.** { *; }
113 | -keep class android.arch.** { *; }
114 | -dontwarn android.arch.**
115 |
116 | -keep class org.apache.commons.** {*;}
117 |
118 |
119 | #<------------ utmiss config start------------>
120 | -keep class dji.sdk.utmiss.** { *; }
121 | -keep class utmisslib.** { *; }
122 | #<------------ utmiss config end------------>
--------------------------------------------------------------------------------
/MediaManagerDemo/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
35 |
36 |
44 |
45 |
53 |
54 |
62 |
63 |
71 |
72 |
80 |
81 |
89 |
90 |
98 |
99 |
100 |
106 |
107 |
116 |
117 |
123 |
124 |
132 |
133 |
137 |
138 |
145 |
146 |
154 |
155 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/res/layout/activity_default_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
17 |
18 |
21 |
22 |
23 |
29 |
30 |
34 |
35 |
38 |
39 |
42 |
43 |
46 |
47 |
50 |
51 |
54 |
55 |
58 |
59 |
63 |
64 |
68 |
69 |
70 |
79 |
80 |
83 |
84 |
87 |
88 |
91 |
92 |
95 |
96 |
99 |
100 |
103 |
104 |
107 |
108 |
111 |
112 |
115 |
116 |
117 |
123 |
124 |
130 |
131 |
136 |
137 |
138 |
139 |
140 |
146 |
147 |
151 |
152 |
156 |
157 |
158 |
159 |
165 |
166 |
167 |
177 |
178 |
188 |
189 |
197 |
198 |
199 |
205 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/java/com/dji/mediaManagerDemo/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Build;
7 | import android.os.Handler;
8 | import android.os.Looper;
9 | import androidx.core.content.ContextCompat;
10 | import android.util.Log;
11 | import android.widget.Toast;
12 |
13 | import dji.common.error.DJIError;
14 | import dji.common.error.DJISDKError;
15 | import dji.sdk.base.BaseComponent;
16 | import dji.sdk.base.BaseProduct;
17 | import dji.sdk.camera.Camera;
18 | import dji.sdk.products.Aircraft;
19 | import dji.sdk.products.HandHeld;
20 | import dji.sdk.sdkmanager.DJISDKInitEvent;
21 | import dji.sdk.sdkmanager.DJISDKManager;
22 |
23 | public class DemoApplication extends Application {
24 |
25 | public static final String FLAG_CONNECTION_CHANGE = "mediaManager_demo_connection_change";
26 |
27 | private static BaseProduct mProduct;
28 | private Handler mHandler;
29 | private DJISDKManager.SDKManagerCallback mDJISDKManagerCallback;
30 | private Application instance;
31 |
32 | public void setContext(Application application) {
33 | instance = application;
34 | }
35 |
36 | @Override
37 | public Context getApplicationContext() {
38 | return instance;
39 | }
40 |
41 | public DemoApplication() {
42 | }
43 | /**
44 | * This function is used to get the instance of DJIBaseProduct.
45 | * If no product is connected, it returns null.
46 | */
47 | public static synchronized BaseProduct getProductInstance() {
48 | if (null == mProduct) {
49 | mProduct = DJISDKManager.getInstance().getProduct();
50 | }
51 | return mProduct;
52 | }
53 |
54 | public static synchronized Aircraft getAircraftInstance() {
55 | if (!isAircraftConnected()) return null;
56 | return (Aircraft) getProductInstance();
57 | }
58 |
59 | public static synchronized Camera getCameraInstance() {
60 |
61 | if (getProductInstance() == null) return null;
62 |
63 | Camera camera = null;
64 |
65 | if (getProductInstance() instanceof Aircraft){
66 | camera = ((Aircraft) getProductInstance()).getCamera();
67 |
68 | } else if (getProductInstance() instanceof HandHeld) {
69 | camera = ((HandHeld) getProductInstance()).getCamera();
70 | }
71 |
72 | return camera;
73 | }
74 |
75 | public static boolean isAircraftConnected() {
76 | return getProductInstance() != null && getProductInstance() instanceof Aircraft;
77 | }
78 |
79 | public static boolean isHandHeldConnected() {
80 | return getProductInstance() != null && getProductInstance() instanceof HandHeld;
81 | }
82 |
83 | public static boolean isProductModuleAvailable() {
84 | return (null != DemoApplication.getProductInstance());
85 | }
86 |
87 | public static boolean isCameraModuleAvailable() {
88 | return isProductModuleAvailable() &&
89 | (null != DemoApplication.getProductInstance().getCamera());
90 | }
91 |
92 | public static boolean isPlaybackAvailable() {
93 | return isCameraModuleAvailable() &&
94 | (null != DemoApplication.getProductInstance().getCamera().getPlaybackManager());
95 | }
96 |
97 |
98 | @Override
99 | public void onCreate() {
100 | super.onCreate();
101 | mHandler = new Handler(Looper.getMainLooper());
102 |
103 | /**
104 | * When starting SDK services, an instance of interface DJISDKManager.DJISDKManagerCallback will be used to listen to
105 | * the SDK Registration result and the product changing.
106 | */
107 | mDJISDKManagerCallback = new DJISDKManager.SDKManagerCallback() {
108 |
109 | //Listens to the SDK registration result
110 | @Override
111 | public void onRegister(DJIError error) {
112 |
113 | if(error == DJISDKError.REGISTRATION_SUCCESS) {
114 |
115 | Handler handler = new Handler(Looper.getMainLooper());
116 | handler.post(new Runnable() {
117 | @Override
118 | public void run() {
119 | Toast.makeText(getApplicationContext(), "Register Success", Toast.LENGTH_LONG).show();
120 | }
121 | });
122 |
123 | DJISDKManager.getInstance().startConnectionToProduct();
124 |
125 | } else {
126 |
127 | Handler handler = new Handler(Looper.getMainLooper());
128 | handler.post(new Runnable() {
129 |
130 | @Override
131 | public void run() {
132 | Toast.makeText(getApplicationContext(), "Register sdk fails, check network is available", Toast.LENGTH_LONG).show();
133 | }
134 | });
135 |
136 | }
137 | Log.e("TAG", error.toString());
138 | }
139 |
140 | @Override
141 | public void onProductDisconnect() {
142 | Log.d("TAG", "onProductDisconnect");
143 | notifyStatusChange();
144 | }
145 | @Override
146 | public void onProductConnect(BaseProduct baseProduct) {
147 | Log.d("TAG", String.format("onProductConnect newProduct:%s", baseProduct));
148 | notifyStatusChange();
149 |
150 | }
151 |
152 | @Override
153 | public void onProductChanged(BaseProduct baseProduct) {
154 |
155 | }
156 |
157 | @Override
158 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
159 | BaseComponent newComponent) {
160 | if (newComponent != null) {
161 | newComponent.setComponentListener(new BaseComponent.ComponentListener() {
162 |
163 | @Override
164 | public void onConnectivityChange(boolean isConnected) {
165 | Log.d("TAG", "onComponentConnectivityChanged: " + isConnected);
166 | notifyStatusChange();
167 | }
168 | });
169 | }
170 |
171 | Log.d("TAG",
172 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s",
173 | componentKey,
174 | oldComponent,
175 | newComponent));
176 |
177 | }
178 | @Override
179 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {
180 |
181 | }
182 |
183 | @Override
184 | public void onDatabaseDownloadProgress(long l, long l1) {
185 |
186 | }
187 | };
188 |
189 | //Check the permissions before registering the application for android system 6.0 above.
190 | int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
191 | int permissionCheck2 = ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.READ_PHONE_STATE);
192 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (permissionCheck == 0 && permissionCheck2 == 0)) {
193 | //This is used to start SDK services and initiate SDK.
194 | DJISDKManager.getInstance().registerApp(getApplicationContext(), mDJISDKManagerCallback);
195 | Toast.makeText(getApplicationContext(), "registering, pls wait...", Toast.LENGTH_LONG).show();
196 |
197 | } else {
198 | Toast.makeText(getApplicationContext(), "Please check if the permission is granted.", Toast.LENGTH_LONG).show();
199 | }
200 | }
201 |
202 | private void notifyStatusChange() {
203 | mHandler.removeCallbacks(updateRunnable);
204 | mHandler.postDelayed(updateRunnable, 500);
205 | }
206 |
207 | private Runnable updateRunnable = new Runnable() {
208 |
209 | @Override
210 | public void run() {
211 | Intent intent = new Intent(FLAG_CONNECTION_CHANGE);
212 | getApplicationContext().sendBroadcast(intent);
213 | }
214 | };
215 |
216 | }
217 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/java/com/dji/mediaManagerDemo/ConnectionActivity.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.content.pm.PackageManager;
10 | import android.os.AsyncTask;
11 | import android.os.Build;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.core.app.ActivityCompat;
15 | import android.os.Bundle;
16 | import androidx.core.content.ContextCompat;
17 | import android.text.TextUtils;
18 | import android.util.Log;
19 | import android.view.View;
20 | import android.widget.Button;
21 | import android.widget.TextView;
22 | import android.widget.Toast;
23 |
24 | import dji.common.error.DJIError;
25 | import dji.common.error.DJISDKError;
26 | import dji.common.useraccount.UserAccountState;
27 | import dji.common.util.CommonCallbacks;
28 | import dji.keysdk.DJIKey;
29 | import dji.keysdk.KeyManager;
30 | import dji.keysdk.ProductKey;
31 | import dji.keysdk.callback.KeyListener;
32 | import dji.log.DJILog;
33 | import dji.sdk.base.BaseComponent;
34 | import dji.sdk.base.BaseProduct;
35 | import dji.sdk.products.Aircraft;
36 | import dji.sdk.sdkmanager.DJISDKInitEvent;
37 | import dji.sdk.sdkmanager.DJISDKManager;
38 | import dji.sdk.useraccount.UserAccountManager;
39 | import java.util.ArrayList;
40 | import java.util.List;
41 | import java.util.concurrent.atomic.AtomicBoolean;
42 |
43 | public class ConnectionActivity extends Activity implements View.OnClickListener {
44 |
45 | private static final String TAG = MainActivity.class.getName();
46 |
47 | private TextView mTextConnectionStatus;
48 | private TextView mTextProduct;
49 | private TextView mTextModelAvailable;
50 | private TextView mVersionTv;
51 |
52 | private Button mBtnOpen;
53 | private static final String[] REQUIRED_PERMISSION_LIST = new String[]{
54 | Manifest.permission.BLUETOOTH,
55 | Manifest.permission.BLUETOOTH_ADMIN,
56 | Manifest.permission.VIBRATE,
57 | Manifest.permission.INTERNET,
58 | Manifest.permission.ACCESS_WIFI_STATE,
59 | Manifest.permission.ACCESS_COARSE_LOCATION,
60 | Manifest.permission.ACCESS_NETWORK_STATE,
61 | Manifest.permission.ACCESS_FINE_LOCATION,
62 | Manifest.permission.CHANGE_WIFI_STATE,
63 | Manifest.permission.RECORD_AUDIO,
64 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
65 | Manifest.permission.READ_EXTERNAL_STORAGE,
66 | Manifest.permission.READ_PHONE_STATE,
67 | };
68 | private List missingPermission = new ArrayList<>();
69 | private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false);
70 | private static final int REQUEST_PERMISSION_CODE = 12345;
71 | private DJIKey firmwareKey;
72 | private KeyListener firmwareVersionUpdater;
73 | private boolean hasStartedFirmVersionListener = false;
74 |
75 | @Override
76 | protected void onCreate(Bundle savedInstanceState) {
77 | super.onCreate(savedInstanceState);
78 | checkAndRequestPermissions();
79 | setContentView(R.layout.activity_connection);
80 | initUI();
81 |
82 | // Register the broadcast receiver for receiving the device connection's changes.
83 | IntentFilter filter = new IntentFilter();
84 | filter.addAction(DemoApplication.FLAG_CONNECTION_CHANGE);
85 | registerReceiver(mReceiver, filter);
86 | }
87 |
88 | /**
89 | * Checks if there is any missing permissions, and
90 | * requests runtime permission if needed.
91 | */
92 | private void checkAndRequestPermissions() {
93 | // Check for permissions
94 | for (String eachPermission : REQUIRED_PERMISSION_LIST) {
95 | if (ContextCompat.checkSelfPermission(this, eachPermission) != PackageManager.PERMISSION_GRANTED) {
96 | missingPermission.add(eachPermission);
97 | }
98 | }
99 | // Request for missing permissions
100 | if (!missingPermission.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
101 | ActivityCompat.requestPermissions(this,
102 | missingPermission.toArray(new String[missingPermission.size()]),
103 | REQUEST_PERMISSION_CODE);
104 | }
105 | }
106 |
107 | /**
108 | * Result of runtime permission request
109 | */
110 | @Override
111 | public void onRequestPermissionsResult(int requestCode,
112 | @NonNull String[] permissions,
113 | @NonNull int[] grantResults) {
114 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
115 | // Check for granted permission and remove from missing list
116 | if (requestCode == REQUEST_PERMISSION_CODE) {
117 | for (int i = grantResults.length - 1; i >= 0; i--) {
118 | if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
119 | missingPermission.remove(permissions[i]);
120 | }
121 | }
122 | }
123 | // If there is enough permission, we will start the registration
124 | if (missingPermission.isEmpty()) {
125 | startSDKRegistration();
126 | } else {
127 | showToast("Missing permissions!!!");
128 | }
129 | }
130 |
131 | private void startSDKRegistration() {
132 | if (isRegistrationInProgress.compareAndSet(false, true)) {
133 | AsyncTask.execute(new Runnable() {
134 | @Override
135 | public void run() {
136 | showToast( "registering, pls wait...");
137 | DJISDKManager.getInstance().registerApp(ConnectionActivity.this.getApplicationContext(), new DJISDKManager.SDKManagerCallback() {
138 | @Override
139 | public void onRegister(DJIError djiError) {
140 | if (djiError == DJISDKError.REGISTRATION_SUCCESS) {
141 | DJILog.e("App registration", DJISDKError.REGISTRATION_SUCCESS.getDescription());
142 | DJISDKManager.getInstance().startConnectionToProduct();
143 | showToast("Register Success");
144 | } else {
145 | showToast( "Register sdk fails, check network is available: djiError:"+djiError);
146 | }
147 | Log.v(TAG, djiError.getDescription());
148 | }
149 |
150 | @Override
151 | public void onProductDisconnect() {
152 | Log.d(TAG, "onProductDisconnect");
153 | showToast("Product Disconnected");
154 |
155 | }
156 |
157 | @Override
158 | public void onProductConnect(BaseProduct baseProduct) {
159 | Log.d(TAG, String.format("onProductConnect newProduct:%s", baseProduct));
160 | showToast("Product Connected");
161 |
162 | }
163 |
164 | @Override
165 | public void onProductChanged(BaseProduct baseProduct) {
166 |
167 | }
168 |
169 | @Override
170 | public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
171 | BaseComponent newComponent) {
172 | if (newComponent != null) {
173 | newComponent.setComponentListener(new BaseComponent.ComponentListener() {
174 |
175 | @Override
176 | public void onConnectivityChange(boolean isConnected) {
177 | Log.d(TAG, "onComponentConnectivityChanged: " + isConnected);
178 | }
179 | });
180 | }
181 | Log.d(TAG,
182 | String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s",
183 | componentKey,
184 | oldComponent,
185 | newComponent));
186 | }
187 | @Override
188 | public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {
189 |
190 | }
191 |
192 | @Override
193 | public void onDatabaseDownloadProgress(long l, long l1) {
194 |
195 | }
196 | });
197 | }
198 | });
199 | }
200 | }
201 |
202 | @Override
203 | public void onResume() {
204 | Log.e(TAG, "onResume");
205 | super.onResume();
206 | updateTitleBar();
207 | }
208 |
209 | @Override
210 | public void onPause() {
211 | Log.e(TAG, "onPause");
212 | super.onPause();
213 | }
214 |
215 | @Override
216 | public void onStop() {
217 | Log.e(TAG, "onStop");
218 | super.onStop();
219 | }
220 |
221 | public void onReturn(View view){
222 | Log.e(TAG, "onReturn");
223 | this.finish();
224 | }
225 |
226 | @Override
227 | protected void onDestroy() {
228 | Log.e(TAG, "onDestroy");
229 | unregisterReceiver(mReceiver);
230 | removeFirmwareVersionListener();
231 | super.onDestroy();
232 | }
233 |
234 | private void initUI() {
235 | mTextConnectionStatus = (TextView) findViewById(R.id.text_connection_status);
236 | mTextModelAvailable = (TextView) findViewById(R.id.text_model_available);
237 | mTextProduct = (TextView) findViewById(R.id.text_product_info);
238 | mVersionTv = (TextView) findViewById(R.id.textView2);
239 | mVersionTv.setText(getResources().getString(R.string.sdk_version, DJISDKManager.getInstance().getSDKVersion()));
240 | mBtnOpen = (Button) findViewById(R.id.btn_open);
241 | mBtnOpen.setOnClickListener(this);
242 | mBtnOpen.setEnabled(false);
243 | }
244 |
245 | protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
246 | @Override
247 | public void onReceive(Context context, Intent intent) {
248 | refreshSDKRelativeUI();
249 | }
250 | };
251 |
252 | private void updateTitleBar() {
253 | boolean ret = false;
254 | BaseProduct product = DemoApplication.getProductInstance();
255 | if (product != null) {
256 | if(product.isConnected()) {
257 | //The product is connected
258 | showToast(DemoApplication.getProductInstance().getModel() + " Connected");
259 | ret = true;
260 | } else {
261 | if(product instanceof Aircraft) {
262 | Aircraft aircraft = (Aircraft)product;
263 | if(aircraft.getRemoteController() != null && aircraft.getRemoteController().isConnected()) {
264 | // The product is not connected, but the remote controller is connected
265 | showToast("only RC Connected");
266 | ret = true;
267 | }
268 | }
269 | }
270 | }
271 | }
272 |
273 | public void showToast(final String msg) {
274 | runOnUiThread(new Runnable() {
275 | public void run() {
276 | Toast.makeText(ConnectionActivity.this, msg, Toast.LENGTH_SHORT).show();
277 | }
278 | });
279 | }
280 |
281 | private void updateVersion() {
282 | String version = null;
283 | if (DemoApplication.getProductInstance() != null) {
284 | version = DemoApplication.getProductInstance().getFirmwarePackageVersion();
285 | }
286 | if (TextUtils.isEmpty(version)) {
287 | mTextModelAvailable.setText("Firmware version:N/A"); //Firmware version:
288 | } else {
289 | mTextModelAvailable.setText("Firmware version:"+version); //"Firmware version: " +
290 | removeFirmwareVersionListener();
291 | }
292 | }
293 |
294 | @Override
295 | public void onClick(View v) {
296 | if (v.getId() == R.id.btn_open) {
297 | Intent intent = new Intent(this, DefaultLayoutActivity.class);
298 | startActivity(intent);
299 | }
300 | }
301 |
302 | private void refreshSDKRelativeUI() {
303 | BaseProduct mProduct = DemoApplication.getProductInstance();
304 |
305 | if (null != mProduct && mProduct.isConnected()) {
306 | Log.v(TAG, "refreshSDK: True");
307 | mBtnOpen.setEnabled(true);
308 | String str = mProduct instanceof Aircraft ? "DJIAircraft" : "DJIHandHeld";
309 | mTextConnectionStatus.setText("Status: " + str + " connected");
310 | tryUpdateFirmwareVersionWithListener();
311 | if (null != mProduct.getModel()) {
312 | mTextProduct.setText("" + mProduct.getModel().getDisplayName());
313 | } else {
314 | mTextProduct.setText(R.string.product_information);
315 | }
316 | loginAccount();
317 | } else {
318 | Log.v(TAG, "refreshSDK: False");
319 | mBtnOpen.setEnabled(false);
320 |
321 | mTextProduct.setText(R.string.product_information);
322 | mTextConnectionStatus.setText(R.string.connection_loose);
323 | }
324 | }
325 |
326 | private void loginAccount(){
327 | UserAccountManager.getInstance().logIntoDJIUserAccount(this,
328 | new CommonCallbacks.CompletionCallbackWith() {
329 | @Override
330 | public void onSuccess(final UserAccountState userAccountState) {
331 | Log.e(TAG, "Login Success");
332 | showToast("Login Success!");
333 | }
334 | @Override
335 | public void onFailure(DJIError error) {
336 | showToast("Login Error:"
337 | + error.getDescription());
338 | }
339 | });
340 | }
341 |
342 | private void tryUpdateFirmwareVersionWithListener() {
343 | if (!hasStartedFirmVersionListener) {
344 | firmwareVersionUpdater = new KeyListener() {
345 | @Override
346 | public void onValueChange(final Object o, final Object o1) {
347 | runOnUiThread(new Runnable() {
348 | @Override
349 | public void run() {
350 | updateVersion();
351 | }
352 | });
353 | }
354 | };
355 | firmwareKey = ProductKey.create(ProductKey.FIRMWARE_PACKAGE_VERSION);
356 | if (KeyManager.getInstance() != null) {
357 | KeyManager.getInstance().addListener(firmwareKey, firmwareVersionUpdater );
358 | }
359 | hasStartedFirmVersionListener = true;
360 | }
361 | updateVersion();
362 | }
363 | private void removeFirmwareVersionListener() {
364 | if (hasStartedFirmVersionListener) {
365 | if (KeyManager.getInstance() != null) {
366 | KeyManager.getInstance().removeListener(firmwareVersionUpdater);
367 | }
368 | }
369 | hasStartedFirmVersionListener = false;
370 | }
371 | }
372 |
--------------------------------------------------------------------------------
/MediaManagerDemo/app/src/main/java/com/dji/mediaManagerDemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.dji.mediaManagerDemo;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.ProgressDialog;
6 | import android.content.DialogInterface;
7 | import android.graphics.Bitmap;
8 | import android.os.Bundle;
9 | import android.os.Environment;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Button;
14 | import android.widget.EditText;
15 | import android.widget.ImageView;
16 | import android.widget.SlidingDrawer;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | import androidx.annotation.NonNull;
23 | import androidx.recyclerview.widget.LinearLayoutManager;
24 | import androidx.recyclerview.widget.OrientationHelper;
25 | import androidx.recyclerview.widget.RecyclerView;
26 |
27 | import java.io.File;
28 | import java.util.ArrayList;
29 | import java.util.Collections;
30 | import java.util.Comparator;
31 | import java.util.List;
32 |
33 | import dji.common.airlink.PhysicalSource;
34 | import dji.common.camera.SettingsDefinitions;
35 | import dji.common.camera.StorageState;
36 | import dji.common.error.DJICameraError;
37 | import dji.common.error.DJIError;
38 | import dji.common.product.Model;
39 | import dji.common.util.CommonCallbacks;
40 | import dji.log.DJILog;
41 | import dji.sdk.base.BaseProduct;
42 | import dji.sdk.media.DownloadListener;
43 | import dji.sdk.media.FetchMediaTask;
44 | import dji.sdk.media.FetchMediaTaskContent;
45 | import dji.sdk.media.FetchMediaTaskScheduler;
46 | import dji.sdk.media.MediaFile;
47 | import dji.sdk.media.MediaManager;
48 |
49 | public class MainActivity extends Activity implements View.OnClickListener {
50 |
51 | private static final String TAG = MainActivity.class.getName();
52 |
53 | private Button mBackBtn, mDeleteBtn, mReloadBtn, mDownloadBtn, mStatusBtn;
54 | private Button mPlayBtn, mResumeBtn, mPauseBtn, mStopBtn, mMoveToBtn;
55 | private RecyclerView listView;
56 | private FileListAdapter mListAdapter;
57 | private List mediaFileList = new ArrayList();
58 | private MediaManager mMediaManager;
59 | private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;
60 | private FetchMediaTaskScheduler scheduler;
61 | private ProgressDialog mLoadingDialog;
62 | private ProgressDialog mDownloadDialog;
63 | private SlidingDrawer mPushDrawerSd;
64 | File destDir = new File(Environment.getExternalStorageDirectory().getPath() + "/MediaManagerDemo/");
65 | private int currentProgress = -1;
66 | private ImageView mDisplayImageView;
67 | private int lastClickViewIndex =-1;
68 | private View lastClickView;
69 | private TextView mPushTv;
70 | private SettingsDefinitions.StorageLocation storageLocation;
71 |
72 | @Override
73 | protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | setContentView(R.layout.activity_main);
76 | initUI();
77 | DemoApplication.getAircraftInstance().getCamera().setStorageStateCallBack(new StorageState.Callback() {
78 | @Override
79 | public void onUpdate(@NonNull @NotNull StorageState storageState) {
80 | if(storageState.isInserted()) {
81 | storageLocation = SettingsDefinitions.StorageLocation.SDCARD;
82 | DemoApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, new CommonCallbacks.CompletionCallback() {
83 | @Override
84 | public void onResult(DJIError djiError) {
85 | }
86 | });
87 | } else {
88 | storageLocation = SettingsDefinitions.StorageLocation.INTERNAL_STORAGE;
89 | DemoApplication.getAircraftInstance().getCamera().setStorageLocation(SettingsDefinitions.StorageLocation.INTERNAL_STORAGE, new CommonCallbacks.CompletionCallback() {
90 | @Override
91 | public void onResult(DJIError djiError) {
92 | }
93 | });
94 | }
95 | }
96 | });
97 | }
98 |
99 | @Override
100 | protected void onResume() {
101 | super.onResume();
102 | initMediaManager();
103 | }
104 |
105 | @Override
106 | protected void onPause() {
107 | super.onPause();
108 | }
109 |
110 | @Override
111 | protected void onStop() {
112 | super.onStop();
113 | }
114 |
115 | @Override
116 | protected void onDestroy() {
117 | lastClickView = null;
118 | if (mMediaManager != null) {
119 | mMediaManager.stop(null);
120 | mMediaManager.removeFileListStateCallback(this.updateFileListStateListener);
121 | mMediaManager.removeMediaUpdatedVideoPlaybackStateListener(updatedVideoPlaybackStateListener);
122 | mMediaManager.exitMediaDownloading();
123 | if (scheduler!=null) {
124 | scheduler.removeAllTasks();
125 | }
126 | }
127 |
128 | if (DemoApplication.getCameraInstance() != null) {
129 | if (isMavicAir2() || isAir2S() || isM300()) {
130 | DemoApplication.getCameraInstance().exitPlayback(djiError -> {
131 | if (djiError != null) {
132 | DemoApplication.getCameraInstance().setFlatMode(SettingsDefinitions.FlatCameraMode.PHOTO_SINGLE, djiError1 -> {
133 | if (djiError1 != null) {
134 | setResultToToast("Set PHOTO_SINGLE Mode Failed. " + djiError1.getDescription());
135 | }
136 | });
137 | }
138 | });
139 | } else {
140 | DemoApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, djiError -> {
141 | if (djiError != null) {
142 | setResultToToast("Set SHOOT_PHOTO Mode Failed. " + djiError.getDescription());
143 | }
144 | });
145 | }
146 | }
147 |
148 | if (mediaFileList != null) {
149 | mediaFileList.clear();
150 | }
151 | super.onDestroy();
152 | }
153 |
154 | void initUI() {
155 |
156 | //Init RecyclerView
157 | listView = (RecyclerView) findViewById(R.id.filelistView);
158 | LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this, RecyclerView.VERTICAL,false);
159 | listView.setLayoutManager(layoutManager);
160 |
161 | //Init FileListAdapter
162 | mListAdapter = new FileListAdapter();
163 | listView.setAdapter(mListAdapter);
164 |
165 | //Init Loading Dialog
166 | mLoadingDialog = new ProgressDialog(MainActivity.this);
167 | mLoadingDialog.setMessage("Please wait");
168 | mLoadingDialog.setCanceledOnTouchOutside(false);
169 | mLoadingDialog.setCancelable(false);
170 |
171 | //Init Download Dialog
172 | mDownloadDialog = new ProgressDialog(MainActivity.this);
173 | mDownloadDialog.setTitle("Downloading file");
174 | mDownloadDialog.setIcon(android.R.drawable.ic_dialog_info);
175 | mDownloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
176 | mDownloadDialog.setCanceledOnTouchOutside(false);
177 | mDownloadDialog.setCancelable(true);
178 | mDownloadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
179 | @Override
180 | public void onCancel(DialogInterface dialog) {
181 | if (mMediaManager != null) {
182 | mMediaManager.exitMediaDownloading();
183 | }
184 | }
185 | });
186 |
187 | mPushDrawerSd = (SlidingDrawer)findViewById(R.id.pointing_drawer_sd);
188 | mPushTv = (TextView)findViewById(R.id.pointing_push_tv);
189 | mBackBtn = (Button) findViewById(R.id.back_btn);
190 | mDeleteBtn = (Button) findViewById(R.id.delete_btn);
191 | mDownloadBtn = (Button) findViewById(R.id.download_btn);
192 | mReloadBtn = (Button) findViewById(R.id.reload_btn);
193 | mStatusBtn = (Button) findViewById(R.id.status_btn);
194 | mPlayBtn = (Button) findViewById(R.id.play_btn);
195 | mResumeBtn = (Button) findViewById(R.id.resume_btn);
196 | mPauseBtn = (Button) findViewById(R.id.pause_btn);
197 | mStopBtn = (Button) findViewById(R.id.stop_btn);
198 | mMoveToBtn = (Button) findViewById(R.id.moveTo_btn);
199 | mDisplayImageView = (ImageView) findViewById(R.id.imageView);
200 | mDisplayImageView.setVisibility(View.VISIBLE);
201 |
202 | mBackBtn.setOnClickListener(this);
203 | mDeleteBtn.setOnClickListener(this);
204 | mDownloadBtn.setOnClickListener(this);
205 | mReloadBtn.setOnClickListener(this);
206 | mDownloadBtn.setOnClickListener(this);
207 | mStatusBtn.setOnClickListener(this);
208 | mPlayBtn.setOnClickListener(this);
209 | mResumeBtn.setOnClickListener(this);
210 | mPauseBtn.setOnClickListener(this);
211 | mStopBtn.setOnClickListener(this);
212 | mMoveToBtn.setOnClickListener(this);
213 |
214 | }
215 |
216 | private void showProgressDialog() {
217 | runOnUiThread(new Runnable() {
218 | public void run() {
219 | if (mLoadingDialog != null) {
220 | mLoadingDialog.show();
221 | }
222 | }
223 | });
224 | }
225 |
226 | private void hideProgressDialog() {
227 | runOnUiThread(new Runnable() {
228 | public void run() {
229 | if (null != mLoadingDialog && mLoadingDialog.isShowing()) {
230 | mLoadingDialog.dismiss();
231 | }
232 | }
233 | });
234 | }
235 |
236 | private void ShowDownloadProgressDialog() {
237 | if (mDownloadDialog != null) {
238 | runOnUiThread(new Runnable() {
239 | public void run() {
240 | mDownloadDialog.incrementProgressBy(-mDownloadDialog.getProgress());
241 | mDownloadDialog.show();
242 | }
243 | });
244 | }
245 | }
246 |
247 | private void HideDownloadProgressDialog() {
248 | if (null != mDownloadDialog && mDownloadDialog.isShowing()) {
249 | runOnUiThread(new Runnable() {
250 | public void run() {
251 | mDownloadDialog.dismiss();
252 | }
253 | });
254 | }
255 | }
256 |
257 | private void setResultToToast(final String result) {
258 | runOnUiThread(new Runnable() {
259 | public void run() {
260 | Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
261 | }
262 | });
263 | }
264 |
265 | private void setResultToText(final String string) {
266 | if (mPushTv == null) {
267 | setResultToToast("Push info tv has not be init...");
268 | }
269 | MainActivity.this.runOnUiThread(new Runnable() {
270 | @Override
271 | public void run() {
272 | mPushTv.setText(string);
273 | }
274 | });
275 | }
276 |
277 | private void initMediaManager() {
278 | if (DemoApplication.getProductInstance() == null) {
279 | mediaFileList.clear();
280 | mListAdapter.notifyDataSetChanged();
281 | DJILog.e(TAG, "Product disconnected");
282 | return;
283 | } else {
284 | if (null != DemoApplication.getCameraInstance() && DemoApplication.getCameraInstance().isMediaDownloadModeSupported()) {
285 | mMediaManager = DemoApplication.getCameraInstance().getMediaManager();
286 | if (null != mMediaManager) {
287 | mMediaManager.addUpdateFileListStateListener(this.updateFileListStateListener);
288 | mMediaManager.addMediaUpdatedVideoPlaybackStateListener(this.updatedVideoPlaybackStateListener);
289 | if (isMavicAir2() || isAir2S() || isM300()) {
290 | DemoApplication.getCameraInstance().enterPlayback(djiError -> {
291 | if (djiError == null) {
292 | DJILog.e(TAG, "Set cameraMode success");
293 | showProgressDialog();
294 | getFileList();
295 | } else {
296 | setResultToToast("Set cameraMode failed");
297 | }
298 | });
299 | } else {
300 | DemoApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, error -> {
301 | if (error == null) {
302 | DJILog.e(TAG, "Set cameraMode success");
303 | showProgressDialog();
304 | getFileList();
305 | } else {
306 | setResultToToast("Set cameraMode failed");
307 | }
308 | });
309 | }
310 |
311 | if (mMediaManager.isVideoPlaybackSupported()) {
312 | DJILog.e(TAG, "Camera support video playback!");
313 | } else {
314 | setResultToToast("Camera does not support video playback!");
315 | }
316 | scheduler = mMediaManager.getScheduler();
317 | }
318 |
319 | } else if (null != DemoApplication.getCameraInstance()
320 | && !DemoApplication.getCameraInstance().isMediaDownloadModeSupported()) {
321 | setResultToToast("Media Download Mode not Supported");
322 | }
323 | }
324 | return;
325 | }
326 |
327 | private void getFileList() {
328 | mMediaManager = DemoApplication.getCameraInstance().getMediaManager();
329 | if (mMediaManager != null) {
330 |
331 | if ((currentFileListState == MediaManager.FileListState.SYNCING) || (currentFileListState == MediaManager.FileListState.DELETING)){
332 | DJILog.e(TAG, "Media Manager is busy.");
333 | }else{
334 | mMediaManager.refreshFileListOfStorageLocation(storageLocation, djiError -> {
335 | if (null == djiError) {
336 | hideProgressDialog();
337 |
338 | //Reset data
339 | if (currentFileListState != MediaManager.FileListState.INCOMPLETE) {
340 | mediaFileList.clear();
341 | lastClickViewIndex = -1;
342 | lastClickView = null;
343 | }
344 |
345 | List tempList;
346 | if (storageLocation == SettingsDefinitions.StorageLocation.SDCARD) {
347 | tempList = mMediaManager.getSDCardFileListSnapshot();
348 | } else {
349 | tempList = mMediaManager.getInternalStorageFileListSnapshot();
350 | }
351 | if (tempList != null) {
352 | mediaFileList.addAll(tempList);
353 | }
354 | if (mediaFileList != null) {
355 | Collections.sort(mediaFileList, (lhs, rhs) -> {
356 | if (lhs.getTimeCreated() < rhs.getTimeCreated()) {
357 | return 1;
358 | } else if (lhs.getTimeCreated() > rhs.getTimeCreated()) {
359 | return -1;
360 | }
361 | return 0;
362 | });
363 | }
364 | scheduler.resume(error -> {
365 | if (error == null) {
366 | getThumbnails();
367 | }
368 | });
369 | } else {
370 | hideProgressDialog();
371 | setResultToToast("Get Media File List Failed:" + djiError.getDescription());
372 | }
373 | });
374 | }
375 | }
376 | }
377 |
378 | private void getThumbnails() {
379 | if (mediaFileList.size() <= 0) {
380 | setResultToToast("No File info for downloading thumbnails");
381 | return;
382 | }
383 | for (int i = 0; i < mediaFileList.size(); i++) {
384 | getThumbnailByIndex(i);
385 | }
386 | }
387 |
388 | private FetchMediaTask.Callback taskCallback = new FetchMediaTask.Callback() {
389 | @Override
390 | public void onUpdate(MediaFile file, FetchMediaTaskContent option, DJIError error) {
391 | if (null == error) {
392 | if (option == FetchMediaTaskContent.PREVIEW) {
393 | runOnUiThread(new Runnable() {
394 | public void run() {
395 | mListAdapter.notifyDataSetChanged();
396 | }
397 | });
398 | }
399 | if (option == FetchMediaTaskContent.THUMBNAIL) {
400 | runOnUiThread(new Runnable() {
401 | public void run() {
402 | mListAdapter.notifyDataSetChanged();
403 | }
404 | });
405 | }
406 | } else {
407 | DJILog.e(TAG, "Fetch Media Task Failed" + error.getDescription());
408 | }
409 | }
410 | };
411 |
412 | private void getThumbnailByIndex(final int index) {
413 | FetchMediaTask task = new FetchMediaTask(mediaFileList.get(index), FetchMediaTaskContent.THUMBNAIL, taskCallback);
414 | scheduler.moveTaskToEnd(task);
415 | }
416 |
417 | private static class ItemHolder extends RecyclerView.ViewHolder {
418 | ImageView thumbnail_img;
419 | TextView file_name;
420 | TextView file_type;
421 | TextView file_size;
422 | TextView file_time;
423 |
424 | public ItemHolder(View itemView) {
425 | super(itemView);
426 | this.thumbnail_img = (ImageView) itemView.findViewById(R.id.filethumbnail);
427 | this.file_name = (TextView) itemView.findViewById(R.id.filename);
428 | this.file_type = (TextView) itemView.findViewById(R.id.filetype);
429 | this.file_size = (TextView) itemView.findViewById(R.id.fileSize);
430 | this.file_time = (TextView) itemView.findViewById(R.id.filetime);
431 | }
432 | }
433 |
434 | private class FileListAdapter extends RecyclerView.Adapter {
435 | @Override
436 | public int getItemCount() {
437 | if (mediaFileList != null) {
438 | return mediaFileList.size();
439 | }
440 | return 0;
441 | }
442 |
443 | @Override
444 | public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
445 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_info_item, parent, false);
446 | return new ItemHolder(view);
447 | }
448 |
449 | @Override
450 | public void onBindViewHolder(ItemHolder mItemHolder, final int index) {
451 |
452 | final MediaFile mediaFile = mediaFileList.get(index);
453 | if (mediaFile != null) {
454 | if (mediaFile.getMediaType() != MediaFile.MediaType.MOV && mediaFile.getMediaType() != MediaFile.MediaType.MP4) {
455 | mItemHolder.file_time.setVisibility(View.GONE);
456 | } else {
457 | mItemHolder.file_time.setVisibility(View.VISIBLE);
458 | mItemHolder.file_time.setText(mediaFile.getDurationInSeconds() + " s");
459 | }
460 | mItemHolder.file_name.setText(mediaFile.getFileName());
461 | mItemHolder.file_type.setText(mediaFile.getMediaType().name());
462 | mItemHolder.file_size.setText(mediaFile.getFileSize() + " Bytes");
463 | mItemHolder.thumbnail_img.setImageBitmap(mediaFile.getThumbnail());
464 | mItemHolder.thumbnail_img.setOnClickListener(ImgOnClickListener);
465 | mItemHolder.thumbnail_img.setTag(mediaFile);
466 | mItemHolder.itemView.setTag(index);
467 |
468 | if (lastClickViewIndex == index) {
469 | mItemHolder.itemView.setSelected(true);
470 | } else {
471 | mItemHolder.itemView.setSelected(false);
472 | }
473 | mItemHolder.itemView.setOnClickListener(itemViewOnClickListener);
474 |
475 | }
476 | }
477 | }
478 |
479 | private View.OnClickListener itemViewOnClickListener = new View.OnClickListener() {
480 | @Override
481 | public void onClick(View v) {
482 | lastClickViewIndex = (int) (v.getTag());
483 |
484 | if (lastClickView != null && lastClickView != v) {
485 | lastClickView.setSelected(false);
486 | }
487 | v.setSelected(true);
488 | lastClickView = v;
489 | }
490 | };
491 |
492 | private View.OnClickListener ImgOnClickListener = new View.OnClickListener() {
493 | @Override
494 | public void onClick(View v) {
495 | MediaFile selectedMedia = (MediaFile) v.getTag();
496 | if (selectedMedia != null && mMediaManager != null) {
497 | addMediaTask(selectedMedia);
498 | }
499 | }
500 | };
501 |
502 | private void addMediaTask(final MediaFile mediaFile) {
503 | final FetchMediaTaskScheduler scheduler = mMediaManager.getScheduler();
504 | final FetchMediaTask task =
505 | new FetchMediaTask(mediaFile, FetchMediaTaskContent.PREVIEW, new FetchMediaTask.Callback() {
506 | @Override
507 | public void onUpdate(final MediaFile mediaFile, FetchMediaTaskContent fetchMediaTaskContent, DJIError error) {
508 | if (null == error) {
509 | if (mediaFile.getPreview() != null) {
510 | runOnUiThread(new Runnable() {
511 | @Override
512 | public void run() {
513 | final Bitmap previewBitmap = mediaFile.getPreview();
514 | mDisplayImageView.setVisibility(View.VISIBLE);
515 | mDisplayImageView.setImageBitmap(previewBitmap);
516 | }
517 | });
518 | } else {
519 | setResultToToast("null bitmap!");
520 | }
521 | } else {
522 | setResultToToast("fetch preview image failed: " + error.getDescription());
523 | }
524 | }
525 | });
526 |
527 | scheduler.resume(error -> {
528 | if (error == null) {
529 | scheduler.moveTaskToNext(task);
530 | } else {
531 | setResultToToast("resume scheduler failed: " + error.getDescription());
532 | }
533 | });
534 | }
535 |
536 | //Listeners
537 | private MediaManager.FileListStateListener updateFileListStateListener = state -> currentFileListState = state;
538 |
539 | private MediaManager.VideoPlaybackStateListener updatedVideoPlaybackStateListener =
540 | new MediaManager.VideoPlaybackStateListener() {
541 | @Override
542 | public void onUpdate(MediaManager.VideoPlaybackState videoPlaybackState) {
543 | updateStatusTextView(videoPlaybackState);
544 | }
545 | };
546 |
547 | private void updateStatusTextView(MediaManager.VideoPlaybackState videoPlaybackState) {
548 | final StringBuffer pushInfo = new StringBuffer();
549 |
550 | addLineToSB(pushInfo, "Video Playback State", null);
551 | if (videoPlaybackState != null) {
552 | if (videoPlaybackState.getPlayingMediaFile() != null) {
553 | addLineToSB(pushInfo, "media index", videoPlaybackState.getPlayingMediaFile().getIndex());
554 | addLineToSB(pushInfo, "media size", videoPlaybackState.getPlayingMediaFile().getFileSize());
555 | addLineToSB(pushInfo,
556 | "media duration",
557 | videoPlaybackState.getPlayingMediaFile().getDurationInSeconds());
558 | addLineToSB(pushInfo, "media created date", videoPlaybackState.getPlayingMediaFile().getDateCreated());
559 | addLineToSB(pushInfo,
560 | "media orientation",
561 | videoPlaybackState.getPlayingMediaFile().getVideoOrientation());
562 | } else {
563 | addLineToSB(pushInfo, "media index", "None");
564 | }
565 | addLineToSB(pushInfo, "media current position", videoPlaybackState.getPlayingPosition());
566 | addLineToSB(pushInfo, "media current status", videoPlaybackState.getPlaybackStatus());
567 | addLineToSB(pushInfo, "media cached percentage", videoPlaybackState.getCachedPercentage());
568 | addLineToSB(pushInfo, "media cached position", videoPlaybackState.getCachedPosition());
569 | pushInfo.append("\n");
570 | setResultToText(pushInfo.toString());
571 | }
572 | }
573 |
574 | private void addLineToSB(StringBuffer sb, String name, Object value) {
575 | if (sb == null) return;
576 | sb.
577 | append((name == null || "".equals(name)) ? "" : name + ": ").
578 | append(value == null ? "" : value + "").
579 | append("\n");
580 | }
581 |
582 | private void downloadFileByIndex(final int index){
583 | if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.PANORAMA)
584 | || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.SHALLOW_FOCUS)) {
585 | return;
586 | }
587 |
588 | mediaFileList.get(index).fetchFileData(destDir, null, new DownloadListener() {
589 | @Override
590 | public void onFailure(DJIError error) {
591 | HideDownloadProgressDialog();
592 | setResultToToast("Download File Failed" + error.getDescription());
593 | currentProgress = -1;
594 | }
595 |
596 | @Override
597 | public void onProgress(long total, long current) {
598 | }
599 |
600 | @Override
601 | public void onRateUpdate(long total, long current, long persize) {
602 | int tmpProgress = (int) (1.0 * current / total * 100);
603 | if (tmpProgress != currentProgress) {
604 | mDownloadDialog.setProgress(tmpProgress);
605 | currentProgress = tmpProgress;
606 | }
607 | }
608 |
609 | @Override
610 | public void onRealtimeDataUpdate(byte[] bytes, long l, boolean b) {
611 |
612 | }
613 |
614 | @Override
615 | public void onStart() {
616 | currentProgress = -1;
617 | ShowDownloadProgressDialog();
618 | }
619 |
620 | @Override
621 | public void onSuccess(String filePath) {
622 | HideDownloadProgressDialog();
623 | setResultToToast("Download File Success" + ":" + filePath);
624 | currentProgress = -1;
625 | }
626 | });
627 | }
628 |
629 | private void deleteFileByIndex(final int index) {
630 | ArrayList fileToDelete = new ArrayList();
631 | if (mediaFileList.size() > index) {
632 | fileToDelete.add(mediaFileList.get(index));
633 | mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam, DJICameraError>() {
634 | @Override
635 | public void onSuccess(List x, DJICameraError y) {
636 | DJILog.e(TAG, "Delete file success");
637 | runOnUiThread(new Runnable() {
638 | public void run() {
639 | MediaFile file = mediaFileList.remove(index);
640 |
641 | //Reset select view
642 | lastClickViewIndex = -1;
643 | lastClickView = null;
644 |
645 | //Update recyclerView
646 | mListAdapter.notifyItemRemoved(index);
647 | }
648 | });
649 | }
650 |
651 | @Override
652 | public void onFailure(DJIError error) {
653 | setResultToToast("Delete file failed");
654 | }
655 | });
656 | }
657 | }
658 |
659 | private void playVideo() {
660 | mDisplayImageView.setVisibility(View.INVISIBLE);
661 | MediaFile selectedMediaFile = mediaFileList.get(lastClickViewIndex);
662 | if ((selectedMediaFile.getMediaType() == MediaFile.MediaType.MOV) || (selectedMediaFile.getMediaType() == MediaFile.MediaType.MP4)) {
663 | mMediaManager.playVideoMediaFile(selectedMediaFile, error -> {
664 | if (null != error) {
665 | setResultToToast("Play Video Failed " + error.getDescription());
666 | } else {
667 | DJILog.e(TAG, "Play Video Success");
668 | }
669 | });
670 | }
671 | }
672 |
673 | private void moveToPosition(){
674 |
675 | LayoutInflater li = LayoutInflater.from(this);
676 | View promptsView = li.inflate(R.layout.prompt_input_position, null);
677 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
678 | alertDialogBuilder.setView(promptsView);
679 | final EditText userInput = (EditText) promptsView.findViewById(R.id.editTextDialogUserInput);
680 | alertDialogBuilder.setCancelable(false).setPositiveButton("OK", (dialog, id) -> {
681 | String ms = userInput.getText().toString();
682 | mMediaManager.moveToPosition(Integer.parseInt(ms),
683 | new CommonCallbacks.CompletionCallback() {
684 | @Override
685 | public void onResult(DJIError error) {
686 | if (null != error) {
687 | setResultToToast("Move to video position failed" + error.getDescription());
688 | } else {
689 | DJILog.e(TAG, "Move to video position successfully.");
690 | }
691 | }
692 | });
693 | })
694 | .setNegativeButton("Cancel", (dialog, id) -> dialog.cancel());
695 | AlertDialog alertDialog = alertDialogBuilder.create();
696 | alertDialog.show();
697 |
698 | }
699 |
700 | @Override
701 | public void onClick(View v) {
702 | switch (v.getId()) {
703 | case R.id.back_btn: {
704 | this.finish();
705 | break;
706 | }
707 | case R.id.delete_btn:{
708 | deleteFileByIndex(lastClickViewIndex);
709 | break;
710 | }
711 | case R.id.reload_btn: {
712 | getFileList();
713 | break;
714 | }
715 | case R.id.download_btn: {
716 | downloadFileByIndex(lastClickViewIndex);
717 | break;
718 | }
719 | case R.id.status_btn: {
720 | if (mPushDrawerSd.isOpened()) {
721 | mPushDrawerSd.animateClose();
722 | } else {
723 | mPushDrawerSd.animateOpen();
724 | }
725 | break;
726 | }
727 | case R.id.play_btn: {
728 | playVideo();
729 | break;
730 | }
731 | case R.id.resume_btn: {
732 | mMediaManager.resume(error -> {
733 | if (null != error) {
734 | setResultToToast("Resume Video Failed" + error.getDescription());
735 | } else {
736 | DJILog.e(TAG, "Resume Video Success");
737 | }
738 | });
739 | break;
740 | }
741 | case R.id.pause_btn: {
742 | mMediaManager.pause(error -> {
743 | if (null != error) {
744 | setResultToToast("Pause Video Failed" + error.getDescription());
745 | } else {
746 | DJILog.e(TAG, "Pause Video Success");
747 | }
748 | });
749 | break;
750 | }
751 | case R.id.stop_btn: {
752 | mMediaManager.stop(error -> {
753 | if (null != error) {
754 | setResultToToast("Stop Video Failed" + error.getDescription());
755 | } else {
756 | DJILog.e(TAG, "Stop Video Success");
757 | }
758 | });
759 | break;
760 | }
761 | case R.id.moveTo_btn: {
762 | moveToPosition();
763 | break;
764 | }
765 | default:
766 | break;
767 | }
768 | }
769 |
770 | private boolean isMavicAir2() {
771 | BaseProduct baseProduct = DemoApplication.getProductInstance();
772 | if (baseProduct != null) {
773 | return baseProduct.getModel() == Model.MAVIC_AIR_2;
774 | }
775 | return false;
776 | }
777 |
778 | private boolean isAir2S() {
779 | BaseProduct baseProduct = DemoApplication.getProductInstance();
780 | if (baseProduct != null) {
781 | return baseProduct.getModel() == Model.DJI_AIR_2S;
782 | }
783 | return false;
784 | }
785 |
786 | private boolean isM300() {
787 | BaseProduct baseProduct = DemoApplication.getProductInstance();
788 | if (baseProduct != null) {
789 | return baseProduct.getModel() == Model.MATRICE_300_RTK;
790 | }
791 | return false;
792 | }
793 | }
794 |
--------------------------------------------------------------------------------