#include <cstdlib> #include <iostream> class FPSample { public: void function_switch(int sw) { switch (sw) { case 1: m_pFunctionSample = &FPSample::function1; break; case 2: m_pFunctionSample = &FPSample::function2; break; default: std::cout << "default" << std::endl; } } bool function(int x) { return (this->*m_pFunctionSample)(x); // return (*mFunctionSample)(x); // Error } private: typedef bool (FPSample::*FUNCTION_SAMPLE)(int); FUNCTION_SAMPLE m_pFunctionSample; bool function1(int x) { std::cout << "function1 : " << x << std::endl; return true; } bool function2(int x) { std::cout << "function2 : " << x << std::endl; return false; } }; int main(int argc, char** argv) { FPSample mFPSample; int sw; int x; x = 10; sw = 1; mFPSample.function_switch(sw); mFPSample.function(x); sw = 2; mFPSample.function_switch(sw); mFPSample.function(x); return 0; }
2010年6月18日金曜日
忘れがちなC++での関数ポインタ
クラス内部で状態によって呼ぶ出す関数を変えるときには関数ポインタを使うと便利ですが、C++では書き方が若干面倒なので、その記録。
2010年6月14日月曜日
たまには使えるアプリ
Wifiの受信レベルを測定し、それをグラフにするアプリです。
package jp.ac.uu.is.degas.android.wifi;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class WifiViewActicvity extends Activity {
private static final int MENU_START = 0;
private static final int MENU_PAUSE = 1;
private static final int MENU_QUIT = 2;
private MySurfaceView mySurfaceView;
private WifiManager mWifiManager;
private boolean run;
private static final float MIN_LEVEL = -120;
private static final float MAX_LEVEL = 0;
private static final int TIME_BUFFDER_SIZE = 50;
private HashMap apMap;
private long cnt;
private int[] lineColor = { Color.BLUE, Color.CYAN, Color.GREEN,
Color.MAGENTA, Color.RED, Color.YELLOW, Color.WHITE };
private int indexOfColor;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mySurfaceView = new MySurfaceView(getApplication(), 0,
TIME_BUFFDER_SIZE, MIN_LEVEL, MAX_LEVEL, TIME_BUFFDER_SIZE,
(int) ((MAX_LEVEL - MIN_LEVEL) / 10));
setContentView(mySurfaceView);
apMap = new HashMap();
run = false;
cnt = 0;
indexOfColor = 0;
}
private void startScan() {
run = true;
mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
registerReceiver(mBroadcastReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
}
private void pauseScan() {
run = false;
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List scanResults = mWifiManager.getScanResults();
for (ScanResult result : scanResults) {
String bssid = result.BSSID;
int level = result.level;
AccessPoint ap = apMap.get(bssid);
if (ap == null) {
ap = new AccessPoint(TIME_BUFFDER_SIZE + 1);
ap.setColor(lineColor[indexOfColor]);
indexOfColor++;
indexOfColor %= lineColor.length;
}
ap.setLevel(cnt, Float.valueOf(level));
ap.setUpdate(true);
apMap.put(bssid, ap);
}
for (Map.Entry e : apMap.entrySet()) {
AccessPoint ap = e.getValue();
if (!ap.isUpdate()) {
ap.setLevel(cnt, null);
}
ap.setUpdate(false);
apMap.put(e.getKey(), ap);
}
if (run) {
mySurfaceView.setData(cnt, apMap);
cnt++;
startScan();
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_START, 0, "START").setIcon(
android.R.drawable.ic_media_play);
menu.add(0, MENU_PAUSE, 0, "PAUSE").setIcon(
android.R.drawable.ic_media_pause);
menu.add(0, MENU_QUIT, 0, "QUIT").setIcon(
android.R.drawable.ic_menu_close_clear_cancel);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_START:
startScan();
break;
case MENU_PAUSE:
pauseScan();
break;
case MENU_QUIT:
finish();
break;
}
return super.onContextItemSelected(item);
}
}
class AccessPoint {
private Float[] data;
private boolean update;
private int color;
AccessPoint(int size) {
data = new Float[size];
}
void setLevel(long cnt, Float level) {
data[(int) (cnt % data.length)] = level;
}
void setUpdate(boolean update) {
this.update = update;
}
boolean isUpdate() {
return update;
}
void setColor(int color) {
this.color = color;
}
int getColor() {
return color;
}
Float[] getData() {
return data;
}
}
class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,
Runnable {
private SurfaceHolder mSurfaceHolder;
private Thread thread;
private Canvas canvas;
private MyGraph myGraph;
private float minX, maxX, minY, maxY;
private int numDivX, numDivY;
private long cnt;
private HashMap apMap = new HashMap();
MySurfaceView(Context context, float minX, float maxX, float minY,
float maxY, int numDivX, int numDivY) {
super(context);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
myGraph = new MyGraph();
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
this.numDivX = numDivX;
this.numDivY = numDivY;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
thread = new Thread(this);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
thread = null;
}
public void run() {
while (thread != null) {
canvas = mSurfaceHolder.lockCanvas();
myGraph.drawRule(canvas);
String[] bssidName = new String[apMap.size()];
int[] bssidColor = new int[apMap.size()];
int num = 0;
for (Map.Entry e : apMap.entrySet()) {
AccessPoint ap = e.getValue();
Float[] originalData = ap.getData();
int size = originalData.length;
Float[] data = new Float[2 * size];
for (int i = 0; i < size; i++) {
data[2 * i] = Float.valueOf(i);
data[2 * i + 1] = (cnt < size) ? originalData[i]
: originalData[(int) ((i + cnt + 1) % size)];
}
myGraph.drawLines(canvas, data, ap.getColor());
bssidName[num] = e.getKey();
bssidColor[num] = ap.getColor();
num++;
}
if (apMap.size() > 0) {
myGraph.drawLegend(canvas, bssidName, bssidColor);
}
mSurfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
@Override
protected void onSizeChanged(int width, int heigh, int old_w, int old_h) {
int size = (width < heigh) ? width : heigh;
myGraph.setDarwArea(size, size, minX, maxX, minY, maxY, numDivX,
numDivY, false, true);
}
void setData(long cnt, HashMap apMap) {
this.cnt = cnt;
this.apMap = apMap;
}
}
class MyGraph {
private static final float TOP_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する上マージンの比
private static final float BOTTOM_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する下マージンの比
private static final float LEFT_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する左マージンの比
private static final float RIGHT_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する右マージンの比
private boolean labelFlagX; // X軸ラベル表示フラグ
private boolean labelFlagY; // Y軸ラベル表示フラグ
private Paint paintLabel = new Paint();
private float bodyW; // ラベルを含むグラフエリア
private float bodyH; // ラベルを含むグラフエリア
private float graphW; // ラベルを含まないグラフエリア
private float graphH; // ラベルを含まないグラフエリア
private float graphOriginX; // ラベルを含まないグラフエリアの原点
private float graphOriginY; // ラベルを含まないグラフエリアの原点
private float minX, maxX, minY, maxY;
private int numDivX, numDivY;
private float legendOriginX; // 凡例原点
private float legendOriginY; // 凡例原点
private Paint legendLabel = new Paint();
void setDarwArea(float drawW, float drawH, float xMin, float xMax,
float yMin, float yMax, int xDivNum, int yDivNum,
boolean labelXFlag, boolean labelYFlag) {
this.minX = xMin;
this.maxX = xMax;
this.minY = yMin;
this.maxY = yMax;
this.numDivX = xDivNum;
this.numDivY = yDivNum;
this.labelFlagX = labelXFlag;
this.labelFlagY = labelYFlag;
// ラベルを含むグラフエリア
bodyW = (1 - LEFT_MARGIN_RATIO - RIGHT_MARGIN_RATIO) * drawW;
bodyH = (1 - TOP_MARGIN_RATIO - BOTTOM_MARGIN_RATIO) * drawH;
// ラベルを含まないグラフエリア
FontMetrics fontMetrics = paintLabel.getFontMetrics();
graphH = bodyH;
if (labelXFlag) {
graphH += (fontMetrics.top + fontMetrics.bottom);
}
graphW = bodyW;
if (labelYFlag) {
float maxTextWidth = 0;
for (int i = 0; i < yDivNum + 1; i++) {
String text = String
.valueOf(yMin + i * (yMax - yMin) / yDivNum);
float baseX = paintLabel.measureText(text); // テキスト幅
maxTextWidth = (baseX > maxTextWidth) ? baseX : maxTextWidth;
}
graphW -= maxTextWidth;
}
// ラベルを含まないグラフエリアの原点
graphOriginX = LEFT_MARGIN_RATIO * drawW + (bodyW - graphW);
graphOriginY = TOP_MARGIN_RATIO * drawH;
// 凡例原点
legendOriginX = graphOriginX + 0.05f * graphW;
legendOriginY = graphOriginY + 0.05f * graphH;
}
/* グラフの罫線、軸描画 */
void drawRule(Canvas canvas) {
// 背景色
canvas.drawColor(Color.WHITE);
// 罫線
Paint paintRule = new Paint();
paintRule.setStyle(Paint.Style.FILL);
paintRule.setColor(Color.BLACK);
for (int i = 0; i < numDivX + 1; i++) {
canvas.drawLine(graphOriginX + i * (graphW / numDivX),
graphOriginY, graphOriginX + i * (graphW / numDivX),
graphOriginY + graphH, paintRule);
}
for (int i = 0; i < numDivY + 1; i++) {
canvas.drawLine(graphOriginX,
graphOriginY + i * (graphH / numDivY), graphOriginX
+ graphW, graphOriginY + i * (graphH / numDivY),
paintRule);
}
// 軸ラベル
paintLabel.setColor(Color.GRAY);
FontMetrics fontMetrics = paintLabel.getFontMetrics();
if (labelFlagX) {
for (int i = 0; i < numDivX + 1; i++) {
String text = String
.valueOf(minX + i * (maxX - minX) / numDivX);
float baseX = paintRule.measureText(text) / 2; // テキスト幅の半分
float baseY = -fontMetrics.top; // baselineからtopまでの高さ
canvas.drawText(text, graphOriginX + i * (graphW / numDivX)
- baseX, graphOriginY + graphH + baseY, paintLabel);
}
}
if (labelFlagY) {
for (int i = 0; i < numDivY + 1; i++) {
String text = String
.valueOf(minY + i * (maxY - minY) / numDivY);
float baseX = paintLabel.measureText(text); // テキスト幅
float baseY = -fontMetrics.top / 2; // baselineからtopまでの高さの半分
canvas.drawText(text, graphOriginX - baseX, graphOriginY
+ graphH - i * (graphH / numDivY) + baseY, paintLabel);
}
}
}
void drawLines(Canvas canvas, Float[] data, int color) {
// 境界チェック
for (int i = 0; i < data.length / 2; i++) {
if (data[2 * i] != null && data[2 * i + 1] != null) {
data[2 * i] = (data[2 * i] < minX) ? minX : data[2 * i];
data[2 * i] = (data[2 * i] > maxX) ? maxX : data[2 * i];
data[2 * i + 1] = (data[2 * i + 1] < minY) ? minY
: data[2 * i + 1];
data[2 * i + 1] = (data[2 * i + 1] > maxY) ? maxY
: data[2 * i + 1];
}
}
float[] pts = new float[4 * (data.length / 2 - 1)];
// 描画座標へ変換
float pxlParUnitX = graphW / (maxX - minX); // X軸の単位辺りの画素値数
float pxlParUnitY = graphH / (maxY - minY); // Y軸の単位辺りの画素値数
for (int i = 0; i < data.length / 2 - 1; i++) {
if (data[2 * i] != null && data[2 * i + 1] != null
&& data[2 * i + 2] != null && data[2 * i + 3] != null) {
float x1 = data[2 * i];
float y1 = data[2 * i + 1];
float x2 = data[2 * i + 2];
float y2 = data[2 * i + 3];
pts[4 * i] = (x1 - minX) * pxlParUnitX + graphOriginX;
pts[4 * i + 1] = graphH - (y1 - minY) * pxlParUnitY
+ graphOriginY;
pts[4 * i + 2] = (x2 - minX) * pxlParUnitX + graphOriginX;
pts[4 * i + 3] = graphH - (y2 - minY) * pxlParUnitY
+ graphOriginY;
}
}
Paint paint = new Paint();
paint.setColor(color); // 線の色
paint.setStrokeWidth(2); // 線の太さ
canvas.drawLines(pts, paint);
}
void drawLegend(Canvas canvas, String[] name, int[] color) {
Paint paint = new Paint();
float lineLength = 0.05f * graphW;
FontMetrics fontMetrics = legendLabel.getFontMetrics();
float width;
float textW = 0;
for (int i = 0; i < name.length; i++) {
width = legendLabel.measureText(name[i]);
textW = (width > textW) ? width : textW;
}
float textH = -fontMetrics.top + fontMetrics.bottom;
float legendH = name.length * textH + fontMetrics.bottom;
float legendW = textW + lineLength;
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(legendOriginX, legendOriginY, legendOriginX + legendW,
legendOriginY + legendH, paint);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(legendOriginX, legendOriginY, legendOriginX + legendW,
legendOriginY + legendH, paint);
float x, y;
x = legendOriginX;
y = legendOriginY + textH;
for (int i = 0; i < name.length; i++) {
paint.setColor(color[i]);
paint.setStrokeWidth(2);
canvas.drawLine(x, y + fontMetrics.top / 2, x + lineLength, y
+ fontMetrics.top / 2, paint);
paint.setColor(Color.BLACK);
canvas.drawText(name[i], x + lineLength, y, legendLabel);
y += textH;
}
}
}
package jp.ac.uu.is.degas.android.wifi;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class WifiViewActicvity extends Activity {
private static final int MENU_START = 0;
private static final int MENU_PAUSE = 1;
private static final int MENU_QUIT = 2;
private MySurfaceView mySurfaceView;
private WifiManager mWifiManager;
private boolean run;
private static final float MIN_LEVEL = -120;
private static final float MAX_LEVEL = 0;
private static final int TIME_BUFFDER_SIZE = 50;
private HashMap
private long cnt;
private int[] lineColor = { Color.BLUE, Color.CYAN, Color.GREEN,
Color.MAGENTA, Color.RED, Color.YELLOW, Color.WHITE };
private int indexOfColor;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mySurfaceView = new MySurfaceView(getApplication(), 0,
TIME_BUFFDER_SIZE, MIN_LEVEL, MAX_LEVEL, TIME_BUFFDER_SIZE,
(int) ((MAX_LEVEL - MIN_LEVEL) / 10));
setContentView(mySurfaceView);
apMap = new HashMap
run = false;
cnt = 0;
indexOfColor = 0;
}
private void startScan() {
run = true;
mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
registerReceiver(mBroadcastReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
}
private void pauseScan() {
run = false;
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List
for (ScanResult result : scanResults) {
String bssid = result.BSSID;
int level = result.level;
AccessPoint ap = apMap.get(bssid);
if (ap == null) {
ap = new AccessPoint(TIME_BUFFDER_SIZE + 1);
ap.setColor(lineColor[indexOfColor]);
indexOfColor++;
indexOfColor %= lineColor.length;
}
ap.setLevel(cnt, Float.valueOf(level));
ap.setUpdate(true);
apMap.put(bssid, ap);
}
for (Map.Entry
AccessPoint ap = e.getValue();
if (!ap.isUpdate()) {
ap.setLevel(cnt, null);
}
ap.setUpdate(false);
apMap.put(e.getKey(), ap);
}
if (run) {
mySurfaceView.setData(cnt, apMap);
cnt++;
startScan();
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_START, 0, "START").setIcon(
android.R.drawable.ic_media_play);
menu.add(0, MENU_PAUSE, 0, "PAUSE").setIcon(
android.R.drawable.ic_media_pause);
menu.add(0, MENU_QUIT, 0, "QUIT").setIcon(
android.R.drawable.ic_menu_close_clear_cancel);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_START:
startScan();
break;
case MENU_PAUSE:
pauseScan();
break;
case MENU_QUIT:
finish();
break;
}
return super.onContextItemSelected(item);
}
}
class AccessPoint {
private Float[] data;
private boolean update;
private int color;
AccessPoint(int size) {
data = new Float[size];
}
void setLevel(long cnt, Float level) {
data[(int) (cnt % data.length)] = level;
}
void setUpdate(boolean update) {
this.update = update;
}
boolean isUpdate() {
return update;
}
void setColor(int color) {
this.color = color;
}
int getColor() {
return color;
}
Float[] getData() {
return data;
}
}
class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,
Runnable {
private SurfaceHolder mSurfaceHolder;
private Thread thread;
private Canvas canvas;
private MyGraph myGraph;
private float minX, maxX, minY, maxY;
private int numDivX, numDivY;
private long cnt;
private HashMap
MySurfaceView(Context context, float minX, float maxX, float minY,
float maxY, int numDivX, int numDivY) {
super(context);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
myGraph = new MyGraph();
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
this.numDivX = numDivX;
this.numDivY = numDivY;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
thread = new Thread(this);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
thread = null;
}
public void run() {
while (thread != null) {
canvas = mSurfaceHolder.lockCanvas();
myGraph.drawRule(canvas);
String[] bssidName = new String[apMap.size()];
int[] bssidColor = new int[apMap.size()];
int num = 0;
for (Map.Entry
AccessPoint ap = e.getValue();
Float[] originalData = ap.getData();
int size = originalData.length;
Float[] data = new Float[2 * size];
for (int i = 0; i < size; i++) {
data[2 * i] = Float.valueOf(i);
data[2 * i + 1] = (cnt < size) ? originalData[i]
: originalData[(int) ((i + cnt + 1) % size)];
}
myGraph.drawLines(canvas, data, ap.getColor());
bssidName[num] = e.getKey();
bssidColor[num] = ap.getColor();
num++;
}
if (apMap.size() > 0) {
myGraph.drawLegend(canvas, bssidName, bssidColor);
}
mSurfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
@Override
protected void onSizeChanged(int width, int heigh, int old_w, int old_h) {
int size = (width < heigh) ? width : heigh;
myGraph.setDarwArea(size, size, minX, maxX, minY, maxY, numDivX,
numDivY, false, true);
}
void setData(long cnt, HashMap
this.cnt = cnt;
this.apMap = apMap;
}
}
class MyGraph {
private static final float TOP_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する上マージンの比
private static final float BOTTOM_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する下マージンの比
private static final float LEFT_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する左マージンの比
private static final float RIGHT_MARGIN_RATIO = 0.05f; // 描画エリアサイズに対する右マージンの比
private boolean labelFlagX; // X軸ラベル表示フラグ
private boolean labelFlagY; // Y軸ラベル表示フラグ
private Paint paintLabel = new Paint();
private float bodyW; // ラベルを含むグラフエリア
private float bodyH; // ラベルを含むグラフエリア
private float graphW; // ラベルを含まないグラフエリア
private float graphH; // ラベルを含まないグラフエリア
private float graphOriginX; // ラベルを含まないグラフエリアの原点
private float graphOriginY; // ラベルを含まないグラフエリアの原点
private float minX, maxX, minY, maxY;
private int numDivX, numDivY;
private float legendOriginX; // 凡例原点
private float legendOriginY; // 凡例原点
private Paint legendLabel = new Paint();
void setDarwArea(float drawW, float drawH, float xMin, float xMax,
float yMin, float yMax, int xDivNum, int yDivNum,
boolean labelXFlag, boolean labelYFlag) {
this.minX = xMin;
this.maxX = xMax;
this.minY = yMin;
this.maxY = yMax;
this.numDivX = xDivNum;
this.numDivY = yDivNum;
this.labelFlagX = labelXFlag;
this.labelFlagY = labelYFlag;
// ラベルを含むグラフエリア
bodyW = (1 - LEFT_MARGIN_RATIO - RIGHT_MARGIN_RATIO) * drawW;
bodyH = (1 - TOP_MARGIN_RATIO - BOTTOM_MARGIN_RATIO) * drawH;
// ラベルを含まないグラフエリア
FontMetrics fontMetrics = paintLabel.getFontMetrics();
graphH = bodyH;
if (labelXFlag) {
graphH += (fontMetrics.top + fontMetrics.bottom);
}
graphW = bodyW;
if (labelYFlag) {
float maxTextWidth = 0;
for (int i = 0; i < yDivNum + 1; i++) {
String text = String
.valueOf(yMin + i * (yMax - yMin) / yDivNum);
float baseX = paintLabel.measureText(text); // テキスト幅
maxTextWidth = (baseX > maxTextWidth) ? baseX : maxTextWidth;
}
graphW -= maxTextWidth;
}
// ラベルを含まないグラフエリアの原点
graphOriginX = LEFT_MARGIN_RATIO * drawW + (bodyW - graphW);
graphOriginY = TOP_MARGIN_RATIO * drawH;
// 凡例原点
legendOriginX = graphOriginX + 0.05f * graphW;
legendOriginY = graphOriginY + 0.05f * graphH;
}
/* グラフの罫線、軸描画 */
void drawRule(Canvas canvas) {
// 背景色
canvas.drawColor(Color.WHITE);
// 罫線
Paint paintRule = new Paint();
paintRule.setStyle(Paint.Style.FILL);
paintRule.setColor(Color.BLACK);
for (int i = 0; i < numDivX + 1; i++) {
canvas.drawLine(graphOriginX + i * (graphW / numDivX),
graphOriginY, graphOriginX + i * (graphW / numDivX),
graphOriginY + graphH, paintRule);
}
for (int i = 0; i < numDivY + 1; i++) {
canvas.drawLine(graphOriginX,
graphOriginY + i * (graphH / numDivY), graphOriginX
+ graphW, graphOriginY + i * (graphH / numDivY),
paintRule);
}
// 軸ラベル
paintLabel.setColor(Color.GRAY);
FontMetrics fontMetrics = paintLabel.getFontMetrics();
if (labelFlagX) {
for (int i = 0; i < numDivX + 1; i++) {
String text = String
.valueOf(minX + i * (maxX - minX) / numDivX);
float baseX = paintRule.measureText(text) / 2; // テキスト幅の半分
float baseY = -fontMetrics.top; // baselineからtopまでの高さ
canvas.drawText(text, graphOriginX + i * (graphW / numDivX)
- baseX, graphOriginY + graphH + baseY, paintLabel);
}
}
if (labelFlagY) {
for (int i = 0; i < numDivY + 1; i++) {
String text = String
.valueOf(minY + i * (maxY - minY) / numDivY);
float baseX = paintLabel.measureText(text); // テキスト幅
float baseY = -fontMetrics.top / 2; // baselineからtopまでの高さの半分
canvas.drawText(text, graphOriginX - baseX, graphOriginY
+ graphH - i * (graphH / numDivY) + baseY, paintLabel);
}
}
}
void drawLines(Canvas canvas, Float[] data, int color) {
// 境界チェック
for (int i = 0; i < data.length / 2; i++) {
if (data[2 * i] != null && data[2 * i + 1] != null) {
data[2 * i] = (data[2 * i] < minX) ? minX : data[2 * i];
data[2 * i] = (data[2 * i] > maxX) ? maxX : data[2 * i];
data[2 * i + 1] = (data[2 * i + 1] < minY) ? minY
: data[2 * i + 1];
data[2 * i + 1] = (data[2 * i + 1] > maxY) ? maxY
: data[2 * i + 1];
}
}
float[] pts = new float[4 * (data.length / 2 - 1)];
// 描画座標へ変換
float pxlParUnitX = graphW / (maxX - minX); // X軸の単位辺りの画素値数
float pxlParUnitY = graphH / (maxY - minY); // Y軸の単位辺りの画素値数
for (int i = 0; i < data.length / 2 - 1; i++) {
if (data[2 * i] != null && data[2 * i + 1] != null
&& data[2 * i + 2] != null && data[2 * i + 3] != null) {
float x1 = data[2 * i];
float y1 = data[2 * i + 1];
float x2 = data[2 * i + 2];
float y2 = data[2 * i + 3];
pts[4 * i] = (x1 - minX) * pxlParUnitX + graphOriginX;
pts[4 * i + 1] = graphH - (y1 - minY) * pxlParUnitY
+ graphOriginY;
pts[4 * i + 2] = (x2 - minX) * pxlParUnitX + graphOriginX;
pts[4 * i + 3] = graphH - (y2 - minY) * pxlParUnitY
+ graphOriginY;
}
}
Paint paint = new Paint();
paint.setColor(color); // 線の色
paint.setStrokeWidth(2); // 線の太さ
canvas.drawLines(pts, paint);
}
void drawLegend(Canvas canvas, String[] name, int[] color) {
Paint paint = new Paint();
float lineLength = 0.05f * graphW;
FontMetrics fontMetrics = legendLabel.getFontMetrics();
float width;
float textW = 0;
for (int i = 0; i < name.length; i++) {
width = legendLabel.measureText(name[i]);
textW = (width > textW) ? width : textW;
}
float textH = -fontMetrics.top + fontMetrics.bottom;
float legendH = name.length * textH + fontMetrics.bottom;
float legendW = textW + lineLength;
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(legendOriginX, legendOriginY, legendOriginX + legendW,
legendOriginY + legendH, paint);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(legendOriginX, legendOriginY, legendOriginX + legendW,
legendOriginY + legendH, paint);
float x, y;
x = legendOriginX;
y = legendOriginY + textH;
for (int i = 0; i < name.length; i++) {
paint.setColor(color[i]);
paint.setStrokeWidth(2);
canvas.drawLine(x, y + fontMetrics.top / 2, x + lineLength, y
+ fontMetrics.top / 2, paint);
paint.setColor(Color.BLACK);
canvas.drawText(name[i], x + lineLength, y, legendLabel);
y += textH;
}
}
}
2010年6月13日日曜日
Androidで画面の縦横が切り替わった時にActivityが再起動されない方法
AndroidのActivityのlifecycleは
http://developer.android.com/guide/topics/fundamentals.html
の説明にあるようにonCreateから始まってonDestroyで終わります。
Activityが起動すると、
onCreate -> onStart -> onResume
の順序で、Activityが動作します。
終了時には、
onPause -> onStop -> onDestroy
の順序でActivityが終わります。
途中、割り込みなどで、推移します。
画面の縦横が切り替わった時には
onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
の順序で呼ばれます。
これは、画面の縦横変化によって、画面を再構成する必要があるからです。
だけど、Activityによっては、これでは困る場合があります。
そんなときは、AndroidManifest.xmlの対応するActivityに
android:configChanges="orientation"
を加えましょう。
すると、画面の縦横が切り替わってもonPause以降は呼ばれません。
その代わりにonConfigurationChangedが呼ばれます。
http://developer.android.com/guide/topics/fundamentals.html
の説明にあるようにonCreateから始まってonDestroyで終わります。
Activityが起動すると、
onCreate -> onStart -> onResume
の順序で、Activityが動作します。
終了時には、
onPause -> onStop -> onDestroy
の順序でActivityが終わります。
途中、割り込みなどで、推移します。
画面の縦横が切り替わった時には
onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
の順序で呼ばれます。
これは、画面の縦横変化によって、画面を再構成する必要があるからです。
だけど、Activityによっては、これでは困る場合があります。
そんなときは、AndroidManifest.xmlの対応するActivityに
android:configChanges="orientation"
を加えましょう。
すると、画面の縦横が切り替わってもonPause以降は呼ばれません。
その代わりにonConfigurationChangedが呼ばれます。
2010年6月9日水曜日
AndroidでBluetooth~Discoveryまで~
package jp.ac.hoge.android.bluetooth;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.TextView;
public class BluetoothTestActivity extends Activity {
private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_STATE_CHANGE_BT = 2;
private TextView tv_result = null;
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothReceiver mBluetoothReceiver = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv_result = (TextView) findViewById(R.id.tv_result);
tv_result.setText("");
checkBluetooth();
}
private void checkBluetooth() {
tv_result.append("Step 1:Bluetoothの利用可能状態\n");
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
tv_result.append("Bluetoothはサポートされてません\n");
} else {
tv_result.append("Bluetoothはサポートされています\n");
if (mBluetoothAdapter.isEnabled()) {
tv_result.append("Bluetoothは利用可能です\n");
getLocalInformation();
} else {
Intent enableBTIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBTIntent, REQUEST_ENABLE_BT);
Intent stateChangedBTIntent = new Intent(
BluetoothAdapter.ACTION_STATE_CHANGED);
startActivityForResult(stateChangedBTIntent,
REQUEST_STATE_CHANGE_BT);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
tv_result.append("Bluetoothが利用可能になりました\n");
getLocalInformation();
} else if (resultCode == RESULT_CANCELED) {
tv_result.append("Bluetoothは利用不可です\n");
}
} else if (requestCode == REQUEST_STATE_CHANGE_BT) {
switch (resultCode) {
case BluetoothAdapter.STATE_TURNING_ON:
tv_result.append("STATE_TURNING_ON\n");
break;
case BluetoothAdapter.STATE_ON:
tv_result.append("STATE_ON\n");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
tv_result.append("STATE_TURNING_OFF\n");
break;
case BluetoothAdapter.STATE_OFF:
tv_result.append("STATE_OFF\n");
break;
}
}
}
private void getLocalInformation() {
tv_result.append("\nStep 2:自機Bluetoothの調査\n");
tv_result.append(mBluetoothAdapter.getName() + ":"
+ mBluetoothAdapter.getAddress() + "\n");
switch (mBluetoothAdapter.getScanMode()) {
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
tv_result.append("SCAN_MODE_CONNECTABLE:");
break;
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
tv_result.append("SCAN_MODE_CONNECTABLE_DISCOVERABLE:");
break;
case BluetoothAdapter.SCAN_MODE_NONE:
tv_result.append("SCAN_MODE_NONE:");
break;
}
switch (mBluetoothAdapter.getState()) {
case BluetoothAdapter.STATE_OFF:
tv_result.append("STATE_OFF\n");
break;
case BluetoothAdapter.STATE_ON:
tv_result.append("STATE_ON\n");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
tv_result.append("STATE_TURNING_OFF\n");
break;
case BluetoothAdapter.STATE_TURNING_ON:
tv_result.append("STATE_TURNING_ON\n");
break;
}
findPairedDevices();
}
private void findPairedDevices() {
tv_result.append("\nStep 3:登録済みのBluetoothの調査\n");
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
tv_result.append(device.getName() + ":" + device.getAddress()
+ ":" + device.getBluetoothClass() + "\n");
}
} else {
tv_result.append("登録されているBluetoothデバイスはありません\n");
}
discoverDevices();
}
private void discoverDevices() {
tv_result.append("\nStep 4:Bluetoothデバイスの探索\n");
mBluetoothReceiver = new BluetoothReceiver();
registerReceiver(mBluetoothReceiver, new IntentFilter(
BluetoothDevice.ACTION_FOUND));
mBluetoothAdapter.startDiscovery();
tv_result.append("探索開始\n");
}
class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
tv_result.append("Bluetoothデバイスを発見\n");
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
tv_result.append(device.getName() + ":" + device.getAddress()
+ ":" + device.getBluetoothClass() + "\n");
}
}
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
BLUETOOTH_ADMINはstartDiscovery()に必要です。
2010年6月7日月曜日
Nexus One搭載センサー
- TYPE_ACCELEROMETER (加速度センサー)○
- TYPE_GYROSCOPE (ジャイロセンサー)×
- TYPE_LIGHT(光センサー)○
- TYPE_MAGNETIC_FIELD(磁気センサー)○
- TYPE_ORIENTATION(方位センサー)○
- TYPE_PRESSURE(圧力センサー)×
- TYPE_PROXIMITY(近接センサー)○
- TYPE_TEMPERATURE(温度センサー)×
AndroidのHttpのPostでもはまる
AndroidからHttpでPostするときのアプリです。
httpclient.execute(httppost)でこけますが、LogにINTERNETのpermissionがないよと言われるので、AndroidManifest.xmlに
を付け加えます。
サーバアプリはPOSTで投げた文字列をただ2回出力するだけです。
package jp.ac.hoge.android.httppost;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class HttpPostActivity extends Activity {
private static final String URI = "http://hoge/http_post_test.php";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn_sbmit = (Button) findViewById(R.id.btn_sbmit);
btn_sbmit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO 自動生成されたメソッド・スタブ
EditText et_string = (EditText) findViewById(R.id.et_string);
String value = et_string.getText().toString();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(URI);
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(
1);
nameValuePair.add(new BasicNameValuePair("str", value));
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePair));
HttpResponse response = httpclient.execute(httppost);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
response.getEntity().writeTo(byteArrayOutputStream);
TextView tv_result = (TextView) findViewById(R.id.tv_result);
tv_result.setText(byteArrayOutputStream.toString());
} catch (UnsupportedEncodingException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
});
}
}
httpclient.execute(httppost)でこけますが、LogにINTERNETのpermissionがないよと言われるので、AndroidManifest.xmlに
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
を付け加えます。
サーバアプリはPOSTで投げた文字列をただ2回出力するだけです。
2010年6月6日日曜日
AndroidのWifiのscanStartではまる
AndroidでWifiをScanするプログラムです。
このままだとstartScanで落ちてしまいます(もちろんエミュレータでは動かないのので実機Nexous Oneで)。
なので、AndroidManifext.xmlに
の権限を追加します(BREWみたい)。Bluetoothも同じような権限があるみたいだけどまだ未調査。
研究室のデスク周りで6つAPが見つかりました。
SSIDにはアクセスポイント名、BSSIDにはMACアドレス、capabilitiesには暗号化などの方式が表示されます。
inSSIDerみたいなのもすぐできそう。すでにあるかも。
package jp.ac.hoge.android.wifi;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class WifiActivity extends Activity implements OnClickListener {
private TextView tv_search_result;
private WifiManager wifi_mng;
private WifiReceiver wifi_rec;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn_start_search = (Button) findViewById(R.id.btn_start_search);
btn_start_search.setOnClickListener(this);
}
public void onClick(View v) {
// TODO 自動生成されたメソッド・スタブ
if (v.getId() == R.id.btn_start_search) {
tv_search_result = (TextView) findViewById(R.id.tv_search_result);
wifi_mng = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi_rec = new WifiReceiver();
registerReceiver(wifi_rec, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifi_mng.startScan();
tv_search_result.setText("スキャン開始\n");
}
}
class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO 自動生成されたメソッド・スタブ
StringBuffer sb = new StringBuffer();
List<ScanResult> result_list = wifi_mng.getScanResults();
for (int i = 0; i < result_list.size(); i++) {
sb.append(new Integer(i + 1).toString() + ".");
sb.append((result_list.get(i)).toString());
sb.append("\n");
}
tv_search_result.setText(sb);
}
}
}
このままだとstartScanで落ちてしまいます(もちろんエミュレータでは動かないのので実機Nexous Oneで)。
なので、AndroidManifext.xmlに
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
の権限を追加します(BREWみたい)。Bluetoothも同じような権限があるみたいだけどまだ未調査。
研究室のデスク周りで6つAPが見つかりました。
SSIDにはアクセスポイント名、BSSIDにはMACアドレス、capabilitiesには暗号化などの方式が表示されます。
inSSIDerみたいなのもすぐできそう。すでにあるかも。
登録:
投稿 (Atom)