2011年2月22日火曜日

au IS04 (REGZA Phone) がADBでデバイス認識されない(MAC OS10.6.6)

タイトルの通りですが、MAC OSXでのAndroid開発環境では、通常は端末をデバッグモードでUSB接続した場合、とくにドライバのインストール作業などを行わずに使用することができました。

(過去に問題なく接続できた端末)
・HTC HT03A
・HTC Desire
・SonyEricsson EXPERIA
・SHARP IS01
・SHARP IS03

今回、TOSHIBA IS04 で実機検証する機会があり、今までと同じようにUSB接続してみたところADB上で認識されません。

WEB上で色々と調べた結果、以下の方法で解決したのでまとめておきます。

1.  .androidディレクトリ(だいたいはユーザディレクトリの直下にあります)
にadb_usb.iniというファイルがあるか確認

2. なければ adb_usb.ini の作成
こちらのサイトを参考にさせていただきました。
http://d.hatena.ne.jp/rmiya/20091109

3. adb_usb.ini にIS04のベンダーID
0x0930
を追加

4. ADBを再起動

端末を接続し、 adb devices コマンド、またはEclipeなどのUI上で端末が表示されれば成功です。


ちなみに、Windows向けにはドライバが配布されているようです。

2011年1月28日金曜日

Android開発 - 画面の縦横を検知して回転するボタンを作る(3)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)
Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

Javaのコードは2種類
・Main.java (メインのアクティビティクラス)
・AnimationController.java (回転アニメーションの制御)
になります。


AnimationController.java

import android.hardware.SensorEvent;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class AnimationController {

boolean yoko = false;
float touchY;
long ANIM_ROTATE_SPEED = 200;

public void rotateCube(SensorEvent event, ImageButton[] img) {


if (!yoko && event.values[2] > 60 && event.values[2] < 80) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(0, 90, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = true;
}


if (yoko && event.values[2] > -10 && event.values[2] < 10) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(90, 0, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = false;
}
}
}



Main.java



import java.util.List;


import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class Main extends Activity implements SensorEventListener, OnClickListener{

AnimationController animationController = new AnimationController(); 

SensorManager mSensorManager = null;
private boolean mRegisteredSensor;
float touchY;
float moveY;
boolean yoko = false;
RotateAnimation rotateAnimation;


ImageButton button01;
ImageButton button02;
ImageButton button03;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mRegisteredSensor = false;


button01 = (ImageButton)findViewById(R.id.button01);
button02 = (ImageButton)findViewById(R.id.button02);
button03 = (ImageButton)findViewById(R.id.button03);
    }


@Override
protected void onResume() {

List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if (sensors.size() > 0) {
Sensor sensor = sensors.get(0);
mRegisteredSensor = mSensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
}
super.onResume();
}


@Override
protected void onPause() {

if (mRegisteredSensor) {
mSensorManager.unregisterListener(this);
mRegisteredSensor = false;
}
super.onPause();
}


@Override
protected void onStop() {

mSensorManager.unregisterListener(this);
super.onStop();
}


@Override
public void onClick(View v) {


switch( v.getId() ){
case R.id.button01:
//ボタンタッチ時の処理
break;
case R.id.button02:
//ボタンタッチ時の処理
break;
case R.id.button03:
//ボタンタッチ時の処理
break;
}
}


@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}


@Override
public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {


ImageButton[] img = {button01,button02,button03};
animationController.rotateCube(event, img);
}
}
}



Main.java の onSensorChanged → Sensor.TYPE_ORIENTATIONで傾きを検知し、SensorEvent と 対象となるボタンを AnimationController に渡しています。

センサーイベントの event.values[2] でY軸の傾きの値が取れます。
event.values[2] = 60〜80 でボタンを横向きに、
event.values[2] = -10〜10 でボタンを縦向きにアニメーションさせていますが、このあたりの設定は改善の余地がありそうです。



センサーイベントの実装は、以下のサイトを参考にさせていただきました。
http://www.adakoda.com/android/000182.html

2011年1月25日火曜日

Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)


