@blog.justoneplanet.info

日々勉強

もっとandroidでカメラを使う

前回のコードを使ってプレビュー画面の画像を保存できるようにした。まぁ、備忘録程度。

■オートフォーカスを使う

以下のように記述するとオートフォーカスを使うことができる。

package info.justoneplanet.android.camera;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;

public class CameraActivity extends Activity {
    
    private Camera mCamera;
    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/" + "sample.jpg";
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 全画面表示
        // 基本的にはcameraは水平方向での利用を想定してるので
        // manifestでorientation設定しておく
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        
        // プレビューのViewをセット
        CameraPreview cameraPreview = new CameraPreview(this);
        setContentView(cameraPreview);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            
            mCamera.autoFocus(new AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    camera.autoFocus(null);
                    camera.takePicture(
                            new ShutterCallback() {
                                @Override
                                public void onShutter() {
                                }
                            },
                            // 生データ
                            new PictureCallback() {
                                @Override
                                public void onPictureTaken(byte[] data, Camera camera) {
                                }
                            },
                            // jpgデータ
                            new PictureCallback() {
                                @Override
                                public void onPictureTaken(byte[] data, Camera camera) {
                                    // 保存処理
                                    FileOutputStream fileOutputStream = null;
                                    try {
                                        fileOutputStream = new FileOutputStream(PATH);
                                        fileOutputStream.write(data);
                                        fileOutputStream.flush();
                                        fileOutputStream.close();
                                    } catch (FileNotFoundException e) {
                                        e.printStackTrace();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                    );
                    camera.startPreview();
                }
            });
            return true;
        }
        return super.onTouchEvent(event);
    }
    
    /**
     * カメラのプレビューするSurfaceview
     * @author justoneplanet
     */
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        private SurfaceHolder mHolder;

        public CameraPreview(Context context) {
            super(context);
            
            mHolder = getHolder();
            mHolder.addCallback(this);
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(width, height);
            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }

        /**
         * 生成時に実行されカメラをopenする
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            if (mCamera != null) {
                return;
            }
            mCamera = Camera.open();
            try {
                mCamera.setPreviewDisplay(holder);
            }
            catch (IOException e) {
                mCamera.release();
                mCamera = null;
            }
        }

        /**
         * 閉じるときに実行されカメラのリソースを解放する
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

■プレビュー画像を使う

以下のようにすることでプレビュー画像を保存する事ができる。

package info.justoneplanet.android.camera;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;

public class CameraActivity extends Activity {
    
    private Camera mCamera;
    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/" + "sample.jpg";
    
    private byte[] mTempData  = null;
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 全画面表示
        // 基本的にはcameraは水平方向での利用を想定してるので
        // manifestでorientation設定しておく
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        
        // プレビューのViewをセット
        CameraPreview cameraPreview = new CameraPreview(this);
        setContentView(cameraPreview);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            
            mCamera.autoFocus(new AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    camera.autoFocus(null);
                    camera.setPreviewCallback(new PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] data, Camera camera) {
                            Log.e("onPreviewFrame", "onPreviewFrame");
                            if (data != null) {
                                mTempData = new byte[data.length];
                                for (int i = 0; i < mTempData.length; i++) {
                                    mTempData[i] = data[i];
                                }
                                Size size = mCamera.getParameters().getPreviewSize();
                                Bitmap bmp = Bitmap.createBitmap(
                                        Util.decodeYUV(mTempData, size.width, size.height),
                                        size.width,
                                        size.height,
                                        Config.ARGB_8888
                                );
                                FileOutputStream fileOutputStream = null;
                                try {
                                    fileOutputStream = new FileOutputStream(PATH);
                                    bmp.compress(CompressFormat.JPEG, 90, fileOutputStream);
                                    fileOutputStream.flush();
                                    fileOutputStream.close();
                                } catch (FileNotFoundException e) {
                                    e.printStackTrace();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                            camera.setPreviewCallback(null);
                        }
                    });
                    camera.startPreview();
                }
            });
            return true;
        }
        return super.onTouchEvent(event);
    }
    
    /**
     * カメラのプレビューするSurfaceview
     * @author justoneplanet
     */
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        private SurfaceHolder mHolder;

        public CameraPreview(Context context) {
            super(context);
            
            mHolder = getHolder();
            mHolder.addCallback(this);
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(width, height);
            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }

        /**
         * 生成時に実行されカメラをopenする
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            if (mCamera != null) {
                return;
            }
            mCamera = Camera.open();
            try {
                mCamera.setPreviewDisplay(holder);
            }
            catch (IOException e) {
                mCamera.release();
                mCamera = null;
            }
        }

        /**
         * 閉じるときに実行されカメラのリソースを解放する
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

但し、プレビューで使用している画像形式はjpg形式ではないのでデコードがひつようになる。

デコード関数

package info.justoneplanet.android.camera;

/**
 * ユーティリティ
 * @author justoneplanet
 */
