2011年5月27日 星期五

AudioRecorder功能

AudioRecorder功能
AudioRecorder這個物件可以設定錄音的品質(頻率、取樣數、聲道)
但是錄出來的資料是原始音頻檔(PCM)
後續還要加Header將其轉換成可播放的格式,例如WAV
下面是使用AudioRecorder做錄音的範例
在範例中,AudioRecorder需要放在另一個線程(Thread)執行
    // 按鈕操作
    public void onClick(View v) {
        // Press start record
        if (v.getId() == R.id.recStart) {
        isRecording = true;
            thread = new Thread(new Runnable() {
                public void run() {
                    record();
                }
            });
            thread.start();

        }
        // Press stop record        else if (v.getId() == R.id.recStop) {
        isRecording = false;
        // 可以用"thread.join()"讓thread進入blocked狀態,目前直接在結束的地方寫"thread.stop();"
        // try {
        //     thread.join();
        // } catch (InterruptedExpection e) { }
        }
    }

    private void record() {
        pcmFile = new File(myDataPath.getAbsolutePath() + "/record.pcm");
        // Delete any previous recording.
        if (pcmFile.exists())
            pcmFile.delete();
        // Create the new file.
        try {
            pcmFile.createNewFile();
        } catch (IOException e) {
            throw new IllegalStateException("Failed to create " + pcmFile.toString());
        }
        // Start record pcm data        try {
            // Create a DataOuputStream to write the audio data into the saved file.            OutputStream os = new FileOutputStream(pcmFile);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream dos = new DataOutputStream(bos);
  
            // Create a new AudioRecord object to record the audio.
            int bufferSize =
            AudioRecord.getMinBufferSize(
                sampleRateInHz,
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
  
            AudioRecord audioRecord =
                new AudioRecord(
                    MediaRecorder.AudioSource.MIC,
                    sampleRateInHz,
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);
            byte[] buffer = new byte[bufferSize];
            audioRecord.startRecording();
            while (isRecording) {
                int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
                for (int i = 0; i < bufferReadResult; i++)
                    dos.write(buffer[i]);
            }
  
            // filler, data size need can %8 = 0            if (dos.size()%8  != 0) {
                int filler = 0;
                filler = 8 - (dos.size()%8);
                for (int i = 0 ; i < filler ; i++) {
                    dos.writeByte(0);
                }
            }
  
            // stop record and close the file.            audioRecord.stop();
            dos.close();
        } catch (Throwable t) { }
        // stop thread, this method may be not great, we can use the "thread.join( )" method
        thread.stop();
    }

2011年5月25日 星期三

目錄

目錄
Android基礎知識
    Activity類別
    Intent & Bundle物件
    Service類別
    BroadcastReceiver物件
    SharedPreferences物件
    Notification
Android版面設計
    LinearLayout版面配置
    RelativeLayout版面配置
    ScrollView物件 
Android物件應用
    SeekBar物件
    Rating Bar物件
    Toggle Button物件
    Radio Button物件
    CheckBox物件
    Gallery物件
    ProgressBar物件
    MediaPlayer物件
    AudioManager物件
    EditText物件   
    ListView物件
    Menu物件
    Toast & Log物件
    Timer物件
    Dialog物件
    Button物件
    Spinner物件
Android資料讀取
    KeyEven接收
    Battery資訊
    DisplayResolution資訊
    NMEA資訊
Android感測器
    Accelerometer感測器
    OnTouchEvent偵測
    Light感測器
    Gyroscope感測器
    Orientation感測器
Android功能設計
    Wake up lock功能
    設定Brightness功能
    SD card read/write功能
    WiFi功能
    FingerPaint功能

    AudioRecorder功能 - 5/27
Android其他問題
    Rotation問題
    Application類別
    Load Image
    System Settings修改
    How to scan a barcode from another Android application via Intents   

   

SeekBar物件

SeekBar物件
    public void onCreate(Bundle savedInstanceState) {
        .........
        skb_seekbar = (SeekBar)findViewById(R.id.seekbar);
        skb_seekbar.setOnSeekBarChangeListener(change);
    }

    private OnSeekBarChangeListener change = new OnSeekBarChangeListener() {
        public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
        txv_percentage.setText(String.valueOf(arg1));
        set_brightness(arg1);
    }
    public void onStartTrackingTouch(SeekBar seekBar) {}
    public void onStopTrackingTouch(SeekBar seekBar) {}

Orientation感測器