まずはManifestファイルから

■AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="jp.mediba.android.RotateCube"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" 
                 android:label="@string/app_name"
                 android:debuggable="true" >
        <activity android:name=".Main"
                  android:label="@string/app_name"
                  android:screenOrientation="portrait">
            <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="4" />
</manifest> 



Activityタグ内で android:screenOrientation="portrait" を指定し、画面自体は縦表示で固定します。


続いてレイアウトファイル

■Main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ImageButton
android:id="@+id/button01"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
<ImageButton
android:id="@+id/button02"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
<ImageButton
android:id="@+id/button03"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
</LinearLayout>


サンプルではアプリランチャー的なイメージで ImageButton を使いますが、ImageViewやTextView等でも作成可能です。


次回は実際にアニメーションを行うコードを作っていきます。

Android開発 - 画面の縦横を検知して回転するボタンを作る(3)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)

Androidアプリの開発で、主にUI関係の話をしていると、
「iPhoneぽく」「iPhoneみたいに・・・」といった要望がしばしば出てきます。

直感的でわかりやすく、且つ格好良いインターフェースという点においてはAndroidよりもiOSに分があるのが現状のようです。


今回は、「画面の縦横切替をアニメーションで多少なりとも格好良く見せる」チャレンジをしてみます。
通常、下のような画面の場合


端末を横向きにすると、



このような画面に切り替わります。

これを
・レイアウトそのものは縦画面で固定
・プログラム内で端末の動きを検知しアイコン画像がアニメーションで90度回転
・アニメーション後は以下のような表示に
してみたいと思います。


続きは次回。

Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

2010年12月10日金曜日

2010年11月29日月曜日

傾き、加速度の手振れノイズをフィルターする

人間の手の震えもありますが、端末で取れる加速度センサーの値は、結構細かく震えています。
この加速度センサーの値をもとにLinearで中心にあるボールを動かしたかったのですが、この震えのせいで、
きれいに移動しないで、ぴょこぴょこと跳ねているような動きに見えてしまうので困りました。

センサーの精度かと思って、そちらを調査してみたり、
アニメーションの処理飛びなのかと思ってログを見てみたりしていたのですが、
特に解決策は見つからず。

結局のところこのブレを減らすための解決策が必要だろうと推測して、ノイズフィルターを探していたところ身近なところに解決策がありました。

DJミキサーでよくある、ハイパスフィルターとローパスフィルターです。

ハイパスフィルターは、つまみを回すとだんだんシャキシャキの音になってくあれですw。
ローパスフィルターは、つまみを回すとだんだんモコモコの音になってくあれですw。


WikiPedia ローパスフィルター(ハイカット)
ローパスフィルタ(Low-pass filter: LPF)はフィルタ回路の一種で、低周波を良く通し、ある遮断周波数より高い周波数の帯域を通さない(減衰させる)フィルタである。

WikiPedia ハイパスフィルター(ローカット)
ハイパスフィルタ(High-pass filter: HPF)はフィルタ回路の一種で、高周波を良く通し、遮断周波数より低い周波数の帯域を通さない(減衰させる)フィルタである。 日本語では「高域通過濾波器」とも言われる。また英語では「low-cut filter」とも言われ、これは「bass-cut filter」または「rumble filter」としてオーディオ機器などで使用される。


加速度は、重力加速度+手振れなどの実際の端末の動きが加速度が影響してきます。
あるXYZで考えてどれか一方向についての変化
重力加速度の変化:端末の大体の傾きになりますので周波数で考えるとだんだん傾いていれば低い周波数です。
端末の動きの変化:手振れなので重力加速度の変化より高い周波数のノイズになります。

ぴょこぴょこと動いてしまうのは、「端末の動きの変化」が影響しているので、高い周波数をカットすればいい。すなわち低い周波数だけ通せばいいということになります。

ってことで、ロジック。
一つ前の値と比較しながら、値を取ります。
XYだけの例です。

部分的に抜き出すとわけわからなくなったので、全部載せます。

イメージを最初に真ん中において、ローパスフィルタをかけた加速度で、イメージを移動しています。

