android – The Industrious Squirrel https://blog.chadweisshaar.com Tue, 07 Feb 2017 01:05:39 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 https://blog.chadweisshaar.com/wp-content/uploads/2016/07/favicon.png android – The Industrious Squirrel https://blog.chadweisshaar.com 32 32 Experimenting with Bluetooth https://blog.chadweisshaar.com/2012/11/25/experimenting-with-bluetooth/ https://blog.chadweisshaar.com/2012/11/25/experimenting-with-bluetooth/#comments Mon, 26 Nov 2012 03:54:10 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=247 Continue reading "Experimenting with Bluetooth"]]> One of the challenges writing games for the touch-table is handling hidden information. So far we have used two solutions: Physical blinds that rest above the sensor and block the view of the other players, and a touch-to-reveal system where the player blocks the view with their hand and touches the screen to reveal their cards.

Many of our users have smartphones, and I thought that it would make sense to let them use their smartphone for the display of the hidden information. In the past, have experimented with a web based system where the game is hosted on a webpage and played on browsers. This works, but when the game is written in C++ for the touch-table, the game has to send data to the web-server so that the clients can display it. This creates extra overhead and lag.

Instead, I thought it would work better to send the hidden information directly to the phones over bluetooth. So I set out to write a C++ server that would use bluetooth to broadcast data to Android clients. This ended up being more difficult than I expected, but I did get it to work and wanted to post what I have done.

The first step was to create a C++ bluetooth server. I was surprised by how low-level the bluetooth API is in C++. Making a bluetooth server is much like setting up a socket connection where you have to locate and enable the network adapter first. Once the socket is open, you also have to broadcast the service that you are providing:

// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
    wprintf(L"WSAStartup failed: %d\n", iResult);
    return 1;
}

// Look for bluetooth radios
BLUETOOTH_FIND_RADIO_PARAMS findParams;
findParams.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS );
HANDLE bluetoothRadio;
HBLUETOOTH_RADIO_FIND radioFindHandle = BluetoothFindFirstRadio(&findParams, &bluetoothRadio);
while ( radioFindHandle != nullptr)
{
  wprintf(L"Found Bluetooth radio\n");
  wprintf(L"Opening server socket for bluetooth connections...\n");
  SOCKET btSock = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
  if ( btSock == INVALID_SOCKET )
    wprintf(L"Error creating socket: %d\n", WSAGetLastError());
  else
  {
    WSAPROTOCOL_INFO protoInfo;
    int infoStructSize = sizeof(protoInfo);
    if ( getsockopt(btSock, SOL_SOCKET, SO_PROTOCOL_INFO, (char*)&protoInfo, &infoStructSize) )
    {
      wprintf(L"Error getting socket options: %d\n", WSAGetLastError());
    }
    else
    {
      // Bind the socket
      SOCKADDR_BTH address;
      address.addressFamily = AF_BTH;
      address.btAddr = 0;
      address.serviceClassId = GUID_NULL;
      address.port = BT_PORT_ANY;
      if ( bind(btSock, (sockaddr*)&address, sizeof(address)) )
      {
        wprintf(L"Error binding socket: %d\n", WSAGetLastError());
      }
      else
      {
        int addressLen = sizeof(address);
        sockaddr* pAddress = (sockaddr*)&address;
        getsockname(btSock, pAddress, &addressLen);
        wprintf(L"Bind successfull: device=%04x%08x channel = %d\n",
          GET_NAP(address.btAddr), GET_SAP(address.btAddr), address.port);

        // Listen for connections. (This would normally go into a thread)
        if ( listen(btSock, SOMAXCONN) )
        {
          wprintf(L"Error listening for connections: %d\n", WSAGetLastError());
        }
        else
        {
          // Register our service so that the clients can lookup this server
          // by service name
          wprintf(L"Registering service...\n");
          WSAQUERYSET service;
          memset(&service, 0, sizeof(service));
          service.dwSize = sizeof(service);
          service.lpszServiceInstanceName = _T("TouchGameBTServer");
          service.lpszComment = _T("Push game data to devices");
          GUID serviceGUID = GenericNetworkingServiceClass_UUID;
          service.lpServiceClassId = &serviceGUID;
          service.dwNumberOfCsAddrs = 1;
          service.dwNameSpace = NS_BTH;
          CSADDR_INFO csAddr;
          memset(&csAddr, 0, sizeof(csAddr));
          csAddr.LocalAddr.iSockaddrLength = sizeof(SOCKADDR_BTH);
          csAddr.LocalAddr.lpSockaddr = pAddress;
          csAddr.iSocketType = SOCK_STREAM;
          csAddr.iProtocol = BTHPROTO_RFCOMM;
          service.lpcsaBuffer = &csAddr;
          if ( WSASetService(&service, RNRSERVICE_REGISTER, 0) )
          {
            wprintf(L"Error registering game service: %d\n", WSAGetLastError());
          }
          else
          {
            // Now accept connections from clients. This call will block till a connection is made
            wprintf(L"Service registered. Accepting connections...\n");
            SOCKADDR_BTH clientAddr;
            int addrSize = sizeof(clientAddr);
            SOCKET clientSocket = accept(btSock, (sockaddr*)&clientAddr, &addrSize);
            if ( clientSocket != INVALID_SOCKET )
            {
              // Send some data. At this point we just have a full-duplex socket connection
              // so we can send/receive anything we need.
              wprintf(L"Client connected from %04x%08x on channel %d.",
                GET_NAP(clientAddr.btAddr), GET_SAP(clientAddr.btAddr), clientAddr.port);
              char* message = "Hello, world";
              send(clientSocket, message, sizeof(message),0); 
              char buffer[1024] = {0};
              int dataSize = recv(clientSocket, buffer, sizeof(buffer), 0);
            }
          }
        }
      }
    }
  }

  CloseHandle(bluetoothRadio);
  if ( !BluetoothFindNextRadio(radioFindHandle, &bluetoothRadio) )
  {
    BluetoothFindRadioClose(radioFindHandle);
    radioFindHandle = nullptr;
  }
}

