text:
---
title: Creating a TapFly and ActiveTrack Missions Application
version: v4.11
date: 2019-09-23
github: https://github.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions
keywords: [Android Phantom 4 Mission, TapFly mission demo, ActiveTrack mission demo]
---

In this tutorial, you will learn how to use the TapFly and ActiveTrack Missions of DJI Android SDK to create a cool application for Mavic Pro. Also, you will get familiar with `ActiveTrackOperator`, `TapFlyMissionOperator` and using the Simulator of DJI Assistant 2 for testing, which is convenient for you to test the missions indoor. We will use Android Studio 3.0 version for demo here. So let's get started!

You can download the tutorial's final sample code project from this [Github Page](https://github.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions).

## Introduction

The TapFly and ActiveTrack missions bring you a more autonomous flying experience. They are originally supported by Phantom 4, now they are also supported by Mavic Pro, Phantom 4 Pro, Phantom 4 Advanced, Spark, M200 and Inspire 2.

### TapFly Mission

Given a coordinate in the live video stream (which can come from a user tap), the aircraft will calculate and fly towards the coordinate's direction in the real world. During a flight, the aircraft will automatically detect and avoid obstacles. Also, the aircraft will stop flying in the direction if it reaches its radius limitation, the mission is stopped, the user pulls back on the pitch stick or if it comes to an obstacle it cannot bypass.

During the mission, you can use the remote controller's yaw stick to adjust the heading of the aircraft, which also adjusts the direction of flight to the new yaw.

Here is a  video  for you to get the first impression of the TapFly Mission.

### ActiveTrack Mission

An ActiveTrack Mission allows an aircraft to track a moving subject using the vision system and without a GPS tracker on the subject. To use an ActiveTrack mission:

The main camera is used to track the target, so the gimbal cannot be adjusted during an ActiveTrack mission. During the mission, the aircraft can be manually flown with pitch, roll and throttle to move around the subject being tracked.

Here is a  video  for you to get the first impression of the ActiveTrack Mission.

## Application Activation and Aircraft Binding in China

 For DJI SDK mobile application used in China, it's required to activate the application and bind the aircraft to the user's DJI account.

 If an application is not activated, the aircraft not bound (if required), or a legacy version of the SDK (< 4.1) is being used, flight will be limited to a cylinder of 100m diameter and 30m height to ensure the aircraft stays within line of sight.

 To learn how to implement this feature, please check this tutorial [Application Activation and Aircraft Binding](./ActivationAndBinding.html).

## Implementing the UI of Application

Now that you know the details of the two missions, we can start working on the application.

### Importing Maven Dependency

Open Android Studio and select **File -> New -> New Project** to create a new project, named 'P4MissionsDemo'. Enter the company domain and package name(Here we use "com.dji.P4MissionsDemo") you want and press Next. Set the minimum SDK version as `API 19: Android 4.4 (KitKat)` for "Phone and Tablet" and press Next. Then select "Empty Activity" and press Next. Lastly, leave the Activity Name as "MainActivity", and the Layout Name as "activity_main", Press "Finish" to create the project.

In our previous tutorial [Importing and Activating DJI SDK in Android Studio Project](../application-development-workflow/workflow-integrate.html#Android-Studio-Project-Integration), you have learned how to import the Android SDK Maven Dependency and activate your application. If you haven't read that previously, please take a look at it and implement the related features. Once you've done that, continue to implement the next features.

### Building the Layouts of Activities

#### 1. Implementing MApplication and DJIDemoApplication

You can check the [Creating an Camera Application](./index.html#1-creating-mapplication-class) tutorial and the [sample project](https://github.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions) of this tutorial for the detailed implementations of the `MApplication` and `DJIDemoApplication`.

#### 2. Implementing DemoBaseActivity Class

Similarly, create a new Empty Activity class with the name of "DemoBaseActivity" in the `com.dji.p4MissionsDemo` package. Remember to deselect the "Generate Layout File". Replace the code with the following, remember to import the related classes as Android Studio suggested:

~~~java
public class DemoBaseActivity extends FragmentActivity implements SurfaceTextureListener {

    protected TextView mConnectStatusTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mConnectStatusTextView = (TextView) findViewById(R.id.ConnectStatusTextView);

    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    }

}
~~~

We will use this activity class as our base class later. More details of the implementation will be done later.

#### 3. Creating the MainActivity

##### Working on the MainActivity Class

For the implementation of the "MainActivity.java class, please check the [Creating an Camera Application](./index.html#working-on-the-connectionactivity) tutorial and the [sample project](https://github.com/DJI-Mobile-SDK-Tutorials/Android-Phantom4Missions) of this tutorial.

##### Implementing the MainActivity Layout

Open the **activity_main.xml** layout file and replace the code with the following:

~~~xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:keepScreenOn="true"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/main_title_rl"
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:background="@android:color/black" >

        <ImageButton
            android:id="@+id/ReturnBtnMain"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:adjustViewBounds="true"
            android:background="@android:color/transparent"
            android:onClick="onReturn"
            android:scaleType="centerInside"
            android:src="@drawable/selector_back_button" />

        <TextView
            android:id="@+id/ConnectStatusTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/title_activity_mainactivity"
            android:textColor="@android:color/white"
            android:textSize="21sp" />
    </RelativeLayout>
    <TextView android:id="@+id/version_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Firmware version: N/A"/>
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
~~~

  In the xml file, firstly, we implement the RelativeLayout element. We declare an ImageButton(id: ReturnBtnMain) element to exit the application, and a TextView(id: ConnectStatusTextView) element to show the connection status text. Next, create a TextView(id:version_tv) element to show the firmware version and a ListView(id:listView) element to show the list items.

  Next, copy all the image files from this Github sample project to the **drawable** folders inside the **res** folder.

  ![imageFiles](../images/tutorials-and-samples/Android/Phantom4Missions/imageFiles.png)

  Moreover, open the AndroidManifest.xml file and update the ".MainActivity" activity element with several attributes as shown below:

~~~xml
<activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:label="@string/title_activity_mainactivity"
            android:screenOrientation="landscape"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>
~~~

  Furthermore, open the "strings.xml" file in **values** folder and add the following string content:

~~~xml
 <string name="title_activity_mainactivity">P4MissionsDemo</string>
~~~

   Lastly, let's create a new xml file named "demo_info_item.xml" in the layout folder by right-clicking on the "layout" folder and select **New->XML->Layout XML File**. Then replace the code of the file with the following:

~~~xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:layout_marginTop="6dp"
        android:layout_marginBottom="3dp"
        android:layout_marginLeft="10dp"
        android:text="demo title" />

     <TextView
        android:id="@+id/desc"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:layout_marginBottom="6dp"
        android:layout_marginLeft="10dp"
        android:text="demo desc"
        android:textColor="@color/white"/>

</LinearLayout>
~~~

This xml file will help to setup the two TextViews with "title" and "desc" ids for the convertView of DemoListAdapter.

Now, if you check the activity_main.xml file, you can see the preview screenshot of MainActivity as shown below:

For more details, please check the source code of this tutorial's Github sample project.

#### 4. Creating the PointingTestActivity

##### Implementing the PointingTestActivity Class

   Let's create a new Empty Activity class with the name of "PointingTestActivity" in the `com.dji.p4MissionsDemo` package. Replace the code with the following, remember to import the related classes as Android Studio suggested:

~~~java
public class PointingTestActivity extends DemoBaseActivity implements TextureView.SurfaceTextureListener, View.OnClickListener {

    private static final String TAG = "PointingTestActivity";
    private ImageButton mPushDrawerIb;
    private SlidingDrawer mPushDrawerSd;
    private Button mStartBtn;
    private ImageButton mStopBtn;
    private TextView mPushTv;
    private RelativeLayout mBgLayout;
    private ImageView mRstPointIv;
    private TextView mAssisTv;
    private Switch mAssisSw;
    private TextView mSpeedTv;
    private SeekBar mSpeedSb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_pointing_test);
        super.onCreate(savedInstanceState);
        initUI();
    }

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

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

    private void initUI() {
        mPushDrawerIb = (ImageButton)findViewById(R.id.pointing_drawer_control_ib);
        mPushDrawerSd = (SlidingDrawer)findViewById(R.id.pointing_drawer_sd);
        mStartBtn = (Button)findViewById(R.id.pointing_start_btn);
        mStopBtn = (ImageButton)findViewById(R.id.pointing_stop_btn);
        mPushTv = (TextView)findViewById(R.id.pointing_push_tv);
        mBgLayout = (RelativeLayout)findViewById(R.id.pointing_bg_layout);
        mRstPointIv = (ImageView)findViewById(R.id.pointing_rst_point_iv);
        mAssisTv = (TextView)findViewById(R.id.pointing_assistant_tv);
        mAssisSw = (Switch)findViewById(R.id.pointing_assistant_sw);
        mSpeedTv = (TextView)findViewById(R.id.pointing_speed_tv);
        mSpeedSb = (SeekBar)findViewById(R.id.pointing_speed_sb);

        mPushDrawerIb.setOnClickListener(this);
        mStartBtn.setOnClickListener(this);
        mStopBtn.setOnClickListener(this);
        mSpeedSb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                mSpeedTv.setText(progress + 1 + "");
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
    }

    public void onReturn(View view){
        Log.d(TAG, "onReturn");
        this.finish();
    }

    @Override
    public void onClick(View v) {

        if (v.getId() == R.id.pointing_drawer_control_ib) {
            if (mPushDrawerSd.isOpened()) {
                mPushDrawerSd.animateClose();
            } else {
                mPushDrawerSd.animateOpen();
            }
            return;
        }
    }
}
~~~

 Here, we implement several features:

**1.** Declare the UI member variables like ImageButton, TextView, SeekBar, etc. Then override the `onCreate()` method to invoke the `initUI()` method to initialize the UI elements of the Activity.