Orientation感測器
方向感測器
    sensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    sm.registerListener(oriSensor, sensor, SensorManager.SENSOR_DELAY_NORMAL);

    // Azimuth : 0=North, 90=East, 180=South, 270=West     private SensorEventListener oriSensor = new SensorEventListener() {
        public void onAccuracyChanged(Sensor sensor, int accuracy) { }

        public void onSensorChanged(SensorEvent event) {
        txtMsg.setText(
            "(Azimuth, Pitch, Roll) = \n" + event.values[0] + "\n" + event.values[1] + "\n" + event.values[2]);
        }
    };

Gyroscope感測器

Gyroscope感測器
陀螺儀感測器
    sensor = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
    sm.registerListener(gyroSensor, sensor, SensorManager.SENSOR_DELAY_NORMAL);

    private SensorEventListener gyroSensor = new SensorEventListener() {
         public void onAccuracyChanged(Sensor sensor, int accuracy) { }

         public void onSensorChanged(SensorEvent event) {
             txtMsg.setText("(x, y, z) = \n" + event.values[0] + "\n" + event.values[1] + "\n" + event.values[2]);
        }
    };

2011年5月24日 星期二

ScrollView物件

ScrollView物件當資料訊息過大,導致物件僅顯示部分資料時
可以使用ScrollView物件,將所有的訊息顯示出來

<ScrollView
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"    >
    <TextView 
        android:id="@+id/msg"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text=""    />
</ScrollView>

RelativeLayout版面配置

RelativeLayout版面配置相對佈局版面配置,可指定一物件位於另一物件的相對位置(上下左右)
Default設定,物件位於左上角

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"    >
    <TextView
        android:id="@+id/key_msg"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="15pt"
        android:text="Please press all keys."  />
    <TextView
        android:id="@+id/key_menu"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/key_msg"
        android:text="Menu"  />
    <TextView
        android:id="@+id/key_back"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/key_menu"
        android:text="Back"  />
    <TextView
        android:id="@+id/key_vol_add"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/key_back"
        android:text="Volume +"  />
    <TextView
        android:id="@+id/key_vol_dec"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/key_vol_add"
        android:text="Volume -"  />
    <Button
        android:id="@+id/pass"
        android:layout_width="150px"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"        android:text="PASS"  />
    <Button
        android:id="@+id/fail"
        android:layout_width="150px"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"        android:layout_alignParentRight="true"        android:text="FAIL"  />
</RelativeLayout>

Rating Bar物件

Rating Bar物件    <RatingBar
        android:id="@+id/ratingbar"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:numStars="5"
       
android:stepSize="1.0"/>


    RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar);
    ratingbar
.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
       
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
           
Toast.makeText(HelloFormStuff.this, "New Rating: " + rating, Toast.LENGTH_SHORT).show();
       
}
    });

Toggle Button物件

Toggle Button物件通常用於開/關選項設定
    <ToggleButton android:id="@+id/togglebutton"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:textOn="Vibrate on"
       
android:textOff="Vibrate off"/>


    ToggleButton togglebutton = (ToggleButton) findViewById(R.id.togglebutton);
    togglebutton
.setOnClickListener(new OnClickListener() {
       
public void onClick(View v) {
           
// Perform action on clicks
           
if (togglebutton.isChecked()) {
               
Toast.makeText(HelloFormStuff.this, "Checked", Toast.LENGTH_SHORT).show();
           
} else {
               
Toast.makeText(HelloFormStuff.this, "Not checked", Toast.LENGTH_SHORT).show();
           
}
       
}
    });

Radio Button物件

Radio Button物件通常用於"單選"項目
mian.xml
    <RadioGroup
       
android:layout_width="fill_parent"
       
android:layout_height="wrap_content"
       
android:orientation="vertical">
       
<RadioButton

            android:id="@+id/radio_red"
           
android:layout_width="wrap_content"
            
android:layout_height="wrap_content"
           
android:text="Red" />
       
<RadioButton

            android:id="@+id/radio_blue"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="Blue" />
   
</RadioGroup>


Xxx.java
    public void onCreate(Bundle savedInstanceState) {
        .......
        RadioButton radio_red = (RadioButton) findViewById(R.id.radio_red);
        
RadioButton radio_blue = (RadioButton) findViewById(R.id.radio_blue);
        radio_red
.setOnClickListener(radio_listener);
        radio_blue
.setOnClickListener(radio_listener);

    }

    private OnClickListener radio_listener = new OnClickListener() {
       
public void onClick(View v) {
           
// Perform action on clicks
           
RadioButton rb = (RadioButton) v;
            // 顯示選擇項目

            Toast.makeText(HelloFormStuff.this, rb.getText(), Toast.LENGTH_SHORT).show();
       
}
    };