public class Util {
    /**
     * YUV形式から色の配列に変換する
     * @param data
     * @param width
     * @param height
     * @return
     * @throws NullPointerException
     * @throws IllegalArgumentException
     */
    public static int[] decodeYUV(byte[] data, int width, int height) throws NullPointerException, IllegalArgumentException {
        int size = width * height;
        if (data == null) {
            throw new NullPointerException("bufffer data is null");
        }
        if (data.length < size) {
            throw new IllegalArgumentException("buffer data is illegal");
        }
        
        int[] out = new int[size];
        
        int Y, Cr = 0, Cb = 0;
        for (int i = 0; i < height; i++) {
            
            int index = i * width;
            int jDiv2 = i >> 1;
            
            for (int i2 = 0; i2 < width; i2++) {
                Y = data[index];
                if (Y < 0) {
                    Y += 255;
                }
                if ((i2 & 0x1) != 1) {
                    int c0ff = size + jDiv2 * width + (i2 >> 1) * 2;
                    Cb = data[c0ff];
                    if (Cb < 0) {
                        Cb += 127;
                    }
                    else {
                        Cb -= 128;
                    }
                    Cr = data[c0ff + 1];
                    if (Cr < 0) {
                        Cr += 127;
                    }
                    else {
                        Cr -= 128;
                    }
                }
                // red
                int R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);
                if (R < 0) {
                    R = 0;
                }
                else if (R > 255) {
                    R = 255;
                }
                
                // green
                int G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5);
                if (G < 0) {
                    G = 0;
                }
                else if (G > 255) {
                    G = 255;
                }
                
                int B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6);
                if (B < 0) {
                    B = 0;
                }
                else if (B > 255) {
                    B = 255;
                }
                out[index] = 0xff000000 + (B << 16) + (G << 8) + R;
                index++;
            }
        }
        return out;
    }
}

ファイルの保存をメインスレッドで行ってるのは手抜き。

androidでカメラを使う

凄く基本的なコード。別にすごいことはしてない。備忘録程度。

■カメラを起動する

AndroidManifest.xml

以下の記述をManifestファイルに記述してカメラを使えるようにする。

<uses-permission android:name="android.permission.CAMERA" />

以下の記述をactivityの属性に追記し、カメラの向きを端末の向きに合わせる。

<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="landscape">

MainActivity.java

まぁ、いつも通りベタに書いておく。ちょっと違うのはCameraPreviewクラスをインスタンス化して使用する部分。

package jp.info.justoneplanet.android.usecamera;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);// titleの表示分で縦横比が崩れる
        mCameraPreview = new CameraPreview(this);
        setContentView(mCameraPreview);
    }
}

CameraPreview.java

SurfaceViewを継承してカメラを実際に扱う部分を作る。

package jp.info.justoneplanet.android.usecamera;

import java.io.IOException;