**2.** In the `initUI()` method, we create the member variables by invoking the `fineViewById()` method and passing the related id value declared in the associated layout xml file. Then call the `setOnClickListener()` method by assigning "this" to it for all the Button member variables. Next implement the SeekBar's `setOnSeekBarChangeListener()` method and override the three interface methods of OnSeekBarChangeListener. Here we update the text value of SeekBar in the `onProgresshanged()` method.

**3.** Lastly, we override the `onClick()` method to implement the click action of the `mPushDrawerIb` ImageButton. When you press the `mPushDrawerIb`, it will add animations when open and close the `mPushDrawerSd`, which is a **SlidingDrawer**.

##### Working on PointingTestActivity Layout

  Open the colors.xml file in the **values** folder and replace the content with the following:

~~~xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="button_normal">#50808080</color>
    <color name="button_press">#5086BFFF</color>
    <color name="white">#FFFFFF</color>
    <color name="black">#000000</color>
</resources>
~~~
  Here, we add button press and normal colors, white and black colors.

  Moreover, add the two new string elements to the strings.xml file:

~~~xml
<string name="push_info">Push Info</string>
<string name="title_activity_pointing_test">TapFly Sample</string>
~~~

  Then, update the styles.xml with the following code:

~~~xml
<resources>

</resources>
~~~

Lastly, jump over to your associated layout in "layout/activity_ pointing_test.xml" file and replace everything with the same xml file from the tutorial's Github Sample Project, since the xml file's content is too much, we don't show them here.

For the UI, we declare a main title, a return button, a connect status text view, a pointing button, etc. Here is a screenshot of the preview of PointingTestActivity:

#### 5. Creating the TrackingTestActivity

##### Working on TrackingTestActivity Class

Once you finish the steps above, let's create a new Empty Activity class with the name of "TrackingTestActivity" in the `com.dji.p4MissionsDemo` package. Replace the code with the following:

~~~java
public class TrackingTestActivity extends DemoBaseActivity implements SurfaceTextureListener, OnClickListener, View.OnTouchListener {

    private static final String TAG = "TrackingTestActivity";
    private ImageButton mPushDrawerIb;
    private SlidingDrawer mPushInfoSd;
    private ImageButton mStopBtn;
    private ImageView mTrackingImage;
    private RelativeLayout mBgLayout;
    private TextView mPushInfoTv;
    private TextView mPushBackTv;
    private TextView mGestureModeTv;
    private Switch mPushBackSw;
    private Switch mGestureModeSw;
    private ImageView mSendRectIV;
    private Button mConfigBtn;
    private Button mConfirmBtn;
    private Button mRejectBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_tracking_test);
        super.onCreate(savedInstanceState);
        initUI();
    }

    private void initUI() {
        mPushDrawerIb = (ImageButton)findViewById(R.id.tracking_drawer_control_ib);
        mPushInfoSd = (SlidingDrawer)findViewById(R.id.tracking_drawer_sd);
        mStopBtn = (ImageButton)findViewById(R.id.tracking_stop_btn);
        mTrackingImage = (ImageView) findViewById(R.id.tracking_rst_rect_iv);
        mBgLayout = (RelativeLayout)findViewById(R.id.tracking_bg_layout);
        mPushInfoTv = (TextView)findViewById(R.id.tracking_push_tv);
        mSendRectIV = (ImageView)findViewById(R.id.tracking_send_rect_iv);
        mPushBackSw = (Switch)findViewById(R.id.tracking_pull_back_sw);
        mPushBackTv = (TextView)findViewById(R.id.tracking_backward_tv);
        mGestureModeTv = (TextView)findViewById(R.id.gesture_mode_tv);
        mGestureModeSw = (Switch)findViewById(R.id.gesture_mode_enable_sw);
        mConfigBtn = (Button)findViewById(R.id.recommended_configuration_btn);
        mConfirmBtn = (Button)findViewById(R.id.confirm_btn);
        mRejectBtn = (Button)findViewById(R.id.reject_btn);
        mStopBtn.setOnClickListener(this);
        mBgLayout.setOnTouchListener(this);
        mPushDrawerIb.setOnClickListener(this);
        mConfigBtn.setOnClickListener(this);
        mConfirmBtn.setOnClickListener(this);
        mRejectBtn.setOnClickListener(this);
    }

    public void onReturn(View view){
        Log.d(TAG, "onReturn");
        this.finish();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tracking_stop_btn:
                break;
            case R.id.tracking_drawer_control_ib:
                if (mPushInfoSd.isOpened()) {
                    mPushInfoSd.animateClose();
                } else {
                    mPushInfoSd.animateOpen();
                }
                break;
            case R.id.recommended_configuration_btn:
                break;
            case R.id.confirm_btn:
                break;
            case R.id.reject_btn:
                break;
            default:
                break;
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }
}
~~~

Here, we implement several features:

**1.** Declare the UI member variables like ImageButton, SlidingDrawer, SeekBar, etc. Then override the `onCreate()` method to invoke the `initUI()` method to initialize the UI elements of the Activity.

**2.** In the `initUI()` method, we create the member variables by invoking the `fineViewById()` method and passing the related id value declared in the associated layout xml file. Then call the `setOnClickListener()` method by assigning "this" to it for all the Button member variables.

**3.** Lastly, we override the `onClick()` method to implement the click action of the `mStopBtn`, `mConfigBtn`, `mConfirmBtn`, `mRejectBtn` and `mPushDrawerIb` member variables. When you press the `mPushDrawerIb` ImageButton, it will add animation to open and close the `mPushInfoSd`.

Next, open the strings.xml file and add the following code:

~~~xml
    <string name="title_activity_tracking_test">ActiveTrack Sample</string>
    <string name="demo_desc_tracking">ActiveTrack Mission</string>
    <string name="demo_desc_pointing">TapFly Mission</string>
~~~

Finally, jump over to your associated layout in layout/activity_ tracking_test.xml and replace everything with the same xml file from the tutorial's Github Sample Project, since the xml file's content is a lot, we don't show them here. For more details, please check the related xml file from the Github Sample Project of the demo project.

For the UI, we declare a main title, a return button, a connect status text view, a TextureView to show live video stream, an ImageView to show the tracking rectangle, etc. Here is a screenshot of the preview of TrackingTestActivity:

#### 6. Preview the UI of the Application

Now, let's open the dimens.xml file and replace the code with the following:

~~~xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <dimen name="left_button_list_button_width">150dp</dimen>
    <dimen name="left_button_list_button_height">45dp</dimen>
    <dimen name="left_button_list_button_padding_left">5dp</dimen>
    <dimen name="left_button_list_button_padding_right">5dp</dimen>
    <dimen name="left_button_list_button_margin_left">10dp</dimen>
    <dimen name="left_button_list_button_margin_top">10dp</dimen>
    <dimen name="left_button_list_button_text_size">14sp</dimen>

    <dimen name="test_log_textsize">17sp</dimen>
</resources>
~~~

Next, open the AndroidManifest.xml file and modify the **.PointingTestActivity** and **.TrackingTestActivity** elements as shown below:

~~~xml
    <activity
        android:name=".TrackingTestActivity"
        android:label="@string/title_activity_tracking_test"
        android:launchMode="singleInstance"
        android:screenOrientation="landscape"
        android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
    </activity>
    <activity
        android:name=".PointingTestActivity"
        android:label="@string/title_activity_pointing_test"
        android:launchMode="singleInstance"
        android:screenOrientation="landscape"
        android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
    </activity>
~~~

In the code above, we modify the label, launchMode, screenOrientation and theme attributes for the two Activities.

We have gone through a long process to setup the UI of the application. Now, let's build and run the project and install it in your Android device to test it. If everything goes well, you may see something similar to the following animation:

### Registering the Application

After you finish the above steps, let's register our application with the **App Key** you apply from DJI Developer Website. If you are not familiar with the App Key, please check the [Get Started](../quick-start/index.html).

Now let's open the "AndroidManifest.xml" file and add the following elements above the **application** element:

~~~xml
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature
        android:name="android.hardware.usb.host"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.usb.accessory"
        android:required="true" />

    <application
        android:name=".MApplication"
        android:allowBackup="true"
        tools:replace="android:icon"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
~~~

Here, we add uses permissions and uses features for the app. They are required for registration.

Then add the following elements above the **MainActivity** activity element:

~~~xml

        <uses-library android:name="com.android.future.usb.accessory" />
        <meta-data
            android:name="com.dji.sdk.API_KEY"
            android:value="Please enter your App Key here." />
        <activity
            android:name="dji.sdk.sdkmanager.DJIAoaControllerActivity"
            android:theme="@android:style/Theme.Translucent" >
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
            </intent-filter>
            <meta-data
                android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                android:resource="@xml/accessory_filter" />
        </activity>
        <service android:name="dji.sdk.sdkmanager.DJIGlobalService" >
        </service>

~~~

In the code above, we enter the **App Key** of the application under the `android:name="com.dji.sdk.API_KEY"` attribute. For more details of the "AndroidManifest.xml" file, please check the Github source code of the demo project.

Since we have implemented the registration logics in the "DJIDemoApplication.java" and "MainActivity.java" files previously, we don't explain the details here.

Now, let's build and run the project and install it in your Android device to test it. If everything goes well, you should see the "success" textView like the following screenshot when you register the app successfully.

![registerSuccess](../images/tutorials-and-samples/Android/Phantom4Missions/registerSuccess.png)

## Coordinate Transformations for Missions

Before we dive into the implementation of two missions, let's learn something about the special coordinate transformations of them.

### TapFly Mission Coordinate Transformation

If we check the **TapFlyExecutionState** class, you can see the following two public methods:

~~~java

public Vector getDirection ()
public PointF getImageLocation ()

~~~

**1.** The `getDirection ()` method returns a DJIVector object, which represents a cartesian vector in 3D space. You can get the actual flying direction of the aircraft using the N-E-D(North-East-Down) coordinate system when the aircraft is executing a TapFly mission.

**2.** The `getImageLocation ()` method returns a PointF object, which represents the image point from the live video stream where the vision system should calculate the flight direction from. The image point is normalized to [0,1] where (0,0) is the top left corner and (1,1) is the bottom right.

