Part 1: Basic Bluetooth communications using App Inventor

(Some very minor updates were made to this in November 2019).

This tutorial covers basic App Inventor Bluetooth communications  code.   Subsequent tutorials will add additional features. To implement and test this sample code, you need access to two Android devices – one to act as a Bluetooth “server” and the other to act as a “Bluetooth” client.

I tested this code using an old LG smart phone running Android 2.2 and a new Nexus 5 running Android 5.0.1.  I also tested this code using the Nexus 5 paired with a Nexus 7 tablet. (Update I have since also run this on an Honor 8 phone and a Pixel 2, with much newer versions of Android.)

This tutorial is lengthy – it introduces Bluetooth communications, then presents the user interface and blocks code for both the server and client programs, and then discusses how to set up the Bluetooth Communications link using “pairing”.

Downloadable App Inventor source code for the client and server is at the end of this post.

This is the first of several  posts on Bluetooth. This first post covers basic connections and the sending and receiving of text between two Bluetooth devices. The two halves of the link – client and server – are kept in separate apps to keep this simple,  however, it is possible for a single app to act as both a client and a server. A subsequent post will show how to send other types of data, such as numbers, and introduce additional features for using Bluetooth communications.

Related:

Introduction to Bluetooth

Bluetooth is the communications technology with a funny name.[1] Bluetooth is actually named for a long ago Danish king who worked to unite groups of people, which is similar to Bluetooth’s goal of interconnecting different devices.  The King’s real name was “Harald” but he had a nickname that translates as “Bluetooth” – no one knows for sure why he had this nickname but one thought is he had one dark tooth that may have appeared black or blue. And that is certainly an obscure way to choose a name for new technologies!

Bluetooth establishes a very low power, short range (up to 10 meters) communications link between two devices. Bluetooth uses the same frequency band (2.4 Ghz) as Wi-Fi, but uses different technology. Both Bluetooth and Wi-Fi use forms of spread spectrum radio links that result in signals moving around within a wide band in ways that enable sharing of the spectrum by multiple devices. But the two technologies serve different purposes, are  not identical, and cannot communicate with one another.

Bluetooth applications include common wireless headsets for wired and cellular phones, and in-ear cordless adapters for phones. Bluetooth is also used by cordless headphones and to exchange address cards between devices, and for industrial applications where sensors collect and send data into a network.

There are two forms of Bluetooth – classic Bluetooth, which  we use in the sample applications, and a newer version known as Bluetooth low energy, Bluetooth BLE, Bluetooth LE or Bluetooth Smart – all referring to the same new technology.  The newest Android devices running Android 4.3 or newer, usually support the newest Bluetooth Smart technology. Regardless, we use classic Bluetooth which is backwards compatible to older phones, and is the technology supported by App Inventor.

Setting up a Bluetooth devices involves “pairing” the two devices and establishing a connection. This will be covered later in this tutorial.

Footnote:

[1] Actually there is another communications technology with a funny name called TWAIN, which is an acronym for “Technology without and interesting name” (really!)

The Designer View

There are two separate apps for Bluetooth communications – one is a “server” app that runs on one device, and the other is a “client” app that runs on a second device.

Bluetooth must be enabled on both devices, and the devices need to be paired before running these apps. (How to do this is explained near the end of this tutorial.)

The server must be run first on one device and then the client app on the 2nd device connects to the server before data can be sent between the two devices. More on this later in this tutorial.

The server user interface is shown here:

BTServerDesigner

The main components of the server interface design are:

  • Accept Connection Button – press this to set the server to accept a connection from another device. Connections are not possible until the AcceptConnection service is started.
  • Send the following text Button – the text is the following text box is sent to the other Bluetooth device.
  • Disconnect Button
  • Status messages – Status about the communications link, and any messages received from the other device are shown on the display
  • Non-visible components – The apps use a clock to cause activities to occur at a preset interval. The Notifier1 component is used to display error messages (see tutorial on the use of Notifier), and BluetoothServer1 provides the Bluetooth support. The BluetoothClient1 and BluetoothServer1 components are located in the Connectivity section of the Designer palette.

How each of the buttons and components are used to run the program are explained later, in a section on setting up Bluetooth on your devices and running the apps.

The client user interface is shown here:

BTClientDesignerThe user interface is similar to the server except instead of  AcceptConnection there is a Connect to device button, and instead of a BluetoothServer1 component, the BluetoothClient1 components is used.

The Connect to device button is actually a ListPicker component and not a standard button.

For both the client and server apps, the TimerInterval of the Clock properties is set to 1000 milliseconds or 1 second. Other small values may be used. This value determines how frequently to check the Bluetooth link for incoming data from the other device. As shown, each app will check the link once per second.

BTClockProperties

Blocks Code

Bluetooth Server app

We start with the server app implementation.  The client app is presented after the server app.

The first step is to check that Bluetooth is activated or switched on.  If not, an error message is displayed reminding the user to open Android’s Settings and then switch Bluetooth to on.

The Initialize event occurs  when the app is launched – and this is a good place to check whether or not Bluetooth is enabled on the device.

BTServerInit

Assuming that Bluetooth on the device is currently “on”,    the next step is to accept a connection from another device when the btnAcceptConnection button has been pressed. This causes Bluetooth to begin listening for an incoming connection.

Once a connection request has been received and processed, a ConnectionAccepted event occurs. In our basic app, we update the status message on the app screen.

BTServerAcceptConnect

The Timer Event Handles Receiving of Data

Receiving data sent over Bluetooth takes  place in the Clock1.Timer event handler. Remember, the clock is  set so that the Timer event happens once per second. Every  second, the app will check if any data has been received.

To prevent reading data  when Bluetooth is not connected (this would cause an error), an if-then statement checks the IsConnected property of BluetoothServer1. This value is set to true when the devices are connected  and false if the connection is not currently available.

IsConnected should be  true if a connection has been accepted. But because this is a wireless connection, a device might go out of range or be turned off,  breaking the connection. It is good programming practice to check that the connection is working before trying to send or receive data.

The property BytesAvailableToReceive tells us how much data is available (one text character is equal to one “byte” of data). If this value is zero, then no data is available. But if the value is greater than zero, then our app may read the incoming data and update the status and messages to the app display.

BTServerTimer

The Send Text button event handler is similar to the receive code located inside the Timer event except that data is sent  using the SendText method to transmit the data to the other device.

The Disconnect button handler is self explanatory!

BTServerSendDisc

Error  Handling

One thing to know about wireless communications is that errors happen. For most of our App Inventor apps, we ignore potential errors – if errors occur, the app stops running and Android displays an  error message.

Rather than letting that occur, our app can intercept the error condition by adding an error event handler to the main screen, Screen1. The ErrorOccurred event has four parameter values (local variables) that contain information about the error. The error handler displays the  error values on the screen, rather than shutting down the app.

BTServerErrorHandler

Bluetooth Client App

Now that the server app is complete, we present the client app that runs on the other device. In many ways, the client app is a mirror image of the server, but refers to the BlutoothClient1 component instead of the BluetoothServer1 component.

App Initialization

Same as the server, except it  uses  BluetoothClient1.

BTClientInit

Connecting

When the two devices are running, the server app is set up first to accept connections. Then, on the client side, the user selects the Connect ListPicker button and selects the device name from a list of available Bluetooth devices.  Because the list of devices is in the form of a list, the ListPicker is a great interface component to display the device list and handle the selection. (See my earlier tutorial on ListPicker.)

Before the list is displayed, the list is filled with the list of Bluetooth devices (AddressesAndNames). The set lblStatus.Text block may be deleted as it was used during my testing and is not needed in the final version of the client.

BTClientSend

After the device has been selected with the ListPicker user interface, the Connect method of BluetoothClient1 establishes the connection. The method returns a value of true if the connection was successful; in which case a message is sent to the server app.

Disconnect is self explanatory.

BTClientDisconnect

Receiving Data

Like with the server, the reception of data is implemented using a timer. Once per second, the client checks to see if data is available, and if it is, reads and displays the data on the app display.

BTClientTimer

While the server must be running prior to the client making a connection, once the two devices are connected, either app can send data to the other app, at any time.

Error Handling

The client’s error handling is identical to the server’s error handling.

BTClientErrorHandler

Setting Up A Bluetooth Connection

Before you use the Bluetooth communications apps, do the following:

  1. Use Build .apk or other method to obtain the server app, download and install on your first Android device.
  2. Use Build .apk or other method to obtain the client app, download and install on your second Android device.
  3. Go in to the Android Settings and turn on the Bluetooth feature.   The user interface for the Bluetooth configuration varies slightly depending on which version of Android you have.  On 2.2, for example, you need to select Wireless & Networks, and then choose Bluetooth, while on Android 5.0, Bluetooth appears in the topmost Settings menu.
  4. In newer versions of Android, when the Bluetooth Settings menu is active, your device is broadcasting its availability to other nearby devices. On older versions, you may need to click an option to make your device “discoverable”. (Note – my Nexus 5 is not visible on my very old LG 2.2 device – however, the Nexus 5 sees the LG and the two can be connected from the Nexus 5 side).
  5. Once your two devices see each other over Bluetooth, you may be prompted to “pair” the devices, or (depending on Android version), you may have to manually choose the device and then choose pairing. Follow the on screen instructions.
  6. Once the two devices are “paired”, launch the Server app and select Accept Connection.
  7. On the other device, launch the Client app and select Connect. If all goes well, you should see a “client connected” message on the Server app.