-------------------------------------------------------------------------------------
    private RadioGroup.OnCheckedChangeListener change =
        new RadioGroup.OnCheckedChangeListener() {
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (checkedId == mRadio1.getId()) {
                Toast.makeText(radio.this, "1", Toast.LENGTH_SHORT).show();
            }
            if (checkedId == mRadio2.getId()) {
                Toast.makeText(radio.this, "2", Toast.LENGTH_SHORT).show();
            }
        }
    };

CheckBox物件

CheckBox物件
通常用於設定開/關選項
    checkbox.setOnClickListener(new OnClickListener() {
       
public void onClick(View v) {
           
// Perform action on clicks, depending on whether it's now checked
           
if (((CheckBox) v).isChecked()) {
               
Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show();
           
} else {
               
Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show();
           
}
       
}
    });

2011年5月23日 星期一

Gallery物件

Gallery物件畫廊,大部分用於顯示圖片
Gallery.java
    Gallery g = (Gallery) findViewById(R.id.gallery);
    g.setAdapter(new ImageAdapter(this));
    g.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // function
        }
    }

    public class ImageAdapter extends BaseAdapter {
        int mGalleryItemBackground;
        private Context mContext;
        private Integer[] mImageIds = {
            R.drawable.sample01,        R.drawable.sample02,        R.drawable.sample03,
            R.drawable.sample04,        R.drawable.sample05,        R.drawable.sample06,
            R.drawable.sample07,        R.drawable.sample08,        R.drawable.sample09     };
   
        // 建構子,當new新物件時會進到這裡做初始化的動作
        public ImageAdapter(Context c) {
            mContext = c;
            TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery);
            mGalleryItemBackground = a.getResourceId(
                R.styleable.HelloGallery_android_galleryItemBackground, 0);
            a.recycle();
        }
   
        public int getCount() {    return mImageIds.length;    }
        public Object getItem(int position) {    return position;    }
        public long getItemId(int position) {    return position;    }
   
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);
            i.setImageResource(mImageIds[position]);
            i.setLayoutParams(new Gallery.LayoutParams(320, 480));
            i.setScaleType(ImageView.ScaleType.FIT_XY);
            i.setBackgroundResource(mGalleryItemBackground);
            return i;
        }
    }

main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <Gallery xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/gallery"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    />
values的資料夾下新增HelloGallery的style
attrs.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="HelloGallery">
            <attr name="android:galleryItemBackground" />
        </declare-styleable>
    </resources>

2011年4月28日 星期四

How to scan a barcode from another Android application via Intents

How to scan a barcode from another Android application via Intents
透過其他的應用程式,使用其內部所提供的功能
    public Button.OnClickListener mScan = new Button.OnClickListener() {
       
public void onClick(View v) {
           
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
            intent
.setPackage("com.google.zxing.client.android");
            // "SCAN_MODE" for all unknow code

            intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
            // use this method, can get the response by "onActivityResult( )"
            startActivityForResult(intent, 0);
       
}
    };
    // receive the result    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
       
if (requestCode == 0) // this line maybe can marked
           
if (resultCode == RESULT_OK) // -1
               
String contents = intent.getStringExtra("SCAN_RESULT");
               
String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
               
// Handle successful scan
           
} else if (resultCode == RESULT_CANCELED) // 0
               
// Handle cancel
           
}
       
}
    }

2011年4月25日 星期一

NMEA資訊

NMEA資訊
    // get location service
    LocationManager location = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    // set location update settings(time...)
     location.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,new LocationListener(){
        public void onLocationChanged(Location loc) {}
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status,Bundle extras) {}
    });
    // listen the NMEA information when change
    location.addNmeaListener(new NmeaListener() {
        public void onNmeaReceived(long timestamp, String nmea) {
            msg.append(nmea);
        }
    });

System Settings修改

System Settings修改
    // get screen off timeout time
    try {
        time = Settings.System.getInt(
            this.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT);
    } catch (SettingNotFoundException e) {
        e.printStackTrace();
    }
    // modify timeout time to 15 seconds
    Settings.System.putInt(
        this.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 15000);
    // modify rotation enable, 1: auto rotate on; 0: auto rotate off
    Settings.System.putInt(
        this.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1);
    // vibrator control
    vb = (Vibrator)getApplication().getSystemService(Service.VIBRATOR_SERVICE);
    vb.vibrate(1000*1000);    // parameter: vibrate time(ms)
    vb.cancel();    // stop

2011年4月21日 星期四

Load Image

