Bluescan
Code: bluescan.pde Download: bluescan.jad bluescan.jar Obfuscated: bluescan.jad bluescan.jar |
// Bluescan
// by Francis Li
// http://www.francisli.com/
//
// inspired by
//
// Jabberwocky
// by Intel Research Berkeley
// http://www.urban-atmospheres.net/Jabberwocky/index.htm
//
// Posted January 2, 2006
//
// Bluescan discovers nearby bluetooth devices and represents them on the screen
// as a cellphone icon (even though they may be PCs or other devices). As they are discovered,
// they appear at the top of the screen, then slowly drift down until they disappear at the bottom.
// Newly discovered devices are red, devices you've encountered before are green. The more times
// you encounter a device, the bigger the icon will be.
//
import processing.bluetooth.*;
final String SOFTKEY_DISCOVER = "Discover";
final String SOFTKEY_CANCEL = "Cancel";
PFont font;
Bluetooth bt;
boolean discovering;
CellphoneIcon[] icons;
int numIcons;
int selected;
Record[] records;
int numRecords;
int prev;
void setup() {
//// get and set the default system font
font = loadFont();
textFont(font);
//// instantiate a new bluetooth object
bt = new Bluetooth(this);
//// initialize the records array to a default size
records = new Record[8];
numRecords = 0;
//// initialize the icons array to a default size
icons = new CellphoneIcon[8];
numIcons = 0;
//// set up a command softkey to start discovery process
softkey(SOFTKEY_DISCOVER);
//// cap framerate
framerate(20);
//// align everything center
textAlign(CENTER);
//// load previously saved records
String[] savedRecords = loadStrings("records.txt");
int numSaved = savedRecords.length;
Record r;
for (int i = 0; i < numSaved; i++) {
r = new Record(savedRecords[i]);
addRecord(r);
}
}
void destroy() {
//// before the midlet is destroyed, save records
String[] savedRecords = new String[numRecords];
for (int i = 0; i < numRecords; i++) {
savedRecords[i] = records[i].toString();
}
saveStrings("records.txt", savedRecords);
}
void draw() {
//// set a nice blue sea background
background(0xff0099ff);
//// update frame timing
int current = millis();
int elapsed = current - prev;
prev = current;
//// move icons based on elapsed time
for (int i = 0; i < numIcons; i++) {
icons[i].move(elapsed);
if (icons[i].ty >= (height - icons[i].height() / 2)) {
icons[i].tscale_fp = 0;
}
}
//// if icons have reached the bottom, remove them from the array
for (int i = numIcons - 1; i >= 0; i--) {
if (icons[i].scale_fp == 0) {
icons[i] = null;
arraycopy(icons, i + 1, icons, i, numIcons - i - 1);
numIcons--;
selected--;
}
}
if (selected < 0) {
selected = 0;
}
//// draw the icons
for (int i = 0; i < numIcons; i++) {
icons[i].draw();
}
//// draw name of current selection
if (selected < numIcons) {
Record r = icons[selected].r;
//// draw the name under the icon
if (r.name == Device.UNKNOWN) {
//// if the record name is unknown, check the device to see if it has
//// been updated in the background discovery process
r.name = r.device.name;
}
int width = textWidth(r.name);
stroke(0);
fill(255);
rect(icons[selected].x - width / 2 - 2, icons[selected].y + icons[selected].height() / 2, width + 4, font.height + 4);
fill(0);
text(r.name, icons[selected].x, icons[selected].y + icons[selected].height() / 2 + font.baseline + 2);
}
//// draw the current number of visible devices
text(str(numIcons), width / 2, height);
}
void keyPressed() {
if (key == '5') {
//// testing animation on the emulator, just puts a dummy device/icon on the screen
Record r = new Record();
r.name = "Test";
r.count = random(5);
addIcon(r);
} else if (keyCode == LEFT) {
//// update selection
if (numIcons > 0) {
selected = (selected - 1 + numIcons) % numIcons;
}
} else if (keyCode == RIGHT) {
//// update selection
if (numIcons > 0) {
selected = (selected + 1) % numIcons;
}
}
}
void softkeyPressed(String label) {
if (label.equals(SOFTKEY_DISCOVER)) {
//// start discovery process
discovering = true;
bt.discover();
softkey(SOFTKEY_CANCEL);
} else if (label.equals(SOFTKEY_CANCEL)) {
//// cancel discovery process
discovering = false;
bt.cancel();
softkey(SOFTKEY_DISCOVER);
}
}
void libraryEvent(Object library, int event, Object data) {
if (library == bt) {
switch (event) {
case Bluetooth.EVENT_DISCOVER_DEVICE:
//// new device discovered!
Device d = (Device) data;
Record r = null;
String address = d.address;
boolean found = false;
//// first, look for it in existing records list
for (int i = 0; i < numRecords; i++) {
if (records[i].address.equals(address)) {
/// found! update count and last encounter time
r = records[i];
r.count++;
//// a bit of a hack to get an absolute system time (unlike millis() which is relative to app start)
r.last = (int) (System.currentTimeMillis() / 1000);
r.device = d;
found = true;
break;
}
}
if (found) {
found = false;
//// see if it is currently on screen
for (int i = 0; i < numIcons; i++) {
if (icons[i].r == r) {
icons[i].tx = icons[i].height() / 2;
found = true;
break;
}
}
if (!found) {
//// put it on screen!
addIcon(r);
}
} else {
//// not found, so create a new record
r = new Record();
r.name = d.name;
r.address = d.address;
r.count = 1;
r.last = (int) (System.currentTimeMillis() / 1000);
r.device = d;
addRecord(r);
addIcon(r);
}
break;
case Bluetooth.EVENT_DISCOVER_DEVICE_COMPLETED:
//// done, reset command key and state
discovering = false;
softkey(SOFTKEY_DISCOVER);
break;
}
}
}
//// adds a record to the array, expanding it if necessary
void addRecord(Record r) {
records[numRecords] = r;
numRecords++;
if (numRecords == records.length) {
Record[] oldRecords = records;
records = new Record[2 * numRecords];
arraycopy(oldRecords, 0, records, 0, numRecords);
}
}
//// puts an icon on the screen
void addIcon(Record r) {
CellphoneIcon i = new CellphoneIcon();
i.r = r;
i.tscale_fp = (3 + r.count) * ONE / 4;
i.x = i.tx = 10 + random(width - 20);
i.y = i.ty = i.height() / 2;
icons[numIcons] = i;
numIcons++;
if (numIcons == icons.length) {
CellphoneIcon[] oldIcons = icons;
icons = new CellphoneIcon[2 * numIcons];
arraycopy(oldIcons, 0, icons, 0, numIcons);
}
}
//// a data structure to store device info, and to read/write it from strings
class Record {
String name;
String address;
int count;
int last;
Device device;
public Record() {
}
public Record(String savedRecord) {
String[] parts = split(savedRecord, ",");
name = parts[0];
address = parts[1];
count = int(parts[2]);
last = int(parts[3]);
}
String toString() {
return name + "," + address + "," + count + "," + last;
}
}
//// a data structure to store icon info, as well as render it to screen
class CellphoneIcon {
/** Reference to device history record object */
Record r;
/** the actual x, y location on the screen */
int x, y;
/** the actual scale of the icon on the screen */
int scale_fp;
/** accumulated distance */
int dx_fp, dy_fp;
/** the target x, y, and scale */
int tx, ty, tscale_fp;
/** accumulated distance of target motion */
int dty_fp;
/** x, y velocities */
int vx_fp, vy_fp;
int width() {
return fptoi(tscale_fp * 12);
}
int height() {
return fptoi(tscale_fp * 30);
}
void move(int elapsed) {
//// quickly reach target scale
int dscale_fp = (tscale_fp - scale_fp) / 2;
if (dscale_fp == 0) {
scale_fp = tscale_fp;
} else {
scale_fp += dscale_fp;
}
//// target y moves downward at constant velocity
dty_fp += elapsed * itofp(8) / 1000;
if (dty_fp > ONE) {
ty += fptoi(floor(dty_fp));
dty_fp = dty_fp - floor(dty_fp);
}
//// target x randomly shifts
tx += random(-2, 2);
if (tx < 10) {
tx = 10;
} else if (tx > (width - 10)) {
tx = width - 10;
}
//// icon accelerates towards target
vy_fp += (ty - y) * itofp(2) * elapsed / 1000;
if (vy_fp > itofp(16)) {
vy_fp = itofp(16);
} else if (vy_fp < -itofp(16)) {
vy_fp = -itofp(16);
}
dy_fp += elapsed * vy_fp / 1000;
if ((dy_fp > ONE) || (dy_fp < -ONE)) {
y += fptoi(floor(dy_fp));
dy_fp = dy_fp - floor(dy_fp);
}
vx_fp += (tx - x) * itofp(2) * elapsed / 1000;
if (vx_fp > itofp(16)) {
vx_fp = itofp(16);
} else if (vx_fp < -itofp(16)) {
vx_fp = -itofp(16);
}
dx_fp += elapsed * vx_fp / 1000;
if ((dx_fp > ONE) || (dx_fp < -ONE)) {
x += fptoi(floor(dx_fp));
dx_fp = dx_fp - floor(dx_fp);
}
}
void draw() {
noStroke();
if (r.count > 1) {
fill(0xff00ff00);
} else {
fill(0xffff0000);
}
//// antenna
rect(x - fptoi(scale_fp * 12) / 2 + fptoi(scale_fp * 12) - fptoi(scale_fp * 3), y - fptoi(scale_fp * 25) / 2 - fptoi(scale_fp * 5), fptoi(scale_fp * 3), fptoi(scale_fp * 5));
//// body
rect(x - fptoi(scale_fp * 12) / 2, y - fptoi(scale_fp * 25) / 2, fptoi(scale_fp * 12), fptoi(scale_fp * 25));
//// screen
fill(230);
rect(x - fptoi(scale_fp * 12) / 2 + fptoi(scale_fp * 2), y - fptoi(scale_fp * 25) / 2 + fptoi(scale_fp * 2), fptoi(scale_fp * 12) - 2 * fptoi(scale_fp * 2), fptoi(scale_fp * 8));
}
}
|