WSACleanup();

Then I created the Android client. Android provided a higher level API, but had its own set of issues. Since it is a phone, the bluetooth antenna is usually off to save power. While it is possible to simply turn it on, the correct approach is to start an intent to ask the user to turn on the antenna. Of course we also had to request the bluetooth permissions. Here is the code to request the user turn on the antenna:

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
StringBuilder message = new StringBuilder();
if (adapter.isEnabled()) {
  message.append("Bluetooth address: " + adapter.getAddress() + "\n");
  message.append("Bluetooth name: " + adapter.getName() + "\n");
} else {
  message.append("Enabling bluetooth");
  Intent enableBluetooth = new Intent(
      BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enableBluetooth, ENABLE_BLUETOOTH_ACTIVITY);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if ( requestCode == ENABLE_BLUETOOTH_ACTIVITY && resultCode == RESULT_OK ) {
    findServerDevice();
  }
}

Next we want to connect to the server device.
The bluetooth antenna can be bonded to a device (they have connected to each other before). Or it may need to scan for new devices to connect to. Performing a scan is expensive in time and battery, so we first check the bonded devices.

public void findServerDevice() {
  BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  // Start with the bonded devices
  if ( !detectDevice(adapter.getBondedDevices())){
    // If that doesn't work, then perform a scan
    if ( adapter.isDiscovering()) adapter.cancelDiscovery();
    DeviceReceiver receiver = new DeviceReceiver();
    registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
    registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
    registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED));
    adapter.startDiscovery();
  }
}
public boolean detectDevice(Set<BluetoothDevice> devicesToScan) {
  myDevice = null; mySocket = null;
  for ( BluetoothDevice device : devicesToScan ) {
    // Check to see if this device supports this app
    UUID serviceName = UUID.fromString("00001201-0000-1000-8000-00805F9B34FB");
    try {
      BluetoothSocket client = device.createRfcommSocketToServiceRecord(serviceName);
      if ( client == null ) {
        continue;
      }
      client.connect();
      myDevice = device;
      mySocket = client;
    } catch (IOException e) {
      continue;
    }
    break;
  }
  // Receive data over the socket
  if ( mySocket != null ) 
    loadImage(message);
  
  return mySocket != null;
}