import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
{
    SurfaceHolder mHolder;
    Camera mCamera;
    public CameraPreview(Context context)
    {
        super(context);
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(width, height);
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder)
    {
        if(mCamera == null){
            mCamera = Camera.open();
            try{
                mCamera.setPreviewDisplay(holder);
            }
            catch(IOException e){
                mCamera.release();
                mCamera = null;
            }
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder)
    {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
}

■カメラの画像を保存してみる

上述のコードを改造して楽しむことにする。

AndroidManifest.xml

以下の記述をManifestファイルに記述してSDカードにアクセスできるようにする。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

MainActivity.java

onTouchEventが実装されたのと、カメラのインスタンスをMainActivityクラスでも使用する点が変更点である。

package jp.info.justoneplanet.android.usecamera;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {
    private CameraPreview mCameraPreview;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        
        mCameraPreview = new CameraPreview(this);
        setContentView(mCameraPreview);
    }

    private static final File OUTPUT_FILE = new File("/sdcard/usecamera.jpg");
    @Override
    public boolean onTouchEvent(MotionEvent event){
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            Camera mCamera = mCameraPreview.getCamera();
            mCamera.takePicture(
                    new ShutterCallback(){
                        @Override
                        public void onShutter()
                        {
                        }
                    },
                    new PictureCallback(){
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera)
                        {
                        }
                    },
                    new PictureCallback(){
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera)
                        {
                            FileOutputStream out = null;
                            try{
                                out = new FileOutputStream(OUTPUT_FILE);
                                out.write(data);
                                out.flush();
                                out.close();
                            }
                            catch(FileNotFoundException e){
                                e.printStackTrace();
                            }
                            catch(IOException e){
                                e.printStackTrace();
                            }
                        }
                    }
            );
        }
        return false;
    }
}

CameraPreview.java

MainActivityクラスでCameraのインスタンスを使用するために、getterメソッドを追記した。それ以外は何も変わっていない。

package jp.info.justoneplanet.android.usecamera;

import java.io.IOException;

import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
{
    SurfaceHolder mHolder;
    Camera mCamera;
    public CameraPreview(Context context)
    {
        super(context);
        
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(width, height);
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder)
    {
        if(mCamera == null){
            mCamera = Camera.open();
            
            try{
                mCamera.setPreviewDisplay(holder);
            }
            catch(IOException e){
                mCamera.release();
                mCamera = null;
            }
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder)
    {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
    
    public Camera getCamera(){
        return mCamera;
    }
}

やっぱandroidを触るのって楽しい((o(^-^)o))ワクワク

androidで端末の情報にアクセスする

■SIMのシリアル番号

以下のようにすることでSIMのシリアル番号にアクセスできる。

package info.justoneplanet.android.sample.id;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;

public class AndroidIdActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        Log.e("SIM", telephonyManager.getSimSerialNumber());
    }
}

パーミッション

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

■UUID

UUIDは不変で128bitの固有のIDである。

一元管理していたり,重複をチェックする仕組みがないのに,世界でただ一つのIDを自由にいくらでも作って自分の機器を管理・識別するために使える

package info.justoneplanet.android.sample.id;

import java.util.UUID;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

/**
 * AppUUID
 * @author justoneplanet
 */
public class AppUUID {
    private static String uuid = null;
    private static final String UUID_KEY = "UUID_KEY";
    
    public static String get(Context context) {
        if (uuid != null) {// 既にapp内からinvokeされている場合
            return uuid;
        }
        
        SharedPreferences sharedPreferences = context.getSharedPreferences(UUID_KEY, Context.MODE_PRIVATE);
        uuid = sharedPreferences.getString(UUID_KEY, null);
        if (uuid == null) {// 何も設定されていない場合
            uuid = UUID.randomUUID().toString();// randomな文字列を生成
            Editor editor = sharedPreferences.edit();
            editor.putString(UUID_KEY, uuid);
            editor.commit();// 保存
        }
        return uuid;
    }
}

パーミッションは必要ない。

Log.e("AppUUID", AppUUID.get(getApplicationContext()));