Here is a diagram to show the coordinate transformation of the mission:

![tapFlyMissionCoordinate](../images/tutorials-and-samples/Android/Phantom4Missions/android_tapFlyMissionCoordinate.png)

As the diagram shown above, you can see the process of transformation.

- The `target` object shown above is transformed from TouchPoint (PointF) to a Video Stream Coordinate System PointF.

- The `getDirection()` method shown above belongs to the **N-E-D (North-East-Down) Coordinate System** and you can invoke this method to get the field value from the SDK.

- The `imageLocation()` method shown above belongs to the **Video Stream Coordinate System** and you can invoke this method to get the field value from the SDK.

So in our demo application, in order to implement the TapFly mission, we should transform the user's touch location (A PointF object) of Android View Coordinate System into the image location (A PointF object) of Video Stream Coordination System and pass it to the following `target` object of DJITapFlyMission:

~~~java
/**
 *  The image point from the video feed where the vision system should calculate the flight direction from. The image point is normalized to [0,1] where (0,0) is the top left corner and (1,1) is the bottom right.
 */
public PointF target
~~~

### ActiveTrack Mission Coordinate Transformation

Next, let's check the **ActiveTrackTrackingState** class, you may see the following public getter method:

~~~java
public RectF getTargetRect()
~~~

Check the **ActiveTrackMission** class, you can also see this method:

~~~java
public void setTargetRect(RectF var1)
~~~

**1.** You can invoke the `getTargetRect ()` method to get a RectF object which is a rectangle in the live video stream view image that represents the target being tracked. The rectangle is normalized to [0,1] where (0,0) is the top left of the video preview and (1,1) is the bottom right.

**2.** By invoking the `setTargetRect(RectF var1)` method, you can set the target rect object, which is a RectF class object, it represents a bounding box for the target. The rectangle is normalized to [0,1] where (0,0) is the top left of the video preview and (1,1) is the bottom right.

If the mission is initialized with a PointF object, the vision system will try to recognize object around the point and return the representative rect in the MissionProgressStatusCallback.

Here is a diagram to show the coordinate transformation of the ActiveTrack mission:

![ActiveTrackMissionCoordinate](../images/tutorials-and-samples/Android/Phantom4Missions/android_ActiveTrackMissionCoordinateSystem.png)

As the diagram shown above, you can see the process of transformation.

- The `getTargetRect()` and `setTargetRect(RectF var1)` methods shown above belongs to the **Video Stream Coordinate System**.

So in order to implement the ActiveTrack Mission, we should transform the user's touch rect (A RectF object) of Android View Coordinate System into the tracking rect (A RectF object) of Video Stream Coordination System and pass it to the `setTargetRect(RectF var1)` method of `ActiveTrackMission`. You can get the tracking rect object by invoking the `getTargetRect()` method of `ActiveTrackTrackingState`. And you can use it to update the rectangle on your screen.

## Implementing the TapFly Mission

### Updating the DemoBaseActivity

Before we implement the TapFly Mission, we should update the DemoBaseActivity.java class to configure the live video streaming feature. Let's open the file and add the following codes to it:

~~~java
private static final String TAG = MainActivity.class.getName();
protected VideoFeeder.VideoDataListener mReceivedVideoDataListener = null;
protected DJICodecManager mCodecManager = null;
private BaseProduct mProduct;

//To store index chosen in PopupNumberPicker listener
protected static int[] INDEX_CHOSEN = {-1, -1, -1};

protected TextView mConnectStatusTextView;

protected TextureView mVideoSurface = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
    filter.addAction(DJIDemoApplication.FLAG_CONNECTION_CHANGE);
    registerReceiver(mReceiver, filter);

    mVideoSurface = (TextureView) findViewById(R.id.video_previewer_surface);
    mConnectStatusTextView = (TextView) findViewById(R.id.ConnectStatusTextView);

    if (null != mVideoSurface) {
        mVideoSurface.setSurfaceTextureListener(this);
    }

    // The callback for receiving the raw H264 video data for camera live view
    mReceivedVideoDataListener = new VideoFeeder.VideoDataListener() {

        @Override
        public void onReceive(byte[] videoBuffer, int size) {
            if(mCodecManager != null){
                mCodecManager.sendDataToDecoder(videoBuffer, size);
            }
        }
    };

}
~~~

Here we declare a TextureView(`mVideoSurface` object) to show the live video stream data. We use the `video_previewer_surface` id from its layout xml file to create the object. This id should be the same as PointingTestActivity and TrackingTestActivity's layout settings. Then create the callback variable `mReceivedVideoDataListener` to implement the DJICamera's interface methods for receiving video data.

Moreover, we implement the `initPreviewer()` method as shown below to check product connection status and set the `mReceivedVideoDataListener` as the listener of VideoFeeder:

~~~java
private void initPreviewer() {
    try {
        mProduct = DJIDemoApplication.getProductInstance();
    } catch (Exception exception) {
        mProduct = null;
    }

    if (mProduct == null || !mProduct.isConnected()) {
        showToast("Disconnect");
    } else {
        if (null != mVideoSurface) {
            mVideoSurface.setSurfaceTextureListener(this);
        }

        if (!mProduct.getModel().equals(Model.UNKNOWN_AIRCRAFT)) {
            VideoFeeder.getInstance().getPrimaryVideoFeed().addVideoDataListener(mReceivedVideoDataListener);
        }
    }
}
~~~

For more details of the implementation, please check the "DemoBaseActivity.java" file in this tutorial's Github sample project.

### Working on the PointingTestActivity

#### Showing the Live Video Stream

Now let's come back to the "PointingTestActivity.java" class and override the `onCreate()` method firstly:

~~~java
@Override
protected void onCreate(Bundle savedInstanceState) {

    setContentView(R.layout.activity_pointing_test);
    super.onCreate(savedInstanceState);
    initUI();
}
~~~

In the method shown above, we invoke the `setContentView()` method firstly to show the PointingTestActivity view. Then invoke the DemoBaseActivity class's `onCreate()` method to implement the live video stream showing methods. Lastly, invoke the `initUI()` to initialize all the UI elements.

#### Working on the TapFly Mission

##### Configure Mission

Before we start to create the `TapFlyMission` object, let's use the `TapFlyMissionOperator` to configure the following settings:

**1.** AutoFlightSpeed

You can set the aircraft's auto flight speed during the mission by invoking the `setAutoFlightSpeed()` method of `TapFlyMissionOperator`. The range for it is [1, 10] m/s.

**2.** isHorizontalObstacleAvoidanceEnabled

If you want to allow the aircraft to bypass or move around an obstacle by going to the left or right of the obstacle when executing TapFly mission, you can set this member variable to YES. Otherwise, the aircraft will only go over an obstacle to avoid it.

**3.** Target

This is where we should pass the coordinate transformation PointF object to, we can use the `getTapFlyPoint()` method to do the coordinate transformation and return the PointF object. It's the image point from the video feed where the vision system should calculate the flight direction from.

Now, let's implement the above settings in source code, in the `initUI()` method, let's improve the `setOnSeekBarChangeListener()` method of `mSpeedSb` as shown below:

~~~java
mSpeedSb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        mSpeedTv.setText(progress + 1 + "");
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        getTapFlyOperator().setAutoFlightSpeed(getSpeed(), new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError error) {
                setResultToToast(error == null ? "Set Auto Flight Speed Success" : error.getDescription());
            }
        });
    }
});
~~~

In the code above, we invoke the `setAutoFlightSpeed()` method of `TapFlyMissionOperator` in the `onStopTrackingTouch()` method of `setOnSeekBarChangeListener()` to configure the auto flight speed for TapFly mission.

Next, let's implement the `initTapFlyMission()` method to initialize the `mTapFlyMission` variable and set the `isHorizontalObstacleAvoidanceEnabled` boolean value as shown below:

~~~java
private void initTapFlyMission() {
    mTapFlyMission = new TapFlyMission();
    mTapFlyMission.isHorizontalObstacleAvoidanceEnabled = mAssisSw.isChecked();
    mTapFlyMission.tapFlyMode = TapFlyMode.FORWARD;
}
~~~

Here we use `FORWARD` value of the `TapFlyMode` enum, for more details of the `TapFlyMode`, please check this [documentation](http://developer.dji.com/api-reference/android-api/Components/Missions/DJITapFlyMission.html#djitapflymission_djitapflymode_inline).

Moreover, let's implement the following two methods to manage the mission coordinate transformations:

~~~java
private PointF getTapFlyPoint(View iv) {
    if (iv == null) return null;
    View parent = (View)iv.getParent();
    float centerX = iv.getLeft() + iv.getX()  + ((float)iv.getWidth()) / 2;
    float centerY = iv.getTop() + iv.getY() + ((float)iv.getHeight()) / 2;
    centerX = centerX < 0 ? 0 : centerX;
    centerX = centerX > parent.getWidth() ? parent.getWidth() : centerX;
    centerY = centerY < 0 ? 0 : centerY;
    centerY = centerY > parent.getHeight() ? parent.getHeight() : centerY;

    return new PointF(centerX / parent.getWidth(), centerY / parent.getHeight());
}

private void showPointByTapFlyPoint(final PointF point, final ImageView iv) {
    if (point == null || iv == null) {
        return;
    }
    final View parent = (View)iv.getParent();
     PointingTestActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
             iv.setX(point.x * parent.getWidth() - iv.getWidth() / 2);
             iv.setY(point.y * parent.getHeight() - iv.getHeight() / 2);
             iv.setVisibility(View.VISIBLE);
             iv.requestLayout();
         }
     });
}
~~~

We can use the `getTapFlyPoint()` method to transform the tap point position of Android View coordinate system to the video stream coordinate system. In contrast, we use the `showPointByTapFlyPoint()` method to transform the tap point position(We use `mRstPointIv` to represent it) from video stream coordinate system back to the Android View coordinate system and show it on screen.

Lastly, let's override the `onTouch()` method to track the **ACTION_UP** gesture of MotionEvent:

~~~java
@Override
public boolean onTouch(View v, MotionEvent event) {
    if (v.getId() == R.id.pointing_bg_layout) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_UP:
            if (mTapFlyMission != null) {
                mStartBtn.setVisibility(View.VISIBLE);
                mStartBtn.setX(event.getX() - mStartBtn.getWidth() / 2);
                mStartBtn.setY(event.getY() - mStartBtn.getHeight() / 2);
                mStartBtn.requestLayout();
                mTapFlyMission.target = getTapFlyPoint(mStartBtn);
            } else {
                setResultToToast("TapFlyMission is null");
            }
            break;

        default:
            break;
        }
    }
    return true;
}
~~~

Here, we update the `mStartBtn`'s position to the position user press. Then we invoke the `getTapFlyPoint()` method to do the coordinate transformation and pass it to TapFlyMission's `target` member variable.

##### Start and Stop Mission

Next, let's override the `onClick()` method to implement the click action of `mStartBtn` and `mStopBtn` buttons to start and stop the DJITapFlyMission:

~~~java
@Override
public void onClick(View v) {
    if (v.getId() == R.id.pointing_drawer_control_ib) {
        if (mPushDrawerSd.isOpened()) {
            mPushDrawerSd.animateClose();
        } else {
            mPushDrawerSd.animateOpen();
        }
        return;
    }
    if (getTapFlyOperator() != null) {
        switch (v.getId()) {
        case R.id.pointing_start_btn:
            getTapFlyOperator().startMission(mTapFlyMission, new CommonCallbacks.CompletionCallback() {
                @Override
                public void onResult(DJIError error) {
                    setResultToToast(error == null ? "Start Mission Successfully" : error.getDescription());
                    if (error == null){
                        setVisible(mStartBtn, false);
                    }
                }
            });
            break;
        case R.id.pointing_stop_btn:
            getTapFlyOperator().stopMission(new CommonCallbacks.CompletionCallback() {
                @Override
                public void onResult(DJIError error) {
                    setResultToToast(error == null ? "Stop Mission Successfully" : error.getDescription());
                }
            });
            break;
        default:
            break;
        }
    } else {
        setResultToToast("TapFlyMission Operator is null");
    }
}
~~~

In the code above, we use a switch statement to identify the `mStartBtn` and `mStopBtn` buttons' click action. In the 'mStartBtn' click action case, we invoke the `startMission()` method of `TapFlyMissionOperator` to start the mission and update the visibilities of the `mStartBtn` button.

In the `mStopBtn` click action case, we invoke the `stopMission()` method of `TapFlyMissionOperator` to stop the mission.

##### Add Listener to Receive Mission Events

During the TapFly mission execution, we can add a listener to receive the mission events for status infos. You can use this status infos to inform users of the results or update the UI interface.

Now, let's add the following code at the bottom of `onCreate()` method:

~~~java
@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_pointing_test);
    super.onCreate(savedInstanceState);
    initUI();
    getTapFlyOperator().addListener(new TapFlyMissionOperatorListener() {
        @Override
        public void onUpdate(@Nullable TapFlyMissionEvent aggregation) {
            TapFlyExecutionState executionState = aggregation.getExecutionState();
            if (executionState != null){
                showPointByTapFlyPoint(executionState.getImageLocation(), mRstPointIv);
            }

            StringBuffer sb = new StringBuffer();
            String errorInformation = (aggregation.getError() == null ? "null" : aggregation.getError().getDescription()) + "\n";
            String currentState = aggregation.getCurrentState() == null ? "null" : aggregation.getCurrentState().getName();
            String previousState = aggregation.getPreviousState() == null ? "null" : aggregation.getPreviousState().getName();
            Utils.addLineToSB(sb, "CurrentState: ", currentState);
            Utils.addLineToSB(sb, "PreviousState: ", previousState);
            Utils.addLineToSB(sb, "Error:", errorInformation);

            TapFlyExecutionState progressState = aggregation.getExecutionState();

            if (progressState != null) {
                Utils.addLineToSB(sb, "Heading: ", progressState.getRelativeHeading());
                Utils.addLineToSB(sb, "PointX: ", progressState.getImageLocation().x);
                Utils.addLineToSB(sb, "PointY: ", progressState.getImageLocation().y);
                Utils.addLineToSB(sb, "BypassDirection: ", progressState.getBypassDirection().name());
                Utils.addLineToSB(sb, "VectorX: ", progressState.getDirection().getX());
                Utils.addLineToSB(sb, "VectorY: ", progressState.getDirection().getY());
                Utils.addLineToSB(sb, "VectorZ: ", progressState.getDirection().getZ());
                setResultToText(sb.toString());
            }

            TapFlyMissionState missionState = aggregation.getCurrentState();
            if (!((missionState == TapFlyMissionState.EXECUTING) || (missionState == TapFlyMissionState.EXECUTION_PAUSED)
                    || (missionState == TapFlyMissionState.EXECUTION_RESETTING))){
                setVisible(mRstPointIv, false);
                setVisible(mStopBtn, false);
            }else
            {
                setVisible(mStopBtn, true);
                setVisible(mStartBtn, false);
            }
        }
    });
}
~~~

In the code above, we implement the following features:

1. Invoke the `addListener()` method of `TapFlyMissionOperator` and implement the `onUpdate()` method to receive the TapFly mission events.
2. In the `onUpdate()` method, we firstly get the `TapFlyExecutionState` object `executionState` from the updated `aggregation` variable. Next, check if the `executionState` is null, if not, invoke the `showPointByTapFlyPoint()` method to update the position of the`mRstPointIv` image View (A green circle) on screen. This green circle represents the direction which Mavic Pro will fly towards.
3. Moreover, store the TapFly execution state infos into the StringBuffer `sb` and show it on the `mPushTv` TextView.
4. Lastly, we get the updated `TapFlyMissionState` and set visible property for `mRstPointIv`, `mStartBtn` and `mStopBtn`.

For more implementation details of the `PointingTestActivity` class, please check the Github source code.

Now let's build and run the project to install the app to your Android device, if everything goes well, you should be able to use the TapFly mission of Mavic Pro now.

>**Important**: Remember to switch the remote controller to **P** mode before you test the TapFly mission.

Here is a gif animation for you to get a better understanding of using the TapFly mission feature:

In the animation, when you tap on the screen, a green circle with a "GO" button appears, which is the direction you want Mavic Pro fly towards. Then, press the **GO** button, Mavic Pro will start to execute the TapFly mission and fly. When you want to stop the mission, just press the **X** button, Mavic Pro will stop immediately and hover there.

## Implementing ActiveTrack Mission

### Working on the TrackingTestActivity

#### Showing the Live Video Stream

Now let's go to TrackingTestActivity.java class and override the `onCreate()` method firstly:

~~~java
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_tracking_test);
        super.onCreate(savedInstanceState);
        initUI();
    }
~~~

In the method shown above, we invoke the `setContentView()` method firstly to show the TrackingTestActivity view. Then invoke the DemoBaseActivity class's `onCreate()` method to implement the live video stream showing methods. Lastly, invoke the `initUI()` to initialize all the UI elements.

#### Working on the ActiveTrack Mission

##### Configure Mission

Before we start to create the `ActiveTrackMission` object, let's use the `ActiveTrackOperator` to configure the following settings:

- Enable/Disable Gesture Mode

Gesture mode allows the subject to confirm tracking as well as take pictures using gestures. Raise your arms in a **V**, the human subject can accept the confirmation to track them. Gesture mode can only be enabled when the aircraft is flying but not tracking a target. If the aircraft is already tracking a target, disabling gesture mode will stop the ActiveTrack mission.

You can check this [video](https://www.djivideos.com/watch/b45aa08d-0bd3-46df-a89e-e36f94dffbe9) to get a better understanding of the Gesture Mode.

Now let's implement the `setChecked()` and `setOnCheckedChangeListener()` methods of the `mGestureModeSw` switch at the bottom of the `initUI()` method as shown below:

~~~java
mGestureModeSw.setChecked(getActiveTrackOperator().isGestureModeEnabled());

mGestureModeSw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
    {
        getActiveTrackOperator().setGestureModeEnabled(isChecked, new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError error) {
                setResultToToast("Set GestureMode Enabled: " + (error == null
                        ? "Success"
                        : error.getDescription()));
            }
        });
    }
});
~~~

In the code above, we firstly invoke the `isGestureModeEnabled()` method of `ActiveTrackOperator` to check if the gesture mode is enabled and update the value of the `mGestureModeSw` switch. Next, invoke the `setGestureModeEnabled()` method of `ActiveTrackOperator` to set the gesture mode and inform users by showing a toast message in the completion callback.

- Enable/Disable Retreat

When retreat is enabled, the aircraft will retreat (fly backwards) when the target comes toward it. When it is disabled, the aircraft will not retreat and instead rotate the gimbal pitch down to track the target as it goes underneath. If the target goes beyond the gimbal's pitch stop, the target will be lost and the mission will stop.

Here, let's implement the `setOnCheckedChangeListener()` method of the `mPushBackSw` switch at the bottom of the `initUI()` method as shown below:

~~~java
mPushBackSw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
    {
        getActiveTrackOperator().setRetreatEnabled(isChecked, new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError error) {
                setResultToToast("Set RetreatEnabled: " + (error == null
                        ? "Success"
                        : error.getDescription()));
            }
        });
    }
});
~~~

As you see the code above, we invoke the `setRetreatEnabled()` method of `ActiveTrackOperator` to enable the retreat feature. Next, in the completion callback, inform users by showing a toast message.

- Set Recommended Configuration

Using this feature, we can set the recommended camera and gimbal configuration that optimizes performance for the ActiveTrack Mission in most environments.

Now, let's implement the `onClick()` method of the `mConfigBtn` button as shown below:

~~~objc
case R.id.recommended_configuration_btn:
    getActiveTrackOperator().setRecommendedConfiguration(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            setResultToToast("Set Recommended Config" + (error == null ? "Success" : error.getDescription()));
        }
    });
    break;
~~~