As you can see, the Android code is much shorter and simpler. As usual, the Windows APIs are difficult to use with lots of ugly structs and magic constants.

I don’t show the cod in the C++ example, but I added the ability to send an image over bluetooth and display it on the phone. The C++ cod for this was very simple, just open up the file and stream the data over the socket. On the Android side, I needed to save the file and load it into a view. I used the internal storage on the phone to save the image and the BitmapFactory to load it into an image. Here is the Android code:

protected void loadImage(StringBuilder message)
{
  // DEBUG: See what files we already have
  Log.d("Storage", getFilesDir().getAbsolutePath());
  for ( String file : fileList() ) {
    Log.d("Storage", file);
    deleteFile(file);
  }
  try {
    InputStream is = mySocket.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    String command = reader.readLine(); 
    if ( command.startsWith("SendFile") ) {
      String filename = reader.readLine();
      int fileSize = Integer.parseInt(reader.readLine());
      message.append("SendFile: "+filename+ "("+ fileSize+")\n");
      byte[] buffer = new byte[1024];
      FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);
      int bytesLoaded = 0;
      while ( bytesLoaded < fileSize ) {
        int readSize = 0;
        Log.d("Transfer", "Recieved: "+bytesLoaded+"/"+fileSize+" remaining: "+(fileSize-bytesLoaded));
        if ( fileSize - bytesLoaded > buffer.length )
          readSize = is.read(buffer);
        else
          readSize = is.read(buffer, 0, fileSize-bytesLoaded);
        if ( readSize == -1 ){
          message.append("Failed to load all data.\n");
          break;
        }
        bytesLoaded += readSize;
        fos.write(buffer, 0, readSize);
      }
      Log.d("Transfer", "Data received and saved.");
      fos.close();
      File newFile = new File(getFilesDir(), filename);
      Log.d("Storage", "Exists: "+newFile.exists() + " Readable: "+newFile.canRead() + " length: "+newFile.length());
      DisplayView displayView = (DisplayView) findViewById(R.id.DISPLAY_VIEW);
      FileInputStream fis = openFileInput(filename);
      displayView.setBitmap(BitmapFactory.decodeStream(fis));
    }
    
  } catch (IOException e) {
    message.append("Couldn't connect: "+e.getMessage());
    e.printStackTrace();
  }			
}

Overall I am happy with this prototype. Unfortunately there are a couple of fairly severe limitations. The first is that only Android phones that download the touchtable app can play. This isn’t too much of a problem for our group of friends, but is a problem when trying to sell to a larger audience. The second problem is that it is very difficult to have any client side logic without writing a separate app per game. And while it may not be an issue to ask people to download one app, they may be less interested in downloading an app per game.

]]>
https://blog.chadweisshaar.com/2012/11/25/experimenting-with-bluetooth/feed/ 1
Rooting my Android phone https://blog.chadweisshaar.com/2012/05/24/rooting-my-android-phone/ https://blog.chadweisshaar.com/2012/05/24/rooting-my-android-phone/#respond Thu, 24 May 2012 23:52:35 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=215 Continue reading "Rooting my Android phone"]]> This morning I rooted my android G2x. The main motivation was curiosity, but there were a few things that I wanted to improve about my phone. T-Mobile didn’t pre-load too much junk onto the phone, but there was the T-Mobile app-pack and Mall, Nova and Tegra game stores, and the lite version of TeleNav. Also, to get a good ad-blocker you need to have root access.

So I took the plunge and rooted the phone. There was a point when I thought the phone was bricked, but it all worked out in the end.

Even without the mistakes that I made, I would say that the benefits do not justify the effort (at least for my phone). I am glad that I did it, but more for the experience than the end result.

I picked the CyanogenMod ROM to replace my stock ROM since it seemed like the most popular and best supported ROM. Their web page even had step-by-step instructions for rooting the phone, installing a ROM manager, backing up the phone and installing their latest ROM.