Key Features Shown

  • Introduction to Bluetooth wireless
  • User interface for a Bluetooth server and client app
  • Use of the Bluetooth Server and Client components to set up a link
  • Use of error handling
  • Setting up devices for Bluetooth communications
  • More features in future tutorials!

Downloads

  • BTClient1.aia App Inventor  source file  (App Inventor source code files have the filename extension .aia)
  • BTServer1.aia App Inventor source file
  • Download the source code to your computer. Then, in App Inventor, go to the Projects menu and select “Import project (.aia) from my computer…”

E-Books and Printed Books

If you find these tutorials helpful (I hope you do!) please take a look at my books on App Inventor. To learn more about the books and where to get them (they are inexpensive) please see my App Inventor Books page.

  • App Inventor 2 Introduction (Volume 1 e-book)
    Step-by-step guide to easy Android programming
  • App Inventor 2 Advanced Concepts (Volume 2 e-book)
    Step-by-step guide to Advanced features including TinyDB
  • App Inventor 2 Databases and Files (Volume 3 e-book)
    Step-by-step TinyDB, TinyWebDB, Fusion Tables and Files
  • App Inventor 2 Graphics, Animation and Charts (Volume 4 e-book and printed book)
    Step-by-step guide to graphics, animation and charts

Thank you for visiting! — Ed

Please Share on Social Media

Please click on the buttons below this post to share with your friends on Facebook or other social media.

If you are not already following this blog, click on the following links to like on Facebook, add to your Google+ circles or follow on Twitter or in your RSS news reader. Thank you for visiting!

 