Here, we can invoke the `setRecommendedConfiguration()` method of `ActiveTrackOperator` to set the recommended camera and gimbal configuration. Then in the completion callback, show a toast message to inform users of the results.

##### Start the Mission

Once you finish the steps above, let's continue to implement the following methods to start the ActiveTrack mission:

~~~java
private RectF getActiveTrackRect(View iv) {
    View parent = (View)iv.getParent();
    return new RectF(
            ((float)iv.getLeft() + iv.getX()) / (float)parent.getWidth(),
            ((float)iv.getTop() + iv.getY()) / (float)parent.getHeight(),
            ((float)iv.getRight() + iv.getX()) / (float)parent.getWidth(),
            ((float)iv.getBottom() + iv.getY()) / (float)parent.getHeight()
    );
}

private double calcManhattanDistance(double point1X, double point1Y, double point2X, double point2Y) {
    return Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y);
}

@Override
public boolean onTouch(View v, MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isDrawingRect = false;
            downX = event.getX();
            downY = event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            if (calcManhattanDistance(downX, downY, event.getX(), event.getY()) < 20 && !isDrawingRect) {
                return true;
            }
            isDrawingRect = true;
            mSendRectIV.setVisibility(View.VISIBLE);
            int l = (int)(downX < event.getX() ? downX : event.getX());
            int t = (int)(downY < event.getY() ? downY : event.getY());
            int r = (int)(downX >= event.getX() ? downX : event.getX());
            int b = (int)(downY >= event.getY() ? downY : event.getY());
            mSendRectIV.setX(l);
            mSendRectIV.setY(t);
            mSendRectIV.getLayoutParams().width = r - l;
            mSendRectIV.getLayoutParams().height = b - t;
            mSendRectIV.requestLayout();

            break;

        case MotionEvent.ACTION_UP:

            RectF rectF = getActiveTrackRect(mSendRectIV);
            PointF pointF = new PointF(downX / mBgLayout.getWidth(), downY / mBgLayout.getHeight());
            RectF pointRectF = new RectF(pointF.x, pointF.y, 0, 0);
            mActiveTrackMission = isDrawingRect ? new ActiveTrackMission(rectF, ActiveTrackMode.TRACE) :
                    new ActiveTrackMission(pointRectF, ActiveTrackMode.TRACE);

            getActiveTrackOperator().startTracking(mActiveTrackMission, new CommonCallbacks.CompletionCallback() {
                @Override
                public void onResult(DJIError error) {
                    setResultToToast("Start Tracking: " + (error == null
                                ? "Success"
                                : error.getDescription()));
                }
            });
            mSendRectIV.setVisibility(View.INVISIBLE);
            break;
        default:
            break;
    }

    return true;
}
~~~

In the code above, we implement the following features:

1. In the getActiveTrackRect() method, we transform the tracking rectangle of Android View coordinate system to the video stream coordinate system.
2. Next, in the `calcManhattanDistance()` method, we calculate the Manhattan distance between two points when drawing rect on the screen.
3. Moreover, we implement the `onTouch()` method to handle the `ACTION_DOWN`, `ACTION_MOVE` and `ACTION_UP` MotionEvents. In the `ACTION_DOWN` and `ACTION_MOVE` events, we mainly work on updating the size and position of the white `mSendRectIV` rectangle on screen when user draws.
4. In the `ACTION_UP` event, we firstly invoke the `getActiveTrackRect()` method and pass the `mSendRectIV` variable to transform the drawing rectangle to the video stream coordinate system. Next, check the value of the `isDrawingRect` and initialize the `mActiveTrackMission` variable accordingly. Here, we use the `TRACE` mode of the [ActiveTrackMode](http://developer.dji.com/api-reference/android-api/Components/Missions/DJIActiveTrackMission.html?search=trace&i=0&#djiactivetrackmission_djiactivetrackmode_inline). Furthermore, invoke the `startTracking()` method of `ActiveTrackOperator` to start the ActiveTrack mission and inform users by showing a toast message. Lastly, we hide the `mSendRectIV` image view.

##### Accept and Reject Confirmation

When the vision system is not sure if the tracking rectangle is around the user's desired target, it will need confirmation before starting to fly relative to the target. Let's implement the `onClick()` method of the `mConfirmBtn` button as shown below:

~~~java
case R.id.confirm_btn:
    getActiveTrackOperator().acceptConfirmation(new CommonCallbacks.CompletionCallback() {

        @Override
        public void onResult(DJIError error) {
            setResultToToast(error == null ? "Accept Confirm Success!" : error.getDescription());
        }
    });
    break;
~~~

Here, we invoke the `acceptConfirmation()` method of `ActiveTrackOperator` to accept the confirmation and show a toast message to inform users of the results.

If you want to stop the aircraft from following the target, and ask for user's confirmation again, you can implement the `onClick()` method of the `mRejectBtn` button as shown below:

~~~java
case R.id.reject_btn:
    getActiveTrackOperator().rejectConfirmation(new CommonCallbacks.CompletionCallback() {

        @Override
        public void onResult(DJIError error) {
            setResultToToast(error == null ? "Reject Confirm Success!" : error.getDescription());
        }
    });
    break;
~~~

In the code above, we invoke the `rejectConfirmation()` method of `ActiveTrackOperator` to reject the confirmation and stop the aircraft from following the target. Then show a toast message to inform users of the results.

##### Add Listener to Receive Mission Events

During the ActiveTrack mission execution, we can add a listener to receive the mission events for status infos. You can use this status infos to inform users of the results or update the UI interface.

Now, let's implement the `ActiveTrackMissionOperatorListener` interface and add the following code at the bottom of the `onCreate()` method:

~~~java
@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_tracking_test);
    super.onCreate(savedInstanceState);
    initUI();
    getActiveTrackOperator().addListener(this);
}
~~~

Here we add `TrackingTestActivity` as the listener to receive mission events. Next, let's implement the `updateActiveTrackRect()` method and `onUpdate` callback method as shown below:

~~~java

private void updateActiveTrackRect(final ImageView iv, final ActiveTrackMissionEvent event) {
    if (iv == null || event == null) return;
    View parent = (View)iv.getParent();

    if (event.getTrackingState() != null){
        RectF trackingRect = event.getTrackingState().getTargetRect();
        final int l = (int)((trackingRect.centerX() - trackingRect.width() / 2) * parent.getWidth());
        final int t = (int)((trackingRect.centerY() - trackingRect.height() / 2) * parent.getHeight());
        final int r = (int)((trackingRect.centerX() + trackingRect.width() / 2) * parent.getWidth());
        final int b = (int)((trackingRect.centerY() + trackingRect.height() / 2) * parent.getHeight());

        TrackingTestActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {

                ActiveTrackTargetState targetState = event.getTrackingState().getState();

                if ((targetState == ActiveTrackTargetState.CANNOT_CONFIRM)
                        || (targetState == ActiveTrackTargetState.UNKNOWN))
                {
                    iv.setImageResource(R.drawable.visual_track_cannotconfirm);
                } else if (targetState == ActiveTrackTargetState.WAITING_FOR_CONFIRMATION) {
                    iv.setImageResource(R.drawable.visual_track_needconfirm);
                } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_LOW_CONFIDENCE){
                    iv.setImageResource(R.drawable.visual_track_lowconfidence);
                } else if (targetState == ActiveTrackTargetState.TRACKING_WITH_HIGH_CONFIDENCE){
                    iv.setImageResource(R.drawable.visual_track_highconfidence);
                }
                iv.setVisibility(View.VISIBLE);
                iv.setX(l);
                iv.setY(t);
                iv.getLayoutParams().width = r - l;
                iv.getLayoutParams().height = b - t;
                iv.requestLayout();
            }
        });
    }
}

@Override
public void onUpdate(ActiveTrackMissionEvent event) {

    StringBuffer sb = new StringBuffer();
    String errorInformation = (event.getError() == null ? "null" : event.getError().getDescription()) + "\n";
    String currentState = event.getCurrentState() == null ? "null" : event.getCurrentState().getName();
    String previousState = event.getPreviousState() == null ? "null" : event.getPreviousState().getName();
    Utils.addLineToSB(sb, "CurrentState: ", currentState);
    Utils.addLineToSB(sb, "PreviousState: ", previousState);
    Utils.addLineToSB(sb, "Error:", errorInformation);

    ActiveTrackTrackingState trackingState = event.getTrackingState();
    if (trackingState != null){
        RectF trackingRect = trackingState.getTargetRect();
        if (trackingRect != null) {

            Utils.addLineToSB(sb, "Rect center x: ", trackingRect.centerX());
            Utils.addLineToSB(sb, "Rect center y: ", trackingRect.centerY());
            Utils.addLineToSB(sb, "Rect Width: ", trackingRect.width());
            Utils.addLineToSB(sb, "Rect Height: ", trackingRect.height());
            Utils.addLineToSB(sb, "Reason", trackingState.getReason().name());
            Utils.addLineToSB(sb, "Target Index: ", trackingState.getTargetIndex());
            Utils.addLineToSB(sb, "Target Type", trackingState.getType().name());
            Utils.addLineToSB(sb, "Target State", trackingState.getState().name());

            setResultToText(sb.toString());
        }
    }

    updateActiveTrackRect(mTrackingImage, event);

    ActiveTrackState state = event.getCurrentState();
    if (state == ActiveTrackState.FINDING_TRACKED_TARGET ||
            state == ActiveTrackState.AIRCRAFT_FOLLOWING ||
            state == ActiveTrackState.ONLY_CAMERA_FOLLOWING ||
                    state == ActiveTrackState.CANNOT_CONFIRM ||
                    state == ActiveTrackState.WAITING_FOR_CONFIRMATION ||
                    state == ActiveTrackState.PERFORMING_QUICK_SHOT){

        TrackingTestActivity.this.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                mStopBtn.setVisibility(View.VISIBLE);
                mStopBtn.setClickable(true);
                mConfirmBtn.setVisibility(View.VISIBLE);
                mConfirmBtn.setClickable(true);
                mRejectBtn.setVisibility(View.VISIBLE);
                mRejectBtn.setClickable(true);
                mConfigBtn.setVisibility(View.INVISIBLE);
            }
        });
    }else
    {
        TrackingTestActivity.this.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                mStopBtn.setVisibility(View.INVISIBLE);
                mStopBtn.setClickable(false);
                mConfirmBtn.setVisibility(View.INVISIBLE);
                mConfirmBtn.setClickable(false);
                mRejectBtn.setVisibility(View.INVISIBLE);
                mRejectBtn.setClickable(false);
                mConfigBtn.setVisibility(View.VISIBLE);
                mTrackingImage.setVisibility(View.INVISIBLE);
            }
        });
    }
}
~~~