I first wanted to try out the built in backup/restore capability. It is accessed by holding volume-down while turning on the phone. This was supposed to bring up a GUI where I could backup my current setup. Instead, this just did a factory reset and deleted all my apps. I had backed up the SD card and I use Google for all my contacts/calendar/mail, so all of that was safe, but settings and apps were lost.

The first step to installing a new ROM is to root the phone. The cyanogen page had instructions, but I had read about a simpler way with unlockroot.com. This is a windows application that roots a wide variety of phones. The G2X is supported and I already have the phone drivers installed, so it was just a matter of running the program.

The second step is to replace the default boot loader. This is the risky part of the procedure since the boot loader is used to recover the phone if the ROM doesn’t load. I followed the cyanogen instructions and downloaded ROM manager from the app store. It needed root permissions and successfully replaced the boot loader.

The third step is to download the ROM that you want and put in on the SD card. The ROM manager can do this step for you, but I did it manually so that I could get the version that I wanted.

Finally you use the ROM manager to load the new ROM. I did this from the ROM manager app on the phone which was a mistake. It seemed to be working: after rebooting, the boot loader came up, made a backup of the existing ROM, installed the Cyanogen ROM and rebooted. However, the new ROM didn’t work. I still don’t know why it didn’t work since I did get that same ROM to successfully load eventually.

Now that the main ROM didn’t load, I needed to use the boot loader to restore the backup. I could get the boot loader to come up, and I could move the cursor with the volume buttons. But I couldn’t select anything. It is supposed to use the power button, but apparently that doesn’t work with the G2. At this point I thought that the phone was bricked. The main ROM wouldn’t load and the boot loader was unusable. Lesson learned: Try out the boot loader first.

After doing some internet research, I found out that the G2x has an APX mode that you can use to load a boot loader. I also found a boot loader called NVFlash that works with the G2x. The APX mode is very strange. You have to take out the battery, press volume up and down, then plug in the usb cable. Windows sees the APX device and you can install the drivers. Then you run the NVFlash “OneClickRecoveryFlasher” which will load a variety of boot loaders.

With that boot loader I was able to use the phone controls to make selections and loaded the Cyanogen ROM again. This time it worked and the phone booted to Cyanogen MOD.

After that there were two major problems. One was that the phone wasn’t treating the internal SD card and memory the same way that it did before. I wasn’t able to plug the phone into the computer and see the files. This had to be fixed by changing where the phone mounted the internal SD card. To do this I had to remount the file system as read-write, change the permissions on two files and edit them with a downloaded text editor app.

The second problem was that I couldn’t get Swype. I’ve gotten very used to it and it is far superior to the stock android keyboard. I went through Swype’s system and signed up for their beta, downloaded their installer app which then couldn’t download the actual app. I couldn’t figure out what was wrong with that, but I did find instructions for pulling the version of Swype that came with the G2x and reinstalling it.

So, if I were doing it all over from scratch again here are the steps needed:

  1. Install the windows LG drivers
  2. Download the ROM and copy it to the root directory on the sd card.
  3. Download and run the unlockroot application from unlockroot.com
  4. Download the APX driver and NVFlash app from djmcnz.batteryboss.org
  5. Remove phone battery, hold vol up and vol down, plug in USB
  6. Install the APX driver for the unrecognized APX device. Unplug the USB
  7. Remove phone battery, hold vol up and vol down, plug in USB, run the NVFlash app, install a boot loader, release vol-up and vol-down, unplug USB.
  8. Replace the batter, hold vol-down and turn on phone.
  9. Backup up the existing ROM and install the new ROM with the boot loader
  10. Reboot.
  11. Go to the android-sdk/platform-tools and run adb shell
  12. su and then re-mount the /system partition with read-write (mount -o remount,rw -t xxx /dev/xxx /system)
  13. Change permissions on /etc/vold.fstab and /system/build.prop
  14. Edit these two files to mount emmc to /mnt/sdcard and sdcard to /mnt/sdcard/external_sd
  15. Extract the Swype.apx and .so from the old /system and /system/lib directories.
  16. Put Swype.apx in /system and /sdcard. Put the library in /system/lib
  17. Run the Swype.apx off the sdcard to install it
  18. Download AdAway from the market and run. It updates the hosts file to remove ad servers.

