Titanium Nagoya Chatroom Vol. 2

に参加してきました。
http://atnd.org/events/25349:TitaniumNagoyaChatroomVol2
そこで紹介したアプリのコードをとりあえずここに上げときます。

Titanium.UI.setBackgroundColor('#000');

// constants

var consts = {
  IPAddress: Ti.Platform.address,
  ServerPort: 54321,
  BufferSize: 1024 * 64,
  NumberOfImages: 9
};
var funcs = {
  readCallback: null,
  sendPhoto: null,
  sendPhotoTo: null,
  connectTo: null,
  scanServers: null,
  setImageView: null
};
var vars = {
  scanIndex: 0,
  Sockets: {},
  myImageFile: null,
  ImageViews: [],
  ImageViewIndex: 0,
};

// Views

var win = Titanium.UI.createWindow({
  title : 'Photo Exchange',
  backgroundColor : '#fff'
});
var view = Ti.UI.createView({
  width : "100%",
  height : "100%",
  layout : "horizontal",
  backgroundColor : "#eee"
});
win.add(view);

var logarea1 = Ti.UI.createTextArea({
  value : '',
  editable : false,
  font : {
    fontSize : 14
  },
  left : 0,
  top : 0,
  width : 160,
  height : 150
});
var logarea2 = Ti.UI.createTextArea({
  value : '',
  editable : false,
  font : {
    fontSize : 14
  },
  left : 0,
  top : 0,
  width : 160,
  height : 150
});
view.add(logarea1);
view.add(logarea2)
var addToLog1 = function(msg) {
  var text = msg + logarea1.value;
  if(text.length > 1000)
    text = text.substring(0, 1000);
  logarea1.value = text;
};
var addToLog2 = function(msg) {
  var text = msg + logarea2.value;
  if(text.length > 1000)
    text = text.substring(0, 1000);
  logarea2.value = text;
};

var myImageView = Ti.UI.createImageView({
  width : 160,
  height : 120,
  left : 0,
  top : 0,
  backgroundColor : '#888'
});
view.add(myImageView);

var cameraButton = Ti.UI.createButton({
  title : 'camera',
  left : 0,
  top : 40,
  width : 160,
  height : 40
});
view.add(cameraButton);

for (var i = 0; i < consts.NumberOfImages; i ++) {
  var imageView = Ti.UI.createImageView({
    left: 0,
    top: 0,
    width: 154,
    height: 118,
    borderWidth: 1,
    backgroundColor: '#88c'
  });
  vars.ImageViews[i] = imageView;
  view.add(imageView);
}

win.open();

// camera

cameraButton.addEventListener('click', function() {
  Titanium.Media.showCamera({
    success : function(event) {
      var cropRect = event.cropRect;
      var image = event.media;
      myImageView.image = image;
      var myImage = myImageView.toImage();
      var file = Ti.Filesystem.createTempFile(Ti.Filesystem.tempDirectory)
      addToLog1("size:" + file.size + "\n");
      file.write(Ti.Android ? myImage.media : myImage);
      if (file.size > 400)
        vars.myImageFile = file;
      addToLog1("size:" + file.size + " path:" + file.nativePath + "\n");
      funcs.sendPhoto();
    },
    cancel : function() {
    },
    error : function(error) {
    },
    saveToPhotoGallery : false,
    allowEditing : false,
    mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO],
  });
});

// functions

funcs.setImageView = function(image) {
  vars.ImageViews[vars.ImageViewIndex].image = image;
  vars.ImageViewIndex = (vars.ImageViewIndex + 1) % consts.NumberOfImages;
};