In the code above, we implement the following features:
1. In the `updateActiveTrackRect()` method, we update the `mTrackingImage` image view's position and size based on the current target rect. Also, update the image resource of the `mTrackingImage` variable based on the `ActiveTrackTargetState`.
2. Next, in the `onUpdate()` method, we create a StringBuffer `sb` object and store the ActiveTrack execution state infos into it and show it on the `mPushInfoTv` TextView.
3. Moreover, invoke the `updateActiveTrackRect()` method to update the position of the `mTrackingImage` image View (A rectangle with different colors) on screen base on the updated `ActiveTrackMissionEvent`.
4. Lastly, get the updated `ActiveTrackState` object and update the UI interfaces' **visibility** and **clickable** status.

##### Stop the Mission

Lastly, let's continue to implement the `onClick()` method of the `mStopBtn` button as shown below:

~~~java
case R.id.tracking_stop_btn:
    getActiveTrackOperator().stopTracking(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            setResultToToast(error == null ? "Stop Tracking Success!" : error.getDescription());
        }
    });

    break;
~~~

Here, we invoke the `stopTracking()` method of `ActiveTrackOperator` to stop executing the ActiveTrack mission and show a toast message to inform users of the result.

For more implementation details of the **TrackingTestActivity.java** file, please check this tutorial's Github source code.

Now let's build and run the project, if everything goes well, you should be able to use the ActiveTrack mission of Mavic Pro now.

>**Important**: Remember to switch the remote controller to **P** mode before you test the ActiveTrack mission.

Here are two gif animations for you to get a better understanding of using the ActiveTrack mission:

- TRACE Mode

Here we use the `TRACE` mode of `ActiveTrackMode` for demonstration. In the animation above, you can see there is a person riding a bicycle there, you can touch the screen to draw a white rectangle on him. Then the rectangle locks on him and turns purple when the `ActiveTrackTargetState` is `WAITING_FOR_CONFIRMATION`. Press the **A** button to accept the confirmation. After the confirmation, the rectangle turns green and the ActiveTrack mission starts. The person rides around and the green rectangle will follow him to track its movement.

Press the **X** button if you want to stop the ActiveTrack mission. By the way, you can try to switch on the "RetreatEnabled" switcher on the upper left corner of the screen to enable the **Retreat** feature. Once you go towards the Mavic Pro, it will fly backwards.

- Enable Gesture Mode

In the animation above, you can see there is a person standing there, when he raise his arms in a **V**, the Mavic Pro will accept the confirmation and start to track him automatically. Press the **X** button if you want to stop the ActiveTrack mission.

### Using the DJI Assistant 2 for Mission Testing

Since most of our developers don't have a perfect testing environment, like a big indoor space, wide backyard, etc. If we need to go outdoors and bring our laptop to debug and test our application everytime, it's time-consuming and not efficient.

Luckily, we have a new DJI Assistant 2 (Includes the 3D Simulator) for you to test the mission easily on your Mac. The simulator creates a virtual 3D environment from flight data transmitted to the Mac.