There are some good instructions at http://theunlockr.com/2011/05/03/how-to-flash-a-custom-recovery-image-on-the-t-mobile-g2x/ and http://forum.xda-developers.com/showthread.php?t=1049154

]]>
https://blog.chadweisshaar.com/2012/05/24/rooting-my-android-phone/feed/ 0
Practice Log Webapp https://blog.chadweisshaar.com/2012/02/28/practice-log-webapp/ https://blog.chadweisshaar.com/2012/02/28/practice-log-webapp/#respond Wed, 29 Feb 2012 04:45:04 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=147 Continue reading "Practice Log Webapp"]]> I have spent the last couple days working on my Practice Log application. I make the website for downloading the application nicer looking, wrote some documentation, created a simple web application and added a couple features to the android app.

The website: weissoft.com/practicelog looked pretty bad and may have been discouraging people from downloading the software. The new look is better:

I am not a web designer, so it is still lacking some polish. I used some of the css from the wordpress theme that this blog is using and the free icon that the application itself uses.

The web site allows you to login and see/edit your log. It is not as full featured as the windows application, but it provides a way for the users of the android app to access their log on a large screen and, more importantly, to export their data. Here is what the site looks like today:

This site uses the same color scheme as the main practice log page and jquery-ui buttons and dialogs:

If you haven’t used jQuery before, it is very, very nice. I strongly recommend it. There is a bit of a learning curve and it makes some callback functions look uglier. But the benefits are huge. Making that dialog would have taken me hours without jQuery. Here is the code to do the login dialog:

<div id=”login_dialog” title=”Login”>
<form name=”login”>
<table>
<tr><td>Username:</td><td><input type=”text” name=”username”/></td></tr>
<tr><td>Password:</td><td><input type=”password” name=”password”/></td></tr>
</table>
</form>
</div>

  $('#login_dialog').dialog({
    autoOpen: false,
    modal: true,
    buttons: {
      "Ok": function() {
        // Call the php to login
      $.post("../login.php", {
        username: document.login.username.value,
        password: document.login.password.value
        }, function(xml) {
...
        });
      },
      "Cancel": function() {
        $(this).dialog("close");
      }
    }
  });

 

And that includes the some of the code that actually logs the user in. jQuery also makes it easy to operate on a set of page elements or XML. The most difficult part of developing the web site was getting the table body to scroll without the table header scrolling too. I’ll make a separate blog entry for how I solved that problem since it took me a while to figure out. The majority of my time was spent picking colors and tweaking layout. Somehow html layout is very non-intuitive to me and it takes me a long time to get things looking the way I want. The export button prompts the user to download a .csv file of their data. This works by setting the location.href to a server side php. The php script sets the Content-Disposition header to the file and then writes the CSV data to the output stream. Here are the interesting lines of code:

  header("Content-Disposition: attachment; filename=practiceData.csv");
  $outStr = fopen("php://output", "w");
  while ( $row = mysql_fetch_assoc($result) )
  {
    $data = array($row['day'], $row['minutes'], $row['note']);
    fputcsv($outStr, $data);
  }
  fclose($outStr);

 

I also made a new version of the Android app. Navigating between days was non-intuitive and slow. The only way to change the displayed day was to swipe left/right on the main screen. That method still works, but I added a couple of buttons to make it more obvious. I also added the capability to click on a particular day displayed in the week view to change to that day. You can now swipe left/right on the week view to go back/forward 10 weeks and the days with notes are highlighted. I made the note section expand to fill the available space on larger devices and added a menu option that takes you to the website so that you can export your data.