funcs.connectTo = function(index) {
  var aa = consts.IPAddress.split(".");
  aa[3] = index;
  var socket = Ti.Network.Socket.createTCP({
    port : consts.ServerPort,
    host : aa.join("."),
    connected : function(e) {
      var cs = e.socket;
      cs.readBuffer = Ti.createBuffer({
        length : consts.BufferSize
      });
      var index = parseInt(cs.host.split(".")[3]);
      vars.Sockets[index] = cs;
      Ti.Stream.read(cs, cs.readBuffer, funcs.readCallback);
      addToLog1("connected to " + index + "\n");
      funcs.sendPhotoTo(index);
    },
    error : function(e) {
      var index = parseInt(e.socket.host.split(".")[3]);
      vars.Sockets[index] = null;
      addToLog2(" " + index);
    }
  });
  socket.connect();
};

funcs.sendPhotoTo = function(index) {
  if (!vars.myImageFile)
    return;
  var socket = vars.Sockets[index];
  if (!socket)
    return;
  addToLog2(" " + socket + "index");
  if (socket.state != Ti.Network.Socket.CONNECTED) {
    vars.Sockets[index] = null;
    return;
  }

  addToLog1("send to " + socket.host + "\n");
  var img = vars.myImageFile.read();
  var stream = Ti.Stream.createStream({
    mode : Ti.Stream.MODE_READ,
    source : img
  });
  var len = img.length;
  var header = Ti.createBuffer({length: 4});
  Ti.Codec.encodeNumber({
    source: len,
    position: 0,
    dest: header,
    type: Ti.Codec.TYPE_INT,
    byteOrder: Ti.Codec.BIG_ENDIAN
  })
  var footer = Ti.createBuffer({
    length : consts.BufferSize - len - 4
  });
  addToLog1("photo sending size " + len + "\n");
  socket.write(header);
  Ti.Stream.writeStream(stream, socket, len);
  socket.write(footer);
  addToLog1("photo sent size " + len + "\n");
};

funcs.sendPhoto = function() {
  for(var i = 1; i <= 254; i++)
    funcs.sendPhotoTo(i);
};

// read from socket

funcs.readCallback = function(e) {
  addToLog1("readCallback()\n");
  var socket = e.source;
  var plen = e.bytesProcessed;
  if (plen < 0) {
    var index = parseInt(socket.host.split(".")[3]);
    vars.Sockets[index] = null;
    return;
  }
  addToLog1("read bytes " + plen + "\n");
  if (!socket.inputCache) {
    socket.inputCache = Ti.createBuffer({
      length : consts.BufferSize
    });
    socket.inputIndex = 0;
  }
  var index = 0;
  while (index < plen && socket.inputIndex < consts.BufferSize)
    socket.inputCache[socket.inputIndex++] = socket.readBuffer[index++];
  if (socket.inputIndex == consts.BufferSize) {
    var len = Ti.Codec.decodeNumber({
      source: socket.inputCache,
      position: 0,
      type: Ti.Codec.TYPE_INT,
      byteOrder: Ti.Codec.BIG_ENDIAN
    });
    var imgbuf = socket.inputCache.clone(4, len);
    var image = imgbuf.toBlob();
    funcs.setImageView(image);
    socket.inputIndex = 0;
  }
  while (index < plen)
    socket.inputCache[socket.inputIndex++] = socket.readBuffer[index++];
  addToLog1("cached bytes " + socket.inputIndex + "\n");
  Ti.Stream.read(socket, socket.readBuffer, funcs.readCallback);
};

// listen socket

var listen = Ti.Network.Socket.createTCP({
  port : consts.ServerPort,
  listenQueueSize: 20,
  accepted : function(e) {
    addToLog1("accepted " + e.socket + "\n");
    var asocket = e.inbound;
    asocket.readBuffer = Ti.createBuffer({
      length : consts.BufferSize
    });
    Ti.Stream.read(asocket, asocket.readBuffer, funcs.readCallback);
    var index = parseInt(asocket.host.split(".")[3]);
    vars.Sockets[index] = asocket;
    addToLog1("connect from " + index + "\n");
    funcs.sendPhotoTo(index);
  },
  error : function(e) {
    addToLog1(">> error " + e.error + "\n");
  }
});
listen.listen();
addToLog1(">> listening " + consts.IPAddress + "\n");
listen.accept({});

