New version of android-sample appication. Added AR.Drone settings configuration to android. Improved d main UI

Esse commit está contido em:
Denis Shmyga
2012-12-17 19:14:49 +02:00
commit b13026caa0
20 arquivos alterados com 745 adições e 192 exclusões
+19 -23
Ver Arquivo
@@ -4,46 +4,42 @@
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.DUMP" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
<uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk
android:minSdkVersion="12"
android:minSdkVersion="8"
android:targetSdkVersion="12" />
<application
android:icon="@drawable/ic_launcher"
android:icon="@drawable/ardron_icon"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
android:label="@string/title_activity_main"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ConfigurationActivity"
android:label="@string/title_activity_settings"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SettingsPrefs"
android:label="@string/title_settings"
android:theme="@android:style/Theme.Black">
</activity>
</application>
</manifest>
+10 -4
Ver Arquivo
@@ -76,13 +76,19 @@ limitations under the License.
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.0.1.2</version>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.codeminders</groupId>
<artifactId>javadrone-api</artifactId>
<version>${currentVersion}</version>
<groupId>com.google.android</groupId>
<artifactId>annotations</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.codeminders</groupId>
<artifactId>javadrone-api</artifactId>
<version>${currentVersion}</version>
</dependency>
</dependencies>
</project>
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 18 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 2.9 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 18 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.9 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.8 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 3.9 KiB