アプリ間の固有の値であり再インストールすれば値は変わるので潔い。

■ANDROID_ID

package info.justoneplanet.android.sample.id;

import android.app.Activity;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.util.Log;

public class AndroidIdActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        String androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
        Log.e("ANDROID_ID", androidId);
    }
}

■IMEI

package info.justoneplanet.android.sample.id;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;

public class AndroidIdActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        Log.e("IMEI", telephonyManager.getDeviceId());
    }
}

パーミッション

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

androidで位置情報を取得する

7/10にHT-03Aの発売が決まってにわかに活気づいてきました。但し、まだまだ日本語文献が少ないですな。特にリファレンスは厳しいな。

■コード

package info.justoneplanet.android.sample.location;

import android.app.Activity;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.widget.TextView;

public class LocationActivity extends Activity implements LocationListener {
    private LocationManager locationManager;
    private String provider;
    private Criteria criteria;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        criteria = new Criteria();
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    }
    
    @Override
    public void onResume() {
        super.onResume();
        // "gps"とか"network"とか選んでくれる
        provider = locationManager.getBestProvider(criteria, true);

        // 位置情報の更新間隔を時間と移動距離で設定できる
        locationManager.requestLocationUpdates(provider, 1000, 1, this);
        
        ((TextView) findViewById(R.id.provider)).setText(provider);
        displayProvider(locationManager.getProvider(provider));
    }
    
    @Override
    public void onPause() {
        super.onPause();
        // 位置情報の取得には電力を使うのでactiveでなくなったら更新しない
        locationManager.removeUpdates(this);
    }

    /**
     * 位置情報が変更されたとき
     */
    @Override
    public void onLocationChanged(Location location) {
        ((TextView) findViewById(R.id.altitude)).setText(String.valueOf(location.getAltitude()));
        ((TextView) findViewById(R.id.longitude)).setText(String.valueOf(location.getLongitude()));
        ((TextView) findViewById(R.id.latitude)).setText(String.valueOf(location.getLatitude()));
    }

    /**
     * 機器が使えなくなった時
     */
    @Override
    public void onProviderDisabled(String provider) {
        ((TextView) findViewById(R.id.provider)).setText(provider + "::disable");
        provider = locationManager.getBestProvider(criteria, true);
    }

    @Override
    public void onProviderEnabled(String provider) {
        ((TextView) findViewById(R.id.provider)).setText(provider + "::enable");
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        ((TextView) findViewById(R.id.provider)).setText(provider + "(" + status + ")");
    }
    
    private void displayProvider(LocationProvider locationProvider) {
        ((TextView) findViewById(R.id.information)).setText(locationProvider.getName());
    }
}

コード

昔のコード。汚いけど残しておく。

package org.example.locationtest;

import java.util.List;
import android.app.Activity;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.widget.TextView;

public class LocationTest extends Activity implements LocationListener {
    private static final String[] A = {
        "n/a",
        "fine",
        "coarse"
    };
    private static final String[] P = {
        "n/a",
        "low",
        "medium",
        "high"
    };
    private static final String[] S = {
        "out of service",
        "temporarily unavailable",
        "available"
    };
    private LocationManager mgr;
    private TextView output;
    private String best;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
        output = (TextView) findViewById(R.id.output);
        
        log("Location providers:");
        dumpProviders();
        
        Criteria criteria = new Criteria();
        best = mgr.getBestProvider(criteria, true);
        log("\nBest Provider is: " + best);
        