Load Image
    String myJpgPath = "/sdcard/test2.jpg";
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 2;
    Bitmap bm = BitmapFactory.decodeFile(myJpgPath, options);
    jpgView.setImageBitmap(bm);

Notification

Notification
簡易範例
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
     
    Notification notification = new Notification();
    notification.defaults |= Notification.DEFAULT_VIBRATE;
    mNotificationManager.notify(123, notification);

2011年4月20日 星期三

Light感測器

Light感測器
    public void onCreate(Bundle savedInstanceState) {
        ................
        // get reference to SensorManager
        SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
        Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT);
        sm.registerListener(lsn, sensor, SensorManager.SENSOR_LIGHT);
    }

    SensorEventListener lsn = new SensorEventListener() {
        public void onAccuracyChanged(Sensor sensor, int accuracy) { }

        public void onSensorChanged(SensorEvent event) {
            // light sensor informations
            cloudy.setText(String.valueOf(SensorManager.LIGHT_CLOUDY));
            fullmoon.setText(String.valueOf(SensorManager.LIGHT_FULLMOON));
            no_moon.setText(String.valueOf(SensorManager.LIGHT_NO_MOON));
            overcast.setText(String.valueOf(SensorManager.LIGHT_OVERCAST));
            shade.setText(String.valueOf(SensorManager.LIGHT_SHADE));
            sunlight.setText(String.valueOf(SensorManager.LIGHT_SUNLIGHT));
            sunlight_max.setText(String.valueOf(SensorManager.LIGHT_SUNLIGHT_MAX));
            sunrise.setText(String.valueOf(SensorManager.LIGHT_SUNRISE));
            // light sensor values
            txtMsg.setText("Ambient light level = " + event.values[0] + " lux");
        }
    };

FingerPaint功能

FingerPaint功能
下面為一繪圖的範例
    public class Project1 extends Activity {
        private Bitmap  mBitmap;
        private MyView mView;

        public void onCreate (Bundle bundle) {
            super.onCreate(bundle);
            // remove the title, and display "full screen"
            this.requestWindowFeature(Window.FEATURE_NO_TITLE);
            this.getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
            // get the windows resolution, for bitmap use
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            // create a new bitmap for paint
            mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
            // use "MyView" class, this is define by author
            mView = new MyView(this);
            setContentView(mView);
        }

        private class MyView extends View {
            private Canvas mCanvas;
            private Path mPath;
            private Paint mBitmapPaint;
            private Paint mPaint;

            private float new_x, new_y;
            private float old_x, old_y;

            public MyView(Context context) {
                super(context);
                // create and initial object
                mCanvas = new Canvas(mBitmap);
                mPath = new Path();
                mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        
                mPaint = new Paint();
                // make paint more smooth
                mPaint.setAntiAlias(true);
                mPaint.setDither(true);
                // (1.FILL 2.FILL_AND_STROKE 3.STROKE)
                mPaint.setStyle(Paint.Style.STROKE);
                // (1.BEVEL 2.MITER 3.ROUND) default is MITER
                mPaint.setStrokeJoin(Paint.Join.ROUND);
                // (1.BUTT 2.ROUND 3.SQUARE) default is BUIT
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                // if set "0", will be a line
                mPaint.setStrokeWidth(12);
                mPaint.setColor(Color.GREEN);
            }
    
            protected void onDraw(Canvas canvas) {
                // set background color
                canvas.drawColor(Color.WHITE);
                // draw the specified bitmap
                canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
                // the path will be filled or framed based on the Style in the paint
                canvas.drawPath(mPath, mPaint);
            }
 
            public boolean onTouchEvent(MotionEvent event) {
                new_x = event.getX();
                new_y = event.getY();
      
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    // save the previous path, then reset the path
                    mPath.reset();
                    // start position
                    mPath.moveTo(new_x, new_y);
                    old_x = new_x;
                    old_y = new_y;
                }
                else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                    float dx = Math.abs(new_x - old_x);
                    float dy = Math.abs(new_y - old_y);
          
                    if (dx >= 4 || dy >= 4) {
                        // set path from (old_x, old_y) to ((new_x + old_x)/2, (new_y + old_y)/2)
                        mPath.quadTo(old_x, old_y, (new_x + old_x)/2, (new_y + old_y)/2);
                        old_x = new_x;
                        old_y = new_y;
                    }
                }
                else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // unknown, this line like no used
                    mPath.lineTo(old_x, old_y);
                    // paint the path when "ACTION_UP"
                    mCanvas.drawPath(mPath, mPaint);
                    // save the paint
                    mPath.reset();
                }
      
                // update the paint, it will recall the onDraw function
                invalidate();
                return true;
            }
        }
    }