+94 -62
Ver Arquivo
@@ -1,72 +1,104 @@
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ps3"
<?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:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/display"
android:layout_width="249dp"
android:layout_height="206dp"
android:layout_x="37dp"
android:layout_y="46dp"
android:src="@drawable/ic_action_search" />
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textView1"
android:layout_width="172dp"
android:layout_height="wrap_content"
android:layout_x="70dp"
android:layout_y="5dp"
android:text="AR.Drone Connection State:"
android:textStyle="bold" />
<TextView
android:id="@+id/state_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp"
android:text="@string/drone_state"
android:textStyle="bold" />
<TextView
android:id="@+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="118dp"
android:layout_y="22dp"
android:text="DISCONNECTED"
android:textColor="#FF0000"
android:textStyle="bold" />
<TextView
android:id="@+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/default_state"
android:textColor="#FF0000"
android:textStyle="bold" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/usb_joystick_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp"
android:text="@string/usb_joystick_state"
android:textStyle="bold" />
<TextView
android:id="@+id/joystick_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/default_state"
android:textColor="#FF0000"
android:textStyle="bold" />
</TableRow>
</TableLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_gravity="top"
android:layout_weight=".8"
android:paddingBottom="5dp" >
<ImageView
android:id="@+id/display"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:contentDescription="@string/display_desc"
android:scaleType="fitCenter"
android:src="@drawable/ardrone_front" />
</LinearLayout>
<Button
android:id="@+id/land"
android:layout_width="wrap_content"
android:id="@+id/takeOffOrland"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_x="22dp"
android:layout_y="301dp"
android:clickable="false"
android:text="Land"
android:text="@string/btn_take_off"
android:visibility="visible" />
<Button
android:id="@+id/takeOff"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_x="234dp"
android:layout_y="301dp"
android:clickable="false"
android:longClickable="false"
android:text="TakeOff"
android:visibility="visible" />
<Button
android:id="@+id/connect"
style="?android:attr/buttonStyleSmall"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_x="25dp"
android:layout_y="250dp"
android:text="Connect" />
<Button
android:id="@+id/ps3Button"
android:layout_width="116dp"
android:layout_height="wrap_content"
android:layout_x="128dp"
android:layout_y="251dp"
android:text="Connect PS3" />
</AbsoluteLayout>
android:baselineAligned="false"
android:gravity="bottom"
android:weightSum="1.0">
<Button
android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:text="@string/btn_connect" />
<Button
android:id="@+id/ps3Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:text="@string/btn_connect_ps3" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp">
<TextView android:id="@android:id/title"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="22dp"
android:typeface="sans"
android:textStyle="normal"
android:textColor="#ffffff"/>
<TextView android:id="@+id/seekBarPrefUnitsRight"
android:layout_alignParentRight="true"
android:layout_below="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/seekBarPrefValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/seekBarPrefUnitsRight"
android:layout_below="@android:id/title"
android:gravity="right"/>
<TextView android:id="@+id/seekBarPrefUnitsLeft"
android:layout_below="@android:id/title"
android:layout_toLeftOf="@id/seekBarPrefValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="@android:id/summary"
android:layout_alignParentLeft="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/seekBarPrefUnitsLeft"
android:layout_below="@android:id/title"/>
<LinearLayout android:id="@+id/seekBarPrefBarContainer"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/summary"/>
</RelativeLayout>
@@ -2,4 +2,7 @@
<item android:id="@+id/menu_settings"
android:title="@string/menu_settings"
android:orderInCategory="100" />
<item android:id="@+id/menu_exit"
android:title="@string/str_exit"
android:orderInCategory="101" />
</menu>
+27 -1
Ver Arquivo
@@ -3,6 +3,32 @@
<string name="app_name">ControlTower</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">ControlTower</string>
<string name="title_activity_settings">Settings</string>
<string name="str_exit">Exit</string>
<string name="drone_state">AR.Drone State:</string>
<string name="default_state">DISCONNECTED</string>
<string name="display_desc">AR.Drone Camera signal</string>
<string name="btn_land">Land</string>
<string name="btn_take_off">TakeOff</string>
<string name="btn_connect">Connect</string>
<string name="btn_connect_ps3">Connect PS3</string>
<string name="usb_joystick_state">USB PS3 controller State:</string>
<string name="max_altitude">Altitude</string>
<string name="max_angle">Angle</string>
<string name="vertical_speed">Vertical Speed</string>
<string name="rotation_speed">Rotation Speed</string>
<string name="controller_deadzone">Controller Deadzone</string>
<string name="max_altitude_desc">Maximum drone altitude in meters</string>
<string name="max_angle_desc">Maximum bending angle for the drone in degrees</string>
<string name="vertical_speed_desc">Maximum vertical speed, in milimeters per second</string>
<string name="rotation_speed_desc">Maximum yaw speed, in degrees per second.</string>
<string name="controller_deadzone_desc">Minimum controller axis position change that will impact on drone, in percents</string>
<string name="btn_cancel">Cancel</string>
<string name="btn_save">Save</string>
<string name="configuration">Configuration</string>
<string name="title_settings">Settings</string>
<string name="controller_configuration">USB Controller</string>
<string name="ardrone_configuration">AR.Drone</string>
</resources>
+71
Ver Arquivo
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:javadron="http://code.google.com/p/javadrone">
<PreferenceCategory android:title="@string/ardrone_configuration">
<com.codeminders.ardrone.preferences.SeekBarPreference
android:key="pref_altitude_max"
android:title="@string/max_altitude"
android:summary="@string/max_altitude_desc"
android:defaultValue="1.5"
android:max="1"
android:persistent="true"
javadron:max="10.0"
javadron:min="0.0"
javadron:interval="0.05"
javadron:unitsLeft=""
javadron:unitsRight="m"/>
<com.codeminders.ardrone.preferences.SeekBarPreference
android:key="pref_angle_max"
android:title="@string/max_angle"
android:summary="@string/max_angle_desc"
android:defaultValue="6"
android:max="1"
android:persistent="true"
javadron:max="57.0"
javadron:min="0.0"
javadron:interval="0.06"
javadron:unitsLeft=""
javadron:unitsRight="°"/>
<com.codeminders.ardrone.preferences.SeekBarPreference
android:key="pref_vertical_speed_max"
android:title="@string/vertical_speed"
android:summary="@string/vertical_speed_desc"
android:defaultValue="1"
android:max="1"
android:persistent="true"
javadron:max="3.0"
javadron:min="0.0"
javadron:interval="0.03"
javadron:unitsLeft=""
javadron:unitsRight="m/s"/>
<com.codeminders.ardrone.preferences.SeekBarPreference
android:key="pref_rotation_speed_max"
android:title="@string/rotation_speed"
android:summary="@string/rotation_speed_desc"
android:defaultValue="50"
android:max="1"
android:persistent="true"
javadron:max="350.0"
javadron:min="40.0"
javadron:interval="1"
javadron:unitsLeft=""
javadron:unitsRight="°/s"
javadron:roundValue="true"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/controller_configuration">
<com.codeminders.ardrone.preferences.SeekBarPreference
android:key="pref_controller_deadzone"
android:title="@string/controller_deadzone"
android:summary="@string/controller_deadzone_desc"
android:defaultValue="30"
android:max="1"
android:persistent="true"
javadron:max="100.0"
javadron:min="0.0"
javadron:interval="5"
javadron:unitsLeft=""
javadron:unitsRight="%"
javadron:roundValue="true"/>
</PreferenceCategory>
</PreferenceScreen>
@@ -12,7 +12,8 @@ public class ControllerThread extends Thread{
ARDrone drone;
Controller controller;
private final ControlMap controlMap = new ControlMap();
private static float CONTROL_THRESHOLD = 0.5f;
private float controlThreshhold = 0.5f;
private static final long READ_UPDATE_DELAY_MS = 5L;
private final AtomicBoolean flipSticks = new AtomicBoolean(false);
@@ -91,22 +92,22 @@ public class ControllerThread extends Thread{
float vertical_speed = 0f;
float angular_speed = 0f;
if(Math.abs(((float) leftX) / 128f) > CONTROL_THRESHOLD)
if(Math.abs(((float) leftX) / 128f) > controlThreshhold)
{
left_right_tilt = ((float) leftX) / 128f;
}
if(Math.abs(((float) leftY) / 128f) > CONTROL_THRESHOLD)
if(Math.abs(((float) leftY) / 128f) > controlThreshhold)
{
front_back_tilt = ((float) leftY) / 128f;
}
if(Math.abs(((float) rightX) / 128f) > CONTROL_THRESHOLD)
if(Math.abs(((float) rightX) / 128f) > controlThreshhold)
{
angular_speed = ((float) rightX) / 128f;
}
if(Math.abs(-1 * ((float) rightY) / 128f) > CONTROL_THRESHOLD)
if(Math.abs(-1 * ((float) rightY) / 128f) > controlThreshhold)
{
vertical_speed = -1 * ((float) rightY) / 128f;
}
@@ -149,6 +150,12 @@ public class ControllerThread extends Thread{
}
}
}
public void setControlThreshhold(float controlThreshhold) {
this.controlThreshhold = controlThreshhold;
}
}
@@ -2,6 +2,7 @@ package com.codeminders.ardrone;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Iterator;
@@ -10,19 +11,28 @@ import com.codeminders.ardrone.controller.usbhost.AfterGlowUsbHostController;
import com.codeminders.ardrone.controller.usbhost.SonyPS3UsbHostController;
import com.codeminders.ardrone.controller.usbhost.UsbHostController;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -30,24 +40,31 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity implements DroneVideoListener {
@SuppressLint({ "NewApi", "NewApi", "NewApi", "NewApi" })
public class MainActivity extends Activity implements DroneVideoListener, OnSharedPreferenceChangeListener {
private static final long CONNECTION_TIMEOUT = 10000;
static ARDrone drone;
ImageView display;
TextView state;
TextView joystick_state;
Button connectButton;
UsbHostController controller;
Button connectUsbControllerButton;
Button btnConnectUsbControllerButton;
Button btnTakeOffOrLand;
private Builder usbNotSupportedDialog;
UsbManager manager;
ControllerThread ctrThread;
private static final String ACTION_USB_PERMISSION = "com.access.device.USB_PERMISSION";
private static final String TAG = "AR.Drone";
static MainActivity mainActivity;
SharedPreferences prefs;
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
@@ -67,148 +84,186 @@ public class MainActivity extends Activity implements DroneVideoListener {
controller = new SonyPS3UsbHostController(deviceConnected, manager);
joystickFound = true;
} catch (Throwable e) {
connectUsbControllerButton.setText("Error");
joystick_state.setText("Error");
}
} else if (AfterGlowUsbHostController.isA(deviceConnected)) {
try {
controller = new AfterGlowUsbHostController(deviceConnected, manager);
joystickFound = true;
} catch (Throwable e) {
connectUsbControllerButton.setText("Error");
joystick_state.setText("Error");
}
}
if (joystickFound) {
connectUsbControllerButton.setEnabled(false);
connectUsbControllerButton.setText("Connected");
btnConnectUsbControllerButton.setEnabled(false);
joystick_state.setText("Connected");
joystick_state.setTextColor(Color.GREEN);
// Start joystick reading thread
ctrThread = new ControllerThread(drone, controller);
ctrThread.setName("Controll Thread");
loadControllerDeadZone();
ctrThread.start();
}
}
} else {
connectUsbControllerButton.setText("Denied");
connectUsbControllerButton.setEnabled(false);
joystick_state.setText("Denied");
}
}
}
}
};
private Builder turnOnWiFiDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActivity = this;
setContentView(R.layout.activity_main);
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
state = (TextView) findViewById(R.id.state);
joystick_state = (TextView) findViewById(R.id.joystick_state);
display = (ImageView) findViewById(R.id.display);
connectButton = (Button) findViewById(R.id.connect);
Button btnLand = (Button) findViewById(R.id.land);
btnLand.setEnabled(false);
Button btnTakeOff = (Button) findViewById(R.id.takeOff);
btnTakeOff.setEnabled(false);
btnTakeOffOrLand = (Button) findViewById(R.id.takeOffOrland);
btnTakeOffOrLand.setEnabled(false);
turnOnWiFiDialog = new AlertDialog.Builder(this);
turnOnWiFiDialog.setMessage("Please turn on WiFi and connect to AR.Drone wireless accsess point");
turnOnWiFiDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}});
final Button btnConnect = (Button) findViewById(R.id.connect);
btnConnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
state.setTextColor(Color.RED);
state.setText("Connecting...");
(new DroneStarter()).execute(MainActivity.drone);
WifiManager connManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (connManager.isWifiEnabled()) {
state.setTextColor(Color.RED);
state.setText("Connecting..." + connManager.getConnectionInfo().getSSID());
btnConnect.setEnabled(false);
(new DroneStarter()).execute(MainActivity.drone);
} else {
turnOnWiFiDialog.show();
}
}
});
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
connectUsbControllerButton = (Button) findViewById(R.id.ps3Button);
connectUsbControllerButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
UsbDevice device = null;
while (deviceIterator.hasNext()) {
device = deviceIterator.next();
break;
}
if (null != device) {
PendingIntent permissionIntent = PendingIntent.getBroadcast(mainActivity, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter permissionFilter = new IntentFilter(ACTION_USB_PERMISSION);
mainActivity.registerReceiver(usbReceiver, permissionFilter);
manager.requestPermission(device, permissionIntent);
}
}
});
}
public void showButtons() {
final Button takeOff = (Button) findViewById(R.id.takeOff);
if (takeOff != null) {
takeOff.setVisibility(View.VISIBLE);
takeOff.setClickable(true);
takeOff.setEnabled(true);
takeOff.setOnClickListener(new View.OnClickListener() {
btnConnectUsbControllerButton = (Button) findViewById(R.id.ps3Button);
if (android.os.Build.VERSION.SDK_INT >= 12) {
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
final PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
btnConnectUsbControllerButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
takeOff();
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
UsbDevice device = null;
while (deviceIterator.hasNext()) {
device = deviceIterator.next();
break;
}
if (null != device) {
IntentFilter permissionFilter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver, permissionFilter);
manager.requestPermission(device, permissionIntent);
}
}
});
} else {
usbNotSupportedDialog = new AlertDialog.Builder(this);
usbNotSupportedDialog.setMessage("Your phone does not support USB connections");
usbNotSupportedDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}});
btnConnectUsbControllerButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
usbNotSupportedDialog.show();
}
});
}
final Button land = (Button) findViewById(R.id.land);
if (land != null) {
land.setVisibility(View.VISIBLE);
land.setClickable(true);
land.setEnabled(true);
land.setOnClickListener(new View.OnClickListener() {
prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);
}
private void droneOnConnected() {
state.setTextColor(Color.GREEN);
state.setText("Connected");
loadDroneSettingsFromPref();
connectButton.setEnabled(false);
drone.addImageListener(this);
if (btnTakeOffOrLand != null) {
btnTakeOffOrLand.setVisibility(View.VISIBLE);
btnTakeOffOrLand.setClickable(true);
btnTakeOffOrLand.setEnabled(true);
btnTakeOffOrLand.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
land();
try
{
drone.clearEmergencySignal();
drone.trim();
} catch(Throwable e)
{
Log.e(TAG, "Faliled init drone" , e);
}
if (btnTakeOffOrLand.getText().equals(getString(R.string.btn_land))) {
try
{
drone.land();
} catch(Throwable e)
{
Log.e(TAG, "Faliled to execute take off command" , e);
}
btnTakeOffOrLand.setText(R.string.btn_take_off);
} else {
try
{
drone.takeOff();
} catch(Throwable e)
{
Log.e(TAG, "Faliled to execute take off command" , e);
}
btnTakeOffOrLand.setText(R.string.btn_land);
}
}
});
}
}
private void takeOff() {
try
{
drone.clearEmergencySignal();
drone.trim();
drone.takeOff();
} catch(Throwable e)
{
e.printStackTrace();
}
}
private void land() {
try
{
drone.land();
} catch(Throwable e)
{
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
menu.add(0, 1, 1, R.string.str_exit);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
case R.id.menu_settings:
startActivity(new Intent(this, SettingsPrefs.class));
break;
case 1:
case R.id.menu_exit:
exitOptionsDialog();
break;
}
@@ -218,12 +273,10 @@ public class MainActivity extends Activity implements DroneVideoListener {
private void exitOptionsDialog()
{
// Disconnect from the done
try {
drone.disconnect();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "failed to stop ar. drone", e);
}
finish();
}
@@ -246,7 +299,6 @@ private class VideoDisplayer extends AsyncTask<Void, Integer, Void> {
public int h;
public VideoDisplayer(int x, int y, int width, int height, int[] arr, int off, int scan) {
super();
// do stuff
rgbArray = arr;
offset = off;
scansize = scan;
@@ -257,7 +309,6 @@ private class VideoDisplayer extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... params) {
b = Bitmap.createBitmap(rgbArray, offset, scansize, w, h, Bitmap.Config.RGB_565);
b.setDensity(100);
return null;
@@ -276,23 +327,24 @@ private class DroneStarter extends AsyncTask<ARDrone, Integer, Boolean> {
ARDrone drone = drones[0];
try {
drone = new ARDrone(InetAddress.getByAddress(ARDrone.DEFAULT_DRONE_IP), 10000, 60000);
MainActivity.drone = drone; // passing in null objects will not pass object refs
MainActivity.drone = drone;
drone.connect();
drone.clearEmergencySignal();
drone.waitForReady(CONNECTION_TIMEOUT);
drone.playLED(1, 10, 4);
drone.addImageListener(MainActivity.mainActivity);
drone.selectVideoChannel(ARDrone.VideoChannel.HORIZONTAL_ONLY);
drone.setCombinedYawMode(true);
return true;
} catch (Exception e) {
Log.e(TAG, "Failed to connect to drone", e);
try {
drone.clearEmergencySignal();
drone.clearImageListeners();
drone.clearNavDataListeners();
drone.clearStatusChangeListeners();
drone.disconnect();
} catch (Exception e1) {
} catch (Exception ex) {
Log.e(TAG, "Failed to clear drone state", ex);
}
}
@@ -301,15 +353,92 @@ private class DroneStarter extends AsyncTask<ARDrone, Integer, Boolean> {
protected void onPostExecute(Boolean success) {
if (success.booleanValue()) {
state.setTextColor(Color.GREEN);
state.setText("Connected");
connectButton.setEnabled(false);
mainActivity.showButtons();
droneOnConnected();
} else {
state.setTextColor(Color.RED);
state.setText("Error");
connectButton.setEnabled(true);
}
}
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(PREF_MAX_ALTITUDE)) {
droneLoadMaxAltitude();
} else if (key.equals(PREF_MAX_ANGLE)) {
droneLoadMaxAngle();
} else if (key.equals(PREF_MAX_VERICAL_SPEED)) {
droneLoadMaxVerticalSpeed();
} else if (key.equals(PREF_MAX_ROTATION_SPEED)) {
drobeLoadMaxRotationSpeed();
} else if (key.equals(PREF_MAX_CONTROLLER_DEDZONE)) {
loadControllerDeadZone();
}
}
public static String PREF_MAX_ALTITUDE = "pref_altitude_max";
public static String PREF_MAX_ANGLE = "pref_angle_max";
public static String PREF_MAX_VERICAL_SPEED = "pref_vertical_speed_max";
public static String PREF_MAX_ROTATION_SPEED = "pref_rotation_speed_max";
public static String PREF_MAX_CONTROLLER_DEDZONE = "pref_controller_deadzone";
public static String DRONE_MAX_YAW_PARAM_NAME = "control:control_yaw";
public static String DRONE_MAX_VERT_SPEED_PARAM_NAME = "control:control_vz_max";
public static String DRONE_MAX_EULA_ANGLE = "control:euler_angle_max";
public static String DRONE_MAX_ALTITUDE = "control:altitude_max";
private void loadDroneSettingsFromPref() {
droneLoadMaxAltitude();
droneLoadMaxAngle();
droneLoadMaxVerticalSpeed();
drobeLoadMaxRotationSpeed();
loadControllerDeadZone();
}
private void drobeLoadMaxRotationSpeed() {
if (null != drone && prefs.contains(PREF_MAX_ROTATION_SPEED)) {
setDroneParam(DRONE_MAX_YAW_PARAM_NAME, String.valueOf(prefs.getFloat(PREF_MAX_ROTATION_SPEED, 50f) * Math.PI / 180f));
}
}
private void loadControllerDeadZone() {
if (null != ctrThread && prefs.contains(PREF_MAX_CONTROLLER_DEDZONE)) {
ctrThread.setControlThreshhold(prefs.getFloat(PREF_MAX_ROTATION_SPEED, 30f) / 100f);
}
}
private void droneLoadMaxVerticalSpeed() {
if (null != drone && prefs.contains(PREF_MAX_VERICAL_SPEED)) {
setDroneParam(DRONE_MAX_YAW_PARAM_NAME, String.valueOf(Math.round(prefs.getFloat(PREF_MAX_VERICAL_SPEED, 1f) * 1000)));
}
}
private void droneLoadMaxAngle() {
if (null != drone && prefs.contains(PREF_MAX_ANGLE)) {
setDroneParam(DRONE_MAX_EULA_ANGLE, String.valueOf(prefs.getFloat(PREF_MAX_ANGLE, 6f) * Math.PI / 180f));
}
}
private void droneLoadMaxAltitude() {
if (null != drone && prefs.contains(PREF_MAX_ALTITUDE)) {
setDroneParam(DRONE_MAX_ALTITUDE, String.valueOf(Math.round(prefs.getFloat(PREF_MAX_ALTITUDE, 1.5f) * 1000)));
}
}
private void setDroneParam(final String name, final String value) {
new Thread(new Runnable() {
@Override
public void run() {
try {
drone.setConfigOption(name, value);
} catch (IOException ex) {
Log.e(TAG, "Failed to set drone parameter (" + name + ") to value: " + value , ex);
}
}
}).start();
}
}
@@ -0,0 +1,15 @@
package com.codeminders.ardrone;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsPrefs extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
@@ -0,0 +1,213 @@
package com.codeminders.ardrone.preferences;
import com.codeminders.ardrone.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {
private static final String TAG = SeekBarPreference.class.getSimpleName();
private static final float DEFAULT_VALUE = 50;
private static final String APP_NS = "http://code.google.com/p/javadrone";
private float maxValue = 100;
private float minValue = 0;
private float interval = 1;
private float currentValue;
private boolean roundValue = false;
private String unitsLeft = "";
private String unitsRight = "";
private SeekBar seekBar;
private TextView statusText;
public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initPreference(context, attrs);
}
public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPreference(context, attrs);
Log.d(TAG, "Preferences are installed");
}
private void initPreference(Context context, AttributeSet attrs) {
Log.d(TAG, "Set values from xml");
setValuesFromXml(attrs);
this.seekBar = new SeekBar(context, attrs);
this.seekBar.setMax(Math.round((this.maxValue - this.minValue)/this.interval));
this.seekBar.setOnSeekBarChangeListener(this);
}
private void setValuesFromXml(AttributeSet attrs) {
this.maxValue = attrs.getAttributeFloatValue(APP_NS, "max", 100);
this.minValue = attrs.getAttributeFloatValue(APP_NS, "min", 0);
this.unitsLeft = getAttributeStringValue(attrs, APP_NS, "unitsLeft", "");
this.unitsRight = getAttributeStringValue(attrs, APP_NS, "unitsRight", "");
this.roundValue = attrs.getAttributeBooleanValue(APP_NS, "roundValue", false);
try {
String newInterval = attrs.getAttributeValue(APP_NS, "interval");
if(newInterval != null)
this.interval = Float.parseFloat(newInterval);
}
catch(Exception e) {
Log.e(TAG, "Invalid interval value", e);
}
}
private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
String value = attrs.getAttributeValue(namespace, name);
if(value == null)
value = defaultValue;
return value;
}
@Override
protected View onCreateView(ViewGroup parent){
Log.d(TAG, "Start creating view");
RelativeLayout layout = null;
try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
}
catch(Exception e) {
Log.e(TAG, "Error creating seek bar preference", e);
}
return layout;
}
@Override
public void onBindView(View view) {
super.onBindView(view);
Log.d(TAG, "Start binding view");
try
{
// move our seekbar to the new view we've been given
ViewParent oldContainer = this.seekBar.getParent();
ViewGroup newContainer = (ViewGroup) view.findViewById(R.id.seekBarPrefBarContainer);
if (oldContainer != newContainer) {
// remove the seekbar from the old view
if (oldContainer != null) {
((ViewGroup) oldContainer).removeView(this.seekBar);
}
// remove the existing seekbar (there may not be one) and add ours
newContainer.removeAllViews();
newContainer.addView(this.seekBar, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
catch(Exception e) {
Log.e(TAG, "Error binding view: ", e);
}
updateView(view);
}
/**
* Update a SeekBarPreference view with our current state
* @param view
*/
protected void updateView(View view) {
Log.d(TAG, "updateView");
try {
RelativeLayout layout = (RelativeLayout)view;
this.statusText = (TextView)layout.findViewById(R.id.seekBarPrefValue);
this.statusText.setText( roundValue ? String.valueOf((int) this.currentValue) : String.valueOf(this.currentValue));
this.statusText.setMinimumWidth(30);
this.seekBar.setProgress((int)Math.round((this.currentValue - this.minValue)/this.interval));
TextView unitsRight = (TextView)layout.findViewById(R.id.seekBarPrefUnitsRight);
unitsRight.setText(this.unitsRight);
TextView unitsLeft = (TextView)layout.findViewById(R.id.seekBarPrefUnitsLeft);
unitsLeft.setText(this.unitsLeft);
}
catch(Exception e) {
Log.e(TAG, "Error updating seek bar preference", e);
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Log.d(TAG, "onProgressChanged");
float newValue = ((float)Math.round((progress*this.interval+ this.minValue)*100))/100 ;
if(newValue > this.maxValue)
newValue = this.maxValue;
else if(newValue < this.minValue)
newValue = this.minValue;
if(!callChangeListener(Math.round(newValue))){
seekBar.setProgress(Math.round((this.currentValue - this.minValue)/this.interval));
return;
}
this.currentValue = newValue;
this.statusText.setText(roundValue ? String.valueOf((int)newValue) : String.valueOf(newValue));
persistFloat(newValue);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
protected Object onGetDefaultValue(TypedArray ta, int index){
Log.d(TAG,"onGetDefaultValue");
float defaultValue = ta.getFloat(index, DEFAULT_VALUE);
return defaultValue;
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
Log.d(TAG,"onSetInitialValue");
if(restoreValue) {
Log.d(TAG,"restoreValue");
this.currentValue = getPersistedFloat(this.currentValue);
}
else {
float temp = (float)this.minValue;
try {
temp = (Float)defaultValue;
}
catch(Exception e) {
Log.e(TAG, "Invalid default value: " + defaultValue.toString(), e);
}
persistFloat(temp);
this.currentValue = temp;
}
}
}