        log("\nLocations (starting with last known):");
        Location location = mgr.getLastKnownLocation(best);
        dumpLocation(location);
    }
    
    @Override
    protected void onResume(){
    	super.onResume();
    	mgr.requestLocationUpdates(best, 15000, 1, this);
    }
    @Override
    protected void onPause(){
    	super.onPause();
    	mgr.removeUpdates(this);
    }
        
    public void onLocationChanged(Location location){
    	dumpLocation(location);
    }
    @Override
    public void onProviderDisabled(String provider) {
        log("\nProvider disabled:" + provider);
    }
    @Override
	public void onProviderEnabled(String provider) {
    	log("\nProvider enabled:" + provider);
	}
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        log("\nProvider status changed:" + provider + ", status=" + S[status] + ", extras=" + extras);
    }

    private void log(String string) {
        output.append(string + "\n");
    }
    private void dumpLocation(Location location) {
        if(location == null){
            log("\nLocation[unknown]");
        }
        else{
            log("\n" + location.toString().replace(",", ",\n\t").replace("[", "[\n\t").replace("]", "\n]"));
        }
    }
    private void dumpProviders() {
        List<String> providers = mgr.getAllProviders();
        for (String provider : providers) {
            dumpProvider(provider);
        }
    }
    private void dumpProvider(String provider) {
        LocationProvider info = mgr.getProvider(provider);
        StringBuilder builder = new StringBuilder();
        builder.append("LocationProvider[")
            .append("\n\tname=")
            .append(info.getName())
            .append(",\n\tenabled=")
            .append(mgr.isProviderEnabled(provider))
            .append(",\n\tgetAccuracy=")
            .append(A[info.getAccuracy()])
            .append(",\n\tgetPowerRequirement=")
            .append(P[info.getPowerRequirement()])
            .append(",\n\thasMonetaryCost=")
            .append(info.hasMonetaryCost())
            .append(",\n\trequiresCell=")
            .append(info.requiresCell())
            .append(",\n\trequiresNetwork=")
            .append(info.requiresNetwork())
            .append(",\n\trequiresSatellite=")
            .append(info.requiresSatellite())
            .append(",\n\tsupportsAltitude=")
            .append(info.supportsAltitude())
            .append(",\n\tsupportsBearing=")
            .append(info.supportsBearing())
            .append(",\n\tsupportsSpeed=")
            .append(info.supportsSpeed())
            .append("\n]");
        log(builder.toString());
    }
}

Javaの配列宣言がPHPやJavaScriptと異なっててどうもしっくりこないな。

void org.example.locationtest.LocationTest.onCreate(Bundle savedInstanceState)

super.onCreate(savedInstanceState);

スーパークラスのメソッドをコール。

setContentView(R.layout.main);

androidのView Wigetを使ってActivityの画面を生成する。

mgr = (LocationManager) getSystemService(LOCATION_SERVICE);

LocationManagerオブジェクトを取得し変数に格納。

output = (TextView) findViewById(R.id.output);

Resource IDに基づいてAndroid Viewを探す。

Criteria criteria = new Criteria();

Criteriaオブジェクトの生成。location providerの選択のためにapplicationの尺度を示すらしい。

best = mgr.getBestProvider(criteria, true);

状況に応じた最良のセンサー名をbest変数に格納する。

Location location = mgr.getLastKnownLocation(best);

センサーによっては位置を取得するのに時間がかかるので最後に取得した値を利用する。

void org.example.locationtest.LocationTest.onResume()

アプリがforegroundに復活した時の挙動を定義。

super.onResume();
mgr.requestLocationUpdates(best, 15000, 1, this);

スーパークラスのメソッドをコール。位置情報の定期更新を設定する。

void org.example.locationtest.LocationTest.onPause()

アプリがbackgroundにある時の挙動を定義。

super.onPause();
mgr.removeUpdates(this);

スーパークラスのメソッドをコール。アップデートを休止する(位置情報の更新を無効にする)。

void org.example.locationtest.LocationTest.dumpProviders()

for (String provider : providers) {
    dumpProvider(provider);
}

JDK5.0からできるようになった記法らしい。コロンの右側に配列(もしくはコレクション)を配置しループをぶん回せる。ちなみにこの記法はJavaScriptでは使えない。

void org.example.locationtest.LocationTest.log(String string)

output.append(string + "\n");

引数のstringが出力に追加されるイメージですな。

■画面

こんな風に表示されます。

gpsのデータ