89 thoughts on “Part 1: Basic Bluetooth communications using App Inventor”

  1. Hey! Really helpful tutorial… I’m creating this new app that requires PvP feature.. I hope that I can use this as reference for my app ! Your contributions will be very much acknowledged!

    1. Your are most welcome – I appreciate hearing that these tutorials are helpful! Thanks for the feedback!

      Ed

      1. I am getting an error anytime I try to send data as a list “could not decode element 1 as integer” I try to send bytes as list text and number from database what am I doing wrong.

        1. We’d need to see the blocks code – sounds like a programming error that is fixable.

          Am guessing that the item you are trying to convert to an integer is an actual list element. There are several ways to force the conversion. You might try a define global or local variable that is first assigned an integer value like 0. Then let that variable get the value of the list element. It should convert it to an integer there.

          Ed

    1. I realize this question is old – but YES! The source code here is intended to illustrate how to do things – no guarantees as it is not done as rigorously as done for a commercial product! But I post the code here for anyone to use in their projects!

      Ed

  2. One thing! I get this error
    “Error:com.google.appinventor.components.runtime.BluetoothClient@21b34368,507,Connect,Unable to connect . Is the device turned on”

    obviously turned it on.. no luck on it yet 🙂
    thanks

    1. Sure. That’s why they are available! But no guarantees, make sure you test in you own app!

    2. This error happened to me when I was trying to connect while being connected. Try to avoid the user opening the list picker again while being connected

  3. Hi,

    I would like to know how to receive and compare numbers using app inventor 2 programing. I am using an arduino with a bluetooth shield.
    Can you help me?

    Thank you

    1. It is possible – but I have not yet implemented Arduino–>Bluetooth–>Android App Inventor – so I cannot help you right now but perhaps someone else can.

      It may also depend on which Bluetooth shield you have for the Arduino. I know that this one
      http://hobbycomponents.com/wireless/64-jy-mcu-bluetooth-wireless-serial-port-module-slave
      will work to talk to an Android App Inventor app.

      However, some of the Bluetooth shields are Bluetooth LE (low energy) which is a newer standard that is part of Bluetooth. It provides for low power/long battery life for applications in health care, sensor networks (like security or environmental sensing). Bluetooth LE also requires support in your device (my Nexus 5 has both traditional Bluetooth and Bluetooth LE). But App Inventor does not support the Bluetooth LE mode so we cannot yet write apps directly in App Inventor that communicate with a Bluetooth LE device.

      (I could be wrong here – I looked into this a while ago. I have the parts sitting on my desk and just need to get to work on getting Arduino–BT–App Inventor working!)

      Ed

    1. Hi Thierry,

      I have a different Bluetooth LE card – and I have it talking between the Arduino and an Android app supplied by the vendor, running on my Nexus 5 smart phone. But that is not an App Inventor app. My recollection from going through the App Inventor source code itself is that App Inventor does not work with the low energy version of Bluetooth. That said, many Bluetooth devices support both the newer LE standard and also the original Bluetooth standard (e.g. Bluetooth 2.1 and upwards). Without knowing the specifics of that board, you might give it a try and see first if your Android phone device can see the BLE card (probably can), and then write some App Inventor code to see if it can just make a connection.

      Ed

  4. Hi Edward,
    I need to create a Multiple bluetooth connections to multiple devices to implement a “chat room”. I don’t know what i do. I read and undestand your article about Bluetooth communications between 2 devices, but i don’t know how to make it between three or four or five, ect device. Could you help me?

    1. Bluetooth only pairs 2 devices.

      I’m waiting for an airplane flight and can’t lookup anymore right at the moment.

      Ed

  5. Hey there, im trying to build an attendance system using bluetooth, i would like to know, how to restrict the server to accept connections ,only from specified mac addresses and also how to link server to a database to store the attendance .

  6. Muchas gracias hermano, me fue de suma utilidad para una aplicación que estoy realizando, aun me faltan las pruebas finales claro.

  7. Hey i tried to access the bluetooth project and test on it but i have a problem everytime i hit accept connection or connect device it freezes. anyway i can select the bluetooth to pair with the bluetooth module from the program?

    1. A lot of people have this working okay. What type of phone(s) are you using?

      For example, I can get my Android 5 Nexus 5 to talk to an old LG Android 2.2 phone, but I have to jump through hurdles to make it work because of changes in Bluetooth support between those versions.

      Ed

  8. i made blutooth chat app. when i click listpicker it opens and always shows blank screen. it can’t display BT device name. please tell me what is the mistake is going on?

    1. It should show the list of known bluetooth devices. Have you “paired” the bluetooth device before running the program?

      For some unknown reason, it seems the App Inventor’s call to get the list of BT devices is returning no devices.

  9. OK Ed question 2?

    do you know if there is away to link to a bluetooth headset.
    I want to use the button on the headset to work as a click event in my program?

    also your site is good and helpful. I am tempted to make a site with some guides my self.

    1. Paul,
      This might be possible but would be very complex. App Inventor supports some Bluetooth communications (but not the newer “LE” low energy type) and can likely link to a BT headset. Once the link is established, compatible devices communicate with a “protocol” over the link. For those not familiar with protocols, think of this as defining who talks first on the link and what are appropriate replies and had the data back and forth is formulated. Is it possible for an App Inventor program to implement the protocol to a BT headset? Possibly.

      There are a lot of protocols, for different applications, defined for Bluetooth. You can see a nice summary at Wikipedia https://en.wikipedia.org/wiki/List_of_Bluetooth_protocols.

      I am guessing that the synchronous communications-oriented link is the one that headsets use. The next step would be to search online to see how that protocol is defined and to see if the BT headset and AI code can actually see bits going back and forth.

      Ed

    1. I think you are asking – could the server and client apps, which I created as 2 separate apps, be combined into one app? Yes, they could. They do not have to be in separate apps. I kept them separate so that the concept of the client and server could be explained in a simple example – combining them into a single app would make the example a little more complicated.

      Ed

  10. Is it possible to have the server accept connections from more than one device at a time? Trying to design an attendance app where a lecturer can send out a bluetooth signal and present students can connect and send back their student numbers to be marked as having attended.

    1. Originally, I thought multiple device support would not be possible. However, Bluetooth does support the concept of up to 7 devices connected to a “master” device (for example, on my Nexus 7, I can use a Bluetooth keyboard and a Bluetooth mouse, simultaneously). The question is, then, does App Inventor support this capability? I do not know the answer to that. But what I would perhaps first try to do is something like the following:

      1. Drag a Bluetooth component (such as the BTServer) into the Designer window.
      2. Drag a second Bluetooth Bluetooth component (another BTServer) into the Designer window.
      3. Implement the connection and receive code for both BTServer components – one will be named BluetoothServer1 and the other will be BluetoothServer2.
      4. Now, get two more Android phones and implement the Client code and see if you can set up two connections – one going to Server1 and the other going to Server2.

      For now, duplicating the code for each Bluetooth channel is going to be the simplest to explain. However, there is a way to write one set of code that can maybe handle both servers – but that would need a whole tutorial on another programming concept before we even get to the Bluetooth part.

      If you try this, let us know how this work? This could be a great tutorial opportunity for the blog!

      Ed

      1. Hi Ed.This really worked and done a trick..Awsome man!!! I have been working on it as a part of my project and done it..

        1. I am sorry to disturb..but I have a doubt..is it possible to have many bluetoothclient to be used in client application??I think it works but still i didnot try it out..

          1. You set up the multiple Bluetooth components? If that works, let us know! And if you wish to share sample code, I could post it here to help others – if this all works!

          2. Yeah sure Ed..but how to share and can I have multiple client??I tried it but didnot work..

          3. Ed..can you please help me to display the history of received tetxs in that app??I am using currently file component and im trying it..not sure if it will give me proper result..

    2. Also, another thought – it just so happens that I am a volunteer engineering mentor for a FIRST Robotics team (#4488). One of the students is implementing an attendance app in App Inventor.

      Each student has a Team #4488 ID card they are supposed to have with them during each robotics meeting and event. On the card we are printing a QR Code with the student’s ID#. The attendance app does a QR code scan of the student IDs. This does, of course, require the students to sequentially walk by the Nexus 7 tablet we have out at the beginning of meetings.

      I imagine we will be making this code public, once its ready, as our team tries to help out other robotics teams as much as possible. Even if you are not doing robots, you’d be welcome to the code!

      If you want to write your own, I have sample code to scan QR codes available in this tutorial
      http://appinventor.pevest.com/?p=1086

      Ed

      1. Perfect thanks for the info.
        Yes I’ll try adding the coding for QR Code scanning as another option. So my app will have both Bluetooth Option for recording attendance and a QR Code scanning option.
        Thanks for the help, looking forward to seeing the code for what ye finish with and seeing if I can return any help to ye.

      2. Hi Ed,
        Sorry to be bothering you again.
        Just a thought, do you think its possible to have the app export all the text received to the BluetoothServer as a list, and then using the share function, email it to a specified email address.
        Currently testing your idea of dragging in multiple bluetooth servers to allow multiple connections.
        Thanks for the idea.

        1. James,

          Yes, you can certainly save the output to a text file stored on the device, and then transfer that file to email or another device using various methods.

          You can find my tutorials on basic text files using this web site search
          http://appinventor.pevest.com/?s=text+files

          I used a free app from the Google Play store called File Manager. I navigated to the text file I created, selected the file (by placing a checkmark to the right of the file) and then sent via email.

          Thus, your ideas should work out fine.

          A more complex approach could even store values into a TinyDB database, or remotely into a cloud-based database using TinyWebDB or Google Fusion Tables. The advantage of the latter approach is that it moves the data into a cloud-based database accessible from a browser or (with Fusion) downloadable to a Google Docs spreadsheet or Microsoft Excel spreadsheet. I describe how to do that in Volume 3 of my e-book series, available from Amazon http://amzn.to/1UxQGSO

          Ed

      3. Yeah Ed.,I got it …and regarding multiple bluetooth connection you have to add to the accept connection method 7or less servers and that works…Thank you again man!!!!

  11. Why I sent it possible to have an app that allows me to connect my iPod too 6 Bluetooth speakers at the same time I am trying as we speak to creat this app. Connect 8 Bluetooth headsets to one cell phone to run the office would be nice also

    1. Lee,

      Classic Bluetooth can support one “master” device paired with up to 7 additional devices. Bluetooth LE (low energy) is a newer kind of Bluetooth (but not backwards compatible with older devices). Bluetooth LE does not have a specific limit on the # of devices that can be connected.

      Based on my past experiments and looking at the MIT App Inventor source code directly, App Inventor works with the “classic” form of Bluetooth and not LE.

      There may be additional useful information here – including in the comments there
      http://appinventor.pevest.com/?p=569

      I have some comments also on how you might connect multiple Bluetooth devices in App Inventor – I have not tried those ideas myself, yet – but worth a try – see here: http://appinventor.pevest.com/?p=520&cpage=1#comment-35746

      Ed

      1. Scenario is I have 6 Budweiser speakers and the iPod will only connect to one at a time also tried iphone 3 same thing

        1. That is probably a limitation of the iPod / iPhone / iOS software, or the app running on iOS. They may not have envisioned that someone would want to connect one device to multiple speakers – and chose not to implement that feature.

          From the comments on this page, it seems there would be a lot of interest in getting multiple bluetooth links working from one Android device.

          1. Hi Ed.I have published my bluetooth free chat app on app inventor gallery so you can find the codes there.Thank you Ed.,I think may be it helps you..

  12. Hey Guys,
    I tried putting in more servers and replicating the coding for up to 7 servers,unfortunately I only had 3 devices I could test on and was able to receive data to the server device from the 2 client devices at the same time, however I now have an error code appearing in the status area coming up as the following;
    ” Error:com.google.appinventor.components.runtime.BluetoothServer@43821af8,ReceiveText,515,Not connected to a Bluetooth device.”
    I was wondering if any of ye might be able to help me out. Seeing as I know when I replicated the code for just 2 client devices and there was no error that data transmission was possible and genereal bluetooth capabilities allow up to 7 clients, I was wondering could ye help me or give me an an opinion with the error. Is this coming up because not all 7 bluetooth servers have a client connected? I can still receive data as I have another label to show the text received via bluetooth but the error stays in the status label. So to say if I connected 7 clients to the 7 servers the error may go away? Or is there a different reason for this? Any help would be great.

  13. Hello, is there an app where two wireless ear pieces can talk together using Bluetooth and no cell service? Thanks

    1. Check the Google Play store. I suspect there are free apps that will do this where you can connect your bluetooth earpiece to your phone, and then use your phone to talk to another Android phone over Wi-Fi. There are plenty of Android to Android over WiFi apps in the Google Play store.

      Ed

  14. package com.raw.arview;

    import java.io.IOException;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    import java.lang.Integer;
    import java.lang.Float;
    import java.lang.Math;
    import java.util.UUID;

    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Path;
    import android.graphics.RectF;
    import android.hardware.Camera;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.os.Bundle;
    import android.os.PowerManager;
    import android.os.PowerManager.WakeLock;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.util.TypedValue;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Window;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    import com.raw.utils.Compatibility;
    import com.raw.utils.PaintUtils;
    import android.graphics.Paint;

    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothServerSocket;
    import android.bluetooth.BluetoothSocket;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.Gravity;
    import android.widget.EditText;
    import android.view.Gravity;

    public class ARView extends Activity implements SensorEventListener{

    private static Context _context;
    WakeLock mWakeLock;
    CameraView cameraView;
    RadarMarkerView radarMarkerView;
    public RelativeLayout upperLayerLayout;
    static PaintUtils paintScreen;
    static DataView dataView;
    boolean isInited = false;
    public static float azimuth;
    public static float pitch;
    public static float roll;
    public double latitudeprevious;
    public double longitude;
    String locationContext;
    String provider;
    DisplayMetrics displayMetrics;
    Camera camera;
    public int screenWidth;
    public int screenHeight;

    private float RTmp[] = new float[9];
    private float Rot[] = new float[9];
    private float I[] = new float[9];
    private float grav[] = new float[3];
    private float mag[] = new float[3];
    private float results[] = new float[3];
    private SensorManager sensorMgr;
    private List sensors;
    private Sensor sensorGrav, sensorMag;

    static final float ALPHA = 0.25f;
    protected float[] gravSensorVals;
    protected float[] magSensorVals;

    //……..bluetooth

    public static final int MESSAGE_READ = 1;

    private static final String TAG = “BluetoothServer”;
    private static final boolean DEBUG = true;

    private static final UUID MY_UUID = UUID.fromString(“000011008-0000-1000-8000-00805F9B34FB”);
    private static final int REQUEST_ENABLE_BT = 3;

    private BluetoothAdapter mBTAdapter;
    private AcceptThread mAcceptThread;
    private EditText view;

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

    final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, “”);
    //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

    screenHeight = displayMetrics.heightPixels;
    screenWidth = displayMetrics.widthPixels;

    screenHeight = 480;
    screenWidth = 640;

    upperLayerLayout = new RelativeLayout(this);
    RelativeLayout.LayoutParams upperLayerLayoutParams = new RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams.FILL_PARENT, android.widget.RelativeLayout.LayoutParams.FILL_PARENT);
    upperLayerLayout.setLayoutParams(upperLayerLayoutParams);
    upperLayerLayout.setBackgroundColor(Color.TRANSPARENT);

    _context = this;
    cameraView = new CameraView(this);
    radarMarkerView = new RadarMarkerView(this, displayMetrics, upperLayerLayout);

    displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    view = (EditText)findViewById(R.id.editText1);
    view.setGravity(Gravity.TOP | Gravity.LEFT);

    mBTAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBTAdapter == null) {
    Log.i(TAG, “device does not support Bluetooth”);
    }

    FrameLayout headerFrameLayout = new FrameLayout(this);
    /*RelativeLayout headerRelativeLayout = new RelativeLayout(this);
    RelativeLayout.LayoutParams relaLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
    headerRelativeLayout.setBackgroundColor(Color.BLACK);
    headerRelativeLayout.setLayoutParams(relaLayoutParams);
    Button button = new Button(this);
    RelativeLayout.LayoutParams buttonparams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    buttonparams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
    button.setLayoutParams(buttonparams);
    button.setText(“Cancel”);
    button.setPadding(15, 0, 15, 0);

    TextView titleTextView = new TextView(this);
    RelativeLayout.LayoutParams textparams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    textparams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
    textparams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    titleTextView.setLayoutParams(textparams);
    titleTextView.setText(“Augmented Reality View”); */

    //headerRelativeLayout.addView(button);
    //headerRelativeLayout.addView(titleTextView);
    //headerFrameLayout.addView(headerRelativeLayout);
    setContentView(cameraView);
    addContentView(radarMarkerView, new LayoutParams(
    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    //addContentView(headerFrameLayout, new FrameLayout.LayoutParams(
    // LayoutParams.FILL_PARENT, 44,
    // Gravity.TOP));
    addContentView(upperLayerLayout, upperLayerLayoutParams);

    if(!isInited){
    dataView = new DataView(ARView.this);
    paintScreen = new PaintUtils();
    isInited = true;
    }

    upperLayerLayout.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
    Toast.makeText(_context, “RELATIVE LAYOUT CLICKED”, Toast.LENGTH_SHORT).show();
    }
    });

    cameraView.setOnTouchListener(new OnTouchListener() {

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

    for (int i = 0 ; i < dataView.coordinateArray.length; i++) {
    if((int)event.getX() dataView.coordinateArray[i][0]){
    if((int)event.getY() dataView.coordinateArray[i][1]){
    Toast.makeText(_context, “match Found its “+dataView.places[i], Toast.LENGTH_SHORT).show();
    return false;
    }
    }
    }
    return true;
    }
    });
    }

    public static Context getContext() {
    return _context;
    }

    public int convertToPix(int val){
    float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, _context.getResources().getDisplayMetrics());
    return (int)px;

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

    }

    @Override
    protected void onStart() {
    super.onStart();

    if (!mBTAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }
    else {
    setDiscoveralbe();
    }
    }

    @Override
    protected void onPause() {
    super.onPause();
    this.mWakeLock.release();
    mAcceptThread.cancel();
    super.onPause();
    sensorMgr.unregisterListener(this, sensorGrav);
    sensorMgr.unregisterListener(this, sensorMag);
    sensorMgr = null;
    }

    @Override
    protected void onResume() {

    super.onResume();
    this.mWakeLock.acquire();

    mAcceptThread = new AcceptThread();
    mAcceptThread.start();
    sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

    sensors = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if (sensors.size() > 0) {
    sensorGrav = sensors.get(0);
    }

    sensors = sensorMgr.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
    if (sensors.size() > 0) {
    sensorMag = sensors.get(0);
    }

    sensorMgr.registerListener(this, sensorGrav, SensorManager.SENSOR_DELAY_NORMAL);
    sensorMgr.registerListener(this, sensorMag, SensorManager.SENSOR_DELAY_NORMAL);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_ENABLE_BT) {
    if (resultCode == Activity.RESULT_OK) {
    view.append(“Enabled BT\n”);

    setDiscoveralbe();
    }
    }
    super.onActivityResult(requestCode, resultCode, data);
    }

    private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
    BluetoothServerSocket tmp = null;
    try {
    tmp = mBTAdapter.listenUsingRfcommWithServiceRecord(“BluetoothServer”, MY_UUID);
    }
    catch (IOException e) { }
    mmServerSocket = tmp;
    }

    @Override
    public void run() {
    BluetoothSocket socket = null;
    while (true) {
    try {
    socket = mmServerSocket.accept();
    }
    catch (IOException e) {
    break;
    }

    if (socket != null) {
    manageConnectedSocket(socket);
    try {
    mmServerSocket.close();
    } catch (IOException e) {
    }
    break;
    }
    }
    }

    public void cancel() {
    try {
    mmServerSocket.close();
    }
    catch (IOException e) { }
    }
    }

    public void manageConnectedSocket(BluetoothSocket socket) {
    if (DEBUG) Log.d(TAG, “Connected”);
    com.raw.arview.ConnectedThread server = new com.raw.arview.ConnectedThread(mHandler, socket);
    server.start();
    }

    private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case MESSAGE_READ:
    byte[] readBuf = (byte[])msg.obj;
    String readMessage = new String(readBuf, 0, msg.arg1);
    view.append(readMessage);
    }
    }
    };

    private void setDiscoveralbe() {
    view.append(“set BT as being discoverable during 2 minutes\n”);
    Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120); // 2 minutes
    startActivity(discoverableIntent);
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {

    }

    @Override
    public void onSensorChanged(SensorEvent evt) {

    if (evt.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    gravSensorVals = lowPass(evt.values.clone(), gravSensorVals);
    grav[0] = evt.values[0];
    grav[1] = evt.values[1];
    grav[2] = evt.values[2];

    } else if (evt.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
    magSensorVals = lowPass(evt.values.clone(), magSensorVals);
    mag[0] = evt.values[0];
    mag[1] = evt.values[1];
    mag[2] = evt.values[2];

    }

    if (gravSensorVals != null && magSensorVals != null) {
    boolean success = SensorManager.getRotationMatrix(RTmp, I, gravSensorVals, magSensorVals);

    int rotation = Compatibility.getRotation(this);

    /*if (rotation == 1) {
    SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_X, SensorManager.AXIS_MINUS_Z, Rot);
    } else {
    SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_Z, Rot);
    }

    if(success) {
    SensorManager.getOrientation(Rot, results);

    ARView.azimuth = (float) (((results[0] * 180) / Math.PI) + 180);
    ARView.pitch = (float) (((results[1] * 180 / Math.PI)) + 90);
    ARView.roll = (float) (((results[2] * 180 / Math.PI)));

    }*/

    if (success) {
    SensorManager.getOrientation(RTmp, results);
    ARView.azimuth = results[0];
    ARView.pitch = results[1];
    ARView.roll = results[2];
    }

    radarMarkerView.postInvalidate();
    }

    }

    protected float[] lowPass( float[] input, float[] output ) {
    if ( output == null ) return input;

    for ( int i=0; i<input.length; i++ ) {
    output[i] = output[i] + ALPHA * (input[i] – output[i]);
    }
    return output;
    }
    }
    class CameraView extends SurfaceView implements SurfaceHolder.Callback {

    ARView arView;
    SurfaceHolder holder;
    Camera camera;

    public CameraView(Context context) {
    super(context);
    arView = (ARView) context;

    holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    try {
    Camera.Parameters parameters = camera.getParameters();
    try {
    List supportedSizes = null;
    supportedSizes = com.raw.utils.Compatibility.getSupportedPreviewSizes(parameters);

    Iterator itr = supportedSizes.iterator();
    while(itr.hasNext()) {
    Camera.Size element = itr.next();
    element.width -= w;
    element.height -= h;
    }
    Collections.sort(supportedSizes, new ResolutionsOrder());
    //parameters.setPreviewSize(w + supportedSizes.get(supportedSizes.size()-1).width, h + supportedSizes.get(supportedSizes.size()-1).height);
    parameters.setPreviewSize(arView.screenWidth , arView.screenHeight);
    } catch (Exception ex) {
    parameters.setPreviewSize(arView.screenWidth , arView.screenHeight);
    }

    camera.setParameters(parameters);
    camera.startPreview();
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }

    camera = Camera.open();
    arView.camera = camera;
    camera.setPreviewDisplay(holder);
    } catch (Exception ex) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }
    } catch (Exception ignore) {

    }
    }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }

    }
    class RadarMarkerView extends View{

    String dataa = “Azimuth”;
    String datab = “Pitch”;
    String datac = “Roll”;
    String deg = “°”;
    String senvalve = “”;
    String pitvalve = “”;
    public int pitch = 0;
    public int roll = 0;
    public int azimuth = 0;

    public int pitchscale = 0;

    public double azimuthdeg = 0.0d;
    public double pitchdeg = 0.0d;
    public double rolldeg = 0.0d;
    public float azi =0.0f;

    Paint mPaint = new Paint();
    ARView arView;
    DisplayMetrics displayMetrics;
    RelativeLayout upperLayoutView = null;
    public RadarMarkerView(Context context, DisplayMetrics displayMetrics, RelativeLayout rel) {
    super(context);
    mPaint.setColor(Color.GREEN);
    mPaint.setTextSize(35);
    //mPaint.setStrokeWidth(1 / getResources().getDisplayMetrics().density);
    mPaint.setStrokeWidth(6);
    mPaint.setAntiAlias(true);

    arView = (ARView) context;
    this.displayMetrics = displayMetrics;
    upperLayoutView = rel;
    }

    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    ARView.paintScreen.setWidth(canvas.getWidth());
    ARView.paintScreen.setHeight(canvas.getHeight());
    ARView.paintScreen.setCanvas(canvas);

    if (!ARView.dataView.isInited()) {
    ARView.dataView.init(ARView.paintScreen.getWidth(), ARView.paintScreen.getHeight(),arView.camera, displayMetrics,upperLayoutView);
    }

    //ARView.dataView.draw(ARView.paintScreen, ARView.azimuth, ARView.pitch, ARView.roll);

    ARView.dataView.draw(ARView.paintScreen, azi, ARView.pitch, ARView.roll);

    ////////////////////////// arc begin

    float width = (float)getWidth();
    float height = (float)getHeight();
    float radius;

    if (width > height){

    radius = height/3;

    }else{

    radius = width/2;
    }

    Path path = new Path();

    path.addCircle(width/2,

    height/2,radius,

    Path.Direction.CW);

    Paint paint = new Paint();

    paint.setColor(Color.GREEN);

    paint.setStrokeWidth(5);

    paint.setStyle(Paint.Style.FILL);

    float center_x, center_y;
    final RectF oval = new RectF();

    paint.setStyle(Paint.Style.STROKE);
    center_x = width/2;

    center_y = height / 2;

    oval.set(center_x – radius,

    center_y – radius,

    center_x + radius,

    center_y + radius);

    canvas.drawArc(oval, 210, 120, false, paint);
    ///arc ends

    mPaint.setTextSize(25f);

    //azimuth center horizontal lines
    //canvas.drawLine(442, 70, 517, 70, mPaint);
    //canvas.drawText(“15”, 432, 78, mPaint);
    //canvas.drawText(“15”, 527, 78, mPaint);

    canvas.drawLine(392,130,567,130,mPaint);
    canvas.drawText(“10”, 352, 138, mPaint);
    canvas.drawText(“10”, 577, 138, mPaint);

    canvas.drawLine(442,190,517,190,mPaint);
    canvas.drawText(“5”, 412, 198, mPaint);
    canvas.drawText(“5”, 527, 198, mPaint);

    canvas.drawLine(392,220,567,220,mPaint);
    canvas.drawText(“0”, 372, 228, mPaint);
    canvas.drawText(“0”, 577, 228, mPaint);

    canvas.drawLine(442,280,517,280,mPaint);
    canvas.drawText(“-5”, 408, 288, mPaint);
    canvas.drawText(“-5”, 527, 288, mPaint);

    canvas.drawLine(392,340,567,340,mPaint);
    canvas.drawText(“-10”, 348, 348, mPaint);
    canvas.drawText(“-10”, 577, 348, mPaint);
    //displaying plus on screen

    // canvas.drawLine(480,220,480,320, mPaint); //plus vertical
    // canvas.drawLine(430, 270, 530, 270, mPaint); //plus horizontal

    // targent square sign

    // canvas.drawLine(430,170,380,170,mPaint); //top corner left h line
    // canvas.drawLine(380,170,380,220,mPaint); //top corner left v line
    // canvas.drawLine(380,320,380,370,mPaint); //bottom corner left v line
    // canvas.drawLine(380,370,430,370,mPaint); //bottom corner left h line
    // canvas.drawLine(530,370,580,370,mPaint); //bottom corner right h line
    // canvas.drawLine(580,370,580,320,mPaint); //bottom corner right v line
    // canvas.drawLine(580,220,580,170,mPaint); //top corner right v line
    // canvas.drawLine(580, 170, 530, 170, mPaint); //top corner right h line

    //top header line
    canvas.drawLine(330,50,630,50,mPaint);
    //reading lines for top header
    canvas.drawLine(330,5,330,50,mPaint);
    canvas.drawLine(355,20,355,50,mPaint);
    canvas.drawLine(380,5,380,50,mPaint);
    canvas.drawLine(405,20,405,50,mPaint);
    canvas.drawLine(430,5,430,50,mPaint);
    canvas.drawLine(455,20,455,50,mPaint);
    canvas.drawLine(480,5,480,50,mPaint);
    canvas.drawLine(505,20,505,50,mPaint);
    canvas.drawLine(530,5,530,50,mPaint);
    canvas.drawLine(555,20,555,50, mPaint);
    canvas.drawLine(580,5,580,50,mPaint);
    canvas.drawLine(605,20,605,50, mPaint);
    canvas.drawLine(630,5,630,50,mPaint);

    // vertical left speed line
    canvas.drawLine(80, 170, 80, 470, mPaint);
    // reading scale for speed

    canvas.drawLine(60, 170, 80, 170, mPaint);
    pitvalve = Integer.toString(pitchscale+30);
    canvas.drawText(pitvalve, 20, 178, mPaint);
    canvas.drawLine(60, 220, 80, 220, mPaint);
    pitvalve = Integer.toString(pitchscale+20);
    canvas.drawText(pitvalve, 20, 228, mPaint);
    canvas.drawLine(60, 270, 80, 270, mPaint);
    pitvalve = Integer.toString(pitchscale+10);
    canvas.drawText(pitvalve, 20, 278, mPaint);
    canvas.drawLine(60, 320, 80, 320, mPaint);
    pitvalve = Integer.toString(pitchscale);
    canvas.drawText(pitvalve, 20, 328, mPaint);
    canvas.drawLine(60, 370, 80, 370, mPaint);
    pitvalve = Integer.toString(pitchscale-10);
    canvas.drawText(pitvalve, 10, 378, mPaint);
    canvas.drawLine(60, 420, 80, 420, mPaint);
    pitvalve = Integer.toString(pitchscale-20);
    canvas.drawText(pitvalve, 10, 428, mPaint);
    canvas.drawLine(60, 470, 80, 470, mPaint);
    pitvalve = Integer.toString(pitchscale-30);
    canvas.drawText(pitvalve, 10, 478, mPaint);

    // vertical right ALT line
    canvas.drawLine(880, 170, 880, 470, mPaint);
    // reading lines for ALT line
    canvas.drawLine(880, 170, 900, 170, mPaint);
    canvas.drawText(“30”, 920, 178, mPaint);
    canvas.drawLine(880, 220, 900, 220, mPaint);
    canvas.drawText(“20”, 920, 228, mPaint);
    canvas.drawLine(880, 270, 900, 270, mPaint);
    canvas.drawText(“10”, 920, 278, mPaint);
    canvas.drawLine(880, 320, 900, 320, mPaint);
    canvas.drawText(“0”, 920, 328, mPaint);
    canvas.drawLine(880, 370, 900, 370, mPaint);
    canvas.drawText(“-10”, 910, 378, mPaint);
    canvas.drawLine(880, 420, 900, 420, mPaint);
    canvas.drawText(“-20”, 910, 428, mPaint);
    canvas.drawLine(880, 470, 900, 470, mPaint);
    canvas.drawText(“-30”, 910, 478, mPaint);

    // pointer for speed reading
    canvas.drawLine(80, 320, 110, 300, mPaint);
    canvas.drawLine(110, 300, 140, 300, mPaint);
    canvas.drawLine(140, 300, 140, 340, mPaint);
    canvas.drawLine(140, 340, 110, 340, mPaint);
    canvas.drawLine(110, 340, 80, 320, mPaint);
    pitvalve = Integer.toString(pitchscale);
    canvas.drawText(pitvalve, 120, 328, mPaint);

    // pointer for ALT reading
    canvas.drawLine(880, 320, 850, 300, mPaint);
    canvas.drawLine(850, 300, 820, 300, mPaint);
    canvas.drawLine(820, 300, 820, 340, mPaint);
    canvas.drawLine(820, 340, 850, 340, mPaint);
    canvas.drawLine(850, 340, 880, 320, mPaint);
    canvas.drawText(“0”, 835, 328, mPaint);

    canvas.drawText(datab, 160.0f, 478.0f, mPaint);
    pitchdeg = Math.toDegrees(ARView.pitch);
    pitch = (int)pitchdeg;

    if(pitch < 0) {
    pitch = pitch + 90;
    }
    else
    {
    pitch = pitch – 90;
    }
    pitchscale = pitch;
    senvalve = Integer.toString(pitch);
    canvas.drawText(senvalve, 225.0f, 478.0f, mPaint);
    canvas.drawText(deg, 265.0f, 478.0f, mPaint);

    canvas.drawText(datac, 280.0f, 478.0f, mPaint);
    rolldeg = Math.toDegrees(ARView.roll);
    /*intervalve = (float)rolldeg;
    senvalve = Float.toString(intervalve);*/
    roll = (int)rolldeg;
    senvalve = Integer.toString(roll);
    canvas.drawText(senvalve, 330.0f, 478.0f, mPaint);
    canvas.drawText(deg, 370.0f, 478.0f, mPaint);

    canvas.drawText(dataa, 400.0f, 478.0f, mPaint);
    azimuthdeg = Math.toDegrees(ARView.azimuth);
    if (azimuthdeg < 0.0){
    azimuthdeg = azimuthdeg + 360.0f;
    }
    azi = (float) azimuthdeg;
    azimuth = (int)azimuthdeg;
    senvalve = Integer.toString(azimuth);
    canvas.drawText(senvalve, 505.0f, 478.0f, mPaint);
    canvas.drawText(deg, 560.0f, 478.0f, mPaint);

    }
    }
    class ResolutionsOrder implements java.util.Comparator {
    public int compare(Camera.Size left, Camera.Size right) {

    return Float.compare(left.width + left.height, right.width + right.height);
    }
    }

  15. Please explain the following code and how Bluetooth works so that i can redraw on ondraw method. Further can be displayed on the screen.
    package com.raw.arview;

    import java.io.IOException;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    import java.lang.Integer;
    import java.lang.Float;
    import java.lang.Math;
    import java.util.UUID;

    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Path;
    import android.graphics.RectF;
    import android.hardware.Camera;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.os.Bundle;
    import android.os.PowerManager;
    import android.os.PowerManager.WakeLock;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.util.TypedValue;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Window;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    import com.raw.utils.Compatibility;
    import com.raw.utils.PaintUtils;
    import android.graphics.Paint;

    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothServerSocket;
    import android.bluetooth.BluetoothSocket;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.Gravity;
    import android.widget.EditText;
    import android.view.Gravity;

    public class ARView extends Activity implements SensorEventListener{

    private static Context _context;
    WakeLock mWakeLock;
    CameraView cameraView;
    RadarMarkerView radarMarkerView;
    public RelativeLayout upperLayerLayout;
    static PaintUtils paintScreen;
    static DataView dataView;
    boolean isInited = false;
    public static float azimuth;
    public static float pitch;
    public static float roll;
    public double latitudeprevious;
    public double longitude;
    String locationContext;
    String provider;
    DisplayMetrics displayMetrics;
    Camera camera;
    public int screenWidth;
    public int screenHeight;

    private float RTmp[] = new float[9];
    private float Rot[] = new float[9];
    private float I[] = new float[9];
    private float grav[] = new float[3];
    private float mag[] = new float[3];
    private float results[] = new float[3];
    private SensorManager sensorMgr;
    private List sensors;
    private Sensor sensorGrav, sensorMag;

    static final float ALPHA = 0.25f;
    protected float[] gravSensorVals;
    protected float[] magSensorVals;

    //……..bluetooth

    public static final int MESSAGE_READ = 1;

    private static final String TAG = “BluetoothServer”;
    private static final boolean DEBUG = true;

    private static final UUID MY_UUID = UUID.fromString(“000011008-0000-1000-8000-00805F9B34FB”);
    private static final int REQUEST_ENABLE_BT = 3;

    private BluetoothAdapter mBTAdapter;
    private AcceptThread mAcceptThread;
    private EditText view;

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

    final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, “”);
    //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

    screenHeight = displayMetrics.heightPixels;
    screenWidth = displayMetrics.widthPixels;

    screenHeight = 480;
    screenWidth = 640;

    upperLayerLayout = new RelativeLayout(this);
    RelativeLayout.LayoutParams upperLayerLayoutParams = new RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams.FILL_PARENT, android.widget.RelativeLayout.LayoutParams.FILL_PARENT);
    upperLayerLayout.setLayoutParams(upperLayerLayoutParams);
    upperLayerLayout.setBackgroundColor(Color.TRANSPARENT);

    _context = this;
    cameraView = new CameraView(this);
    radarMarkerView = new RadarMarkerView(this, displayMetrics, upperLayerLayout);

    displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    view = (EditText)findViewById(R.id.editText1);
    view.setGravity(Gravity.TOP | Gravity.LEFT);

    mBTAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBTAdapter == null) {
    Log.i(TAG, “device does not support Bluetooth”);
    }

    FrameLayout headerFrameLayout = new FrameLayout(this);
    /*RelativeLayout headerRelativeLayout = new RelativeLayout(this);
    RelativeLayout.LayoutParams relaLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
    headerRelativeLayout.setBackgroundColor(Color.BLACK);
    headerRelativeLayout.setLayoutParams(relaLayoutParams);
    Button button = new Button(this);
    RelativeLayout.LayoutParams buttonparams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    buttonparams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
    button.setLayoutParams(buttonparams);
    button.setText(“Cancel”);
    button.setPadding(15, 0, 15, 0);

    TextView titleTextView = new TextView(this);
    RelativeLayout.LayoutParams textparams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    textparams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
    textparams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    titleTextView.setLayoutParams(textparams);
    titleTextView.setText(“Augmented Reality View”); */

    //headerRelativeLayout.addView(button);
    //headerRelativeLayout.addView(titleTextView);
    //headerFrameLayout.addView(headerRelativeLayout);
    setContentView(cameraView);
    addContentView(radarMarkerView, new LayoutParams(
    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    //addContentView(headerFrameLayout, new FrameLayout.LayoutParams(
    // LayoutParams.FILL_PARENT, 44,
    // Gravity.TOP));
    addContentView(upperLayerLayout, upperLayerLayoutParams);

    if(!isInited){
    dataView = new DataView(ARView.this);
    paintScreen = new PaintUtils();
    isInited = true;
    }

    upperLayerLayout.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
    Toast.makeText(_context, “RELATIVE LAYOUT CLICKED”, Toast.LENGTH_SHORT).show();
    }
    });

    cameraView.setOnTouchListener(new OnTouchListener() {

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

    for (int i = 0 ; i < dataView.coordinateArray.length; i++) {
    if((int)event.getX() dataView.coordinateArray[i][0]){
    if((int)event.getY() dataView.coordinateArray[i][1]){
    Toast.makeText(_context, “match Found its “+dataView.places[i], Toast.LENGTH_SHORT).show();
    return false;
    }
    }
    }
    return true;
    }
    });
    }

    public static Context getContext() {
    return _context;
    }

    public int convertToPix(int val){
    float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, _context.getResources().getDisplayMetrics());
    return (int)px;

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

    }

    @Override
    protected void onStart() {
    super.onStart();

    if (!mBTAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }
    else {
    setDiscoveralbe();
    }
    }

    @Override
    protected void onPause() {
    super.onPause();
    this.mWakeLock.release();
    mAcceptThread.cancel();
    super.onPause();
    sensorMgr.unregisterListener(this, sensorGrav);
    sensorMgr.unregisterListener(this, sensorMag);
    sensorMgr = null;
    }

    @Override
    protected void onResume() {

    super.onResume();
    this.mWakeLock.acquire();

    mAcceptThread = new AcceptThread();
    mAcceptThread.start();
    sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

    sensors = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if (sensors.size() > 0) {
    sensorGrav = sensors.get(0);
    }

    sensors = sensorMgr.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
    if (sensors.size() > 0) {
    sensorMag = sensors.get(0);
    }

    sensorMgr.registerListener(this, sensorGrav, SensorManager.SENSOR_DELAY_NORMAL);
    sensorMgr.registerListener(this, sensorMag, SensorManager.SENSOR_DELAY_NORMAL);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_ENABLE_BT) {
    if (resultCode == Activity.RESULT_OK) {
    view.append(“Enabled BT\n”);

    setDiscoveralbe();
    }
    }
    super.onActivityResult(requestCode, resultCode, data);
    }

    private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
    BluetoothServerSocket tmp = null;
    try {
    tmp = mBTAdapter.listenUsingRfcommWithServiceRecord(“BluetoothServer”, MY_UUID);
    }
    catch (IOException e) { }
    mmServerSocket = tmp;
    }

    @Override
    public void run() {
    BluetoothSocket socket = null;
    while (true) {
    try {
    socket = mmServerSocket.accept();
    }
    catch (IOException e) {
    break;
    }

    if (socket != null) {
    manageConnectedSocket(socket);
    try {
    mmServerSocket.close();
    } catch (IOException e) {
    }
    break;
    }
    }
    }

    public void cancel() {
    try {
    mmServerSocket.close();
    }
    catch (IOException e) { }
    }
    }

    public void manageConnectedSocket(BluetoothSocket socket) {
    if (DEBUG) Log.d(TAG, “Connected”);
    com.raw.arview.ConnectedThread server = new com.raw.arview.ConnectedThread(mHandler, socket);
    server.start();
    }

    private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case MESSAGE_READ:
    byte[] readBuf = (byte[])msg.obj;
    String readMessage = new String(readBuf, 0, msg.arg1);
    view.append(readMessage);
    }
    }
    };

    private void setDiscoveralbe() {
    view.append(“set BT as being discoverable during 2 minutes\n”);
    Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120); // 2 minutes
    startActivity(discoverableIntent);
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {

    }

    @Override
    public void onSensorChanged(SensorEvent evt) {

    if (evt.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    gravSensorVals = lowPass(evt.values.clone(), gravSensorVals);
    grav[0] = evt.values[0];
    grav[1] = evt.values[1];
    grav[2] = evt.values[2];

    } else if (evt.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
    magSensorVals = lowPass(evt.values.clone(), magSensorVals);
    mag[0] = evt.values[0];
    mag[1] = evt.values[1];
    mag[2] = evt.values[2];

    }

    if (gravSensorVals != null && magSensorVals != null) {
    boolean success = SensorManager.getRotationMatrix(RTmp, I, gravSensorVals, magSensorVals);

    int rotation = Compatibility.getRotation(this);

    /*if (rotation == 1) {
    SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_X, SensorManager.AXIS_MINUS_Z, Rot);
    } else {
    SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_Z, Rot);
    }

    if(success) {
    SensorManager.getOrientation(Rot, results);

    ARView.azimuth = (float) (((results[0] * 180) / Math.PI) + 180);
    ARView.pitch = (float) (((results[1] * 180 / Math.PI)) + 90);
    ARView.roll = (float) (((results[2] * 180 / Math.PI)));

    }*/

    if (success) {
    SensorManager.getOrientation(RTmp, results);
    ARView.azimuth = results[0];
    ARView.pitch = results[1];
    ARView.roll = results[2];
    }

    radarMarkerView.postInvalidate();
    }

    }

    protected float[] lowPass( float[] input, float[] output ) {
    if ( output == null ) return input;

    for ( int i=0; i<input.length; i++ ) {
    output[i] = output[i] + ALPHA * (input[i] – output[i]);
    }
    return output;
    }
    }
    class CameraView extends SurfaceView implements SurfaceHolder.Callback {

    ARView arView;
    SurfaceHolder holder;
    Camera camera;

    public CameraView(Context context) {
    super(context);
    arView = (ARView) context;

    holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    try {
    Camera.Parameters parameters = camera.getParameters();
    try {
    List supportedSizes = null;
    supportedSizes = com.raw.utils.Compatibility.getSupportedPreviewSizes(parameters);

    Iterator itr = supportedSizes.iterator();
    while(itr.hasNext()) {
    Camera.Size element = itr.next();
    element.width -= w;
    element.height -= h;
    }
    Collections.sort(supportedSizes, new ResolutionsOrder());
    //parameters.setPreviewSize(w + supportedSizes.get(supportedSizes.size()-1).width, h + supportedSizes.get(supportedSizes.size()-1).height);
    parameters.setPreviewSize(arView.screenWidth , arView.screenHeight);
    } catch (Exception ex) {
    parameters.setPreviewSize(arView.screenWidth , arView.screenHeight);
    }

    camera.setParameters(parameters);
    camera.startPreview();
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }

    camera = Camera.open();
    arView.camera = camera;
    camera.setPreviewDisplay(holder);
    } catch (Exception ex) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }
    } catch (Exception ignore) {

    }
    }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    try {
    if (camera != null) {
    try {
    camera.stopPreview();
    } catch (Exception ignore) {
    }
    try {
    camera.release();
    } catch (Exception ignore) {
    }
    camera = null;
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }

    }
    class RadarMarkerView extends View{

    String dataa = “Azimuth”;
    String datab = “Pitch”;
    String datac = “Roll”;
    String deg = “°”;
    String senvalve = “”;
    String pitvalve = “”;
    public int pitch = 0;
    public int roll = 0;
    public int azimuth = 0;

    public int pitchscale = 0;

    public double azimuthdeg = 0.0d;
    public double pitchdeg = 0.0d;
    public double rolldeg = 0.0d;
    public float azi =0.0f;

    Paint mPaint = new Paint();
    ARView arView;
    DisplayMetrics displayMetrics;
    RelativeLayout upperLayoutView = null;
    public RadarMarkerView(Context context, DisplayMetrics displayMetrics, RelativeLayout rel) {
    super(context);
    mPaint.setColor(Color.GREEN);
    mPaint.setTextSize(35);
    //mPaint.setStrokeWidth(1 / getResources().getDisplayMetrics().density);
    mPaint.setStrokeWidth(6);
    mPaint.setAntiAlias(true);

    arView = (ARView) context;
    this.displayMetrics = displayMetrics;
    upperLayoutView = rel;
    }

    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    ARView.paintScreen.setWidth(canvas.getWidth());
    ARView.paintScreen.setHeight(canvas.getHeight());
    ARView.paintScreen.setCanvas(canvas);

    if (!ARView.dataView.isInited()) {
    ARView.dataView.init(ARView.paintScreen.getWidth(), ARView.paintScreen.getHeight(),arView.camera, displayMetrics,upperLayoutView);
    }

    //ARView.dataView.draw(ARView.paintScreen, ARView.azimuth, ARView.pitch, ARView.roll);

    ARView.dataView.draw(ARView.paintScreen, azi, ARView.pitch, ARView.roll);

    ////////////////////////// arc begin

    float width = (float)getWidth();
    float height = (float)getHeight();
    float radius;

    if (width > height){

    radius = height/3;

    }else{

    radius = width/2;
    }

    Path path = new Path();

    path.addCircle(width/2,

    height/2,radius,

    Path.Direction.CW);

    Paint paint = new Paint();

    paint.setColor(Color.GREEN);

    paint.setStrokeWidth(5);

    paint.setStyle(Paint.Style.FILL);

    float center_x, center_y;
    final RectF oval = new RectF();

    paint.setStyle(Paint.Style.STROKE);
    center_x = width/2;

    center_y = height / 2;

    oval.set(center_x – radius,

    center_y – radius,

    center_x + radius,

    center_y + radius);

    canvas.drawArc(oval, 210, 120, false, paint);
    ///arc ends

    mPaint.setTextSize(25f);

    //azimuth center horizontal lines
    //canvas.drawLine(442, 70, 517, 70, mPaint);
    //canvas.drawText(“15”, 432, 78, mPaint);
    //canvas.drawText(“15”, 527, 78, mPaint);

    canvas.drawLine(392,130,567,130,mPaint);
    canvas.drawText(“10”, 352, 138, mPaint);
    canvas.drawText(“10”, 577, 138, mPaint);

    canvas.drawLine(442,190,517,190,mPaint);
    canvas.drawText(“5”, 412, 198, mPaint);
    canvas.drawText(“5”, 527, 198, mPaint);

    canvas.drawLine(392,220,567,220,mPaint);
    canvas.drawText(“0”, 372, 228, mPaint);
    canvas.drawText(“0”, 577, 228, mPaint);

    canvas.drawLine(442,280,517,280,mPaint);
    canvas.drawText(“-5”, 408, 288, mPaint);
    canvas.drawText(“-5”, 527, 288, mPaint);

    canvas.drawLine(392,340,567,340,mPaint);
    canvas.drawText(“-10”, 348, 348, mPaint);
    canvas.drawText(“-10”, 577, 348, mPaint);
    //displaying plus on screen

    // canvas.drawLine(480,220,480,320, mPaint); //plus vertical
    // canvas.drawLine(430, 270, 530, 270, mPaint); //plus horizontal

    // targent square sign

    // canvas.drawLine(430,170,380,170,mPaint); //top corner left h line
    // canvas.drawLine(380,170,380,220,mPaint); //top corner left v line
    // canvas.drawLine(380,320,380,370,mPaint); //bottom corner left v line
    // canvas.drawLine(380,370,430,370,mPaint); //bottom corner left h line
    // canvas.drawLine(530,370,580,370,mPaint); //bottom corner right h line
    // canvas.drawLine(580,370,580,320,mPaint); //bottom corner right v line
    // canvas.drawLine(580,220,580,170,mPaint); //top corner right v line
    // canvas.drawLine(580, 170, 530, 170, mPaint); //top corner right h line

    //top header line
    canvas.drawLine(330,50,630,50,mPaint);
    //reading lines for top header
    canvas.drawLine(330,5,330,50,mPaint);
    canvas.drawLine(355,20,355,50,mPaint);
    canvas.drawLine(380,5,380,50,mPaint);
    canvas.drawLine(405,20,405,50,mPaint);
    canvas.drawLine(430,5,430,50,mPaint);
    canvas.drawLine(455,20,455,50,mPaint);
    canvas.drawLine(480,5,480,50,mPaint);
    canvas.drawLine(505,20,505,50,mPaint);
    canvas.drawLine(530,5,530,50,mPaint);
    canvas.drawLine(555,20,555,50, mPaint);
    canvas.drawLine(580,5,580,50,mPaint);
    canvas.drawLine(605,20,605,50, mPaint);
    canvas.drawLine(630,5,630,50,mPaint);

    // vertical left speed line
    canvas.drawLine(80, 170, 80, 470, mPaint);
    // reading scale for speed

    canvas.drawLine(60, 170, 80, 170, mPaint);
    pitvalve = Integer.toString(pitchscale+30);
    canvas.drawText(pitvalve, 20, 178, mPaint);
    canvas.drawLine(60, 220, 80, 220, mPaint);
    pitvalve = Integer.toString(pitchscale+20);
    canvas.drawText(pitvalve, 20, 228, mPaint);
    canvas.drawLine(60, 270, 80, 270, mPaint);
    pitvalve = Integer.toString(pitchscale+10);
    canvas.drawText(pitvalve, 20, 278, mPaint);
    canvas.drawLine(60, 320, 80, 320, mPaint);
    pitvalve = Integer.toString(pitchscale);
    canvas.drawText(pitvalve, 20, 328, mPaint);
    canvas.drawLine(60, 370, 80, 370, mPaint);
    pitvalve = Integer.toString(pitchscale-10);
    canvas.drawText(pitvalve, 10, 378, mPaint);
    canvas.drawLine(60, 420, 80, 420, mPaint);
    pitvalve = Integer.toString(pitchscale-20);
    canvas.drawText(pitvalve, 10, 428, mPaint);
    canvas.drawLine(60, 470, 80, 470, mPaint);
    pitvalve = Integer.toString(pitchscale-30);
    canvas.drawText(pitvalve, 10, 478, mPaint);

    // vertical right ALT line
    canvas.drawLine(880, 170, 880, 470, mPaint);
    // reading lines for ALT line
    canvas.drawLine(880, 170, 900, 170, mPaint);
    canvas.drawText(“30”, 920, 178, mPaint);
    canvas.drawLine(880, 220, 900, 220, mPaint);
    canvas.drawText(“20”, 920, 228, mPaint);
    canvas.drawLine(880, 270, 900, 270, mPaint);
    canvas.drawText(“10”, 920, 278, mPaint);
    canvas.drawLine(880, 320, 900, 320, mPaint);
    canvas.drawText(“0”, 920, 328, mPaint);
    canvas.drawLine(880, 370, 900, 370, mPaint);
    canvas.drawText(“-10”, 910, 378, mPaint);
    canvas.drawLine(880, 420, 900, 420, mPaint);
    canvas.drawText(“-20”, 910, 428, mPaint);
    canvas.drawLine(880, 470, 900, 470, mPaint);
    canvas.drawText(“-30”, 910, 478, mPaint);

    // pointer for speed reading
    canvas.drawLine(80, 320, 110, 300, mPaint);
    canvas.drawLine(110, 300, 140, 300, mPaint);
    canvas.drawLine(140, 300, 140, 340, mPaint);
    canvas.drawLine(140, 340, 110, 340, mPaint);
    canvas.drawLine(110, 340, 80, 320, mPaint);
    pitvalve = Integer.toString(pitchscale);
    canvas.drawText(pitvalve, 120, 328, mPaint);

    // pointer for ALT reading
    canvas.drawLine(880, 320, 850, 300, mPaint);
    canvas.drawLine(850, 300, 820, 300, mPaint);
    canvas.drawLine(820, 300, 820, 340, mPaint);
    canvas.drawLine(820, 340, 850, 340, mPaint);
    canvas.drawLine(850, 340, 880, 320, mPaint);
    canvas.drawText(“0”, 835, 328, mPaint);

    canvas.drawText(datab, 160.0f, 478.0f, mPaint);
    pitchdeg = Math.toDegrees(ARView.pitch);
    pitch = (int)pitchdeg;

    if(pitch < 0) {
    pitch = pitch + 90;
    }
    else
    {
    pitch = pitch – 90;
    }
    pitchscale = pitch;
    senvalve = Integer.toString(pitch);
    canvas.drawText(senvalve, 225.0f, 478.0f, mPaint);
    canvas.drawText(deg, 265.0f, 478.0f, mPaint);

    canvas.drawText(datac, 280.0f, 478.0f, mPaint);
    rolldeg = Math.toDegrees(ARView.roll);
    /*intervalve = (float)rolldeg;
    senvalve = Float.toString(intervalve);*/
    roll = (int)rolldeg;
    senvalve = Integer.toString(roll);
    canvas.drawText(senvalve, 330.0f, 478.0f, mPaint);
    canvas.drawText(deg, 370.0f, 478.0f, mPaint);

    canvas.drawText(dataa, 400.0f, 478.0f, mPaint);
    azimuthdeg = Math.toDegrees(ARView.azimuth);
    if (azimuthdeg < 0.0){
    azimuthdeg = azimuthdeg + 360.0f;
    }
    azi = (float) azimuthdeg;
    azimuth = (int)azimuthdeg;
    senvalve = Integer.toString(azimuth);
    canvas.drawText(senvalve, 505.0f, 478.0f, mPaint);
    canvas.drawText(deg, 560.0f, 478.0f, mPaint);

    }
    }
    class ResolutionsOrder implements java.util.Comparator {
    public int compare(Camera.Size left, Camera.Size right) {

    return Float.compare(left.width + left.height, right.width + right.height);
    }
    }

    1. Yes! If you wanted to create a game that was played between two Android phones, you could do this using App Inventor and Bluetooth to communicate game actions between the phone. Sounds like a great idea!

      Ed

  16. Hi, Thanks for the tutorial, really helpful.
    Can you please help me in a question? I just couldn’t figure out if I use multiple screens and I connected to the bluetooth, how can I send data from the other screens? Is it possible to send the necessary thigs to the other screens?

    1. You would need to add the Bluetooth control to each screen. I can see some problems with that, however. This is something I will try to experiment with eventually. Right now I am working on Bluetooth LE, which is a new feature in App Inventor.

  17. Thank you so much for this tutorial! I’m not very well-versed with development, but I’m working on it. I’m trying to create an app that very simply connects with a bluetooth device not to transmit data, but to then set off an alarm if that connection is broken (as in, the user’s phone moves too far away from the device to maintain the connection). It seems like everything here is focused on using the BTClient to connect for communication between two phones. Is it possible to use this to establish a link with a non-communication device? I tried testing it using a bluetooth speaker I have – my phone in general recognized that a bluetooth object was present, but nothing came up when I tested the app (both my own using your method and your aia). Help please? 🙂

    1. That is an excellent question! But unfortunately, I do not know the answer as I do not have other Bluetooth devices in order to check on this. I also have a tutorial on the website that connects the Android phone with an Arduino board through a Bluetooth link (its the single most popular tutorial on this web site!) Therefore, I know it is possible to connect Android / App Inventor apps over Bluetooth to non-Android devices. However, in that particular example, I also wrote the code for the Arduino board so that the App Inventor app and the Arduino are compatible.

      Another issue is that there might be a dependency on the version of Bluetooth that is in use. We are presently on version 4.1 or 4.2 but many devices are still using older Bluetooth versions (even back to 2.1). In theory, newer versions of Bluetooth are supposed to be backwards compatible with the older versions. But in practice, I have an older phone with BT 2.1 and it did not fully function with my BT 4.0 device.

      Finally, it is possible that the speaker uses Bluetooth Low Energy (part of the version 4 spec). The example code I have here works only with Bluetooth Classic features and does not support Bluetooth LE. I have some hardware and code that I’ve created which does work with app inventor to link to a Bluetooth LE device and I am slowly working on some more things for this, to eventually post on the web site.

      Ed

  18. Hi i would like to know how do i print to a Bluetooth printer from my Android phone? For start, i dont need anything fancy. I just want to write an application from app inventor to send some text (sales receipt) to a bluetooth printer. How to i use the code that you have and add in code to print to a BT printer? Thanks in advance for your help and advice.

    1. I do not know if this can be done, but it probably would be somewhat difficult to do, if it is possible.

      When you send a file to a printer from your personal computer, your computer’s operating system contains a “print driver”. The print driver software translates requests for font sizes, colors, bold, italics and so on, into the specific commands needed to tell the printer how to display these items. To implement printing would require setting up a connection with the printer, and then properly preparing and formatting the data for the printer.

      Now, it might be possible to connect, and it might be possible to output characters in a standard code (such as ASCII) that display as ordinary text characters. It would be neat if this could be done but I do not have any specific information on how to communicate directly to printers.

      You could try using the basic Bluetooth communications code to see if you can discover a BT-equipped printer and then connect to it. If that works, you could try sending data bytes to the printer and see what happens!

      Ed

      1. thanks for the fast reply. Sorry, i should make it clearer. Actually, the printer i have is a bluetooth thermal receipt printer (http://www.zjiang.com/cn/cpzx/pjdyj/bianxieshilanyadayinji/255.html). Based on the manual, it supports ESC/POS/STAR command.

        So, i would like to learn how do i send these command to print simple text to the receipt printer. At a start, no need fancy. just plain text. later, once I know how it works, only then i start to add in bold font, italic etc. Hope you able to give me some pointers….if possible, some example codes.
        thanks v much.

  19. Dalle indicazioni ho realizzato un App con bluetooth client per comandare arduino per apertura/chiusura tapparella tutto ok.
    Vorrei per attivare Bluetooth all’avvio dell’app e disattivarlo all’uscita, ho visto alcune app già realizzate che all’avvio chiedono di attivare Bluetooth, ma non riesco a trovare lo script con MIT App
    Potete darmi una dritta
    Saluti

  20. Hello. I was trying this app but I receive an error some other people had and didnt get a response.
    (Error Unable to Connect. Is the device turned on?)
    I am not sure on how to fix it, I had it in another app as well that’s why I turned to this one. Obviously, I checked that the device is on, I have a samsung s5. Can you please help me out?

    1. Hi,

      Usually that means that the Bluetooth device has been paired, but the other device is not reachable – either because it is off or because it is out of range.

      One of your devices is a Samsung S5 – what is the other device you are trying to connect to?

      I have been using Bluetooth between two Android devices, and between an Android device and six other Bluetooth connected Arduino boards, where I have separate Bluetooth components for each of the connections (in other words, 6 Bluetooth components added to the app). This is working okay for me.

      Let me know what the other device is in your set up? I’d like to understand this better.

      Ed

Comments are closed.