package jp.mediba.android.xxxxxx;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import android.widget.ImageView;

public class PointViewOverlay extends ImageView {

 private Matrix mMatrix = new Matrix();
 private Matrix mSavedMatrix = new Matrix();
 private float[] currentOrientationValues = {0.0f, 0.0f};
 
 private PointF startPoint = new PointF();
 
 private ImageView imageView;
 private int frameWidth = 0;
 private int frameHeight = 0;
 
 public PointViewOverlay(Context context) {
  super(context);
  // TODO 自動生成されたコンストラクター・スタブ
 }

 public void setImageView(ImageView imageView) {this.imageView = imageView;}
 public void setFrameSize(int frameWidth, int frameHeight) {
  this.frameWidth = frameWidth;
  this.frameHeight = frameHeight;
 }
 
 public void resetStartPoint() {
  mMatrix.set(mSavedMatrix);
  this.startPoint = new PointF((float)this.frameWidth/2,(float)this.frameHeight/2);
  mMatrix.postTranslate(this.startPoint.x, this.startPoint.y);
  imageView.setImageMatrix(mMatrix);
  Log.v("resetStartPoint.",String.valueOf("X:" + this.startPoint.x) + "Y:" + String.valueOf(this.startPoint.y));
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  // TODO 自動生成されたメソッド・スタブ
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 }

 public void animateView( SensorEvent event ) {
  
  if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

   // Lowpass Filter ハイカット これ!
   currentOrientationValues[0] = event.values[0] * 0.1f + currentOrientationValues[0] * (1.0f - 0.1f);
   currentOrientationValues[1] = event.values[1] * 0.1f + currentOrientationValues[1] * (1.0f - 0.1f);

   // 重力加速度
   float accX = currentOrientationValues[0];
   float accY = currentOrientationValues[1];

   // 横画面なのでちょっと大きめにしました。
   float moveX = Math.round(accY*48);
   float moveY = Math.round(accX*32);

   float pointX = this.startPoint.x+moveX;
   float pointY = this.startPoint.y+moveY;
   
   mMatrix.set(mSavedMatrix);
   mMatrix.postTranslate(pointX,pointY);
   
   imageView.setImageMatrix(mMatrix);
   Log.v("animateView","pointX,pointY"+String.valueOf(pointX)+","+String.valueOf(pointY));
   
  }
 }
 
}

2010年11月16日火曜日

DroidDraw Android LayoutXMLのWYSIWYGエディタ

http://www.droiddraw.org/
http://code.google.com/p/droiddraw/

機能を完全には使っていないのですが、レイアウトがWYSIWYGでDrag&Dropできて便利です。
Mac OS X, Windows, Linuxのマルチプラットフォームサポートしています。
使い方さえ覚えればもしかするとデザイナさんでも一人でUI作れるかも?

ADTについているレイアウトエディタだとRelativeLayoutの中に入れた、2つのLinearLayoutを左右にふって上合わせにするプロパティーがどこにあるか見つけにくい(ってかあるのか?)のですが、それをマウス操作で上にあわせたり下にあわせたりできます。
(* (ADT) Android Development Tools for the Eclipse IDE )

これだけで、非常にストレスが減る!
Eclipseと連携して操作する所まで入っていないのですが、ファイルの場所を合わせればリソースファイルも読めるようです。

出力は、.apkパッケージで出力したり、XML単体で出力したりできます。
GUIで要素のIDを付ける操作は、いまいち使い勝手が悪いので、ひと通りの配置まで決めたあとは、XMLをEclipseのADTに貼りつけて、名前を付け直したりしています。

どう書いたらうまく並べられるのかの勉強替わりにもなりますね。
ひと通り慣れたら、プロパティーが覚えられそうなのでHTMLのようにタグがきができるようになれるような気がしています。

一点分かりにくいのが、Layout要素を入れ子にすると、外を囲むレイアウトがなんだったかが、GUI上から見えにくいところかな。

でも何にせよ使う利点は十分にあります。

MoonGiftの紹介記事