// scan server

funcs.scanServers = function() {
  vars.scanIndex += 1;
  if (vars.scanIndex >= 254)
    vars.scanIndex = 1;
  if (!vars.Sockets[vars.scanIndex] || 
    vars.Sockets[vars.scanIndex].state != Ti.Network.Socket.CONNECTED) {
    var aa = consts.IPAddress.split(".");
    if(aa[3] != vars.scanIndex)
      funcs.connectTo(vars.scanIndex);
  }
  setTimeout(funcs.scanServers, 235);
};

setTimeout(funcs.scanServers, 1000);

iPhone3Gにbmobile 3GのSIMを刺してテザリング

まぁ代金もとっくに支払ったことだしと思って、寝かしてたiPhone 3Gjailbreakして復活させました。CydiaからTetherMeをインストールして、Bluetooth PANテザリングするのが目的です。
ひとりぶろぐさんで配布されているMacBookの液晶開閉に同期してBluetooth PANを接続切断するLidSyncPAN人柱版を使うと、Macbook Airの蓋のあけしめとBluetooth PANが連動します。さらにBluetoothは待ち受けの消費電力が少ないので、iPhone 3Gでも余裕で一日待ち受けしてくれます。これで、Macbook Airに3G通信が搭載されているのと同じ気分。moyashiさんありがとー。ちなみにAndroidBluetooth PAN経由テザリングでも同じ使い勝手なのを確認してます。Bluetoothh再評価です。
で、今時bmobile 3GのSIMです。U300じゃないです。イオンのSIMでもなければ、bmoile FairのSIMでもありません。bモバイル3G商品詳細(b-mobile3G)|日本通信株式会社プリペイドで買いやすくて、ちょこっと使うんなら安いんですが、時間課金なのでパケット流れてなくても繋いだままだとどんどん残り時間が減っていってしまいます。iPhone 3GにもAPN設定して放っておいたら、まぁ、みるみるぐんぐん減るわ減るわ。これじゃもったいない。
このiPhone 3Gはバッグに入れっぱなしでモデム代わりに使うつもりなので、Bluetooth PANのときだけ繋いでくれないかなーと思う訳です。これでやっと本題。できたっぽいので、その設定を。
先ずbmobile 3GのAPNを入れて、TetherMeとかからテザリングを有効にします。TetherMeの設定画面のAPN Selectionの「Automatic」と「useDataAPN」を両方ともオフに。なんか文句言うダイアログ出ますが続行。このまま放っておくとどんどん残り時間を消費します。
TetherMeの設定から「モバイルデータ通信」を選んで下の方に「インターネットテザリグ」って項目があって、ここにもAPNとかを設定できますのでbmobileの設定を入れちゃいましょう。この状態で、このページのトップの「モバイルデータ通信」の方のAPNはそのままで、ユーザ名とパスワードだけちょこっと変えて繋がらなくします。私の場合、APNも変えちゃたらSIMでのデータ通信ができないと判断されたのか、テザリングもできなくなってしまいましたのでご注意を。
さて、この状態で、iPhone 3G単体ではbmobile 3G通信を使わないけど、テザリングの時だけbmobile 3Gで繋がっちゃうという設定になったと思います。というか、私はこれでなったみたいです。もし真似される方がいらしたら、ちゃんとbmobileのページで、テザリング使ってもいないのでぐんぐん残り時間が減っていってないか確認して下さいね。

絶望先生

「普通に授業中に工作活動する先生とかいますもんねぇ」
「どれだけ絵をつけないで声優さんが声を宛てられるか」
「どれだけ売れれば四期があるのだろう」次も楽しみにしています。
化物語>>>>>>>>>>>>(こえられない壁)」