Updating the android app was quick and mostly painless. I added the new .apk to the marketplace and was able to download the update to my phone after 10 minutes or so.

]]>
https://blog.chadweisshaar.com/2012/02/28/practice-log-webapp/feed/ 0
Practice Log published https://blog.chadweisshaar.com/2012/02/15/practice-log-published/ https://blog.chadweisshaar.com/2012/02/15/practice-log-published/#comments Wed, 15 Feb 2012 23:00:51 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=75 Continue reading "Practice Log published"]]> The PracticeLog application has been released as freeware and the Android version is available on the Marketplace!

After using the program and app for a week and really enjoying the convenience, I have decided to  make it available to the public. In the unlikely scenario where this application becomes popular, I am worried that it may cause too much load on my web server. So I wanted to have some kind of potential revenue stream to offset this risk, but didn’t want to try to sell the software. So I have gone over to the dark side and added an ad to my Android App.

My first attempt to add the ad was a failure. I thought that I would use the Webkit GUI element to display an ad from my website. To that end I tried to setup Google AdWords but was rejected because the PracticeLog page had insufficient content. (At the time it wasn’t linked to the rest of my site). I know now that this isn’t the right way to put a Google ad in an Android App. The right way is AdMob. This is a free an painless system and they have an SDK that you add to the android app. (Note that you do have to be building the app with the latest version of the Android SDK to use AdMob.)

Putting the app onto the Android Marketplace was a bit of a pain. First you have to pay Google $25 for the privilege. This is a one-time fee to register as a developer, but it did make me hesitate, since I doubt I will ever make enough in ad revenue to pay for it. Then the app has to be digitally signed and you have to have perfectly sized screen shots and icons. This was all a hassle, especially through the slightly buggy VirtualBox VM.

Publishing the C# application was a little easier, the main hassle being adding it to various freeware sites. Fortunately, several of them accept .PAD files. This is a file that describes an application and the developer that the freeware sites can read to fill in their submission forms. It had been a long time since I had visited some of these sites, so I also took the time to let them know about the latest version of the MediaDB program.

So far I have 9 downloads and 7 users, 39 ad views, 0 ad clicks and so $0 in revenue. Of course it is still early and I am not really expecting this program to be very popular. Most people who are keeping a practice log are children who don’t have Android phones.

If it does become popular, I will add a “teacher” mode so that a teacher can have access to the practice logs of their students. The teacher could track their practice time and use the notes to assign tasks for the week.

You can get the C# application on my site: http://chadweisshaar.com/weissoft/practicelog and the Android app from the Marketplace.

]]>
https://blog.chadweisshaar.com/2012/02/15/practice-log-published/feed/ 4
Practice Log – Android+MultiUser completed https://blog.chadweisshaar.com/2012/02/03/practice-log-androidmultiuser-completed/ https://blog.chadweisshaar.com/2012/02/03/practice-log-androidmultiuser-completed/#comments Fri, 03 Feb 2012 22:45:07 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=73 Continue reading "Practice Log – Android+MultiUser completed"]]> The changes to the PracticeLog application and the associated android app are completed. They both access the database on my website through the php interface.

I have created a simple user system:

  1. When you create a new user, I store the username and email along with an encrypted password and generated GUID in my user table.
  2. When a user logs in, the given password is encrypted and compared to the stored password. If correct, the GUID is returned.
  3. The other tables are accessed by the users GUID.

The C# changes were fairly simple. I created a login/new-user dialog and left the local database code so that someone could use the program in a offline mode if they didn’t like the idea of logging into my website.

The Android app was a much bigger job. I was able to use all built-in GUI elements, but the life-cycle issues were much more serious than they were in my first Android application. I didn’t want the user to have to log in every time, so I store the users GUID in the application’s configuration data. I also needed to preserve both the timer’s start time and the entered but unsaved practice time when the application is killed. I learned how to prevent the screen rotation from happening and learned how to store the downloaded data from the web during a screen rotation.

Testing the app was a hassle because my phone loses its connection to eclipse after a few seconds. This is probably a problem with the virtual machine that I am using to do the development with. If I had it to do over, I would go ahead and install java and eclipse on my main machine.

I am still considering releasing this application and app, but would like to figure out the ad model for the android app.