You can check the [Using DJI Assistant 2 Simulator](../application-development-workflow/workflow-testing.html#DJI-Assistant-2-Simulator) for its basic usage.

Now you can connect your Android which is running the demo application to the remote controller, and start to test the **TapFly** and **ActiveTrack** missions on the simulator of DJI Assistant 2.

By the way, you can use Wireless Android Debug Bridge (adb) to debug the app using Android Studio when your android device is connecting to the remote controller. If you are not familiar with Android Debug Bridge, please check this  link  for details.

### Summary

  Congratulations! You've finished the demo project and implement the two cool **TapFly** and **ActiveTrack** missions using DJI Mobile SDK. It's easy and straightforward. You've learned how to use the DJITapFlyMission, DJIActiveTrackMission and DJIMissionControl to implement the features.

  But, In order to make a cool **TapFly** and **ActiveTrack** mission application, you still have a long way to go. You can add more necessary features like showing the battery percentage, GPS signal quality, add a checklist like DJI Go app to check the aircraft status before flying, etc. Good luck and hope you enjoy this tutorial!


text:
import { get, isEmpty, concat, without, flatten, flatMap, initial } from 'lodash';
import u from 'unist-builder';

/**
 * Map of Slate node types to MDAST/Remark node types.
 */
const typeMap = {
  'root': 'root',
  'paragraph': 'paragraph',
  'heading-one': 'heading',
  'heading-two': 'heading',
  'heading-three': 'heading',
  'heading-four': 'heading',
  'heading-five': 'heading',
  'heading-six': 'heading',
  'quote': 'blockquote',
  'code': 'code',
  'numbered-list': 'list',
  'bulleted-list': 'list',
  'list-item': 'listItem',
  'table': 'table',
  'table-row': 'tableRow',
  'table-cell': 'tableCell',
  'thematic-break': 'thematicBreak',
  'link': 'link',
  'image': 'image',
};

/**
 * Map of Slate mark types to MDAST/Remark node types.
 */
const markMap = {
  bold: 'strong',
  italic: 'emphasis',
  strikethrough: 'delete',
  code: 'inlineCode',
};

/**
 * Slate treats inline code decoration as a standard mark, but MDAST does
 * not allow inline code nodes to contain children, only a single text
 * value. An MDAST inline code node can be nested within mark nodes such
 * as "emphasis" and "strong", but it cannot contain them.
 *
 * Because of this, if a "code" mark (translated to MDAST "inlineCode") is
 * in the markTypes array, we make the base text node an "inlineCode" type
 * instead of a standard text node.
 */
function processCodeMark(markTypes) {
  const isInlineCode = markTypes.includes('inlineCode');
  const filteredMarkTypes = isInlineCode ? without(markTypes, 'inlineCode') : markTypes;
  const textNodeType = isInlineCode ? 'inlineCode' : 'html';
  return { filteredMarkTypes, textNodeType };
}

/**
 * Returns an array of one or more MDAST text nodes of the given type, derived
 * from the text received. Certain transformations, such as line breaks, cause
 * multiple nodes to be returned.
 */
function createTextNodes(text, type = 'html') {
  /**
   * Split the text string at line breaks, then map each substring to an array
   * pair consisting of an MDAST text node followed by a break node. This will
   * result in nested arrays, so we use `flatMap` to produce a flattened array,
   * and `initial` to leave off the superfluous trailing break.
   */
  const brokenText = text.split('\n');
  const toPair = str => [u(type, str), u('break')];
  return initial(flatMap(brokenText, toPair));
}

/**
 * Wraps a text node in one or more mark nodes by placing the text node in an
 * array and using that as the `children` value of a mark node. The resulting
 * mark node is then placed in an array and used as the child of a mark node for
 * the next mark type in `markTypes`. This continues for each member of
 * `markTypes`. If `markTypes` is empty, the original text node is returned.
 */
function wrapTextWithMarks(textNode, markTypes) {
  const wrapTextWithMark = (childNode, markType) => u(markType, [childNode]);
  return markTypes.reduce(wrapTextWithMark, textNode);
}

/**
 * Converts a Slate Raw text node to an MDAST text node.
 *
 * Slate text nodes without marks often simply have a "text" property with
 * the value. In this case the conversion to MDAST is simple. If a Slate
 * text node does not have a "text" property, it will instead have a
 * "ranges" property containing an array of objects, each with an array of
 * marks, such as "bold" or "italic", along with a "text" property.
 *
 * MDAST instead expresses such marks in a nested structure, with individual
 * nodes for each mark type nested until the deepest mark node, which will
 * contain the text node.
 *
 * To convert a Slate text node's marks to MDAST, we treat each "range" as a
 * separate text node, convert the text node itself to an MDAST text node,
 * and then recursively wrap the text node for each mark, collecting the results
 * of each range in a single array of child nodes.
 *
 * For example, this Slate text node:
 *
 * {
 *   kind: 'text',
 *   ranges: [
 *     {
 *       text: 'test',
 *       marks: ['bold', 'italic']
 *     },
 *     {
 *       text: 'test two'
 *     }
 *   ]
 * }
 *
 * ...would be converted to this MDAST nested structure:
 *
 * [
 *   {
 *     type: 'strong',
 *     children: [{
 *       type: 'emphasis',
 *       children: [{
 *         type: 'text',
 *         value: 'test'
 *       }]
 *     }]
 *   },
 *   {
 *     type: 'text',
 *     value: 'test two'
 *   }
 * ]
 *
 * This example also demonstrates how a single Slate node may need to be
 * replaced with multiple MDAST nodes, so the resulting array must be flattened.
 */
function convertTextNode(node) {

  /**
   * If the Slate text node has no "ranges" property, just return an equivalent
   * MDAST node.
   */
  if (!node.ranges) {
    return createTextNodes(node.text);
  }

  /**
   * If there is no "text" property, convert the text range(s) to an array of
   * one or more nested MDAST nodes.
   */
  const textNodes = node.ranges.map(range => {
    /**
     * Get an array of the mark types, converted to their MDAST equivalent
     * types.
     */
    const { marks = [], text } = range;
    const markTypes = marks.map(mark => markMap[mark.type]);

    /**
     * Code marks must be removed from the marks array, and the presence of a
     * code mark changes the text node type that should be used.
     */
    const { filteredMarkTypes, textNodeType } = processCodeMark(markTypes);

    /**
     * Create the base text node.
     */
    const textNodes = createTextNodes(text, textNodeType);

    /**
     * Recursively wrap the base text node in the individual mark nodes, if
     * any exist.
     */
    return textNodes.map(textNode => wrapTextWithMarks(textNode, filteredMarkTypes));
  });

  /**
   * Since each range will be mapped into an array, we flatten the result to
   * return a single array of all nodes.
   */
  return flatten(textNodes);
}

/**
 * Convert a single Slate Raw node to an MDAST node. Uses the unist-builder `u`
 * function to create MDAST nodes and parses shortcodes.
 */
function convertNode(node, children, shortcodePlugins) {
  switch (node.type) {

    /**
     * General
     *
     * Convert simple cases that only require a type and children, with no
     * additional properties.
     */
    case 'root':
    case 'paragraph':
    case 'quote':
    case 'list-item':
    case 'table':
    case 'table-row':
    case 'table-cell': {
      return u(typeMap[node.type], children);
    }

    /**
     * Shortcodes
     *
     * Shortcode nodes only exist in Slate's Raw AST if they were inserted
     * via the plugin toolbar in memory, so they should always have
     * shortcode data attached. The "shortcode" data property contains the
     * name of the registered shortcode plugin, and the "shortcodeData" data
     * property contains the data received from the shortcode plugin's
     * `fromBlock` method when the shortcode node was created.
     *
     * Here we get the shortcode plugin from the registry and use it's
     * `toBlock` method to recreate the original markdown shortcode. We then
     * insert that text into a new "html" type node (a "text" type node
     * might get encoded or escaped by remark-stringify). Finally, we wrap
     * the "html" node in a "paragraph" type node, as shortcode nodes must
     * be alone in their own paragraph.
     */
    case 'shortcode': {
      const { data } = node;
      const plugin = shortcodePlugins.get(data.shortcode);
      const text = plugin.toBlock(data.shortcodeData);
      const textNode = u('html', text);
      return u('paragraph', { data }, [ textNode ]);
    }

    /**
     * Headings
     *
     * Slate schemas don't usually infer basic type info from data, so each
     * level of heading is a separately named type. The MDAST schema just
     * has a single "heading" type with the depth stored in a "depth"
     * property on the node. Here we derive the depth from the Slate node
     * type - e.g., for "heading-two", we need a depth value of "2".
     */
    case 'heading-one':
    case 'heading-two':
    case 'heading-three':
    case 'heading-four':
    case 'heading-five':
    case 'heading-six': {
      const depthMap = { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 };
      const depthText = node.type.split('-')[1];
      const depth = depthMap[depthText];
      return u(typeMap[node.type], { depth }, children);
    }

    /**
     * Code Blocks
     *
     * Code block nodes have a single text child, and may have a code language
     * stored in the "lang" data property. Here we transfer both the node
     * value and the "lang" data property to the new MDAST node.
     */
    case 'code': {
      const value = get(node.nodes, [0, 'text']);
      const lang = get(node.data, 'lang');
      return u(typeMap[node.type], { lang }, value);
    }

    /**
     * Lists
     *
     * Our Slate schema has separate node types for ordered and unordered
     * lists, but the MDAST spec uses a single type with a boolean "ordered"
     * property to indicate whether the list is numbered. The MDAST spec also
     * allows for a "start" property to indicate the first number used for an
     * ordered list. Here we translate both values to our Slate schema.
     */
    case 'numbered-list':
    case 'bulleted-list': {
      const ordered = node.type === 'numbered-list';
      const props = { ordered, start: get(node.data, 'start') || 1 };
      return u(typeMap[node.type], props, children);
    }

    /**
     * Thematic Breaks
     *
     * Thematic breaks don't have children. We parse them separately for
     * clarity.
     */
    case 'thematic-break': {
      return u(typeMap[node.type]);
    }

    /**
     * Links
     *
     * The url and title attributes of link nodes are stored in properties on
     * the node for both Slate and Remark schemas.
     */
    case 'link': {
      const { url, title } = get(node, 'data', {});
      return u(typeMap[node.type], { url, title }, children);
    }

    /**
     * No default case is supplied because an unhandled case should never
     * occur. In the event that it does, let the error throw (for now).
     */
  }
}

export default function slateToRemark(raw, { shortcodePlugins }) {
  /**
   * The transform function mimics the approach of a Remark plugin for
   * conformity with the other serialization functions. This function converts
   * Slate nodes to MDAST nodes, and recursively calls itself to process child
   * nodes to arbitrary depth.
   */
  function transform(node) {

    /**
     * Call `transform` recursively on child nodes, and flatten the resulting
     * array.
     */
    const children = !isEmpty(node.nodes) && flatten(node.nodes.map(transform));

    /**
     * Run individual nodes through conversion factories.
     */
    return node.kind === 'text' ? convertTextNode(node) : convertNode(node, children, shortcodePlugins);
  }

  /**
   * The Slate Raw AST generally won't have a top level type, so we set it to
   * "root" for clarity.
   */
  raw.type = 'root';

  const mdast = transform(raw);
  return mdast;
}

redpajama_set_name: RedPajamaGithub


text:
//========= Copyright 2016, HTC Corporation. All rights reserved. ===========

using UnityEngine;

namespace HTC.UnityPlugin.PoseTracker
{
    /// <summary>
    /// Describe a pose by position and rotation
    /// </summary>
    public struct Pose
    {
        public Vector3 pos;
        public Quaternion rot;

        public static Pose identity
        {
            get { return new Pose(Vector3.zero, Quaternion.identity); }
        }

        public Pose(Vector3 pos, Quaternion rot)
        {
            this.pos = pos;
            this.rot = rot;
        }

        public Pose(Transform t, bool useLocal = false)
        {
            if(t == null)
            {
                pos = Vector3.zero;
                rot = Quaternion.identity;
            }
            else if (!useLocal)
            {
                pos = t.position;
                rot = t.rotation;
            }
            else
            {
                pos = t.localPosition;
                rot = t.localRotation;
            }
        }

        public override bool Equals(object o)
        {
            if (o is Pose)
            {
                Pose t = (Pose)o;
                return pos == t.pos && rot == t.rot;
            }
            return false;
        }

        public override int GetHashCode()
        {
            return pos.GetHashCode() ^ rot.GetHashCode();
        }

        public static bool operator ==(Pose a, Pose b)
        {
            return a.pos == b.pos && a.rot == b.rot;
        }

        public static bool operator !=(Pose a, Pose b)
        {
            return a.pos != b.pos || a.rot != b.rot;
        }

        public static Pose operator *(Pose a, Pose b)
        {
            return new Pose
            {
                rot = a.rot * b.rot,
                pos = a.pos + a.rot * b.pos
            };
        }

        public void Multiply(Pose a, Pose b)
        {
            rot = a.rot * b.rot;
            pos = a.pos + a.rot * b.pos;
        }

        public void Inverse()
        {
            rot = Quaternion.Inverse(rot);
            pos = -(rot * pos);
        }

        public Pose GetInverse()
        {
            var t = new Pose(pos, rot);
            t.Inverse();
            return t;
        }

        public Vector3 InverseTransformPoint(Vector3 point)
        {
            return Quaternion.Inverse(rot) * (point - pos);
        }

        public Vector3 TransformPoint(Vector3 point)
        {
            return pos + (rot * point);
        }

        public static Pose Lerp(Pose a, Pose b, float t)
        {
            return new Pose(Vector3.Lerp(a.pos, b.pos, t), Quaternion.Slerp(a.rot, b.rot, t));
        }

        public void Lerp(Pose to, float t)
        {
            pos = Vector3.Lerp(pos, to.pos, t);
            rot = Quaternion.Slerp(rot, to.rot, t);
        }

        public static Pose LerpUnclamped(Pose a, Pose b, float t)
        {
            return new Pose(Vector3.LerpUnclamped(a.pos, b.pos, t), Quaternion.SlerpUnclamped(a.rot, b.rot, t));
        }

        public void LerpUnclamped(Pose to, float t)
        {
            pos = Vector3.LerpUnclamped(pos, to.pos, t);
            rot = Quaternion.SlerpUnclamped(rot, to.rot, t);
        }

        public static void SetPose(Transform target, Pose pose, Transform origin = null)
        {
            if (origin != null && origin != target.parent)
            {
                pose = new Pose(origin) * pose;
                pose.pos.Scale(origin.localScale);
                target.position = pose.pos;
                target.rotation = pose.rot;
            }
            else
            {
                target.localPosition = pose.pos;
                target.localRotation = pose.rot;
            }
        }

        public static Pose FromToPose(Pose from, Pose to)
        {
            var invRot = Quaternion.Inverse(from.rot);
            return new Pose(invRot * (to.pos - from.pos), invRot * to.rot);
        }
    }
}


text:
Streaming multipart/form-data parser
====================================

.. image:: https://travis-ci.org/siddhantgoel/streaming-form-data.svg?branch=stable
    :target: https://travis-ci.org/siddhantgoel/streaming-form-data

.. image:: https://badge.fury.io/py/streaming-form-data.svg
    :target: https://pypi.python.org/pypi/streaming-form-data

:code:`streaming_form_data` provides a Python parser for parsing
:code:`multipart/form-data` input chunks (the most commonly used encoding when
submitting data through HTML forms).

Chunk size is determined by the API user, but currently there are no
restrictions on what the chunk size should be, since the parser works
byte-by-byte (which means that passing the entire input as a single chunk should
also work).

Installation
------------

.. code-block:: bash

    $ pip install streaming_form_data

The core parser is written in :code:`Cython`, which is a superset of Python that
compiles the input down to a C extension which can then be imported in normal
Python code.

The compiled C parser code is included in the PyPI package, hence the
installation requires a working C compiler.

Usage
-----

.. code-block:: python

    >>> from streaming_form_data import StreamingFormDataParser
    >>> from streaming_form_data.targets import ValueTarget, FileTarget, NullTarget
    >>>
    >>> headers = {'Content-Type': 'multipart/form-data; boundary=boundary'}
    >>>
    >>> parser = StreamingFormDataParser(headers=headers)
    >>>
    >>> parser.register('name', ValueTarget())
    >>> parser.register('file', FileTarget('/tmp/file.txt'))
    >>> parser.register('discard-me', NullTarget())
    >>>
    >>> for chunk in request.body:
    ...     parser.data_received(chunk)
    ...
    >>>

Usage can broadly be split into three stages.

1. Initialization
~~~~~~~~~~~~~~~~~

The :code:`StreamingFormDataParser` class expects a dictionary of HTTP request
headers when being instantiated. These headers are used to determine the input
:code:`Content-Type` and a few other metadata.

2. Input Registration
~~~~~~~~~~~~~~~~~~~~~

HTML forms typically have multiple fields. For instance, a form could have a
text input field called :code:`name` and a file input field called
:code:`file`.

This needs to be communicated to the parser using the :code:`parser.register`
function. This function expects two arguments - the name of the input field, and
the associated :code:`Target` class (which determines how the input should be
handled).

For instance, if you want to store the contents of the :code:`name` field in an
in-memory variable, and the :code:`file` field in a file on disk, you can tell
this to the parser as follows.

.. code-block:: python

    >>> name_target = ValueTarget()
    >>> file_target = FileTarget('/tmp/file.dat')
    >>>
    >>> parser.register('name', name_target)
    >>> parser.register('file', file_target)

Registering multiple targets is also supported.

.. code-block:: python

    >>> name_target = ValueTarget()
    >>> sha256_target = SHA256Target()
    >>>
    >>> parser.register('file', name_target)
    >>> parser.register('file', sha256_target)

In this case, the contents of the :code:`file` field would be streamed to both
the :code:`ValueTarget` as well as the :code:`SHA256Target`.

3. Streaming data
~~~~~~~~~~~~~~~~~

At this stage the parser has everything it needs to be able to work. Depending
on what web framework you're using, just pass the actual HTTP request body to
the parser, either one chunk at a time or the complete thing at once.

.. code-block:: python

    >> chunk = read_next_chunk() # depends on your web framework of choice
    >>
    >> parser.data_received(chunk)

API
---

:code:`StreamingFormDataParser`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This class is the main entry point, and expects a dictionary of HTTP request
:code:`headers`. These headers are used to determine the input
:code:`Content-Type` and a few other metadata.

:code:`Target` classes
~~~~~~~~~~~~~~~~~~~~~~

When registering inputs with the parser, instances of subclasses of the
:code:`Target` class should be used. These target classes ultimately determine
what to do with the data.

:code:`ValueTarget`
```````````````````

:code:`ValueTarget` objects hold the input in memory.

.. code-block:: python

    >>> target = ValueTarget()

:code:`FileTarget`
``````````````````

:code:`FileTarget` objects stream the contents to a file on-disk.

.. code-block:: python

    >>> target = FileTarget('/tmp/file.txt')

:code:`DirectoryTarget`
``````````````````

:code:`DirectoryTarget` objects stream the contents to a directory on-disk.

.. code-block:: python

    >>> target = DirectoryTarget('/tmp/uploads/')

:code:`SHA256Target`
````````````````````

:code:`SHA256Target` objects calculate a :code:`SHA256` hash of the given input,
and hold the result in memory.

.. code-block:: python

    >>> target = SHA256Target()

:code:`NullTarget`
````````````````````

:code:`NullTarget` objects discard the input completely.

.. code-block:: python

    >>> target = NullTarget()

Custom :code:`Target` classes
`````````````````````````````

It's possible to define custom targets for your specific use case by inheriting
the :code:`streaming_form_data.targets.BaseTarget` class and overriding the
:code:`on_data_received` function.

.. code-block:: python

    >>> from streaming_form_data.targets import BaseTarget
    >>>
    >>> class CustomTarget(BaseTarget):
    ...     def on_data_received(self, chunk):
    ...         do_something_with(chunk)

If the :code:`Content-Disposition` header included the :code:`filename`
directive, this value will be available as the :code:`self.multipart_filename`
attribute in :code:`Target` classes.

Similarly, if the :code:`Content-Type` header is available for the uploaded
files, this value will be available as the :code:`self.multipart_content_type`
attribute in :code:`Target` classes.

:code:`Validator` classes
~~~~~~~~~~~~~~~~~~~~~~~~~

:code:`Target` classes accept a :code:`validator` callable when being
instantiated. Every time :code:`data_received` is called with a given
:code:`chunk`, the target runs this :code:`chunk` through the given callable.

This is useful for performing certain validation tasks like making sure the
input size is not exceeding a certain value. This is shown in the following code
snippet.

.. code-block:: python

    >>> from streaming_form_data.targets import ValueTarget
    >>>
    >>> target = ValueTarget(validator=MaxSizeValidator(100))

Examples
--------

- :code:`Bottle` - https://git.io/vhCUy
- :code:`Flask` - https://git.io/fjPoA
- :code:`Tornado` - https://git.io/vhCUM

If you'd like to document usage with another web framework (which ideally
allows chunked HTTP reads), please open an issue or a pull request.