Here is what the app looks like:

]]>
https://blog.chadweisshaar.com/2012/02/03/practice-log-androidmultiuser-completed/feed/ 1
Practice Log – Android version https://blog.chadweisshaar.com/2012/01/20/practice-log-android-version/ https://blog.chadweisshaar.com/2012/01/20/practice-log-android-version/#comments Fri, 20 Jan 2012 21:59:24 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=68 Continue reading "Practice Log – Android version"]]> I have been using the PracticeLog for a little over a year now and have found it to be very useful. However, there are several features that I never use:

  1. The list of pieces that I am practicing. This would be nice to keep up to date, but even with the “Same as Yesterday” button, I just don’t have the motivation to keep entering the data.
  2. The stopwatch and countdown. I haven’t been practicing in the same room as the computer, so it is not handy to have to turn on the computer both before and after practice time. Instead I have been using a stopwatch on my phone, or just my watch to time the practice and then separately enter the time.

I would like to use my Android phone, which I usually have on me, to record the practice time. To do that, I am going to create a web database and php accessors so that I can load and update practice time from the phone or computer. While doing this conversion, I am going to make a few changes:

  1. Remove the list of pieces practiced per day. It would make the database more complex and I never use the feature.
  2. Make the database multi-user. This will allow me to publish the application and Android app. I am not sure if that will ever happen, but the software has been useful for me, so it might be appreciated by others too.

This will be the first time I have made a multi-user web database, so I am debating how to handle security. I want each user to only have access to their own data, but don’t want the overhead of encrypting all the data.

After my experience with the DurationAlarm application, I suspect that the Android app will take most of the time. But all of the GUI elements that I will need are built in.

]]>
https://blog.chadweisshaar.com/2012/01/20/practice-log-android-version/feed/ 1
Duration Alarm https://blog.chadweisshaar.com/2012/01/15/duration-alarm/ https://blog.chadweisshaar.com/2012/01/15/duration-alarm/#comments Sun, 15 Jan 2012 22:21:40 +0000 http://gator3305.temp.domains/~cweissha/blog/?p=69 Continue reading "Duration Alarm"]]> I have had an Android phone for a while now, and one of the reasons that I picked that particular phone was so that I could create my own applications without going through a central marketplace. Until now, I have never actually done it. The Android marketplace has had all the utilities and apps that I have wanted. But I’ve decided that I want to learn how to write software for Android and there is an app that I have always vaguely wanted and haven’t found.

The app is a duration based alarm. This is a common way to set an alarm for a nap, but I would like to use the same system for an over-night alarm. Since I don’t have a day job, I don’t have to get up at any particular time, but I’d like to limit my sleep to the amount of time I need.

The application is simple enough to be a good problem to learn Android development with.

I have had bad experiences with Java and eclipse in the past, so I’ve decided to do all my Android development in a virtual machine. I used Oracle’s Virtual Box and an old copy of windows XP. While the Virtual Box software is nice (especially since it is free), this took a lot longer than I had expected. I had forgotten how old windows XP is and I spent hours installing updates. Installing eclipse and the android SDK went fairly smoothly and once installed, I was able to hook up my phone and run a sample app through the VM.

The Android SDK documentation is good, and the sample apps provide a lot of examples to follow and I was able to make quick progress on my program. The GUI builder is not bad, but I spent half the time editing the XML directly anyway. The hardest part was the lifecycle. It takes a while to get used to the idea that your program can be killed and re-started with very little notification.

The app took about three days of me working on and off. I was impressed by the Intent system which allowed me to easily use the built in alarm software to handle the alarm part while my app just does alarm scheduling. I was least impressed with the resource ID system and java in general. I have always disliked java and this project reminded me of all the ways that java makes my code ugly and my coding sloppy. There may be a better way to do this, but the default mode for the resource ID system makes all the GUI elements into global variables.

I used the local database to save off the user’s last alarm duration. Once I got used to it, that is a very convenient system. Much like what is built into C#.

I have no plans to put the completed app on the Android Market. It works fine, but I have no desire to test it on other phone models.

]]>
https://blog.chadweisshaar.com/2012/01/15/duration-alarm/feed/ 1