.. toctree::
   :maxdepth: 2
   :caption: Contents:

Indices and tables
==================

* :ref:`search`


text:
return Def.Sprite {
	Texture=NOTESKIN:GetPath('DownRightFoot','Roll Head Active');
	InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
};


text:
<?php
	function hello() {
		exit;
	}
?>
<?php
	require_once('./auth_info.php');
	header('Content-Type:text/xml');
	$id=$_GET['id'];

	$dom = new DOMDocument('1.0','utf-8');							//create document
	$page = $dom->appendChild($dom->createElement('page')); //create root node
	$page->setAttribute('id',$id);
	//$page->setAttribute('test','辛辛苦苦的准备,结果是');

	@ $db = new mysqli($host,$user,$password,'tmp');
	if ( mysqli_connect_errno()) {
		$page->setAttribute('state','error');
		$dom->formatOutput = true;
		echo $dom->saveXML();
		$db->close();
		exit;
	}
	$queryStr = "select id,author,title,board,item_id,rank_times from hot_topic_database where rss_time > '".$id."';";
	//queryStr need more work to solve task_logic
	$results = $db->query($queryStr);
	$number_of_results = $results->num_rows;

	if ( $number_of_results == 10) {
		$page->setAttribute('state','ok');
	 }else if ( $number_of_results < 1) {
		$page->setAttribute('state','empty');
		$number_of_results = 0;
	} else if ( $number_of_results > 10 ) { //impossible
		$number_of_results = 10;
		$page->setAttribute('state','ok');
	} else {
		$page->setAttribute('state','less');
	}
	for ( $i = 0; $i < $number_of_results;$i++ ) {
		$row = $results->fetch_assoc();
		$item = $page->appendChild($dom->createElement('item'));
		$item->setAttribute('id',htmlspecialchars($row['id']));
			$info = $item->appendChild($dom->createElement('info'));
				$info->appendChild($dom->createTextNode(htmlspecialchars($row['title'])));
			$num = $item->appendChild($dom->createElement('n'));
				$num->appendChild($dom->createTextNode(htmlspecialchars($row['rank_times'])));
			$board = $item->appendChild($dom->createElement('board'));
				$board->appendChild($dom->createTextNode(htmlspecialchars($row['board'])));
			$gid = $item->appendChild($dom->createElement('gid'));
				$gid->appendChild($dom->createTextNode(htmlspecialchars($row['item_id'])));
			$author = $item->appendChild($dom->createElement('author'));
				$author->appendChild($dom->createTextNode(htmlspecialchars($row['author'])));
	}
	$results->free();
	$db->close();

	$dom->formatOutput = true;
	echo $dom->saveXML();

?>


text:
<?php

class PagarMe_Request extends PagarMe
{
    private $path;
    private $method;
    private $parameters = array();
    private $headers;
    private $live;

    public function __construct($path, $method, $live = PagarMe::live)
    {
        $this->method = $method;
        $this->path = $path;
        $this->live = $live;
    }
    public function run()
    {
        if (!parent::getApiKey()) {
            throw new PagarMe_Exception("You need to configure API key before performing requests.");
        }

        $this->parameters = array_merge($this->parameters, array( "api_key" => parent::getApiKey()));
        // var_dump($this->parameters);
        // $this->headers = (PagarMe::live) ? array("X-Live" => 1) : array();
        $client = new PagarMe_RestClient(array("method" => $this->method, "url" => $this->full_api_url($this->path), "headers" => $this->headers, "parameters" => $this->parameters ));
        $response = $client->run();
        $decode = json_decode($response["body"], true);
        if ($decode === null) {
            throw new Exception("Failed to decode json from response.\n\n Response: ".var_export($response, true));
        } else {
            if ($response["code"] == 200) {
                return $decode;
            } else {
                throw PagarMe_Exception::buildWithFullMessage($decode);
            }
        }
    }

    public function setParameters($parameters)
    {
        $this->parameters = $parameters;
    }

    public function getParameters()
    {
        return $this->parameters;
    }
}


text:
<?php
/*
 *  Made by Samerton
 *  https://github.com/NamelessMC/Nameless/
 *  NamelessMC version 2.0.0-pr8
 *
 *  License: MIT
 *
 *  404 Not Found page
 */

header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');

const PAGE = 404;
$page_title = '404';
require_once(ROOT_PATH . '/core/templates/frontend_init.php');

// Load modules + template
Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template);

$template->onPageLoad();

require(ROOT_PATH . '/core/templates/navbar.php');
require(ROOT_PATH . '/core/templates/footer.php');

// Assign Smarty variables
$smarty->assign(
    [
        '404_TITLE' => $language->get('errors', '404_title'),
        'CONTENT' => $language->get('errors', '404_content'),
        'BACK' => $language->get('errors', '404_back'),
        'HOME' => $language->get('errors', '404_home'),
        'ERROR' => $language->get('errors', '404_error'),
        'PATH' => (defined('CONFIG_PATH') ? CONFIG_PATH : '')
    ]
);

// Display template
$template->displayTemplate('404.tpl', $smarty);